misc/libphysfs/lzma/CPP/Windows/FileDir.cpp
author nemo
Mon, 10 Apr 2017 12:06:43 -0400
changeset 12213 bb5522e88ab2
permissions -rw-r--r--
bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash

// Windows/FileDir.cpp

#include "StdAfx.h"

#include "FileDir.h"
#include "FileName.h"
#include "FileFind.h"
#include "Defs.h"
#ifndef _UNICODE
#include "../Common/StringConvert.h"
#endif

#ifndef _UNICODE
extern bool g_IsNT;
#endif

namespace NWindows {
namespace NFile {

#if defined(WIN_LONG_PATH) && defined(_UNICODE)
#define WIN_LONG_PATH2
#endif

// SetCurrentDirectory doesn't support \\?\ prefix

#ifdef WIN_LONG_PATH
bool GetLongPathBase(LPCWSTR fileName, UString &res);
bool GetLongPath(LPCWSTR fileName, UString &res);
#endif

namespace NDirectory {

#ifndef _UNICODE
static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 
static UString GetUnicodePath(const CSysString &sysPath)
  { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); }
static CSysString GetSysPath(LPCWSTR sysPath)
  { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
#endif

bool MyGetWindowsDirectory(CSysString &path)
{
  UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
  path.ReleaseBuffer();
  return (needLength > 0 && needLength <= MAX_PATH);
}

bool MyGetSystemDirectory(CSysString &path)
{
  UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
  path.ReleaseBuffer();
  return (needLength > 0 && needLength <= MAX_PATH);
}

#ifndef _UNICODE
bool MyGetWindowsDirectory(UString &path)
{
  if (g_IsNT)
  {
    UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
    path.ReleaseBuffer();
    return (needLength > 0 && needLength <= MAX_PATH);
  }
  CSysString sysPath;
  if (!MyGetWindowsDirectory(sysPath))
    return false;
  path = GetUnicodePath(sysPath);
  return true;
}

bool MyGetSystemDirectory(UString &path)
{
  if (g_IsNT)
  {
    UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
    path.ReleaseBuffer();
    return (needLength > 0 && needLength <= MAX_PATH);
  }
  CSysString sysPath;
  if (!MyGetSystemDirectory(sysPath))
    return false;
  path = GetUnicodePath(sysPath);
  return true;
}
#endif

bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
{
  #ifndef _UNICODE
  if (!g_IsNT)
  {
    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return false;
  }
  #endif 
  HANDLE hDir = ::CreateFileW(fileName, GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  #ifdef WIN_LONG_PATH
  if (hDir == INVALID_HANDLE_VALUE)
  {
    UString longPath;
    if (GetLongPath(fileName, longPath))
      hDir = ::CreateFileW(longPath, GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  }
  #endif

  bool res = false;
  if (hDir != INVALID_HANDLE_VALUE)
  {
    res = BOOLToBool(::SetFileTime(hDir, creationTime, lastAccessTime, lastWriteTime));
    ::CloseHandle(hDir);
  }
  return res;
}

bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
{
  if (::SetFileAttributes(fileName, fileAttributes))
    return true;
  #ifdef WIN_LONG_PATH2
  UString longPath;
  if (GetLongPath(fileName, longPath))
    return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
  #endif
  return false;
}

bool MyRemoveDirectory(LPCTSTR pathName)
{ 
  if (::RemoveDirectory(pathName))
    return true;
  #ifdef WIN_LONG_PATH2
  UString longPath;
  if (GetLongPath(pathName, longPath))
    return BOOLToBool(::RemoveDirectoryW(longPath));
  #endif
  return false;
}

#ifdef WIN_LONG_PATH
bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2)
{
  if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2))
    return false;
  if (d1.IsEmpty() && d2.IsEmpty()) return false;
  if (d1.IsEmpty()) d1 = s1;
  if (d2.IsEmpty()) d2 = s2;
  return true;
}
#endif

bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName)
{ 
  if (::MoveFile(existFileName, newFileName))
    return true;
  #ifdef WIN_LONG_PATH2
  UString d1, d2;
  if (GetLongPaths(existFileName, newFileName, d1, d2)) 
    return BOOLToBool(::MoveFileW(d1, d2));
  #endif
  return false;
}

#ifndef _UNICODE
bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
{  
  if (!g_IsNT)
    return MySetFileAttributes(GetSysPath(fileName), fileAttributes);
  if (::SetFileAttributesW(fileName, fileAttributes))
    return true;
  #ifdef WIN_LONG_PATH
  UString longPath;
  if (GetLongPath(fileName, longPath))
    return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
  #endif
  return false;
}


bool MyRemoveDirectory(LPCWSTR pathName)
{  
  if (!g_IsNT)
    return MyRemoveDirectory(GetSysPath(pathName));
  if (::RemoveDirectoryW(pathName))
    return true;
  #ifdef WIN_LONG_PATH
  UString longPath;
  if (GetLongPath(pathName, longPath))
    return BOOLToBool(::RemoveDirectoryW(longPath));
  #endif
  return false;
}

bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
{  
  if (!g_IsNT)
    return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName));
  if (::MoveFileW(existFileName, newFileName))
    return true;
  #ifdef WIN_LONG_PATH
  UString d1, d2;
  if (GetLongPaths(existFileName, newFileName, d1, d2)) 
    return BOOLToBool(::MoveFileW(d1, d2));
  #endif
  return false;
}
#endif

