Home | History | Annotate | Download | only in Windows
      1 // Windows/FileDir.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #ifndef _UNICODE
      6 #include "../Common/StringConvert.h"
      7 #endif
      8 
      9 #include "FileDir.h"
     10 #include "FileFind.h"
     11 #include "FileName.h"
     12 
     13 #ifndef _UNICODE
     14 extern bool g_IsNT;
     15 #endif
     16 
     17 namespace NWindows {
     18 namespace NFile {
     19 
     20 #if defined(WIN_LONG_PATH) && defined(_UNICODE)
     21 #define WIN_LONG_PATH2
     22 #endif
     23 
     24 // SetCurrentDirectory doesn't support \\?\ prefix
     25 
     26 #ifdef WIN_LONG_PATH
     27 bool GetLongPathBase(LPCWSTR fileName, UString &res);
     28 bool GetLongPath(LPCWSTR fileName, UString &res);
     29 #endif
     30 
     31 namespace NDirectory {
     32 
     33 #ifndef _UNICODE
     34 static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
     35 static UString GetUnicodePath(const CSysString &sysPath)
     36   { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); }
     37 static CSysString GetSysPath(LPCWSTR sysPath)
     38   { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
     39 #endif
     40 
     41 #ifndef UNDER_CE
     42 
     43 bool MyGetWindowsDirectory(CSysString &path)
     44 {
     45   UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
     46   path.ReleaseBuffer();
     47   return (needLength > 0 && needLength <= MAX_PATH);
     48 }
     49 
     50 bool MyGetSystemDirectory(CSysString &path)
     51 {
     52   UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
     53   path.ReleaseBuffer();
     54   return (needLength > 0 && needLength <= MAX_PATH);
     55 }
     56 
     57 #endif
     58 
     59 #ifndef _UNICODE
     60 bool MyGetWindowsDirectory(UString &path)
     61 {
     62   if (g_IsNT)
     63   {
     64     UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
     65     path.ReleaseBuffer();
     66     return (needLength > 0 && needLength <= MAX_PATH);
     67   }
     68   CSysString sysPath;
     69   if (!MyGetWindowsDirectory(sysPath))
     70     return false;
     71   path = GetUnicodePath(sysPath);
     72   return true;
     73 }
     74 
     75 bool MyGetSystemDirectory(UString &path)
     76 {
     77   if (g_IsNT)
     78   {
     79     UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
     80     path.ReleaseBuffer();
     81     return (needLength > 0 && needLength <= MAX_PATH);
     82   }
     83   CSysString sysPath;
     84   if (!MyGetSystemDirectory(sysPath))
     85     return false;
     86   path = GetUnicodePath(sysPath);
     87   return true;
     88 }
     89 #endif
     90 
     91 bool SetDirTime(LPCWSTR fileName, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
     92 {
     93   #ifndef _UNICODE
     94   if (!g_IsNT)
     95   {
     96     ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     97     return false;
     98   }
     99   #endif
    100   HANDLE hDir = ::CreateFileW(fileName, GENERIC_WRITE,
    101       FILE_SHARE_READ | FILE_SHARE_WRITE,
    102       NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
    103   #ifdef WIN_LONG_PATH
    104   if (hDir == INVALID_HANDLE_VALUE)
    105   {
    106     UString longPath;
    107     if (GetLongPath(fileName, longPath))
    108       hDir = ::CreateFileW(longPath, GENERIC_WRITE,
    109         FILE_SHARE_READ | FILE_SHARE_WRITE,
    110         NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
    111   }
    112   #endif
    113 
    114   bool res = false;
    115   if (hDir != INVALID_HANDLE_VALUE)
    116   {
    117     res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
    118     ::CloseHandle(hDir);
    119   }
    120   return res;
    121 }
    122 
    123 bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
    124 {
    125   if (::SetFileAttributes(fileName, fileAttributes))
    126     return true;
    127   #ifdef WIN_LONG_PATH2
    128   UString longPath;
    129   if (GetLongPath(fileName, longPath))
    130     return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
    131   #endif
    132   return false;
    133 }
    134 
    135 bool MyRemoveDirectory(LPCTSTR pathName)
    136 {
    137   if (::RemoveDirectory(pathName))
    138     return true;
    139   #ifdef WIN_LONG_PATH2
    140   UString longPath;
    141   if (GetLongPath(pathName, longPath))
    142     return BOOLToBool(::RemoveDirectoryW(longPath));
    143   #endif
    144   return false;
    145 }
    146 
    147 #ifdef WIN_LONG_PATH
    148 bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2)
    149 {
    150   if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2))
    151     return false;
    152   if (d1.IsEmpty() && d2.IsEmpty()) return false;
    153   if (d1.IsEmpty()) d1 = s1;
    154   if (d2.IsEmpty()) d2 = s2;
    155   return true;
    156 }
    157 #endif
    158 
    159 bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName)
    160 {
    161   if (::MoveFile(existFileName, newFileName))
    162     return true;
    163   #ifdef WIN_LONG_PATH2
    164   UString d1, d2;
    165   if (GetLongPaths(existFileName, newFileName, d1, d2))
    166     return BOOLToBool(::MoveFileW(d1, d2));
    167   #endif
    168   return false;
    169 }
    170 
    171 #ifndef _UNICODE
    172 bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
    173 {
    174   if (!g_IsNT)
    175     return MySetFileAttributes(GetSysPath(fileName), fileAttributes);
    176   if (::SetFileAttributesW(fileName, fileAttributes))
    177     return true;
    178   #ifdef WIN_LONG_PATH
    179   UString longPath;
    180   if (GetLongPath(fileName, longPath))
    181     return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
    182   #endif
    183   return false;
    184 }
    185 
    186 
    187 bool MyRemoveDirectory(LPCWSTR pathName)
    188 {
    189   if (!g_IsNT)
    190     return MyRemoveDirectory(GetSysPath(pathName));
    191   if (::RemoveDirectoryW(pathName))
    192     return true;
    193   #ifdef WIN_LONG_PATH
    194   UString longPath;
    195   if (GetLongPath(pathName, longPath))
    196     return BOOLToBool(::RemoveDirectoryW(longPath));
    197   #endif
    198   return false;
    199 }
    200 
    201 bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
    202 {
    203   if (!g_IsNT)
    204     return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName));
    205   if (::MoveFileW(existFileName, newFileName))
    206     return true;
    207   #ifdef WIN_LONG_PATH
    208   UString d1, d2;
    209   if (GetLongPaths(existFileName, newFileName, d1, d2))
    210     return BOOLToBool(::MoveFileW(d1, d2));
    211   #endif
    212   return false;
    213 }
    214 #endif
    215 
    216 bool MyCreateDirectory(LPCTSTR pathName)
    217 {
    218   if (::CreateDirectory(pathName, NULL))
    219     return true;
    220   #ifdef WIN_LONG_PATH2
    221   if (::GetLastError() != ERROR_ALREADY_EXISTS)
    222   {
    223     UString longPath;
    224     if (GetLongPath(pathName, longPath))
    225       return BOOLToBool(::CreateDirectoryW(longPath, NULL));
    226   }
    227   #endif
    228   return false;
    229 }
    230 
    231 #ifndef _UNICODE
    232 bool MyCreateDirectory(LPCWSTR pathName)
    233 {
    234   if (!g_IsNT)
    235     return MyCreateDirectory(GetSysPath(pathName));
    236   if (::CreateDirectoryW(pathName, NULL))
    237     return true;
    238   #ifdef WIN_LONG_PATH
    239   if (::GetLastError() != ERROR_ALREADY_EXISTS)
    240   {
    241     UString longPath;
    242     if (GetLongPath(pathName, longPath))
    243       return BOOLToBool(::CreateDirectoryW(longPath, NULL));
    244   }
    245   #endif
    246   return false;
    247 }
    248 #endif
    249 
    250 /*
    251 bool CreateComplexDirectory(LPCTSTR pathName)
    252 {
    253   NName::CParsedPath path;
    254   path.ParsePath(pathName);
    255   CSysString fullPath = path.Prefix;
    256   DWORD errorCode = ERROR_SUCCESS;
    257   for (int i = 0; i < path.PathParts.Size(); i++)
    258   {
    259     const CSysString &string = path.PathParts[i];
    260     if (string.IsEmpty())
    261     {
    262       if (i != path.PathParts.Size() - 1)
    263         return false;
    264       return true;
    265     }
    266     fullPath += path.PathParts[i];
    267     if (!MyCreateDirectory(fullPath))
    268     {
    269       DWORD errorCode = GetLastError();
    270       if (errorCode != ERROR_ALREADY_EXISTS)
    271         return false;
    272     }
    273     fullPath += NName::kDirDelimiter;
    274   }
    275   return true;
    276 }
    277 */
    278 
    279 bool CreateComplexDirectory(LPCTSTR _aPathName)
    280 {
    281   CSysString pathName = _aPathName;
    282   int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
    283   if (pos > 0 && pos == pathName.Length() - 1)
    284   {
    285     if (pathName.Length() == 3 && pathName[1] == ':')
    286       return true; // Disk folder;
    287     pathName.Delete(pos);
    288   }
    289   CSysString pathName2 = pathName;
    290   pos = pathName.Length();
    291   for (;;)
    292   {
    293     if (MyCreateDirectory(pathName))
    294       break;
    295     if (::GetLastError() == ERROR_ALREADY_EXISTS)
    296     {
    297       NFind::CFileInfo fileInfo;
    298       if (!fileInfo.Find(pathName)) // For network folders
    299         return true;
    300       if (!fileInfo.IsDir())
    301         return false;
    302       break;
    303     }
    304     pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
    305     if (pos < 0 || pos == 0)
    306       return false;
    307     if (pathName[pos - 1] == ':')
    308       return false;
    309     pathName = pathName.Left(pos);
    310   }
    311   pathName = pathName2;
    312   while (pos < pathName.Length())
    313   {
    314     pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
    315     if (pos < 0)
    316       pos = pathName.Length();
    317     if (!MyCreateDirectory(pathName.Left(pos)))
    318       return false;
    319   }
    320   return true;
    321 }
    322 
    323 #ifndef _UNICODE
    324 
    325 bool CreateComplexDirectory(LPCWSTR _aPathName)
    326 {
    327   UString pathName = _aPathName;
    328   int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
    329   if (pos > 0 && pos == pathName.Length() - 1)
    330   {
    331     if (pathName.Length() == 3 && pathName[1] == L':')
    332       return true; // Disk folder;
    333     pathName.Delete(pos);
    334   }
    335   UString pathName2 = pathName;
    336   pos = pathName.Length();
    337   for (;;)
    338   {
    339     if (MyCreateDirectory(pathName))
    340       break;
    341     if (::GetLastError() == ERROR_ALREADY_EXISTS)
    342     {
    343       NFind::CFileInfoW fileInfo;
    344       if (!fileInfo.Find(pathName)) // For network folders
    345         return true;
    346       if (!fileInfo.IsDir())
    347         return false;
    348       break;
    349     }
    350     pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
    351     if (pos < 0 || pos == 0)
    352       return false;
    353     if (pathName[pos - 1] == L':')
    354       return false;
    355     pathName = pathName.Left(pos);
    356   }
    357   pathName = pathName2;
    358   while (pos < pathName.Length())
    359   {
    360     pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
    361     if (pos < 0)
    362       pos = pathName.Length();
    363     if (!MyCreateDirectory(pathName.Left(pos)))
    364       return false;
    365   }
    366   return true;
    367 }
    368 
    369 #endif
    370 
    371 bool DeleteFileAlways(LPCTSTR name)
    372 {
    373   if (!MySetFileAttributes(name, 0))
    374     return false;
    375   if (::DeleteFile(name))
    376     return true;
    377   #ifdef WIN_LONG_PATH2
    378   UString longPath;
    379   if (GetLongPath(name, longPath))
    380     return BOOLToBool(::DeleteFileW(longPath));
    381   #endif
    382   return false;
    383 }
    384 
    385 #ifndef _UNICODE
    386 bool DeleteFileAlways(LPCWSTR name)
    387 {
    388   if (!g_IsNT)
    389     return DeleteFileAlways(GetSysPath(name));
    390   if (!MySetFileAttributes(name, 0))
    391     return false;
    392   if (::DeleteFileW(name))
    393     return true;
    394   #ifdef WIN_LONG_PATH
    395   UString longPath;
    396   if (GetLongPath(name, longPath))
    397     return BOOLToBool(::DeleteFileW(longPath));
    398   #endif
    399   return false;
    400 }
    401 #endif
    402 
    403 static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo)
    404 {
    405   if (fileInfo.IsDir())
    406     return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
    407   return DeleteFileAlways(pathPrefix + fileInfo.Name);
    408 }
    409 
    410 bool RemoveDirectoryWithSubItems(const CSysString &path)
    411 {
    412   NFind::CFileInfo fileInfo;
    413   CSysString pathPrefix = path + NName::kDirDelimiter;
    414   {
    415     NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
    416     while (enumerator.Next(fileInfo))
    417       if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
    418         return false;
    419   }
    420   if (!MySetFileAttributes(path, 0))
    421     return false;
    422   return MyRemoveDirectory(path);
    423 }
    424 
    425 #ifndef _UNICODE
    426 static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo)
    427 {
    428   if (fileInfo.IsDir())
    429     return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
    430   return DeleteFileAlways(pathPrefix + fileInfo.Name);
    431 }
    432 bool RemoveDirectoryWithSubItems(const UString &path)
    433 {
    434   NFind::CFileInfoW fileInfo;
    435   UString pathPrefix = path + UString(NName::kDirDelimiter);
    436   {
    437     NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard));
    438     while (enumerator.Next(fileInfo))
    439       if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
    440         return false;
    441   }
    442   if (!MySetFileAttributes(path, 0))
    443     return false;
    444   return MyRemoveDirectory(path);
    445 }
    446 #endif
    447 
    448 bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
    449 {
    450   int index;
    451   if (!MyGetFullPathName(fileName, resultName, index))
    452     return false;
    453   resultName = resultName.Left(index);
    454   return true;
    455 }
    456 
    457 bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
    458 {
    459   int index;
    460   if (!MyGetFullPathName(fileName, resultName, index))
    461     return false;
    462   resultName = resultName.Mid(index);
    463   return true;
    464 }
    465 
    466 #ifdef UNDER_CE
    467 bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath)
    468 {
    469   resultPath = fileName;
    470   return true;
    471 }
    472 
    473 bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
    474 {
    475   resultPath = fileName;
    476   // change it
    477   fileNamePartStartIndex = resultPath.ReverseFind(WCHAR_PATH_SEPARATOR);
    478   fileNamePartStartIndex++;
    479   return true;
    480 }
    481 
    482 #else
    483 
    484 bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath)
    485 {
    486   DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
    487   shortPath.ReleaseBuffer();
    488   return (needLength > 0 && needLength < MAX_PATH);
    489 }
    490 
    491 #ifdef WIN_LONG_PATH
    492 
    493 static UString GetLastPart(LPCWSTR path)
    494 {
    495   int i = (int)wcslen(path);
    496   for (; i > 0; i--)
    497   {
    498     WCHAR c = path[i - 1];
    499     if (c == WCHAR_PATH_SEPARATOR || c == '/')
    500       break;
    501   }
    502   return path + i;
    503 }
    504 
    505 static void AddTrailingDots(LPCWSTR oldPath, UString &newPath)
    506 {
    507   int len = (int)wcslen(oldPath);
    508   int i;
    509   for (i = len; i > 0 && oldPath[i - 1] == '.'; i--);
    510   if (i == 0 || i == len)
    511     return;
    512   UString oldName = GetLastPart(oldPath);
    513   UString newName = GetLastPart(newPath);
    514   int nonDotsLen = oldName.Length() - (len - i);
    515   if (nonDotsLen == 0 || newName.CompareNoCase(oldName.Left(nonDotsLen)) != 0)
    516     return;
    517   for (; i != len; i++)
    518     newPath += '.';
    519 }
    520 
    521 #endif
    522 
    523 bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex)
    524 {
    525   resultPath.Empty();
    526   LPTSTR fileNamePointer = 0;
    527   LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
    528   DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
    529   resultPath.ReleaseBuffer();
    530   if (needLength == 0)
    531     return false;
    532   if (needLength >= MAX_PATH)
    533   {
    534     #ifdef WIN_LONG_PATH2
    535     needLength++;
    536     buffer = resultPath.GetBuffer(needLength + 1);
    537     DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
    538     resultPath.ReleaseBuffer();
    539     if (needLength2 == 0 || needLength2 > needLength)
    540     #endif
    541       return false;
    542   }
    543   if (fileNamePointer == 0)
    544     fileNamePartStartIndex = lstrlen(fileName);
    545   else
    546     fileNamePartStartIndex = (int)(fileNamePointer - buffer);
    547   #ifdef _UNICODE
    548   #ifdef WIN_LONG_PATH
    549   AddTrailingDots(fileName, resultPath);
    550   #endif
    551   #endif
    552   return true;
    553 }
    554 
    555 #ifndef _UNICODE
    556 bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
    557 {
    558   resultPath.Empty();
    559   if (g_IsNT)
    560   {
    561     LPWSTR fileNamePointer = 0;
    562     LPWSTR buffer = resultPath.GetBuffer(MAX_PATH);
    563     DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
    564     resultPath.ReleaseBuffer();
    565     if (needLength == 0)
    566       return false;
    567     if (needLength >= MAX_PATH)
    568     {
    569       #ifdef WIN_LONG_PATH
    570       needLength++;
    571       buffer = resultPath.GetBuffer(needLength + 1);
    572       DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
    573       resultPath.ReleaseBuffer();
    574       if (needLength2 == 0 || needLength2 > needLength)
    575       #endif
    576         return false;
    577     }
    578     if (fileNamePointer == 0)
    579       fileNamePartStartIndex = MyStringLen(fileName);
    580     else
    581       fileNamePartStartIndex = (int)(fileNamePointer - buffer);
    582     #ifdef WIN_LONG_PATH
    583     AddTrailingDots(fileName, resultPath);
    584     #endif
    585   }
    586   else
    587   {
    588     CSysString sysPath;
    589     if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex))
    590       return false;
    591     UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex));
    592     UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex));
    593     fileNamePartStartIndex = resultPath1.Length();
    594     resultPath = resultPath1 + resultPath2;
    595   }
    596   return true;
    597 }
    598 #endif
    599 
    600 
    601 bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
    602 {
    603   int index;
    604   return MyGetFullPathName(fileName, path, index);
    605 }
    606 
    607 #ifndef _UNICODE
    608 bool MyGetFullPathName(LPCWSTR fileName, UString &path)
    609 {
    610   int index;
    611   return MyGetFullPathName(fileName, path, index);
    612 }
    613 #endif
    614 
    615 #ifndef _UNICODE
    616 bool GetOnlyName(LPCWSTR fileName, UString &resultName)
    617 {
    618   int index;
    619   if (!MyGetFullPathName(fileName, resultName, index))
    620     return false;
    621   resultName = resultName.Mid(index);
    622   return true;
    623 }
    624 #endif
    625 
    626 #ifndef _UNICODE
    627 bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName)
    628 {
    629   int index;
    630   if (!MyGetFullPathName(fileName, resultName, index))
    631     return false;
    632   resultName = resultName.Left(index);
    633   return true;
    634 }
    635 #endif
    636 
    637 bool MyGetCurrentDirectory(CSysString &path)
    638 {
    639   DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    640   path.ReleaseBuffer();
    641   return (needLength > 0 && needLength <= MAX_PATH);
    642 }
    643 
    644 #ifndef _UNICODE
    645 bool MySetCurrentDirectory(LPCWSTR path)
    646 {
    647   if (g_IsNT)
    648     return BOOLToBool(::SetCurrentDirectoryW(path));
    649   return MySetCurrentDirectory(GetSysPath(path));
    650 }
    651 bool MyGetCurrentDirectory(UString &path)
    652 {
    653   if (g_IsNT)
    654   {
    655     DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    656     path.ReleaseBuffer();
    657     return (needLength > 0 && needLength <= MAX_PATH);
    658   }
    659   CSysString sysPath;
    660   if (!MyGetCurrentDirectory(sysPath))
    661     return false;
    662   path = GetUnicodePath(sysPath);
    663   return true;
    664 }
    665 #endif
    666 
    667 bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension,
    668   CSysString &resultPath, UINT32 &filePart)
    669 {
    670   LPTSTR filePartPointer;
    671   DWORD value = ::SearchPath(path, fileName, extension,
    672     MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
    673   filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath);
    674   resultPath.ReleaseBuffer();
    675   return (value > 0 && value <= MAX_PATH);
    676 }
    677 #endif
    678 
    679 #ifndef _UNICODE
    680 bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension,
    681   UString &resultPath, UINT32 &filePart)
    682 {
    683   if (g_IsNT)
    684   {
    685     LPWSTR filePartPointer = 0;
    686     DWORD value = ::SearchPathW(path, fileName, extension,
    687         MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
    688     filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath);
    689     resultPath.ReleaseBuffer();
    690     return (value > 0 && value <= MAX_PATH);
    691   }
    692 
    693   CSysString sysPath;
    694   if (!MySearchPath(
    695       path != 0 ? (LPCTSTR)GetSysPath(path): 0,
    696       fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0,
    697       extension != 0 ? (LPCTSTR)GetSysPath(extension): 0,
    698       sysPath, filePart))
    699     return false;
    700   UString resultPath1 = GetUnicodePath(sysPath.Left(filePart));
    701   UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart));
    702   filePart = resultPath1.Length();
    703   resultPath = resultPath1 + resultPath2;
    704   return true;
    705 }
    706 #endif
    707 
    708 bool MyGetTempPath(CSysString &path)
    709 {
    710   DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    711   path.ReleaseBuffer();
    712   return (needLength > 0 && needLength <= MAX_PATH);
    713 }
    714 
    715 #ifndef _UNICODE
    716 bool MyGetTempPath(UString &path)
    717 {
    718   path.Empty();
    719   if (g_IsNT)
    720   {
    721     DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    722     path.ReleaseBuffer();
    723     return (needLength > 0 && needLength <= MAX_PATH);
    724   }
    725   CSysString sysPath;
    726   if (!MyGetTempPath(sysPath))
    727     return false;
    728   path = GetUnicodePath(sysPath);
    729   return true;
    730 }
    731 #endif
    732 
    733 UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path)
    734 {
    735   UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1));
    736   path.ReleaseBuffer();
    737   return number;
    738 }
    739 
    740 #ifndef _UNICODE
    741 UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path)
    742 {
    743   if (g_IsNT)
    744   {
    745     UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH));
    746     path.ReleaseBuffer();
    747     return number;
    748   }
    749   CSysString sysPath;
    750   UINT number = MyGetTempFileName(
    751       dirPath ? (LPCTSTR)GetSysPath(dirPath): 0,
    752       prefix ? (LPCTSTR)GetSysPath(prefix): 0,
    753       sysPath);
    754   path = GetUnicodePath(sysPath);
    755   return number;
    756 }
    757 #endif
    758 
    759 UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
    760 {
    761   Remove();
    762   UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
    763   if (number != 0)
    764   {
    765     _fileName = resultPath;
    766     _mustBeDeleted = true;
    767   }
    768   return number;
    769 }
    770 
    771 bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
    772 {
    773   CSysString tempPath;
    774   if (!MyGetTempPath(tempPath))
    775     return false;
    776   if (Create(tempPath, prefix, resultPath) != 0)
    777     return true;
    778   #ifdef UNDER_CE
    779   return false;
    780   #else
    781   if (!MyGetWindowsDirectory(tempPath))
    782     return false;
    783   return (Create(tempPath, prefix, resultPath) != 0);
    784   #endif
    785 }
    786 
    787 bool CTempFile::Remove()
    788 {
    789   if (!_mustBeDeleted)
    790     return true;
    791   _mustBeDeleted = !DeleteFileAlways(_fileName);
    792   return !_mustBeDeleted;
    793 }
    794 
    795 #ifndef _UNICODE
    796 
    797 UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath)
    798 {
    799   Remove();
    800   UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
    801   if (number != 0)
    802   {
    803     _fileName = resultPath;
    804     _mustBeDeleted = true;
    805   }
    806   return number;
    807 }
    808 
    809 bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath)
    810 {
    811   UString tempPath;
    812   if (!MyGetTempPath(tempPath))
    813     return false;
    814   if (Create(tempPath, prefix, resultPath) != 0)
    815     return true;
    816   if (!MyGetWindowsDirectory(tempPath))
    817     return false;
    818   return (Create(tempPath, prefix, resultPath) != 0);
    819 }
    820 
    821 bool CTempFileW::Remove()
    822 {
    823   if (!_mustBeDeleted)
    824     return true;
    825   _mustBeDeleted = !DeleteFileAlways(_fileName);
    826   return !_mustBeDeleted;
    827 }
    828 
    829 #endif
    830 
    831 bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName)
    832 {
    833   /*
    834   CSysString prefix = tempPath + prefixChars;
    835   CRandom random;
    836   random.Init();
    837   */
    838   for (;;)
    839   {
    840     {
    841       CTempFile tempFile;
    842       if (!tempFile.Create(prefix, dirName))
    843         return false;
    844       if (!tempFile.Remove())
    845         return false;
    846     }
    847     /*
    848     UINT32 randomNumber = random.Generate();
    849     TCHAR randomNumberString[32];
    850     _stprintf(randomNumberString, _T("%04X"), randomNumber);
    851     dirName = prefix + randomNumberString;
    852     */
    853     if (NFind::DoesFileOrDirExist(dirName))
    854       continue;
    855     if (MyCreateDirectory(dirName))
    856       return true;
    857     if (::GetLastError() != ERROR_ALREADY_EXISTS)
    858       return false;
    859   }
    860 }
    861 
    862 bool CTempDirectory::Create(LPCTSTR prefix)
    863 {
    864   Remove();
    865   return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
    866 }
    867 
    868 #ifndef _UNICODE
    869 
    870 bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
    871 {
    872   /*
    873   CSysString prefix = tempPath + prefixChars;
    874   CRandom random;
    875   random.Init();
    876   */
    877   for (;;)
    878   {
    879     {
    880       CTempFileW tempFile;
    881       if (!tempFile.Create(prefix, dirName))
    882         return false;
    883       if (!tempFile.Remove())
    884         return false;
    885     }
    886     /*
    887     UINT32 randomNumber = random.Generate();
    888     TCHAR randomNumberString[32];
    889     _stprintf(randomNumberString, _T("%04X"), randomNumber);
    890     dirName = prefix + randomNumberString;
    891     */
    892     if (NFind::DoesFileOrDirExist(dirName))
    893       continue;
    894     if (MyCreateDirectory(dirName))
    895       return true;
    896     if (::GetLastError() != ERROR_ALREADY_EXISTS)
    897       return false;
    898   }
    899 }
    900 
    901 bool CTempDirectoryW::Create(LPCWSTR prefix)
    902 {
    903   Remove();
    904   return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
    905 }
    906 
    907 #endif
    908 
    909 }}}
    910