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
14extern bool g_IsNT;
15#endif
16
17namespace NWindows {
18namespace 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
27bool GetLongPathBase(LPCWSTR fileName, UString &res);
28bool GetLongPath(LPCWSTR fileName, UString &res);
29#endif
30
31namespace NDirectory {
32
33#ifndef _UNICODE
34static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
35static UString GetUnicodePath(const CSysString &sysPath)
36  { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); }
37static CSysString GetSysPath(LPCWSTR sysPath)
38  { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
39#endif
40
41#ifndef UNDER_CE
42
43bool 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
50bool 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
60bool 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
75bool 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
91bool 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
123bool 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
135bool 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
148bool 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
159bool 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
172bool 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
187bool 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
201bool 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
216bool 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
232bool 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/*
251bool 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
279bool 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
325bool 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
371bool 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
386bool 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
403static 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
410bool 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
426static 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}
432bool 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
448bool 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
457bool 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
467bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath)
468{
469  resultPath = fileName;
470  return true;
471}
472
473bool 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
484bool 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
493static 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
505static 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
523bool 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
556bool 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
601bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
602{
603  int index;
604  return MyGetFullPathName(fileName, path, index);
605}
606
607#ifndef _UNICODE
608bool MyGetFullPathName(LPCWSTR fileName, UString &path)
609{
610  int index;
611  return MyGetFullPathName(fileName, path, index);
612}
613#endif
614
615#ifndef _UNICODE
616bool 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
627bool 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
637bool 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
645bool MySetCurrentDirectory(LPCWSTR path)
646{
647  if (g_IsNT)
648    return BOOLToBool(::SetCurrentDirectoryW(path));
649  return MySetCurrentDirectory(GetSysPath(path));
650}
651bool 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
667bool 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
680bool 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
708bool 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
716bool 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
733UINT 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
741UINT 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
759UINT 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
771bool 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
787bool CTempFile::Remove()
788{
789  if (!_mustBeDeleted)
790    return true;
791  _mustBeDeleted = !DeleteFileAlways(_fileName);
792  return !_mustBeDeleted;
793}
794
795#ifndef _UNICODE
796
797UINT 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
809bool 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
821bool CTempFileW::Remove()
822{
823  if (!_mustBeDeleted)
824    return true;
825  _mustBeDeleted = !DeleteFileAlways(_fileName);
826  return !_mustBeDeleted;
827}
828
829#endif
830
831bool 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
862bool CTempDirectory::Create(LPCTSTR prefix)
863{
864  Remove();
865  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
866}
867
868#ifndef _UNICODE
869
870bool 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
901bool CTempDirectoryW::Create(LPCWSTR prefix)
902{
903  Remove();
904  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
905}
906
907#endif
908
909}}}
910