bool MyCreateDirectory(LPCTSTR pathName) 
{ 
  if (::CreateDirectory(pathName, NULL))
    return true;
  #ifdef WIN_LONG_PATH2
  if (::GetLastError() != ERROR_ALREADY_EXISTS)
  {
    UString longPath;
    if (GetLongPath(pathName, longPath))
      return BOOLToBool(::CreateDirectoryW(longPath, NULL));
  }
  #endif
  return false;
}

#ifndef _UNICODE
bool MyCreateDirectory(LPCWSTR pathName)
{  
  if (!g_IsNT)
    return MyCreateDirectory(GetSysPath(pathName));
  if (::CreateDirectoryW(pathName, NULL))
    return true;
  #ifdef WIN_LONG_PATH
  if (::GetLastError() != ERROR_ALREADY_EXISTS)
  {
    UString longPath;
    if (GetLongPath(pathName, longPath))
      return BOOLToBool(::CreateDirectoryW(longPath, NULL));
  }
  #endif
  return false;
}
#endif

/*
bool CreateComplexDirectory(LPCTSTR pathName)
{
  NName::CParsedPath path;
  path.ParsePath(pathName);
  CSysString fullPath = path.Prefix;
  DWORD errorCode = ERROR_SUCCESS;
  for(int i = 0; i < path.PathParts.Size(); i++)
  {
    const CSysString &string = path.PathParts[i];
    if(string.IsEmpty())
    {
      if(i != path.PathParts.Size() - 1)
        return false;
      return true;
    }
    fullPath += path.PathParts[i];
    if (!MyCreateDirectory(fullPath))
    {
      DWORD errorCode = GetLastError();
      if(errorCode != ERROR_ALREADY_EXISTS)
        return false;
    }
    fullPath += NName::kDirDelimiter;
  }
  return true;
}
*/

bool CreateComplexDirectory(LPCTSTR _aPathName)
{
  CSysString pathName = _aPathName;
  int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
  if (pos > 0 && pos == pathName.Length() - 1)
  {
    if (pathName.Length() == 3 && pathName[1] == ':')
      return true; // Disk folder;
    pathName.Delete(pos);
  }
  CSysString pathName2 = pathName;
  pos = pathName.Length();
  for (;;)
  {
    if(MyCreateDirectory(pathName))
      break;
    if (::GetLastError() == ERROR_ALREADY_EXISTS)
    {
      NFind::CFileInfo fileInfo;
      if (!NFind::FindFile(pathName, fileInfo)) // For network folders
        return true;
      if (!fileInfo.IsDirectory())
        return false;
      break;
    }
    pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
    if (pos < 0 || pos == 0)
      return false;
    if (pathName[pos - 1] == ':')
      return false;
    pathName = pathName.Left(pos);
  }
  pathName = pathName2;
  while(pos < pathName.Length())
  {
    pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
    if (pos < 0)
      pos = pathName.Length();
    if (!MyCreateDirectory(pathName.Left(pos)))
      return false;
  }
  return true;
}

