diff options
Diffstat (limited to 'zen/file_access.cpp')
-rw-r--r-- | zen/file_access.cpp | 96 |
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 //############################################################################# } |