summaryrefslogtreecommitdiff
path: root/zen/file_access.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_access.cpp')
-rw-r--r--zen/file_access.cpp96
1 files changed, 81 insertions, 15 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index ea13d381..78da0220 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -167,6 +167,31 @@ bool isFatDrive(const Zstring& filePath) //noexcept
return &buffer[0] == Zstring(L"FAT") ||
&buffer[0] == Zstring(L"FAT32");
}
+
+
+#ifdef ZEN_WIN_VISTA_AND_LATER
+bool isFatDrive(HANDLE hFile) //noexcept
+{
+ const DWORD bufferSize = MAX_PATH + 1; //"The length of the file system name buffer, in TCHARs. The maximum buffer size is MAX_PATH + 1"
+ std::vector<wchar_t> buffer(bufferSize);
+
+ if (!::GetVolumeInformationByHandleW(hFile, //_In_ HANDLE hFile,
+ nullptr, //_Out_writes_opt_(nVolumeNameSize) LPWSTR lpVolumeNameBuffer,
+ 0, //_In_ DWORD nVolumeNameSize,
+ nullptr, //_Out_opt_ LPDWORD lpVolumeSerialNumber,
+ nullptr, //_Out_opt_ LPDWORD lpMaximumComponentLength,
+ nullptr, //_Out_opt_ LPDWORD lpFileSystemFlags,
+ &buffer[0], //_Out_writes_opt_(nFileSystemNameSize) LPWSTR lpFileSystemNameBuffer,
+ bufferSize)) //_In_ DWORD nFileSystemNameSize
+ {
+ assert(false);
+ return false;
+ }
+
+ return &buffer[0] == Zstring(L"FAT") ||
+ &buffer[0] == Zstring(L"FAT32");
+}
+#endif
#endif
}
@@ -247,6 +272,43 @@ std::uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, retu
}
+VolumeId zen::getVolumeId(const Zstring& itemPath) //throw FileError
+{
+#ifdef ZEN_WIN
+ //this works for:
+ //- root paths "C:\", "D:\"
+ //- network shares: \\share\dirname
+ //- indirection: subst S: %USERPROFILE%
+ // -> GetVolumePathName() + GetVolumeInformation() OTOH incorrectly resolves "S:\Desktop\somedir" to "S:\Desktop\" - nice try...
+ const HANDLE hItem = ::CreateFile(zen::applyLongPathPrefix(itemPath).c_str(), //_In_ LPCTSTR lpFileName,
+ 0, //_In_ DWORD dwDesiredAccess,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode,
+ nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ OPEN_EXISTING, //_In_ DWORD dwCreationDisposition,
+ // FILE_FLAG_OPEN_REPARSE_POINT -> no, we follow symlinks!
+ FILE_FLAG_BACKUP_SEMANTICS, //_In_ DWORD dwFlagsAndAttributes,
+ /*needed to open a directory*/
+ nullptr); //_In_opt_ HANDLE hTemplateFile
+ if (hItem == INVALID_HANDLE_VALUE)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"CreateFile");
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hItem));
+
+ BY_HANDLE_FILE_INFORMATION fileInfo = {};
+ if (!::GetFileInformationByHandle(hItem, &fileInfo))
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"GetFileInformationByHandle");
+
+ return fileInfo.dwVolumeSerialNumber;
+
+#elif defined ZEN_LINUX || defined ZEN_MAC
+ struct ::stat fileInfo = {};
+ if (::stat(itemPath.c_str(), &fileInfo) != 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"stat");
+
+ return fileInfo.st_dev;
+#endif
+}
+
+
bool zen::removeFile(const Zstring& filePath) //throw FileError
{
#ifdef ZEN_WIN
@@ -398,7 +460,7 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
if (!::MoveFileEx(pathSourceFmt.c_str(), //__in LPCTSTR lpExistingFileName,
pathTargetFmt.c_str(), //__in_opt LPCTSTR lpNewFileName,
- 0)) //__in DWORD dwFlags
+ 0)) //__in DWORD dwFlags
{
DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
@@ -412,7 +474,7 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
//try again...
if (::MoveFileEx(pathSourceFmt.c_str(), //__in LPCTSTR lpExistingFileName,
pathTargetFmt.c_str(), //__in_opt LPCTSTR lpNewFileName,
- 0)) //__in DWORD dwFlags
+ 0)) //__in DWORD dwFlags
{
//(try to) restore file attributes
::SetFileAttributes(pathTargetFmt.c_str(), oldAttr); //don't handle error
@@ -623,7 +685,7 @@ void setFileTimeByHandle(HANDLE hFile, //throw FileError
nullptr, //__in_opt const FILETIME *lpLastAccessTime,
&lastWriteTime)) //__in_opt const FILETIME *lpLastWriteTime
{
- DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
auto toLargeInteger = [](const FILETIME& ft) -> LARGE_INTEGER
{
@@ -667,8 +729,7 @@ void setFileTimeByHandle(HANDLE hFile, //throw FileError
setFileInfo(basicInfo2); //throw FileError
}
catch (FileError&) {}
-
- ec = ERROR_SUCCESS;
+ return;
}
}
#endif
@@ -676,7 +737,11 @@ void setFileTimeByHandle(HANDLE hFile, //throw FileError
std::wstring errorMsg = replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath));
//add more meaningful message: FAT accepts only a subset of the NTFS date range
- if (ec == ERROR_INVALID_PARAMETER && isFatDrive(filePath))
+#ifdef ZEN_WIN_VISTA_AND_LATER
+ if (ec == ERROR_INVALID_PARAMETER && isFatDrive(hFile))
+#else
+ if (ec == ERROR_INVALID_PARAMETER && isFatDrive(filePath))
+#endif
{
//let's not fail due to an invalid creation time on FAT: http://www.freefilesync.org/forum/viewtopic.php?t=2278
if (creationTime) //retry (single-level recursion at most!)
@@ -718,8 +783,7 @@ void setFileTimeByHandle(HANDLE hFile, //throw FileError
}
}
- if (ec != ERROR_SUCCESS)
- throw FileError(errorMsg, formatSystemError(L"SetFileTime", ec));
+ throw FileError(errorMsg, formatSystemError(L"SetFileTime", ec));
}
}
@@ -1398,7 +1462,7 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
//- automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)!
//- it isn't able to copy most junctions because of missing permissions (although target path can be retrieved alternatively!)
if (!::CreateDirectory(applyLongPathPrefixCreateDir(targetPath).c_str(), //__in LPCTSTR lpPathName,
- nullptr)) //__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ nullptr)) //__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes
{
DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
@@ -1473,7 +1537,7 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
if (::GetFileInformationByHandle(hDirSrc, &dirInfo))
{
::SetFileAttributes(applyLongPathPrefix(targetPath).c_str(), dirInfo.dwFileAttributes);
- //copy "read-only and system attributes": http://blogs.msdn.com/b/oldnewthing/archive/2003/09/30/55100.aspx
+ //copy "read-only and system attributes": https://blogs.msdn.microsoft.com/oldnewthing/20030930-00/?p=42353/
const bool isEncrypted = (dirInfo.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
const bool isCompressed = (dirInfo.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
@@ -1544,7 +1608,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
return ret != INVALID_FILE_ATTRIBUTES && (ret & FILE_ATTRIBUTE_DIRECTORY);
}();
- typedef BOOLEAN (WINAPI* CreateSymbolicLinkFunc)(LPCTSTR lpSymlinkFileName, LPCTSTR lpTargetFileName, DWORD dwFlags);
+ using CreateSymbolicLinkFunc = BOOLEAN (WINAPI*)(LPCTSTR lpSymlinkFileName, LPCTSTR lpTargetFileName, DWORD dwFlags);
const SysDllFun<CreateSymbolicLinkFunc> createSymbolicLink(L"kernel32.dll", "CreateSymbolicLinkW");
if (!createSymbolicLink)
@@ -1663,7 +1727,10 @@ bool canCopyAsSparse(DWORD fileAttrSource, Function getTargetFsFlags) //throw ()
DWORD targetFsFlags = 0;
if (!getTargetFsFlags(targetFsFlags))
- return false;
+ {
+ assert(false);
+ return false;
+ }
assert(targetFsFlags != 0);
return (targetFsFlags & FILE_SUPPORTS_SPARSE_FILES) != 0;
@@ -2069,9 +2136,8 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
0, //_In_ DWORD nOutBufferSize,
&bytesReturned, //_Out_opt_ LPDWORD lpBytesReturned
nullptr)) //_Inout_opt_ LPOVERLAPPED lpOverlapped
- {} //may legitimately fail with ERROR_INVALID_FUNCTION if
-
- // - if target folder is encrypted
+ {} //may legitimately fail with ERROR_INVALID_FUNCTION if:
+ // - target folder is encrypted
// - target volume does not support compressed attribute
//#############################################################################
}
bgstack15