#ifndef _UNICODE

bool CreateComplexDirectory(LPCWSTR _aPathName)
{
  UString pathName = _aPathName;
  int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
  if (pos > 0 && pos == pathName.Length() - 1)
  {
    if (pathName.Length() == 3 && pathName[1] == L':')
      return true; // Disk folder;
    pathName.Delete(pos);
  }
  UString pathName2 = pathName;
  pos = pathName.Length();
  for (;;)
  {
    if(MyCreateDirectory(pathName))
      break;
    if (::GetLastError() == ERROR_ALREADY_EXISTS)
    {
      NFind::CFileInfoW fileInfo;
      if (!NFind::FindFile(pathName, fileInfo)) // For network folders
        return true;
      if (!fileInfo.IsDirectory())
        return false;
      break;
    }
    pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
    if (pos < 0 || pos == 0)
      return false;
    if (pathName[pos - 1] == L':')
      return false;
    pathName = pathName.Left(pos);
  }
  pathName = pathName2;
  while(pos < pathName.Length())
  {
    pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
    if (pos < 0)
      pos = pathName.Length();
    if (!MyCreateDirectory(pathName.Left(pos)))
      return false;
  }
  return true;
}

#endif

bool DeleteFileAlways(LPCTSTR name)
{
  if (!MySetFileAttributes(name, 0))
    return false;
  if (::DeleteFile(name))
    return true;
  #ifdef WIN_LONG_PATH2
  UString longPath;
  if (GetLongPath(name, longPath))
    return BOOLToBool(::DeleteFileW(longPath));
  #endif
  return false;
}

#ifndef _UNICODE
bool DeleteFileAlways(LPCWSTR name)
{  
  if (!g_IsNT)
    return DeleteFileAlways(GetSysPath(name));
  if (!MySetFileAttributes(name, 0))
    return false;
  if (::DeleteFileW(name))
    return true;
  #ifdef WIN_LONG_PATH
  UString longPath;
  if (GetLongPath(name, longPath))
    return BOOLToBool(::DeleteFileW(longPath));
  #endif
  return false;
}
#endif

static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo)
{
  if(fileInfo.IsDirectory())
    return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
  return DeleteFileAlways(pathPrefix + fileInfo.Name);
}

bool RemoveDirectoryWithSubItems(const CSysString &path)
{
  NFind::CFileInfo fileInfo;
  CSysString pathPrefix = path + NName::kDirDelimiter;
  {
    NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
    while(enumerator.Next(fileInfo))
      if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
        return false;
  }
  if (!MySetFileAttributes(path, 0))
    return false;
  return MyRemoveDirectory(path);
}

#ifndef _UNICODE
static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo)
{
  if(fileInfo.IsDirectory())
    return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
  return DeleteFileAlways(pathPrefix + fileInfo.Name);
}
bool RemoveDirectoryWithSubItems(const UString &path)
{
  NFind::CFileInfoW fileInfo;
  UString pathPrefix = path + UString(NName::kDirDelimiter);
  {
    NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard));
    while(enumerator.Next(fileInfo))
      if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
        return false;
  }
  if (!MySetFileAttributes(path, 0))
    return false;
  return MyRemoveDirectory(path);
}
#endif

#ifndef _WIN32_WCE

bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath)
{
  DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
  shortPath.ReleaseBuffer();
  return (needLength > 0 && needLength < MAX_PATH);
}

bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex)
{
  resultPath.Empty();
  LPTSTR fileNamePointer = 0;
  LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
  DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
  resultPath.ReleaseBuffer();
  if (needLength == 0)
    return false;
  if (needLength >= MAX_PATH)
  {
    #ifdef WIN_LONG_PATH2
    needLength++;
    buffer = resultPath.GetBuffer(needLength + 1);
    DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
    resultPath.ReleaseBuffer();
    if (needLength2 == 0 || needLength2 > needLength)
    #endif
      return false;
  }
  if (fileNamePointer == 0)
    fileNamePartStartIndex = lstrlen(fileName);
  else
    fileNamePartStartIndex = (int)(fileNamePointer - buffer);
  return true;
}

