rlm@1: // Windows/FileFind.cpp rlm@1: rlm@1: #include "StdAfx.h" rlm@1: rlm@1: #include "FileFind.h" rlm@1: #ifndef _UNICODE rlm@1: #include "../Common/StringConvert.h" rlm@1: #endif rlm@1: rlm@1: #ifndef _UNICODE rlm@1: extern bool g_IsNT; rlm@1: #endif rlm@1: rlm@1: namespace NWindows { rlm@1: namespace NFile { rlm@1: rlm@1: #if defined(WIN_LONG_PATH) && defined(_UNICODE) rlm@1: #define WIN_LONG_PATH2 rlm@1: #endif rlm@1: rlm@1: bool GetLongPath(LPCWSTR fileName, UString &res); rlm@1: rlm@1: namespace NFind { rlm@1: rlm@1: static const TCHAR kDot = TEXT('.'); rlm@1: rlm@1: bool CFileInfo::IsDots() const rlm@1: { rlm@1: if (!IsDir() || Name.IsEmpty()) rlm@1: return false; rlm@1: if (Name[0] != kDot) rlm@1: return false; rlm@1: return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool CFileInfoW::IsDots() const rlm@1: { rlm@1: if (!IsDir() || Name.IsEmpty()) rlm@1: return false; rlm@1: if (Name[0] != kDot) rlm@1: return false; rlm@1: return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); rlm@1: } rlm@1: #endif rlm@1: rlm@1: static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) rlm@1: { rlm@1: fi.Attrib = fd.dwFileAttributes; rlm@1: fi.CTime = fd.ftCreationTime; rlm@1: fi.ATime = fd.ftLastAccessTime; rlm@1: fi.MTime = fd.ftLastWriteTime; rlm@1: fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; rlm@1: fi.Name = fd.cFileName; rlm@1: #ifndef _WIN32_WCE rlm@1: fi.ReparseTag = fd.dwReserved0; rlm@1: #else rlm@1: fi.ObjectID = fd.dwOID; rlm@1: #endif rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: rlm@1: static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } rlm@1: rlm@1: static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfoW &fi) rlm@1: { rlm@1: fi.Attrib = fd.dwFileAttributes; rlm@1: fi.CTime = fd.ftCreationTime; rlm@1: fi.ATime = fd.ftLastAccessTime; rlm@1: fi.MTime = fd.ftLastWriteTime; rlm@1: fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; rlm@1: fi.Name = fd.cFileName; rlm@1: #ifndef _WIN32_WCE rlm@1: fi.ReparseTag = fd.dwReserved0; rlm@1: #else rlm@1: fi.ObjectID = fd.dwOID; rlm@1: #endif rlm@1: } rlm@1: rlm@1: static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfoW &fi) rlm@1: { rlm@1: fi.Attrib = fd.dwFileAttributes; rlm@1: fi.CTime = fd.ftCreationTime; rlm@1: fi.ATime = fd.ftLastAccessTime; rlm@1: fi.MTime = fd.ftLastWriteTime; rlm@1: fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; rlm@1: fi.Name = GetUnicodeString(fd.cFileName, GetCurrentCodePage()); rlm@1: #ifndef _WIN32_WCE rlm@1: fi.ReparseTag = fd.dwReserved0; rlm@1: #else rlm@1: fi.ObjectID = fd.dwOID; rlm@1: #endif rlm@1: } rlm@1: #endif rlm@1: rlm@1: //////////////////////////////// rlm@1: // CFindFile rlm@1: rlm@1: bool CFindFile::Close() rlm@1: { rlm@1: if (_handle == INVALID_HANDLE_VALUE) rlm@1: return true; rlm@1: if (!::FindClose(_handle)) rlm@1: return false; rlm@1: _handle = INVALID_HANDLE_VALUE; rlm@1: return true; rlm@1: } rlm@1: rlm@1: rlm@1: bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo) rlm@1: { rlm@1: if (!Close()) rlm@1: return false; rlm@1: WIN32_FIND_DATA fd; rlm@1: _handle = ::FindFirstFile(wildcard, &fd); rlm@1: #ifdef WIN_LONG_PATH2 rlm@1: if (_handle == INVALID_HANDLE_VALUE) rlm@1: { rlm@1: UString longPath; rlm@1: if (GetLongPath(wildcard, longPath)) rlm@1: _handle = ::FindFirstFileW(longPath, &fd); rlm@1: } rlm@1: #endif rlm@1: if (_handle == INVALID_HANDLE_VALUE) rlm@1: return false; rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: return true; rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo) rlm@1: { rlm@1: if (!Close()) rlm@1: return false; rlm@1: if (g_IsNT) rlm@1: { rlm@1: WIN32_FIND_DATAW fd; rlm@1: _handle = ::FindFirstFileW(wildcard, &fd); rlm@1: #ifdef WIN_LONG_PATH rlm@1: if (_handle == INVALID_HANDLE_VALUE) rlm@1: { rlm@1: UString longPath; rlm@1: if (GetLongPath(wildcard, longPath)) rlm@1: _handle = ::FindFirstFileW(longPath, &fd); rlm@1: } rlm@1: #endif rlm@1: if (_handle != INVALID_HANDLE_VALUE) rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: } rlm@1: else rlm@1: { rlm@1: WIN32_FIND_DATAA fd; rlm@1: _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, rlm@1: GetCurrentCodePage()), &fd); rlm@1: if (_handle != INVALID_HANDLE_VALUE) rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: } rlm@1: return (_handle != INVALID_HANDLE_VALUE); rlm@1: } rlm@1: #endif rlm@1: rlm@1: bool CFindFile::FindNext(CFileInfo &fileInfo) rlm@1: { rlm@1: WIN32_FIND_DATA fd; rlm@1: bool result = BOOLToBool(::FindNextFile(_handle, &fd)); rlm@1: if (result) rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: return result; rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool CFindFile::FindNext(CFileInfoW &fileInfo) rlm@1: { rlm@1: if (g_IsNT) rlm@1: { rlm@1: WIN32_FIND_DATAW fd; rlm@1: if (!::FindNextFileW(_handle, &fd)) rlm@1: return false; rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: } rlm@1: else rlm@1: { rlm@1: WIN32_FIND_DATAA fd; rlm@1: if (!::FindNextFileA(_handle, &fd)) rlm@1: return false; rlm@1: ConvertWIN32_FIND_DATA_To_FileInfo(fd, fileInfo); rlm@1: } rlm@1: return true; rlm@1: } rlm@1: #endif rlm@1: rlm@1: bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo) rlm@1: { rlm@1: CFindFile finder; rlm@1: return finder.FindFirst(wildcard, fileInfo); rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo) rlm@1: { rlm@1: CFindFile finder; rlm@1: return finder.FindFirst(wildcard, fileInfo); rlm@1: } rlm@1: #endif rlm@1: rlm@1: bool DoesFileExist(LPCTSTR name) rlm@1: { rlm@1: CFileInfo fileInfo; rlm@1: return FindFile(name, fileInfo); rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool DoesFileExist(LPCWSTR name) rlm@1: { rlm@1: CFileInfoW fileInfo; rlm@1: return FindFile(name, fileInfo); rlm@1: } rlm@1: #endif rlm@1: rlm@1: ///////////////////////////////////// rlm@1: // CEnumerator rlm@1: rlm@1: bool CEnumerator::NextAny(CFileInfo &fileInfo) rlm@1: { rlm@1: if (_findFile.IsHandleAllocated()) rlm@1: return _findFile.FindNext(fileInfo); rlm@1: else rlm@1: return _findFile.FindFirst(_wildcard, fileInfo); rlm@1: } rlm@1: rlm@1: bool CEnumerator::Next(CFileInfo &fileInfo) rlm@1: { rlm@1: for (;;) rlm@1: { rlm@1: if (!NextAny(fileInfo)) rlm@1: return false; rlm@1: if (!fileInfo.IsDots()) rlm@1: return true; rlm@1: } rlm@1: } rlm@1: rlm@1: bool CEnumerator::Next(CFileInfo &fileInfo, bool &found) rlm@1: { rlm@1: if (Next(fileInfo)) rlm@1: { rlm@1: found = true; rlm@1: return true; rlm@1: } rlm@1: found = false; rlm@1: return (::GetLastError() == ERROR_NO_MORE_FILES); rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool CEnumeratorW::NextAny(CFileInfoW &fileInfo) rlm@1: { rlm@1: if (_findFile.IsHandleAllocated()) rlm@1: return _findFile.FindNext(fileInfo); rlm@1: else rlm@1: return _findFile.FindFirst(_wildcard, fileInfo); rlm@1: } rlm@1: rlm@1: bool CEnumeratorW::Next(CFileInfoW &fileInfo) rlm@1: { rlm@1: for (;;) rlm@1: { rlm@1: if (!NextAny(fileInfo)) rlm@1: return false; rlm@1: if (!fileInfo.IsDots()) rlm@1: return true; rlm@1: } rlm@1: } rlm@1: rlm@1: bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found) rlm@1: { rlm@1: if (Next(fileInfo)) rlm@1: { rlm@1: found = true; rlm@1: return true; rlm@1: } rlm@1: found = false; rlm@1: return (::GetLastError() == ERROR_NO_MORE_FILES); rlm@1: } rlm@1: rlm@1: #endif rlm@1: rlm@1: //////////////////////////////// rlm@1: // CFindChangeNotification rlm@1: // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. rlm@1: rlm@1: bool CFindChangeNotification::Close() rlm@1: { rlm@1: if (!IsHandleAllocated()) rlm@1: return true; rlm@1: if (!::FindCloseChangeNotification(_handle)) rlm@1: return false; rlm@1: _handle = INVALID_HANDLE_VALUE; rlm@1: return true; rlm@1: } rlm@1: rlm@1: HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter) rlm@1: { rlm@1: _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter); rlm@1: #ifdef WIN_LONG_PATH2 rlm@1: if (!IsHandleAllocated()) rlm@1: { rlm@1: UString longPath; rlm@1: if (GetLongPath(pathName, longPath)) rlm@1: _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); rlm@1: } rlm@1: #endif rlm@1: return _handle; rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter) rlm@1: { rlm@1: if (!g_IsNT) rlm@1: return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); rlm@1: _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter); rlm@1: #ifdef WIN_LONG_PATH rlm@1: if (!IsHandleAllocated()) rlm@1: { rlm@1: UString longPath; rlm@1: if (GetLongPath(pathName, longPath)) rlm@1: _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); rlm@1: } rlm@1: #endif rlm@1: return _handle; rlm@1: } rlm@1: #endif rlm@1: rlm@1: #ifndef _WIN32_WCE rlm@1: bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) rlm@1: { rlm@1: driveStrings.Clear(); rlm@1: UINT32 size = GetLogicalDriveStrings(0, NULL); rlm@1: if (size == 0) rlm@1: return false; rlm@1: CSysString buffer; rlm@1: UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); rlm@1: if (newSize == 0) rlm@1: return false; rlm@1: if (newSize > size) rlm@1: return false; rlm@1: CSysString string; rlm@1: for (UINT32 i = 0; i < newSize; i++) rlm@1: { rlm@1: TCHAR c = buffer[i]; rlm@1: if (c == TEXT('\0')) rlm@1: { rlm@1: driveStrings.Add(string); rlm@1: string.Empty(); rlm@1: } rlm@1: else rlm@1: string += c; rlm@1: } rlm@1: if (!string.IsEmpty()) rlm@1: return false; rlm@1: return true; rlm@1: } rlm@1: rlm@1: #ifndef _UNICODE rlm@1: bool MyGetLogicalDriveStrings(UStringVector &driveStrings) rlm@1: { rlm@1: driveStrings.Clear(); rlm@1: if (g_IsNT) rlm@1: { rlm@1: UINT32 size = GetLogicalDriveStringsW(0, NULL); rlm@1: if (size == 0) rlm@1: return false; rlm@1: UString buffer; rlm@1: UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); rlm@1: if (newSize == 0) rlm@1: return false; rlm@1: if (newSize > size) rlm@1: return false; rlm@1: UString string; rlm@1: for (UINT32 i = 0; i < newSize; i++) rlm@1: { rlm@1: WCHAR c = buffer[i]; rlm@1: if (c == L'\0') rlm@1: { rlm@1: driveStrings.Add(string); rlm@1: string.Empty(); rlm@1: } rlm@1: else rlm@1: string += c; rlm@1: } rlm@1: return string.IsEmpty(); rlm@1: } rlm@1: CSysStringVector driveStringsA; rlm@1: bool res = MyGetLogicalDriveStrings(driveStringsA); rlm@1: for (int i = 0; i < driveStringsA.Size(); i++) rlm@1: driveStrings.Add(GetUnicodeString(driveStringsA[i])); rlm@1: return res; rlm@1: } rlm@1: #endif rlm@1: rlm@1: #endif rlm@1: rlm@1: }}}