Home | History | Annotate | Download | only in Windows
      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