#ifndef _UNICODE
bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
{
  resultPath.Empty();
  if (g_IsNT)
  {
    LPWSTR fileNamePointer = 0;
    LPWSTR buffer = resultPath.GetBuffer(MAX_PATH);
    DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
    resultPath.ReleaseBuffer();
    if (needLength == 0)
      return false;
    if (needLength >= MAX_PATH)
    {
      #ifdef WIN_LONG_PATH
      needLength++;
      buffer = resultPath.GetBuffer(needLength + 1);
      DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
      resultPath.ReleaseBuffer();
      if (needLength2 == 0 || needLength2 > needLength)
      #endif
        return false;
    }
    if (fileNamePointer == 0)
      fileNamePartStartIndex = MyStringLen(fileName);
    else
      fileNamePartStartIndex = (int)(fileNamePointer - buffer);
  }
  else
  {
    CSysString sysPath;
    if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex))
      return false;
    UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex));
    UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex));
    fileNamePartStartIndex = resultPath1.Length();
    resultPath = resultPath1 + resultPath2;
  }
  return true;
}
#endif


bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
{
  int index;
  return MyGetFullPathName(fileName, path, index);
}

#ifndef _UNICODE
bool MyGetFullPathName(LPCWSTR fileName, UString &path)
{
  int index;
  return MyGetFullPathName(fileName, path, index);
}
#endif

bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
{
  int index;
  if (!MyGetFullPathName(fileName, resultName, index))
    return false;
  resultName = resultName.Mid(index);
  return true;
}

#ifndef _UNICODE
bool GetOnlyName(LPCWSTR fileName, UString &resultName)
{
  int index;
  if (!MyGetFullPathName(fileName, resultName, index))
    return false;
  resultName = resultName.Mid(index);
  return true;
}
#endif

bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
{
  int index;
  if (!MyGetFullPathName(fileName, resultName, index))
    return false;
  resultName = resultName.Left(index);
  return true;
}

#ifndef _UNICODE
bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName)
{
  int index;
  if (!MyGetFullPathName(fileName, resultName, index))
    return false;
  resultName = resultName.Left(index);
  return true;
}
#endif

bool MyGetCurrentDirectory(CSysString &path)
{
  DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
  path.ReleaseBuffer();
  return (needLength > 0 && needLength <= MAX_PATH);
}

#ifndef _UNICODE
bool MySetCurrentDirectory(LPCWSTR path)
{
  if (g_IsNT)
    return BOOLToBool(::SetCurrentDirectoryW(path));
  return MySetCurrentDirectory(GetSysPath(path));
}
bool MyGetCurrentDirectory(UString &path)
{
  if (g_IsNT)
  {
    DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    path.ReleaseBuffer();
    return (needLength > 0 && needLength <= MAX_PATH);
  }
  CSysString sysPath;
  if (!MyGetCurrentDirectory(sysPath))
    return false;
  path = GetUnicodePath(sysPath);
  return true;
}
#endif
#endif

bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, 
  CSysString &resultPath, UINT32 &filePart)
{
  LPTSTR filePartPointer;
  DWORD value = ::SearchPath(path, fileName, extension, 
    MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
  filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath);
  resultPath.ReleaseBuffer();
  return (value > 0 && value <= MAX_PATH);
}

#ifndef _UNICODE
bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, 
  UString &resultPath, UINT32 &filePart)
{
  if (g_IsNT)
  {
    LPWSTR filePartPointer = 0;
    DWORD value = ::SearchPathW(path, fileName, extension, 
        MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
    filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath);
    resultPath.ReleaseBuffer();
    return (value > 0 && value <= MAX_PATH);
  }
  
  CSysString sysPath;
  if (!MySearchPath(
      path != 0 ? (LPCTSTR)GetSysPath(path): 0,
      fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0,
      extension != 0 ? (LPCTSTR)GetSysPath(extension): 0,
      sysPath, filePart))
    return false;
  UString resultPath1 = GetUnicodePath(sysPath.Left(filePart));
  UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart));
  filePart = resultPath1.Length();
  resultPath = resultPath1 + resultPath2;
  return true;
}
#endif

bool MyGetTempPath(CSysString &path)
{
  DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
  path.ReleaseBuffer();
  return (needLength > 0 && needLength <= MAX_PATH);
}

