1 // Windows/FileFind.cpp 2 3 #include "StdAfx.h" 4 5 #include "FileFind.h" 6 #include "FileIO.h" 7 #ifndef _UNICODE 8 #include "../Common/StringConvert.h" 9 #endif 10 11 #ifndef _UNICODE 12 extern bool g_IsNT; 13 #endif 14 15 namespace NWindows { 16 namespace NFile { 17 18 #ifdef SUPPORT_DEVICE_FILE 19 bool IsDeviceName(LPCTSTR n); 20 #ifndef _UNICODE 21 bool IsDeviceName(LPCWSTR n); 22 #endif 23 #endif 24 25 #if defined(WIN_LONG_PATH) && defined(_UNICODE) 26 #define WIN_LONG_PATH2 27 #endif 28 29 bool GetLongPath(LPCWSTR fileName, UString &res); 30 31 namespace NFind { 32 33 static const TCHAR kDot = TEXT('.'); 34 35 bool CFileInfo::IsDots() const 36 { 37 if (!IsDir() || Name.IsEmpty()) 38 return false; 39 if (Name[0] != kDot) 40 return false; 41 return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); 42 } 43 44 #ifndef _UNICODE 45 bool CFileInfoW::IsDots() const 46 { 47 if (!IsDir() || Name.IsEmpty()) 48 return false; 49 if (Name[0] != kDot) 50 return false; 51 return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); 52 } 53 #endif 54 55 #define WIN_FD_TO_MY_FI(fi, fd) \ 56 fi.Attrib = fd.dwFileAttributes; \ 57 fi.CTime = fd.ftCreationTime; \ 58 fi.ATime = fd.ftLastAccessTime; \ 59 fi.MTime = fd.ftLastWriteTime; \ 60 fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ 61 fi.IsDevice = false; 62 63 /* 64 #ifdef UNDER_CE 65 fi.ObjectID = fd.dwOID; 66 #else 67 fi.ReparseTag = fd.dwReserved0; 68 #endif 69 */ 70 71 static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) 72 { 73 WIN_FD_TO_MY_FI(fi, fd); 74 fi.Name = fd.cFileName; 75 } 76 77 #ifndef _UNICODE 78 79 static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 80 81 static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfoW &fi) 82 { 83 WIN_FD_TO_MY_FI(fi, fd); 84 fi.Name = fd.cFileName; 85 } 86 87 static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfoW &fi) 88 { 89 WIN_FD_TO_MY_FI(fi, fd); 90 fi.Name = GetUnicodeString(fd.cFileName, GetCurrentCodePage()); 91 } 92 #endif 93 94 //////////////////////////////// 95 // CFindFile 96 97 bool CFindFile::Close() 98 { 99 if (_handle == INVALID_HANDLE_VALUE) 100 return true; 101 if (!::FindClose(_handle)) 102 return false; 103 _handle = INVALID_HANDLE_VALUE; 104 return true; 105 } 106 107 108 bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fi) 109 { 110 if (!Close()) 111 return false; 112 WIN32_FIND_DATA fd; 113 _handle = ::FindFirstFile(wildcard, &fd); 114 #ifdef WIN_LONG_PATH2 115 if (_handle == INVALID_HANDLE_VALUE) 116 { 117 UString longPath; 118 if (GetLongPath(wildcard, longPath)) 119 _handle = ::FindFirstFileW(longPath, &fd); 120 } 121 #endif 122 if (_handle == INVALID_HANDLE_VALUE) 123 return false; 124 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 125 return true; 126 } 127 128 #ifndef _UNICODE 129 bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fi) 130 { 131 if (!Close()) 132 return false; 133 if (g_IsNT) 134 { 135 WIN32_FIND_DATAW fd; 136 _handle = ::FindFirstFileW(wildcard, &fd); 137 #ifdef WIN_LONG_PATH 138 if (_handle == INVALID_HANDLE_VALUE) 139 { 140 UString longPath; 141 if (GetLongPath(wildcard, longPath)) 142 _handle = ::FindFirstFileW(longPath, &fd); 143 } 144 #endif 145 if (_handle != INVALID_HANDLE_VALUE) 146 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 147 } 148 else 149 { 150 WIN32_FIND_DATAA fd; 151 _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, 152 GetCurrentCodePage()), &fd); 153 if (_handle != INVALID_HANDLE_VALUE) 154 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 155 } 156 return (_handle != INVALID_HANDLE_VALUE); 157 } 158 #endif 159 160 bool CFindFile::FindNext(CFileInfo &fi) 161 { 162 WIN32_FIND_DATA fd; 163 bool result = BOOLToBool(::FindNextFile(_handle, &fd)); 164 if (result) 165 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 166 return result; 167 } 168 169 #ifndef _UNICODE 170 bool CFindFile::FindNext(CFileInfoW &fi) 171 { 172 if (g_IsNT) 173 { 174 WIN32_FIND_DATAW fd; 175 if (!::FindNextFileW(_handle, &fd)) 176 return false; 177 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 178 } 179 else 180 { 181 WIN32_FIND_DATAA fd; 182 if (!::FindNextFileA(_handle, &fd)) 183 return false; 184 ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi); 185 } 186 return true; 187 } 188 #endif 189 190 #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; 191 192 void CFileInfoBase::Clear() 193 { 194 Size = 0; 195 MY_CLEAR_FILETIME(CTime); 196 MY_CLEAR_FILETIME(ATime); 197 MY_CLEAR_FILETIME(MTime); 198 Attrib = 0; 199 } 200 201 bool CFileInfo::Find(LPCTSTR wildcard) 202 { 203 #ifdef SUPPORT_DEVICE_FILE 204 if (IsDeviceName(wildcard)) 205 { 206 Clear(); 207 IsDevice = true; 208 NIO::CInFile inFile; 209 if (!inFile.Open(wildcard)) 210 return false; 211 Name = wildcard + 4; 212 if (inFile.LengthDefined) 213 Size = inFile.Length; 214 return true; 215 } 216 #endif 217 CFindFile finder; 218 return finder.FindFirst(wildcard, *this); 219 } 220 221 222 #ifndef _UNICODE 223 bool CFileInfoW::Find(LPCWSTR wildcard) 224 { 225 #ifdef SUPPORT_DEVICE_FILE 226 if (IsDeviceName(wildcard)) 227 { 228 Clear(); 229 IsDevice = true; 230 NIO::CInFile inFile; 231 if (!inFile.Open(wildcard)) 232 return false; 233 Name = wildcard + 4; 234 if (inFile.LengthDefined) 235 Size = inFile.Length; 236 return true; 237 } 238 #endif 239 CFindFile finder; 240 return finder.FindFirst(wildcard, *this); 241 } 242 #endif 243 244 bool DoesFileExist(LPCTSTR name) 245 { 246 CFileInfo fi; 247 return fi.Find(name) && !fi.IsDir(); 248 } 249 250 bool DoesDirExist(LPCTSTR name) 251 { 252 CFileInfo fi; 253 return fi.Find(name) && fi.IsDir(); 254 } 255 256 bool DoesFileOrDirExist(LPCTSTR name) 257 { 258 CFileInfo fi; 259 return fi.Find(name); 260 } 261 262 #ifndef _UNICODE 263 bool DoesFileExist(LPCWSTR name) 264 { 265 CFileInfoW fi; 266 return fi.Find(name) && !fi.IsDir(); 267 } 268 269 bool DoesDirExist(LPCWSTR name) 270 { 271 CFileInfoW fi; 272 return fi.Find(name) && fi.IsDir(); 273 } 274 bool DoesFileOrDirExist(LPCWSTR name) 275 { 276 CFileInfoW fi; 277 return fi.Find(name); 278 } 279 #endif 280 281 ///////////////////////////////////// 282 // CEnumerator 283 284 bool CEnumerator::NextAny(CFileInfo &fi) 285 { 286 if (_findFile.IsHandleAllocated()) 287 return _findFile.FindNext(fi); 288 else 289 return _findFile.FindFirst(_wildcard, fi); 290 } 291 292 bool CEnumerator::Next(CFileInfo &fi) 293 { 294 for (;;) 295 { 296 if (!NextAny(fi)) 297 return false; 298 if (!fi.IsDots()) 299 return true; 300 } 301 } 302 303 bool CEnumerator::Next(CFileInfo &fi, bool &found) 304 { 305 if (Next(fi)) 306 { 307 found = true; 308 return true; 309 } 310 found = false; 311 return (::GetLastError() == ERROR_NO_MORE_FILES); 312 } 313 314 #ifndef _UNICODE 315 bool CEnumeratorW::NextAny(CFileInfoW &fi) 316 { 317 if (_findFile.IsHandleAllocated()) 318 return _findFile.FindNext(fi); 319 else 320 return _findFile.FindFirst(_wildcard, fi); 321 } 322 323 bool CEnumeratorW::Next(CFileInfoW &fi) 324 { 325 for (;;) 326 { 327 if (!NextAny(fi)) 328 return false; 329 if (!fi.IsDots()) 330 return true; 331 } 332 } 333 334 bool CEnumeratorW::Next(CFileInfoW &fi, bool &found) 335 { 336 if (Next(fi)) 337 { 338 found = true; 339 return true; 340 } 341 found = false; 342 return (::GetLastError() == ERROR_NO_MORE_FILES); 343 } 344 345 #endif 346 347 //////////////////////////////// 348 // CFindChangeNotification 349 // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. 350 351 bool CFindChangeNotification::Close() 352 { 353 if (!IsHandleAllocated()) 354 return true; 355 if (!::FindCloseChangeNotification(_handle)) 356 return false; 357 _handle = INVALID_HANDLE_VALUE; 358 return true; 359 } 360 361 HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter) 362 { 363 _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter); 364 #ifdef WIN_LONG_PATH2 365 if (!IsHandleAllocated()) 366 { 367 UString longPath; 368 if (GetLongPath(pathName, longPath)) 369 _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); 370 } 371 #endif 372 return _handle; 373 } 374 375 #ifndef _UNICODE 376 HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter) 377 { 378 if (!g_IsNT) 379 return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); 380 _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter); 381 #ifdef WIN_LONG_PATH 382 if (!IsHandleAllocated()) 383 { 384 UString longPath; 385 if (GetLongPath(pathName, longPath)) 386 _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); 387 } 388 #endif 389 return _handle; 390 } 391 #endif 392 393 #ifndef UNDER_CE 394 bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) 395 { 396 driveStrings.Clear(); 397 UINT32 size = GetLogicalDriveStrings(0, NULL); 398 if (size == 0) 399 return false; 400 CSysString buffer; 401 UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); 402 if (newSize == 0) 403 return false; 404 if (newSize > size) 405 return false; 406 CSysString string; 407 for (UINT32 i = 0; i < newSize; i++) 408 { 409 TCHAR c = buffer[i]; 410 if (c == TEXT('\0')) 411 { 412 driveStrings.Add(string); 413 string.Empty(); 414 } 415 else 416 string += c; 417 } 418 if (!string.IsEmpty()) 419 return false; 420 return true; 421 } 422 423 #ifndef _UNICODE 424 bool MyGetLogicalDriveStrings(UStringVector &driveStrings) 425 { 426 driveStrings.Clear(); 427 if (g_IsNT) 428 { 429 UINT32 size = GetLogicalDriveStringsW(0, NULL); 430 if (size == 0) 431 return false; 432 UString buffer; 433 UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); 434 if (newSize == 0) 435 return false; 436 if (newSize > size) 437 return false; 438 UString string; 439 for (UINT32 i = 0; i < newSize; i++) 440 { 441 WCHAR c = buffer[i]; 442 if (c == L'\0') 443 { 444 driveStrings.Add(string); 445 string.Empty(); 446 } 447 else 448 string += c; 449 } 450 return string.IsEmpty(); 451 } 452 CSysStringVector driveStringsA; 453 bool res = MyGetLogicalDriveStrings(driveStringsA); 454 for (int i = 0; i < driveStringsA.Size(); i++) 455 driveStrings.Add(GetUnicodeString(driveStringsA[i])); 456 return res; 457 } 458 #endif 459 460 #endif 461 462 }}} 463