10 #include "../Common/StringConvert.h"
20 #if defined(WIN_LONG_PATH) && defined(_UNICODE)
21 #define WIN_LONG_PATH2
24 // SetCurrentDirectory doesn't support \\?\ prefix
27 bool GetLongPathBase(LPCWSTR fileName, UString &res);
28 bool GetLongPath(LPCWSTR fileName, UString &res);
31 namespace NDirectory {
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()); }
41 bool MyGetWindowsDirectory(CSysString &path)
43 UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
45 return (needLength > 0 && needLength <= MAX_PATH);
48 bool MyGetSystemDirectory(CSysString &path)
50 UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
52 return (needLength > 0 && needLength <= MAX_PATH);
56 bool MyGetWindowsDirectory(UString &path)
60 UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
62 return (needLength > 0 && needLength <= MAX_PATH);
65 if (!MyGetWindowsDirectory(sysPath))
67 path = GetUnicodePath(sysPath);
71 bool MyGetSystemDirectory(UString &path)
75 UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
77 return (needLength > 0 && needLength <= MAX_PATH);
80 if (!MyGetSystemDirectory(sysPath))
82 path = GetUnicodePath(sysPath);
87 bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
92 ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
96 HANDLE hDir = ::CreateFileW(fileName, GENERIC_WRITE,
97 FILE_SHARE_READ | FILE_SHARE_WRITE,
98 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
100 if (hDir == INVALID_HANDLE_VALUE)
103 if (GetLongPath(fileName, longPath))
104 hDir = ::CreateFileW(longPath, GENERIC_WRITE,
105 FILE_SHARE_READ | FILE_SHARE_WRITE,
106 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
111 if (hDir != INVALID_HANDLE_VALUE)
113 res = BOOLToBool(::SetFileTime(hDir, creationTime, lastAccessTime, lastWriteTime));
119 bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
121 if (::SetFileAttributes(fileName, fileAttributes))
123 #ifdef WIN_LONG_PATH2
125 if (GetLongPath(fileName, longPath))
126 return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
131 bool MyRemoveDirectory(LPCTSTR pathName)
133 if (::RemoveDirectory(pathName))
135 #ifdef WIN_LONG_PATH2
137 if (GetLongPath(pathName, longPath))
138 return BOOLToBool(::RemoveDirectoryW(longPath));
144 bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2)
146 if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2))
148 if (d1.IsEmpty() && d2.IsEmpty()) return false;
149 if (d1.IsEmpty()) d1 = s1;
150 if (d2.IsEmpty()) d2 = s2;
155 bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName)
157 if (::MoveFile(existFileName, newFileName))
159 #ifdef WIN_LONG_PATH2
161 if (GetLongPaths(existFileName, newFileName, d1, d2))
162 return BOOLToBool(::MoveFileW(d1, d2));
168 bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
171 return MySetFileAttributes(GetSysPath(fileName), fileAttributes);
172 if (::SetFileAttributesW(fileName, fileAttributes))
176 if (GetLongPath(fileName, longPath))
177 return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
183 bool MyRemoveDirectory(LPCWSTR pathName)
186 return MyRemoveDirectory(GetSysPath(pathName));
187 if (::RemoveDirectoryW(pathName))
191 if (GetLongPath(pathName, longPath))
192 return BOOLToBool(::RemoveDirectoryW(longPath));
197 bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
200 return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName));
201 if (::MoveFileW(existFileName, newFileName))
205 if (GetLongPaths(existFileName, newFileName, d1, d2))
206 return BOOLToBool(::MoveFileW(d1, d2));
212 bool MyCreateDirectory(LPCTSTR pathName)
214 if (::CreateDirectory(pathName, NULL))
216 #ifdef WIN_LONG_PATH2
217 if (::GetLastError() != ERROR_ALREADY_EXISTS)
220 if (GetLongPath(pathName, longPath))
221 return BOOLToBool(::CreateDirectoryW(longPath, NULL));
228 bool MyCreateDirectory(LPCWSTR pathName)
231 return MyCreateDirectory(GetSysPath(pathName));
232 if (::CreateDirectoryW(pathName, NULL))
235 if (::GetLastError() != ERROR_ALREADY_EXISTS)
238 if (GetLongPath(pathName, longPath))
239 return BOOLToBool(::CreateDirectoryW(longPath, NULL));
247 bool CreateComplexDirectory(LPCTSTR pathName)
249 NName::CParsedPath path;
250 path.ParsePath(pathName);
251 CSysString fullPath = path.Prefix;
252 DWORD errorCode = ERROR_SUCCESS;
253 for(int i = 0; i < path.PathParts.Size(); i++)
255 const CSysString &string = path.PathParts[i];
258 if(i != path.PathParts.Size() - 1)
262 fullPath += path.PathParts[i];
263 if (!MyCreateDirectory(fullPath))
265 DWORD errorCode = GetLastError();
266 if(errorCode != ERROR_ALREADY_EXISTS)
269 fullPath += NName::kDirDelimiter;
275 bool CreateComplexDirectory(LPCTSTR _aPathName)
277 CSysString pathName = _aPathName;
278 int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
279 if (pos > 0 && pos == pathName.Length() - 1)
281 if (pathName.Length() == 3 && pathName[1] == ':')
282 return true; // Disk folder;
283 pathName.Delete(pos);
285 CSysString pathName2 = pathName;
286 pos = pathName.Length();
289 if(MyCreateDirectory(pathName))
291 if (::GetLastError() == ERROR_ALREADY_EXISTS)
293 NFind::CFileInfo fileInfo;
294 if (!NFind::FindFile(pathName, fileInfo)) // For network folders
296 if (!fileInfo.IsDirectory())
300 pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
301 if (pos < 0 || pos == 0)
303 if (pathName[pos - 1] == ':')
305 pathName = pathName.Left(pos);
307 pathName = pathName2;
308 while(pos < pathName.Length())
310 pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
312 pos = pathName.Length();
313 if (!MyCreateDirectory(pathName.Left(pos)))
321 bool CreateComplexDirectory(LPCWSTR _aPathName)
323 UString pathName = _aPathName;
324 int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
325 if (pos > 0 && pos == pathName.Length() - 1)
327 if (pathName.Length() == 3 && pathName[1] == L':')
328 return true; // Disk folder;
329 pathName.Delete(pos);
331 UString pathName2 = pathName;
332 pos = pathName.Length();
335 if(MyCreateDirectory(pathName))
337 if (::GetLastError() == ERROR_ALREADY_EXISTS)
339 NFind::CFileInfoW fileInfo;
340 if (!NFind::FindFile(pathName, fileInfo)) // For network folders
342 if (!fileInfo.IsDirectory())
346 pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
347 if (pos < 0 || pos == 0)
349 if (pathName[pos - 1] == L':')
351 pathName = pathName.Left(pos);
353 pathName = pathName2;
354 while(pos < pathName.Length())
356 pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
358 pos = pathName.Length();
359 if (!MyCreateDirectory(pathName.Left(pos)))
367 bool DeleteFileAlways(LPCTSTR name)
369 if (!MySetFileAttributes(name, 0))
371 if (::DeleteFile(name))
373 #ifdef WIN_LONG_PATH2
375 if (GetLongPath(name, longPath))
376 return BOOLToBool(::DeleteFileW(longPath));
382 bool DeleteFileAlways(LPCWSTR name)
385 return DeleteFileAlways(GetSysPath(name));
386 if (!MySetFileAttributes(name, 0))
388 if (::DeleteFileW(name))
392 if (GetLongPath(name, longPath))
393 return BOOLToBool(::DeleteFileW(longPath));
399 static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo)
401 if(fileInfo.IsDirectory())
402 return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
403 return DeleteFileAlways(pathPrefix + fileInfo.Name);
406 bool RemoveDirectoryWithSubItems(const CSysString &path)
408 NFind::CFileInfo fileInfo;
409 CSysString pathPrefix = path + NName::kDirDelimiter;
411 NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
412 while(enumerator.Next(fileInfo))
413 if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
416 if (!MySetFileAttributes(path, 0))
418 return MyRemoveDirectory(path);
422 static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo)
424 if(fileInfo.IsDirectory())
425 return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
426 return DeleteFileAlways(pathPrefix + fileInfo.Name);
428 bool RemoveDirectoryWithSubItems(const UString &path)
430 NFind::CFileInfoW fileInfo;
431 UString pathPrefix = path + UString(NName::kDirDelimiter);
433 NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard));
434 while(enumerator.Next(fileInfo))
435 if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
438 if (!MySetFileAttributes(path, 0))
440 return MyRemoveDirectory(path);
446 bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath)
448 DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
449 shortPath.ReleaseBuffer();
450 return (needLength > 0 && needLength < MAX_PATH);
453 bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex)
456 LPTSTR fileNamePointer = 0;
457 LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
458 DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
459 resultPath.ReleaseBuffer();
462 if (needLength >= MAX_PATH)
464 #ifdef WIN_LONG_PATH2
466 buffer = resultPath.GetBuffer(needLength + 1);
467 DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
468 resultPath.ReleaseBuffer();
469 if (needLength2 == 0 || needLength2 > needLength)
473 if (fileNamePointer == 0)
474 fileNamePartStartIndex = lstrlen(fileName);
476 fileNamePartStartIndex = (int)(fileNamePointer - buffer);
481 bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
486 LPWSTR fileNamePointer = 0;
487 LPWSTR buffer = resultPath.GetBuffer(MAX_PATH);
488 DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
489 resultPath.ReleaseBuffer();
492 if (needLength >= MAX_PATH)
496 buffer = resultPath.GetBuffer(needLength + 1);
497 DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
498 resultPath.ReleaseBuffer();
499 if (needLength2 == 0 || needLength2 > needLength)
503 if (fileNamePointer == 0)
504 fileNamePartStartIndex = MyStringLen(fileName);
506 fileNamePartStartIndex = (int)(fileNamePointer - buffer);
511 if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex))
513 UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex));
514 UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex));
515 fileNamePartStartIndex = resultPath1.Length();
516 resultPath = resultPath1 + resultPath2;
523 bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
526 return MyGetFullPathName(fileName, path, index);
530 bool MyGetFullPathName(LPCWSTR fileName, UString &path)
533 return MyGetFullPathName(fileName, path, index);
537 bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
540 if (!MyGetFullPathName(fileName, resultName, index))
542 resultName = resultName.Mid(index);
547 bool GetOnlyName(LPCWSTR fileName, UString &resultName)
550 if (!MyGetFullPathName(fileName, resultName, index))
552 resultName = resultName.Mid(index);
557 bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
560 if (!MyGetFullPathName(fileName, resultName, index))
562 resultName = resultName.Left(index);
567 bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName)
570 if (!MyGetFullPathName(fileName, resultName, index))
572 resultName = resultName.Left(index);
577 bool MyGetCurrentDirectory(CSysString &path)
579 DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
580 path.ReleaseBuffer();
581 return (needLength > 0 && needLength <= MAX_PATH);
585 bool MySetCurrentDirectory(LPCWSTR path)
588 return BOOLToBool(::SetCurrentDirectoryW(path));
589 return MySetCurrentDirectory(GetSysPath(path));
591 bool MyGetCurrentDirectory(UString &path)
595 DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
596 path.ReleaseBuffer();
597 return (needLength > 0 && needLength <= MAX_PATH);
600 if (!MyGetCurrentDirectory(sysPath))
602 path = GetUnicodePath(sysPath);
608 bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension,
609 CSysString &resultPath, UINT32 &filePart)
611 LPTSTR filePartPointer;
612 DWORD value = ::SearchPath(path, fileName, extension,
613 MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
614 filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath);
615 resultPath.ReleaseBuffer();
616 return (value > 0 && value <= MAX_PATH);
620 bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension,
621 UString &resultPath, UINT32 &filePart)
625 LPWSTR filePartPointer = 0;
626 DWORD value = ::SearchPathW(path, fileName, extension,
627 MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
628 filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath);
629 resultPath.ReleaseBuffer();
630 return (value > 0 && value <= MAX_PATH);
635 path != 0 ? (LPCTSTR)GetSysPath(path): 0,
636 fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0,
637 extension != 0 ? (LPCTSTR)GetSysPath(extension): 0,
640 UString resultPath1 = GetUnicodePath(sysPath.Left(filePart));
641 UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart));
642 filePart = resultPath1.Length();
643 resultPath = resultPath1 + resultPath2;
648 bool MyGetTempPath(CSysString &path)
650 DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
651 path.ReleaseBuffer();
652 return (needLength > 0 && needLength <= MAX_PATH);
656 bool MyGetTempPath(UString &path)
661 DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
662 path.ReleaseBuffer();
663 return (needLength > 0 && needLength <= MAX_PATH);
666 if (!MyGetTempPath(sysPath))
668 path = GetUnicodePath(sysPath);
673 UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path)
675 UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1));
676 path.ReleaseBuffer();
681 UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path)
685 UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH));
686 path.ReleaseBuffer();
690 UINT number = MyGetTempFileName(
691 dirPath ? (LPCTSTR)GetSysPath(dirPath): 0,
692 prefix ? (LPCTSTR)GetSysPath(prefix): 0,
694 path = GetUnicodePath(sysPath);
699 UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
702 UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
705 _fileName = resultPath;
706 _mustBeDeleted = true;
711 bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
714 if (!MyGetTempPath(tempPath))
716 if (Create(tempPath, prefix, resultPath) != 0)
718 if (!MyGetWindowsDirectory(tempPath))
720 return (Create(tempPath, prefix, resultPath) != 0);
723 bool CTempFile::Remove()
727 _mustBeDeleted = !DeleteFileAlways(_fileName);
728 return !_mustBeDeleted;
733 UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath)
736 UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
739 _fileName = resultPath;
740 _mustBeDeleted = true;
745 bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath)
748 if (!MyGetTempPath(tempPath))
750 if (Create(tempPath, prefix, resultPath) != 0)
752 if (!MyGetWindowsDirectory(tempPath))
754 return (Create(tempPath, prefix, resultPath) != 0);
757 bool CTempFileW::Remove()
761 _mustBeDeleted = !DeleteFileAlways(_fileName);
762 return !_mustBeDeleted;
767 bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName)
770 CSysString prefix = tempPath + prefixChars;
777 if (!tempFile.Create(prefix, dirName))
779 if (!::DeleteFile(dirName))
782 UINT32 randomNumber = random.Generate();
783 TCHAR randomNumberString[32];
784 _stprintf(randomNumberString, _T("%04X"), randomNumber);
785 dirName = prefix + randomNumberString;
787 if(NFind::DoesFileExist(dirName))
789 if (MyCreateDirectory(dirName))
791 if (::GetLastError() != ERROR_ALREADY_EXISTS)
796 bool CTempDirectory::Create(LPCTSTR prefix)
799 return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
804 bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
807 CSysString prefix = tempPath + prefixChars;
814 if (!tempFile.Create(prefix, dirName))
816 if (!DeleteFileAlways(dirName))
819 UINT32 randomNumber = random.Generate();
820 TCHAR randomNumberString[32];
821 _stprintf(randomNumberString, _T("%04X"), randomNumber);
822 dirName = prefix + randomNumberString;
824 if(NFind::DoesFileExist(dirName))
826 if (MyCreateDirectory(dirName))
828 if (::GetLastError() != ERROR_ALREADY_EXISTS)
833 bool CTempDirectoryW::Create(LPCWSTR prefix)
836 return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));