summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/Windows/FileDir.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2016-04-09 21:45:54 +1000
committer Vas Crabb <vas@vastheman.com>2016-04-09 21:52:08 +1000
commite925c494fe30adafb615c075f5eb692dd2b2effa (patch)
treeeed0b7ccadb049ed2dc8a72282c0235c4e94b6ae /3rdparty/lzma/CPP/Windows/FileDir.cpp
parentb13e02f9751424dfc9ce6070676e2e318087a991 (diff)
Update LZMA SDK to 15.14
Diffstat (limited to '3rdparty/lzma/CPP/Windows/FileDir.cpp')
-rw-r--r--3rdparty/lzma/CPP/Windows/FileDir.cpp501
1 files changed, 302 insertions, 199 deletions
diff --git a/3rdparty/lzma/CPP/Windows/FileDir.cpp b/3rdparty/lzma/CPP/Windows/FileDir.cpp
index 88215faa2ad..da71b710bdc 100644
--- a/3rdparty/lzma/CPP/Windows/FileDir.cpp
+++ b/3rdparty/lzma/CPP/Windows/FileDir.cpp
@@ -14,21 +14,17 @@
extern bool g_IsNT;
#endif
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
namespace NWindows {
namespace NFile {
-
-// SetCurrentDirectory doesn't support \\?\ prefix
-
-#ifdef WIN_LONG_PATH
-bool GetLongPathBase(CFSTR fileName, UString &res);
-bool GetLongPath(CFSTR fileName, UString &res);
-#endif
-
-namespace NDirectory {
+namespace NDir {
#ifndef UNDER_CE
-bool MyGetWindowsDirectory(FString &path)
+bool GetWindowsDir(FString &path)
{
UINT needLength;
#ifndef _UNICODE
@@ -50,8 +46,7 @@ bool MyGetWindowsDirectory(FString &path)
return (needLength > 0 && needLength <= MAX_PATH);
}
-
-bool MyGetSystemDirectory(FString &path)
+bool GetSystemDir(FString &path)
{
UINT needLength;
#ifndef _UNICODE
@@ -74,7 +69,7 @@ bool MyGetSystemDirectory(FString &path)
}
#endif
-bool SetDirTime(CFSTR fileName, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
{
#ifndef _UNICODE
if (!g_IsNT)
@@ -83,14 +78,17 @@ bool SetDirTime(CFSTR fileName, const FILETIME *cTime, const FILETIME *aTime, co
return false;
}
#endif
- HANDLE hDir = ::CreateFileW(fs2us(fileName), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ HANDLE hDir = INVALID_HANDLE_VALUE;
+ IF_USE_MAIN_PATH
+ hDir = ::CreateFileW(fs2us(path), 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)
+ if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
{
- UString longPath;
- if (GetLongPath(fileName, longPath))
- hDir = ::CreateFileW(longPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
#endif
@@ -104,87 +102,154 @@ bool SetDirTime(CFSTR fileName, const FILETIME *cTime, const FILETIME *aTime, co
return res;
}
-#ifdef WIN_LONG_PATH
-bool GetLongPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2)
+bool SetFileAttrib(CFSTR path, DWORD attrib)
{
- if (!GetLongPathBase(s1, d1) ||
- !GetLongPathBase(s2, d2))
- return false;
- if (d1.IsEmpty() && d2.IsEmpty())
- return false;
- if (d1.IsEmpty()) d1 = fs2us(s1);
- if (d2.IsEmpty()) d2 = fs2us(s2);
- return true;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::SetFileAttributes(fs2fas(path), attrib))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::SetFileAttributesW(fs2us(path), attrib))
+ return true;
+ #ifdef WIN_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::SetFileAttributesW(superPath, attrib));
+ }
+ #endif
+ }
+ return false;
}
-#endif
-bool MySetFileAttributes(CFSTR fileName, DWORD fileAttributes)
+bool RemoveDir(CFSTR path)
{
#ifndef _UNICODE
if (!g_IsNT)
{
- if (::SetFileAttributes(fs2fas(fileName), fileAttributes))
+ if (::RemoveDirectory(fs2fas(path)))
return true;
}
else
#endif
{
- if (::SetFileAttributesW(fs2us(fileName), fileAttributes))
- return true;
+ IF_USE_MAIN_PATH
+ if (::RemoveDirectoryW(fs2us(path)))
+ return true;
#ifdef WIN_LONG_PATH
- UString longPath;
- if (GetLongPath(fileName, longPath))
- return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::RemoveDirectoryW(superPath));
+ }
#endif
}
return false;
}
-bool MyRemoveDirectory(CFSTR path)
+bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
{
#ifndef _UNICODE
if (!g_IsNT)
{
- if (::RemoveDirectory(fs2fas(path)))
+ if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
return true;
}
else
#endif
{
- if (::RemoveDirectoryW(fs2us(path)))
- return true;
+ IF_USE_MAIN_PATH_2(oldFile, newFile)
+ if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
+ return true;
#ifdef WIN_LONG_PATH
- UString longPath;
- if (GetLongPath(path, longPath))
- return BOOLToBool(::RemoveDirectoryW(longPath));
+ if (USE_SUPER_PATH_2)
+ {
+ UString d1, d2;
+ if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
+ return BOOLToBool(::MoveFileW(d1, d2));
+ }
#endif
}
return false;
}
-bool MyMoveFile(CFSTR existFileName, CFSTR newFileName)
+#ifndef UNDER_CE
+
+EXTERN_C_BEGIN
+typedef BOOL (WINAPI *Func_CreateHardLinkW)(
+ LPCWSTR lpFileName,
+ LPCWSTR lpExistingFileName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ );
+EXTERN_C_END
+
+bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
{
#ifndef _UNICODE
if (!g_IsNT)
{
- if (::MoveFile(fs2fas(existFileName), fs2fas(newFileName)))
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ /*
+ if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL))
return true;
+ */
}
else
#endif
{
- if (::MoveFileW(fs2us(existFileName), fs2us(newFileName)))
- return true;
+ Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW)
+ ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW");
+ if (!my_CreateHardLinkW)
+ return false;
+ IF_USE_MAIN_PATH_2(newFileName, existFileName)
+ if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
+ return true;
#ifdef WIN_LONG_PATH
- UString d1, d2;
- if (GetLongPaths(existFileName, newFileName, d1, d2))
- return BOOLToBool(::MoveFileW(d1, d2));
+ if (USE_SUPER_PATH_2)
+ {
+ UString d1, d2;
+ if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
+ return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
+ }
#endif
}
return false;
}
-bool MyCreateDirectory(CFSTR path)
+#endif
+
+/*
+WinXP-64 CreateDir():
+ "" - ERROR_PATH_NOT_FOUND
+ \ - ERROR_ACCESS_DENIED
+ C:\ - ERROR_ACCESS_DENIED, if there is such drive,
+
+ D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive,
+ C:\nonExistent\folder - ERROR_PATH_NOT_FOUND
+
+ C:\existFolder - ERROR_ALREADY_EXISTS
+ C:\existFolder\ - ERROR_ALREADY_EXISTS
+
+ C:\folder - OK
+ C:\folder\ - OK
+
+ \\Server\nonExistent - ERROR_BAD_NETPATH
+ \\Server\Share_Readonly - ERROR_ACCESS_DENIED
+ \\Server\Share - ERROR_ALREADY_EXISTS
+
+ \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED
+ \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS
+*/
+
+bool CreateDir(CFSTR path)
{
#ifndef _UNICODE
if (!g_IsNT)
@@ -195,200 +260,241 @@ bool MyCreateDirectory(CFSTR path)
else
#endif
{
- if (::CreateDirectoryW(fs2us(path), NULL))
- return true;
+ IF_USE_MAIN_PATH
+ if (::CreateDirectoryW(fs2us(path), NULL))
+ return true;
#ifdef WIN_LONG_PATH
- if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
{
- UString longPath;
- if (GetLongPath(path, longPath))
- return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::CreateDirectoryW(superPath, NULL));
}
#endif
}
return false;
}
-bool CreateComplexDirectory(CFSTR _aPathName)
+/*
+ CreateDir2 returns true, if directory can contain files after the call (two cases):
+ 1) the directory already exists
+ 2) the directory was created
+ path must be WITHOUT trailing path separator.
+
+ We need CreateDir2, since fileInfo.Find() for reserved names like "com8"
+ returns FILE instead of DIRECTORY. And we need to use SuperPath */
+
+static bool CreateDir2(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::CreateDirectory(fs2fas(path), NULL))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::CreateDirectoryW(fs2us(path), NULL))
+ return true;
+ #ifdef WIN_LONG_PATH
+ if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ {
+ if (::CreateDirectoryW(superPath, NULL))
+ return true;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ NFind::CFileInfo fi;
+ if (!fi.Find(us2fs(superPath)))
+ return false;
+ return fi.IsDir();
+ }
+ }
+ #endif
+ }
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ NFind::CFileInfo fi;
+ if (!fi.Find(path))
+ return false;
+ return fi.IsDir();
+}
+
+bool CreateComplexDir(CFSTR _path)
{
- FString pathName = _aPathName;
- int pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR);
- if (pos > 0 && pos == pathName.Length() - 1)
+ #ifdef _WIN32
+
{
- if (pathName.Length() == 3 && pathName[1] == L':')
- return true; // Disk folder;
- pathName.Delete(pos);
+ DWORD attrib = NFind::GetFileAttrib(_path);
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return true;
}
- FString pathName2 = pathName;
- pos = pathName.Length();
+
+ #ifndef UNDER_CE
+
+ if (IsDriveRootPath_SuperAllowed(_path))
+ return false;
+
+ unsigned prefixSize = GetRootPrefixSize(_path);
+
+ #endif
+
+ #endif
+
+ FString path = _path;
+
+ int pos = path.ReverseFind_PathSepar();
+ if (pos >= 0 && (unsigned)pos == path.Len() - 1)
+ {
+ if (path.Len() == 1)
+ return true;
+ path.DeleteBack();
+ }
+
+ const FString path2 = path;
+ pos = path.Len();
+
for (;;)
{
- if (MyCreateDirectory(pathName))
+ if (CreateDir2(path))
break;
if (::GetLastError() == ERROR_ALREADY_EXISTS)
- {
- NFind::CFileInfo fileInfo;
- if (!fileInfo.Find(pathName)) // For network folders
- return true;
- if (!fileInfo.IsDir())
- return false;
- break;
- }
- pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR);
+ return false;
+ pos = path.ReverseFind_PathSepar();
if (pos < 0 || pos == 0)
return false;
- if (pathName[pos - 1] == L':')
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (pos == 1 && IS_PATH_SEPAR(path[0]))
+ return false;
+ if (prefixSize >= (unsigned)pos + 1)
return false;
- pathName = pathName.Left(pos);
+ #endif
+
+ path.DeleteFrom(pos);
}
- pathName = pathName2;
- while (pos < pathName.Length())
+
+ while (pos < (int)path2.Len())
{
- pos = pathName.Find(FCHAR_PATH_SEPARATOR, pos + 1);
- if (pos < 0)
- pos = pathName.Length();
- if (!MyCreateDirectory(pathName.Left(pos)))
+ int pos2 = NName::FindSepar(path2.Ptr(pos + 1));
+ if (pos2 < 0)
+ pos = path2.Len();
+ else
+ pos += 1 + pos2;
+ path.SetFrom(path2, pos);
+ if (!CreateDir(path))
return false;
}
+
return true;
}
-bool DeleteFileAlways(CFSTR name)
+bool DeleteFileAlways(CFSTR path)
{
- if (!MySetFileAttributes(name, 0))
- return false;
+ /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
+ SetFileAttrib("name:stream", ) changes attributes of main file. */
+ {
+ DWORD attrib = NFind::GetFileAttrib(path);
+ if (attrib != INVALID_FILE_ATTRIBUTES
+ && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
+ && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ if (!SetFileAttrib(path, attrib & ~FILE_ATTRIBUTE_READONLY))
+ return false;
+ }
+ }
+
#ifndef _UNICODE
if (!g_IsNT)
{
- if (::DeleteFile(fs2fas(name)))
+ if (::DeleteFile(fs2fas(path)))
return true;
}
else
#endif
{
- if (::DeleteFileW(fs2us(name)))
- return true;
+ /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
+ Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
+ IF_USE_MAIN_PATH
+ if (::DeleteFileW(fs2us(path)))
+ return true;
#ifdef WIN_LONG_PATH
- UString longPath;
- if (GetLongPath(name, longPath))
- return BOOLToBool(::DeleteFileW(longPath));
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::DeleteFileW(superPath));
+ }
#endif
}
return false;
}
-static bool RemoveDirectorySubItems2(const FString pathPrefix, const NFind::CFileInfo &fileInfo)
-{
- if (fileInfo.IsDir())
- return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
- return DeleteFileAlways(pathPrefix + fileInfo.Name);
-}
-bool RemoveDirectoryWithSubItems(const FString &path)
+bool RemoveDirWithSubItems(const FString &path)
{
- NFind::CFileInfo fileInfo;
- FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
+ bool needRemoveSubItems = true;
{
- NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK);
- while (enumerator.Next(fileInfo))
- if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+ NFind::CFileInfo fi;
+ if (!fi.Find(path))
+ return false;
+ if (!fi.IsDir())
+ {
+ ::SetLastError(ERROR_DIRECTORY);
+ return false;
+ }
+ if (fi.HasReparsePoint())
+ needRemoveSubItems = false;
+ }
+
+ if (needRemoveSubItems)
+ {
+ FString s = path;
+ s.Add_PathSepar();
+ unsigned prefixSize = s.Len();
+ s += FCHAR_ANY_MASK;
+ NFind::CEnumerator enumerator(s);
+ NFind::CFileInfo fi;
+ while (enumerator.Next(fi))
+ {
+ s.DeleteFrom(prefixSize);
+ s += fi.Name;
+ if (fi.IsDir())
+ {
+ if (!RemoveDirWithSubItems(s))
+ return false;
+ }
+ else if (!DeleteFileAlways(s))
return false;
+ }
}
- if (!MySetFileAttributes(path, 0))
+
+ if (!SetFileAttrib(path, 0))
return false;
- return MyRemoveDirectory(path);
+ return RemoveDir(path);
}
#ifdef UNDER_CE
-bool MyGetFullPathName(CFSTR fileName, FString &resFullPath)
+bool MyGetFullPathName(CFSTR path, FString &resFullPath)
{
- resFullPath = fileName;
+ resFullPath = path;
return true;
}
#else
-#ifdef WIN_LONG_PATH
-
-static FString GetLastPart(CFSTR path)
-{
- int i = MyStringLen(path);
- for (; i > 0; i--)
- {
- FChar c = path[i - 1];
- if (c == FCHAR_PATH_SEPARATOR || c == '/')
- break;
- }
- return path + i;
-}
-
-static void AddTrailingDots(CFSTR oldPath, FString &newPath)
+bool MyGetFullPathName(CFSTR path, FString &resFullPath)
{
- int len = MyStringLen(oldPath);
- int i;
- for (i = len; i > 0 && oldPath[i - 1] == '.'; i--);
- if (i == 0 || i == len)
- return;
- FString oldName = GetLastPart(oldPath);
- FString newName = GetLastPart(newPath);
- int nonDotsLen = oldName.Length() - (len - i);
- if (nonDotsLen == 0 || newName.CompareNoCase(oldName.Left(nonDotsLen)) != 0)
- return;
- for (; i != len; i++)
- newPath += '.';
-}
-
-#endif
-
-bool MyGetFullPathName(CFSTR fileName, FString &resFullPath)
-{
- resFullPath.Empty();
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- LPTSTR fileNamePointer = 0;
- DWORD needLength = ::GetFullPathName(fs2fas(fileName), MAX_PATH + 1, s, &fileNamePointer);
- if (needLength == 0 || needLength > MAX_PATH)
- return false;
- resFullPath = fas2fs(s);
- return true;
- }
- else
- #endif
- {
- LPWSTR fileNamePointer = 0;
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- DWORD needLength = ::GetFullPathNameW(fs2us(fileName), MAX_PATH + 1, s, &fileNamePointer);
- if (needLength == 0)
- return false;
- if (needLength <= MAX_PATH)
- {
- resFullPath = us2fs(s);
- return true;
- }
- #ifdef WIN_LONG_PATH
- needLength++;
- UString temp;
- LPWSTR buffer = temp.GetBuffer(needLength + 1);
- buffer[0] = 0;
- DWORD needLength2 = ::GetFullPathNameW(fs2us(fileName), needLength, buffer, &fileNamePointer);
- temp.ReleaseBuffer();
- if (needLength2 > 0 && needLength2 <= needLength)
- {
- resFullPath = us2fs(temp);
- AddTrailingDots(fileName, resFullPath);
- return true;
- }
- #endif
- return false;
- }
+ return GetFullPath(path, resFullPath);
}
-bool MySetCurrentDirectory(CFSTR path)
+bool SetCurrentDir(CFSTR path)
{
+ // SetCurrentDirectory doesn't support \\?\ prefix
#ifndef _UNICODE
if (!g_IsNT)
{
@@ -401,7 +507,7 @@ bool MySetCurrentDirectory(CFSTR path)
}
}
-bool MyGetCurrentDirectory(FString &path)
+bool GetCurrentDir(FString &path)
{
path.Empty();
DWORD needLength;
@@ -428,15 +534,12 @@ bool MyGetCurrentDirectory(FString &path)
bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
{
- bool res = MyGetFullPathName(path, resFileName);
+ bool res = MyGetFullPathName(path, resDirPrefix);
if (!res)
- resFileName = path;
- int pos = resFileName.ReverseFind(FCHAR_PATH_SEPARATOR);
- if (pos >= 0)
- {
- resDirPrefix = resFileName.Left(pos + 1);
- resFileName = resFileName.Mid(pos + 1);
- }
+ resDirPrefix = path;
+ int pos = resDirPrefix.ReverseFind_PathSepar();
+ resFileName = resDirPrefix.Ptr(pos + 1);
+ resDirPrefix.DeleteFrom(pos + 1);
return res;
}
@@ -484,7 +587,7 @@ static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COu
{
unsigned t = value & 0xF;
value >>= 4;
- s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ s[k] = (FChar)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
}
s[k] = '\0';
if (outFile)
@@ -510,7 +613,7 @@ static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COu
}
else
{
- if (MyCreateDirectory(path))
+ if (CreateDir(path))
return true;
}
DWORD error = GetLastError();
@@ -580,7 +683,7 @@ bool CTempDir::Remove()
{
if (!_mustBeDeleted)
return true;
- _mustBeDeleted = !RemoveDirectoryWithSubItems(_path);
+ _mustBeDeleted = !RemoveDirWithSubItems(_path);
return !_mustBeDeleted;
}