diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/Windows/FileFind.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/Windows/FileFind.cpp | 605 |
1 files changed, 361 insertions, 244 deletions
diff --git a/src/libs/7zip/win/CPP/Windows/FileFind.cpp b/src/libs/7zip/win/CPP/Windows/FileFind.cpp index e3358f905..7f58288fe 100644 --- a/src/libs/7zip/win/CPP/Windows/FileFind.cpp +++ b/src/libs/7zip/win/CPP/Windows/FileFind.cpp @@ -4,6 +4,7 @@ #include "FileFind.h" #include "FileIO.h" +#include "FileName.h" #ifndef _UNICODE #include "../Common/StringConvert.h" #endif @@ -12,45 +13,55 @@ extern bool g_IsNT; #endif -namespace NWindows { -namespace NFile { +using namespace NWindows; +using namespace NFile; +using namespace NName; -#ifdef SUPPORT_DEVICE_FILE -bool IsDeviceName(LPCTSTR n); -#ifndef _UNICODE -bool IsDeviceName(LPCWSTR n); -#endif -#endif +#if defined(_WIN32) && !defined(UNDER_CE) -#if defined(WIN_LONG_PATH) && defined(_UNICODE) -#define WIN_LONG_PATH2 -#endif +EXTERN_C_BEGIN + +typedef enum +{ + My_FindStreamInfoStandard, + My_FindStreamInfoMaxInfoLevel +} MY_STREAM_INFO_LEVELS; + +typedef struct +{ + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; +} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; -bool GetLongPath(LPCWSTR fileName, UString &res); +typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, + LPVOID findStreamData, DWORD flags); -namespace NFind { +typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); -static const TCHAR kDot = TEXT('.'); +EXTERN_C_END -bool CFileInfo::IsDots() const +#endif + +namespace NWindows { +namespace NFile { + +#ifdef SUPPORT_DEVICE_FILE +namespace NSystem { - if (!IsDir() || Name.IsEmpty()) - return false; - if (Name[0] != kDot) - return false; - return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } +#endif -#ifndef _UNICODE -bool CFileInfoW::IsDots() const +namespace NFind { + +bool CFileInfo::IsDots() const throw() { if (!IsDir() || Name.IsEmpty()) return false; - if (Name[0] != kDot) + if (Name[0] != FTEXT('.')) return false; - return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); + return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == FTEXT('.')); } -#endif #define WIN_FD_TO_MY_FI(fi, fd) \ fi.Attrib = fd.dwFileAttributes; \ @@ -58,6 +69,7 @@ bool CFileInfoW::IsDots() const fi.ATime = fd.ftLastAccessTime; \ fi.MTime = fd.ftLastWriteTime; \ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ + fi.IsAltStream = false; \ fi.IsDevice = false; /* @@ -68,33 +80,31 @@ bool CFileInfoW::IsDots() const #endif */ -static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) +static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); - fi.Name = fd.cFileName; + fi.Name = us2fs(fd.cFileName); + #if defined(_WIN32) && !defined(UNDER_CE) + // fi.ShortName = us2fs(fd.cAlternateFileName); + #endif } #ifndef _UNICODE -static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } - -static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfoW &fi) -{ - WIN_FD_TO_MY_FI(fi, fd); - fi.Name = fd.cFileName; -} - -static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfoW &fi) +static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); - fi.Name = GetUnicodeString(fd.cFileName, GetCurrentCodePage()); + fi.Name = fas2fs(fd.cFileName); + #if defined(_WIN32) && !defined(UNDER_CE) + // fi.ShortName = fas2fs(fd.cAlternateFileName); + #endif } #endif - + //////////////////////////////// // CFindFile -bool CFindFile::Close() +bool CFindFileBase::Close() throw() { if (_handle == INVALID_HANDLE_VALUE) return true; @@ -104,183 +114,344 @@ bool CFindFile::Close() return true; } - -bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fi) +bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) { if (!Close()) return false; - WIN32_FIND_DATA fd; - _handle = ::FindFirstFile(wildcard, &fd); - #ifdef WIN_LONG_PATH2 - if (_handle == INVALID_HANDLE_VALUE) + #ifndef _UNICODE + if (!g_IsNT) { - UString longPath; - if (GetLongPath(wildcard, longPath)) - _handle = ::FindFirstFileW(longPath, &fd); + WIN32_FIND_DATAA fd; + _handle = ::FindFirstFileA(fs2fas(path), &fd); + if (_handle == INVALID_HANDLE_VALUE) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } + else #endif - if (_handle == INVALID_HANDLE_VALUE) - return false; - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); - return true; -} - -#ifndef _UNICODE -bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fi) -{ - if (!Close()) - return false; - if (g_IsNT) { WIN32_FIND_DATAW fd; - _handle = ::FindFirstFileW(wildcard, &fd); + + IF_USE_MAIN_PATH + _handle = ::FindFirstFileW(fs2us(path), &fd); #ifdef WIN_LONG_PATH - if (_handle == INVALID_HANDLE_VALUE) + if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString longPath; - if (GetLongPath(wildcard, longPath)) + if (GetSuperPath(path, longPath, USE_MAIN_PATH)) _handle = ::FindFirstFileW(longPath, &fd); } #endif - if (_handle != INVALID_HANDLE_VALUE) - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); + if (_handle == INVALID_HANDLE_VALUE) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } - else + return true; +} + +bool CFindFile::FindNext(CFileInfo &fi) +{ + #ifndef _UNICODE + if (!g_IsNT) { WIN32_FIND_DATAA fd; - _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, - GetCurrentCodePage()), &fd); - if (_handle != INVALID_HANDLE_VALUE) - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); + if (!::FindNextFileA(_handle, &fd)) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); } - return (_handle != INVALID_HANDLE_VALUE); + else + #endif + { + WIN32_FIND_DATAW fd; + if (!::FindNextFileW(_handle, &fd)) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); + } + return true; } -#endif -bool CFindFile::FindNext(CFileInfo &fi) +#if defined(_WIN32) && !defined(UNDER_CE) + +//////////////////////////////// +// AltStreams + +static FindFirstStreamW_Ptr g_FindFirstStreamW; +static FindNextStreamW_Ptr g_FindNextStreamW; + +struct CFindStreamLoader { - WIN32_FIND_DATA fd; - bool result = BOOLToBool(::FindNextFile(_handle, &fd)); - if (result) - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); - return result; + CFindStreamLoader() + { + g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW"); + g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW"); + } +} g_FindStreamLoader; + +bool CStreamInfo::IsMainStream() const throw() +{ + return Name == L"::$DATA"; +}; + +UString CStreamInfo::GetReducedName() const +{ + UString s = Name; + if (s.Len() >= 6) + if (wcscmp(s.RightPtr(6), L":$DATA") == 0) + s.DeleteFrom(s.Len() - 6); + return s; } -#ifndef _UNICODE -bool CFindFile::FindNext(CFileInfoW &fi) +static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) +{ + si.Size = sd.StreamSize.QuadPart; + si.Name = sd.cStreamName; +} + +bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) { - if (g_IsNT) + if (!Close()) + return false; + if (!g_FindFirstStreamW) { - WIN32_FIND_DATAW fd; - if (!::FindNextFileW(_handle, &fd)) + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } + { + MY_WIN32_FIND_STREAM_DATA sd; + IF_USE_MAIN_PATH + _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0); + if (_handle == INVALID_HANDLE_VALUE) + { + if (::GetLastError() == ERROR_HANDLE_EOF) + return false; + // long name can be tricky for path like ".\dirName". + #ifdef WIN_LONG_PATH + if (USE_SUPER_PATH) + { + UString longPath; + if (GetSuperPath(path, longPath, USE_MAIN_PATH)) + _handle = g_FindFirstStreamW(longPath, My_FindStreamInfoStandard, &sd, 0); + } + #endif + } + if (_handle == INVALID_HANDLE_VALUE) return false; - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); + Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); } - else + return true; +} + +bool CFindStream::FindNext(CStreamInfo &si) +{ + if (!g_FindNextStreamW) { - WIN32_FIND_DATAA fd; - if (!::FindNextFileA(_handle, &fd)) + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } + { + MY_WIN32_FIND_STREAM_DATA sd; + if (!g_FindNextStreamW(_handle, &sd)) return false; - ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); + Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); } return true; } + +bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) +{ + bool res; + if (_find.IsHandleAllocated()) + res = _find.FindNext(si); + else + res = _find.FindFirst(_filePath, si); + if (res) + { + found = true; + return true; + } + found = false; + return (::GetLastError() == ERROR_HANDLE_EOF); +} + #endif + #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; -void CFileInfoBase::Clear() +void CFileInfoBase::Clear() throw() { Size = 0; MY_CLEAR_FILETIME(CTime); MY_CLEAR_FILETIME(ATime); MY_CLEAR_FILETIME(MTime); Attrib = 0; + IsAltStream = false; + IsDevice = false; } - -bool CFileInfo::Find(LPCTSTR wildcard) + +#if defined(_WIN32) && !defined(UNDER_CE) + +static int FindAltStreamColon(CFSTR path) { - #ifdef SUPPORT_DEVICE_FILE - if (IsDeviceName(wildcard)) + for (int i = 0;; i++) { - Clear(); - IsDevice = true; - NIO::CInFile inFile; - if (!inFile.Open(wildcard)) - return false; - Name = wildcard + 4; - if (inFile.LengthDefined) - Size = inFile.Length; - return true; + FChar c = path[i]; + if (c == 0) + return -1; + if (c == ':') + { + if (path[i + 1] == '\\') + if (i == 1 || (i > 1 && path[i - 2] == '\\')) + { + wchar_t c0 = path[i - 1]; + if (c0 >= 'a' && c0 <= 'z' || + c0 >= 'A' && c0 <= 'Z') + continue; + } + return i; + } } - #endif - CFindFile finder; - return finder.FindFirst(wildcard, *this); } +#endif -#ifndef _UNICODE -bool CFileInfoW::Find(LPCWSTR wildcard) +bool CFileInfo::Find(CFSTR path) { #ifdef SUPPORT_DEVICE_FILE - if (IsDeviceName(wildcard)) + if (IsDevicePath(path)) { Clear(); + Name = path + 4; + IsDevice = true; + if (/* path[0] == '\\' && path[1] == '\\' && path[2] == '.' && path[3] == '\\' && */ + path[5] == ':' && path[6] == 0) + { + FChar drive[4] = { path[4], ':', '\\', 0 }; + UInt64 clusterSize, totalSize, freeSize; + if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) + { + Size = totalSize; + return true; + } + } + NIO::CInFile inFile; - if (!inFile.Open(wildcard)) + // ::OutputDebugStringW(path); + if (!inFile.Open(path)) return false; - Name = wildcard + 4; - if (inFile.LengthDefined) - Size = inFile.Length; + // ::OutputDebugStringW(L"---"); + if (inFile.SizeDefined) + Size = inFile.Size; return true; } #endif + + #if defined(_WIN32) && !defined(UNDER_CE) + + int colonPos = FindAltStreamColon(path); + if (colonPos >= 0) + { + UString streamName = fs2us(path + (unsigned)colonPos); + FString filePath = path; + filePath.DeleteFrom(colonPos); + streamName += L":$DATA"; // change it!!!! + if (Find(filePath)) + { + // if (IsDir()) + Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; + Size = 0; + CStreamEnumerator enumerator(filePath); + for (;;) + { + CStreamInfo si; + bool found; + if (!enumerator.Next(si, found)) + return false; + if (!found) + { + ::SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } + if (si.Name.IsEqualToNoCase(streamName)) + { + Name += us2fs(si.Name); + Name.DeleteFrom(Name.Len() - 6); + Size = si.Size; + IsAltStream = true; + return true; + } + } + } + } + + #endif + CFindFile finder; - return finder.FindFirst(wildcard, *this); + if (finder.FindFirst(path, *this)) + return true; + #ifdef _WIN32 + { + DWORD lastError = GetLastError(); + if (lastError == ERROR_BAD_NETPATH || + lastError == ERROR_FILE_NOT_FOUND || + lastError == ERROR_INVALID_NAME // for "\\SERVER\shared" paths that are translated to "\\?\UNC\SERVER\shared" + ) + { + unsigned len = MyStringLen(path); + if (len > 2 && path[0] == '\\' && path[1] == '\\') + { + int startPos = 2; + if (len > kSuperUncPathPrefixSize && IsSuperUncPath(path)) + startPos = kSuperUncPathPrefixSize; + int pos = FindCharPosInString(path + startPos, FTEXT('\\')); + if (pos >= 0) + { + pos += startPos + 1; + len -= pos; + int pos2 = FindCharPosInString(path + pos, FTEXT('\\')); + if (pos2 < 0 || pos2 == (int)len - 1) + { + FString s = path; + if (pos2 < 0) + { + pos2 = len; + s += FTEXT('\\'); + } + s += FCHAR_ANY_MASK; + if (finder.FindFirst(s, *this)) + if (Name == FTEXT(".")) + { + Name.SetFrom(s.Ptr(pos), pos2); + return true; + } + ::SetLastError(lastError); + } + } + } + } + } + #endif + return false; } -#endif -bool DoesFileExist(LPCTSTR name) +bool DoesFileExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && !fi.IsDir(); } -bool DoesDirExist(LPCTSTR name) +bool DoesDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name) && fi.IsDir(); } - -bool DoesFileOrDirExist(LPCTSTR name) +bool DoesFileOrDirExist(CFSTR name) { CFileInfo fi; return fi.Find(name); } -#ifndef _UNICODE -bool DoesFileExist(LPCWSTR name) -{ - CFileInfoW fi; - return fi.Find(name) && !fi.IsDir(); -} - -bool DoesDirExist(LPCWSTR name) -{ - CFileInfoW fi; - return fi.Find(name) && fi.IsDir(); -} -bool DoesFileOrDirExist(LPCWSTR name) -{ - CFileInfoW fi; - return fi.Find(name); -} -#endif - -///////////////////////////////////// -// CEnumerator - bool CEnumerator::NextAny(CFileInfo &fi) { if (_findFile.IsHandleAllocated()) @@ -311,44 +482,11 @@ bool CEnumerator::Next(CFileInfo &fi, bool &found) return (::GetLastError() == ERROR_NO_MORE_FILES); } -#ifndef _UNICODE -bool CEnumeratorW::NextAny(CFileInfoW &fi) -{ - if (_findFile.IsHandleAllocated()) - return _findFile.FindNext(fi); - else - return _findFile.FindFirst(_wildcard, fi); -} - -bool CEnumeratorW::Next(CFileInfoW &fi) -{ - for (;;) - { - if (!NextAny(fi)) - return false; - if (!fi.IsDots()) - return true; - } -} - -bool CEnumeratorW::Next(CFileInfoW &fi, bool &found) -{ - if (Next(fi)) - { - found = true; - return true; - } - found = false; - return (::GetLastError() == ERROR_NO_MORE_FILES); -} - -#endif - //////////////////////////////// // CFindChangeNotification // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. -bool CFindChangeNotification::Close() +bool CFindChangeNotification::Close() throw() { if (!IsHandleAllocated()) return true; @@ -357,105 +495,84 @@ bool CFindChangeNotification::Close() _handle = INVALID_HANDLE_VALUE; return true; } - -HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter) -{ - _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter); - #ifdef WIN_LONG_PATH2 - if (!IsHandleAllocated()) - { - UString longPath; - if (GetLongPath(pathName, longPath)) - _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); - } - #endif - return _handle; -} -#ifndef _UNICODE -HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter) +HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter) { + #ifndef _UNICODE if (!g_IsNT) - return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); - _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter); - #ifdef WIN_LONG_PATH - if (!IsHandleAllocated()) + _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter); + else + #endif { - UString longPath; - if (GetLongPath(pathName, longPath)) - _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); + IF_USE_MAIN_PATH + _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); + #ifdef WIN_LONG_PATH + if (!IsHandleAllocated()) + { + UString longPath; + if (GetSuperPath(path, longPath, USE_MAIN_PATH)) + _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); + } + #endif } - #endif return _handle; } -#endif #ifndef UNDER_CE -bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) + +bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings) { driveStrings.Clear(); - UINT32 size = GetLogicalDriveStrings(0, NULL); - if (size == 0) - return false; - CSysString buffer; - UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); - if (newSize == 0) - return false; - if (newSize > size) - return false; - CSysString string; - for (UINT32 i = 0; i < newSize; i++) + #ifndef _UNICODE + if (!g_IsNT) { - TCHAR c = buffer[i]; - if (c == TEXT('\0')) + driveStrings.Clear(); + UINT32 size = GetLogicalDriveStrings(0, NULL); + if (size == 0) + return false; + AString buf; + UINT32 newSize = GetLogicalDriveStrings(size, buf.GetBuffer(size)); + if (newSize == 0 || newSize > size) + return false; + AString s; + for (UINT32 i = 0; i < newSize; i++) { - driveStrings.Add(string); - string.Empty(); + char c = buf[i]; + if (c == '\0') + { + driveStrings.Add(fas2fs(s)); + s.Empty(); + } + else + s += c; } - else - string += c; + return s.IsEmpty(); } - if (!string.IsEmpty()) - return false; - return true; -} - -#ifndef _UNICODE -bool MyGetLogicalDriveStrings(UStringVector &driveStrings) -{ - driveStrings.Clear(); - if (g_IsNT) + else + #endif { UINT32 size = GetLogicalDriveStringsW(0, NULL); if (size == 0) return false; - UString buffer; - UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); - if (newSize == 0) - return false; - if (newSize > size) + UString buf; + UINT32 newSize = GetLogicalDriveStringsW(size, buf.GetBuffer(size)); + if (newSize == 0 || newSize > size) return false; - UString string; + UString s; for (UINT32 i = 0; i < newSize; i++) { - WCHAR c = buffer[i]; + WCHAR c = buf[i]; if (c == L'\0') { - driveStrings.Add(string); - string.Empty(); + driveStrings.Add(us2fs(s)); + s.Empty(); } else - string += c; + s += c; } - return string.IsEmpty(); + return s.IsEmpty(); } - CSysStringVector driveStringsA; - bool res = MyGetLogicalDriveStrings(driveStringsA); - for (int i = 0; i < driveStringsA.Size(); i++) - driveStrings.Add(GetUnicodeString(driveStringsA[i])); - return res; } -#endif #endif |