#ifndef _UNICODE
bool MyGetTempPath(UString &path)
{
  path.Empty();
  if (g_IsNT)
  {
    DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
    path.ReleaseBuffer();
    return (needLength > 0 && needLength <= MAX_PATH);
  }
  CSysString sysPath;
  if (!MyGetTempPath(sysPath))
    return false;
  path = GetUnicodePath(sysPath);
  return true;
}
#endif

UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path)
{
  UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1));
  path.ReleaseBuffer();
  return number;
}

#ifndef _UNICODE
UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path)
{
  if (g_IsNT)
  {
    UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH));
    path.ReleaseBuffer();
    return number;
  }
  CSysString sysPath;
  UINT number = MyGetTempFileName(
      dirPath ? (LPCTSTR)GetSysPath(dirPath): 0, 
      prefix ? (LPCTSTR)GetSysPath(prefix): 0, 
      sysPath);
  path = GetUnicodePath(sysPath);
  return number;
}
#endif

UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
{
  Remove();
  UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
  if(number != 0)
  {
    _fileName = resultPath;
    _mustBeDeleted = true;
  }
  return number;
}

bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
{
  CSysString tempPath;
  if (!MyGetTempPath(tempPath))
    return false;
  if (Create(tempPath, prefix, resultPath) != 0)
    return true;
  if (!MyGetWindowsDirectory(tempPath))
    return false;
  return (Create(tempPath, prefix, resultPath) != 0);
}

bool CTempFile::Remove()
{
  if (!_mustBeDeleted)
    return true;
  _mustBeDeleted = !DeleteFileAlways(_fileName);
  return !_mustBeDeleted;
}

#ifndef _UNICODE

UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath)
{
  Remove();
  UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
  if(number != 0)
  {
    _fileName = resultPath;
    _mustBeDeleted = true;
  }
  return number;
}

bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath)
{
  UString tempPath;
  if (!MyGetTempPath(tempPath))
    return false;
  if (Create(tempPath, prefix, resultPath) != 0)
    return true;
  if (!MyGetWindowsDirectory(tempPath))
    return false;
  return (Create(tempPath, prefix, resultPath) != 0);
}

bool CTempFileW::Remove()
{
  if (!_mustBeDeleted)
    return true;
  _mustBeDeleted = !DeleteFileAlways(_fileName);
  return !_mustBeDeleted;
}

#endif

bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName)
{
  /*
  CSysString prefix = tempPath + prefixChars;
  CRandom random;
  random.Init();
  */
  for (;;)
  {
    CTempFile tempFile;
    if (!tempFile.Create(prefix, dirName))
      return false;
    if (!::DeleteFile(dirName))
      return false;
    /*
    UINT32 randomNumber = random.Generate();
    TCHAR randomNumberString[32];
    _stprintf(randomNumberString, _T("%04X"), randomNumber);
    dirName = prefix + randomNumberString;
    */
    if(NFind::DoesFileExist(dirName))
      continue;
    if (MyCreateDirectory(dirName))
      return true;
    if (::GetLastError() != ERROR_ALREADY_EXISTS)
      return false;
  }
}

bool CTempDirectory::Create(LPCTSTR prefix)
{ 
  Remove();
  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); 
}

#ifndef _UNICODE

bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
{
  /*
  CSysString prefix = tempPath + prefixChars;
  CRandom random;
  random.Init();
  */
  for (;;)
  {
    CTempFileW tempFile;
    if (!tempFile.Create(prefix, dirName))
      return false;
    if (!DeleteFileAlways(dirName))
      return false;
    /*
    UINT32 randomNumber = random.Generate();
    TCHAR randomNumberString[32];
    _stprintf(randomNumberString, _T("%04X"), randomNumber);
    dirName = prefix + randomNumberString;
    */
    if(NFind::DoesFileExist(dirName))
      continue;
    if (MyCreateDirectory(dirName))
      return true;
    if (::GetLastError() != ERROR_ALREADY_EXISTS)
      return false;
  }
}

bool CTempDirectoryW::Create(LPCWSTR prefix)
{ 
  Remove();
  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); 
}

#endif

}}}