summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/unix/CPP/Windows/FileFind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/unix/CPP/Windows/FileFind.cpp')
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileFind.cpp604
1 files changed, 604 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/Windows/FileFind.cpp b/src/libs/7zip/unix/CPP/Windows/FileFind.cpp
new file mode 100644
index 000000000..9e526a233
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileFind.cpp
@@ -0,0 +1,604 @@
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+#include "FileFind.h"
+#include "../Common/StringConvert.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef ENV_HAVE_LSTAT
+extern "C"
+{
+
+int global_use_lstat=1; // default behaviour : p7zip stores symlinks instead of dumping the files they point to
+}
+#endif
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+void my_windows_split_path(const AString &p_path, AString &dir , AString &base) {
+ int pos = p_path.ReverseFind('/');
+ if (pos == -1) {
+ // no separator
+ dir = ".";
+ if (p_path.IsEmpty())
+ base = ".";
+ else
+ base = p_path;
+ } else if ((pos+1) < p_path.Length()) {
+ // true separator
+ base = p_path.Mid(pos+1);
+ while ((pos >= 1) && (p_path[pos-1] == '/'))
+ pos--;
+ if (pos == 0)
+ dir = "/";
+ else
+ dir = p_path.Left(pos);
+ } else {
+ // separator at the end of the path
+ // pos = p_path.find_last_not_of("/");
+ pos = -1;
+ int ind = 0;
+ while (p_path[ind]) {
+ if (p_path[ind] != '/')
+ pos = ind;
+ ind++;
+ }
+ if (pos == -1) {
+ base = "/";
+ dir = "/";
+ } else {
+ my_windows_split_path(p_path.Left(pos+1),dir,base);
+ }
+ }
+}
+
+static void my_windows_split_path(const UString &p_path, UString &dir , UString &base) {
+ int pos = p_path.ReverseFind(L'/');
+ if (pos == -1) {
+ // no separator
+ dir = L".";
+ if (p_path.IsEmpty())
+ base = L".";
+ else
+ base = p_path;
+ } else if ((pos+1) < p_path.Length()) {
+ // true separator
+ base = p_path.Mid(pos+1);
+ while ((pos >= 1) && (p_path[pos-1] == L'/'))
+ pos--;
+ if (pos == 0)
+ dir = L"/";
+ else
+ dir = p_path.Left(pos);
+ } else {
+ // separator at the end of the path
+ // pos = p_path.find_last_not_of("/");
+ pos = -1;
+ int ind = 0;
+ while (p_path[ind]) {
+ if (p_path[ind] != L'/')
+ pos = ind;
+ ind++;
+ }
+ if (pos == -1) {
+ base = L"/";
+ dir = L"/";
+ } else {
+ my_windows_split_path(p_path.Left(pos+1),dir,base);
+ }
+ }
+}
+
+static int filter_pattern(const char *string , const char *pattern , int flags_nocase) {
+ if ((string == 0) || (*string==0)) {
+ if (pattern == 0)
+ return 1;
+ while (*pattern=='*')
+ ++pattern;
+ return (!*pattern);
+ }
+
+ switch (*pattern) {
+ case '*':
+ if (!filter_pattern(string+1,pattern,flags_nocase))
+ return filter_pattern(string,pattern+1,flags_nocase);
+ return 1;
+ case 0:
+ if (*string==0)
+ return 1;
+ break;
+ case '?':
+ return filter_pattern(string+1,pattern+1,flags_nocase);
+ default:
+ if ( ((flags_nocase) && (tolower(*pattern)==tolower(*string)))
+ || (*pattern == *string)
+ ) {
+ return filter_pattern(string+1,pattern+1,flags_nocase);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+static const TCHAR kDot = TEXT('.');
+
+bool CFileInfo::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+bool CFileInfoW::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+static bool originalFilename(const UString & src, AString & res)
+{
+ // Try to recover the original filename
+ res = "";
+ int i=0;
+ while (src[i])
+ {
+ if (src[i] >= 256) {
+ return false;
+ } else {
+ res += char(src[i]);
+ }
+ i++;
+ }
+ return true;
+}
+
+
+
+// Warning this function cannot update "fileInfo.Name"
+static int fillin_CFileInfo(CFileInfo &fileInfo,const char *filename) {
+ struct stat stat_info;
+
+ int ret;
+#ifdef ENV_HAVE_LSTAT
+ if (global_use_lstat) {
+ ret = lstat(filename,&stat_info);
+ } else
+#endif
+ {
+ ret = stat(filename,&stat_info);
+ }
+
+ if (ret != 0) return ret;
+
+ /* FIXME : FILE_ATTRIBUTE_HIDDEN ? */
+ if (S_ISDIR(stat_info.st_mode)) {
+ fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ } else {
+ fileInfo.Attrib = FILE_ATTRIBUTE_ARCHIVE;
+ }
+
+ if (!(stat_info.st_mode & S_IWUSR))
+ fileInfo.Attrib |= FILE_ATTRIBUTE_READONLY;
+
+ fileInfo.Attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((stat_info.st_mode & 0xFFFF) << 16);
+
+ RtlSecondsSince1970ToFileTime( stat_info.st_ctime, &fileInfo.CTime );
+ RtlSecondsSince1970ToFileTime( stat_info.st_mtime, &fileInfo.MTime );
+ RtlSecondsSince1970ToFileTime( stat_info.st_atime, &fileInfo.ATime );
+
+ fileInfo.IsDevice = false;
+
+ if (S_ISDIR(stat_info.st_mode)) {
+ fileInfo.Size = 0;
+ } else { // file or symbolic link
+ fileInfo.Size = stat_info.st_size; // for a symbolic link, size = size of filename
+ }
+ return 0;
+}
+
+static int fillin_CFileInfo(CFileInfo &fileInfo,const char *dir,const char *name) {
+ char filename[MAX_PATHNAME_LEN];
+ size_t dir_len = strlen(dir);
+ size_t name_len = strlen(name);
+ size_t total = dir_len + 1 + name_len + 1; // 1 = strlen("/"); + le zero character
+ if (total >= MAX_PATHNAME_LEN) throw "fillin_CFileInfo - internal error - MAX_PATHNAME_LEN";
+ memcpy(filename,dir,dir_len);
+ if (dir_len >= 1)
+ {
+ if (filename[dir_len-1] == CHAR_PATH_SEPARATOR)
+ { // delete the '/'
+ dir_len--;
+ }
+ }
+ filename[dir_len] = CHAR_PATH_SEPARATOR;
+ memcpy(filename+(dir_len+1),name,name_len+1); // copy also final '\0'
+
+ fileInfo.Name = name;
+
+ int ret = fillin_CFileInfo(fileInfo,filename);
+ if (ret != 0) {
+ AString err_msg = "stat error for ";
+ err_msg += filename;
+ err_msg += " (";
+ err_msg += strerror(errno);
+ err_msg += ")";
+ throw err_msg;
+ }
+ return ret;
+}
+
+////////////////////////////////
+// CFindFile
+
+bool CFindFile::Close()
+{
+
+ if(_dirp == 0)
+ return true;
+ int ret = closedir(_dirp);
+ if (ret == 0)
+ {
+ _dirp = 0;
+ return true;
+ }
+ return false;
+}
+
+// bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo)
+bool CFindFile::FindFirst(LPCSTR wildcard, CFileInfo &fileInfo)
+{
+ if (!Close())
+ return false;
+
+ if ((!wildcard) || (wildcard[0]==0)) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return false;
+ }
+
+ my_windows_split_path(nameWindowToUnix(wildcard),_directory,_pattern);
+
+ TRACEN((printf("CFindFile::FindFirst : %s (dirname=%s,pattern=%s)\n",wildcard,(const char *)_directory,(const char *)_pattern)))
+
+ _dirp = ::opendir((const char *)_directory);
+ TRACEN((printf("CFindFile::FindFirst : opendir=%p\n",_dirp)))
+
+ if ((_dirp == 0) && (global_use_utf16_conversion)) {
+ // Try to recover the original filename
+ UString ustr = MultiByteToUnicodeString(_directory, 0);
+ AString resultString;
+ bool is_good = originalFilename(ustr, resultString);
+ if (is_good) {
+ _dirp = ::opendir((const char *)resultString);
+ _directory = resultString;
+ }
+ }
+
+ if (_dirp == 0) return false;
+
+ struct dirent *dp;
+ while ((dp = readdir(_dirp)) != NULL) {
+ if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) {
+ int retf = fillin_CFileInfo(fileInfo,(const char *)_directory,dp->d_name);
+ if (retf)
+ {
+ TRACEN((printf("CFindFile::FindFirst : closedir-1(dirp=%p)\n",_dirp)))
+ closedir(_dirp);
+ _dirp = 0;
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+ }
+ TRACEN((printf("CFindFile::FindFirst -%s- true\n",dp->d_name)))
+ return true;
+ }
+ }
+
+ TRACEN((printf("CFindFile::FindFirst : closedir-2(dirp=%p)\n",_dirp)))
+ closedir(_dirp);
+ _dirp = 0;
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+}
+
+bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+ if (!Close())
+ return false;
+ CFileInfo fileInfo0;
+ AString Awildcard = UnicodeStringToMultiByte(wildcard, CP_ACP);
+ bool bret = FindFirst((LPCSTR)Awildcard, fileInfo0);
+ if (bret)
+ {
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.IsDevice = fileInfo0.IsDevice;
+ fileInfo.Name = GetUnicodeString(fileInfo0.Name, CP_ACP);
+ }
+ return bret;
+}
+
+bool CFindFile::FindNext(CFileInfo &fileInfo)
+{
+ if (_dirp == 0)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ struct dirent *dp;
+ while ((dp = readdir(_dirp)) != NULL) {
+ if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) {
+ int retf = fillin_CFileInfo(fileInfo,(const char *)_directory,dp->d_name);
+ if (retf)
+ {
+ TRACEN((printf("FindNextFileA -%s- ret_handle=FALSE (errno=%d)\n",dp->d_name,errno)))
+ return false;
+
+ }
+ TRACEN((printf("FindNextFileA -%s- true\n",dp->d_name)))
+ return true;
+ }
+ }
+ TRACEN((printf("FindNextFileA ret_handle=FALSE (ERROR_NO_MORE_FILES)\n")))
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+}
+
+bool CFindFile::FindNext(CFileInfoW &fileInfo)
+{
+ CFileInfo fileInfo0;
+ bool bret = FindNext(fileInfo0);
+ if (bret)
+ {
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.IsDevice = fileInfo0.IsDevice;
+ fileInfo.Name = GetUnicodeString(fileInfo0.Name, CP_ACP);
+ }
+ return bret;
+}
+
+bool CFileInfo::Find(LPCSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+
+
+// #ifndef _UNICODE
+bool CFileInfoW::Find(LPCWSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+// #endif
+
+bool FindFile(LPCSTR wildcard, CFileInfo &fileInfo)
+{
+ // CFindFile finder;
+ // return finder.FindFirst(wildcard, fileInfo);
+ AString dir,base;
+ my_windows_split_path(wildcard, dir , base);
+ int ret = fillin_CFileInfo(fileInfo,nameWindowToUnix(wildcard));
+ fileInfo.Name = base;
+ TRACEN((printf("FindFile(%s,CFileInfo) ret=%d\n",wildcard,ret)))
+ return (ret == 0);
+}
+
+bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+ // CFindFile finder;
+ // return finder.FindFirst(wildcard, fileInfo);
+ AString name = UnicodeStringToMultiByte(wildcard, CP_ACP);
+ CFileInfo fileInfo0;
+ int ret = fillin_CFileInfo(fileInfo0,nameWindowToUnix((const char *)name));
+ TRACEN((printf("FindFile-1(%s,CFileInfo) ret=%d\n",(const char *)name,ret)))
+ if (ret != 0)
+ {
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(wildcard, resultString);
+ if (is_good) {
+ ret = fillin_CFileInfo(fileInfo0,nameWindowToUnix((const char *)resultString));
+ TRACEN((printf("FindFile-2(%s,CFileInfo) ret=%d\n",(const char *)resultString,ret)))
+ }
+ }
+ if (ret == 0)
+ {
+ UString dir,base;
+ my_windows_split_path(wildcard, dir , base);
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.Name = base;
+ }
+ return (ret == 0);
+}
+
+bool DoesFileExist(LPCSTR name) // FIXME
+{
+ CFileInfo fi;
+ int ret = fillin_CFileInfo(fi,nameWindowToUnix(name));
+ TRACEN((printf("DoesFileExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0) && !fi.IsDir();;
+}
+
+bool DoesDirExist(LPCSTR name) // FIXME
+{
+ CFileInfo fi;
+ int ret = fillin_CFileInfo(fi,nameWindowToUnix(name));
+ TRACEN((printf("DoesDirExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0) && fi.IsDir();;
+}
+
+bool DoesFileOrDirExist(LPCSTR name)
+{
+ CFileInfo fileInfo;
+ int ret = fillin_CFileInfo(fileInfo,nameWindowToUnix(name));
+ TRACEN((printf("DoesFileOrDirExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0);
+}
+
+bool DoesFileExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesFileExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesFileExist((const char *)resultString);
+ }
+ return bret;
+}
+
+bool DoesDirExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesDirExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesDirExist((const char *)resultString);
+ }
+ return bret;
+}
+
+bool DoesFileOrDirExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesFileOrDirExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesFileOrDirExist((const char *)resultString);
+ }
+ return bret;
+}
+
+/////////////////////////////////////
+// CEnumerator
+
+bool CEnumerator::NextAny(CFileInfo &fileInfo)
+{
+ if(_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fileInfo);
+ else
+ return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo)
+{
+ while(true)
+ {
+ if(!NextAny(fileInfo))
+ return false;
+ if(!fileInfo.IsDots())
+ return true;
+ }
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo, bool &found)
+{
+ if (Next(fileInfo))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+bool CEnumeratorW::NextAny(CFileInfoW &fileInfo)
+{
+ if(_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fileInfo);
+ else
+ return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo)
+{
+ while(true)
+ {
+ if(!NextAny(fileInfo))
+ return false;
+ if(!fileInfo.IsDots())
+ return true;
+ }
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found)
+{
+ if (Next(fileInfo))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+
+}}}