summaryrefslogtreecommitdiff
path: root/zen/file_handling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_handling.cpp')
-rw-r--r--zen/file_handling.cpp59
1 files changed, 30 insertions, 29 deletions
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index 3f8d5bbd..fd4239ed 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -205,29 +205,29 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
const int rv = procSl == SYMLINK_FOLLOW ?
:: stat(filename.c_str(), &fileInfo) :
::lstat(filename.c_str(), &fileInfo);
- if (rv != 0) //follow symbolic links
+ if (rv != 0)
throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"stat", getLastError()));
attr.fileSize = UInt64(fileInfo.st_size);
attr.modificationTime = fileInfo.st_mtime;
#endif
}
-}
-UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
+Int64 getFileTime(const Zstring& filename, ProcSymlink procSl) //throw FileError
{
FileAttrib attr;
- getFileAttrib(filename, attr, SYMLINK_FOLLOW); //throw FileError
- return attr.fileSize;
+ getFileAttrib(filename, attr, procSl); //throw FileError
+ return attr.modificationTime;
+}
}
-Int64 zen::getFileTime(const Zstring& filename, ProcSymlink procSl) //throw FileError
+UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
{
FileAttrib attr;
- getFileAttrib(filename, attr, procSl); //throw FileError
- return attr.modificationTime;
+ getFileAttrib(filename, attr, SYMLINK_FOLLOW); //throw FileError
+ return attr.fileSize;
}
@@ -537,8 +537,8 @@ public:
dirs_.push_back(fullName);
return nullptr; //DON'T traverse into subdirs; removeDirectory works recursively!
}
- virtual HandleError reportDirError (const std::wstring& msg) { throw FileError(msg); }
- virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { throw FileError(msg); }
+ virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); }
+ virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); }
private:
CollectFilesFlat(const CollectFilesFlat&);
@@ -1821,14 +1821,17 @@ struct CallbackData
const Zstring& targetFile) :
sourceFile_(sourceFile),
targetFile_(targetFile),
- userCallback(cb) {}
+ userCallback(cb),
+ fileInfoSrc(),
+ fileInfoTrg() {}
const Zstring& sourceFile_;
const Zstring& targetFile_;
CallbackCopyFile* const userCallback; //optional!
ErrorHandling errorHandler;
- FileAttrib newAttrib; //modified by CopyFileEx() at beginning
+ BY_HANDLE_FILE_INFORMATION fileInfoSrc; //modified by CopyFileEx() at beginning
+ BY_HANDLE_FILE_INFORMATION fileInfoTrg; //
Int64 bytesReported; //used internally to calculate bytes transferred delta
};
@@ -1852,7 +1855,7 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
if source is a symlink and COPY_FILE_COPY_SYMLINK is NOT specified, this callback is called and hSourceFile is a handle to the *target* of the link!
file time handling:
- ::CopyFileEx() will copy file modification time (only) over from source file AFTER the last invokation of this callback
+ ::CopyFileEx() will (only) copy file modification time over from source file AFTER the last invokation of this callback
=> it is possible to adapt file creation time of target in here, but NOT file modification time!
CAVEAT: if ::CopyFileEx() fails to set modification time, it silently ignores this error and returns success!!!
see procmon log in: https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3514569&group_id=234430
@@ -1870,38 +1873,31 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
dwStreamNumber == 1) //consider ADS!
{
//#################### return source file attributes ################################
- BY_HANDLE_FILE_INFORMATION fileInfoSrc = {};
- if (!::GetFileInformationByHandle(hSourceFile, &fileInfoSrc))
+ if (!::GetFileInformationByHandle(hSourceFile, &cbd.fileInfoSrc))
{
cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.sourceFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
return PROGRESS_CANCEL;
}
- BY_HANDLE_FILE_INFORMATION fileInfoTrg = {};
- if (!::GetFileInformationByHandle(hDestinationFile, &fileInfoTrg))
+ if (!::GetFileInformationByHandle(hDestinationFile, &cbd.fileInfoTrg))
{
cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.targetFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
return PROGRESS_CANCEL;
}
- cbd.newAttrib.fileSize = UInt64(fileInfoSrc.nFileSizeLow, fileInfoSrc.nFileSizeHigh);
- cbd.newAttrib.modificationTime = toTimeT(fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
- cbd.newAttrib.sourceFileId = extractFileID(fileInfoSrc);
- cbd.newAttrib.targetFileId = extractFileID(fileInfoTrg);
-
//#################### switch to sparse file copy if req. #######################
- if (canCopyAsSparse(fileInfoSrc.dwFileAttributes, cbd.targetFile_)) //throw ()
+ if (canCopyAsSparse(cbd.fileInfoSrc.dwFileAttributes, cbd.targetFile_)) //throw ()
{
cbd.errorHandler.reportErrorShouldCopyAsSparse(); //use a different copy routine!
return PROGRESS_CANCEL;
}
//#################### copy file creation time ################################
- ::SetFileTime(hDestinationFile, &fileInfoSrc.ftCreationTime, nullptr, nullptr); //no error handling!
+ ::SetFileTime(hDestinationFile, &cbd.fileInfoSrc.ftCreationTime, nullptr, nullptr); //no error handling!
//#################### copy NTFS compressed attribute #########################
- const bool sourceIsCompressed = (fileInfoSrc.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
- const bool targetIsCompressed = (fileInfoTrg.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; //already set by CopyFileEx if target parent folder is compressed!
+ const bool sourceIsCompressed = (cbd.fileInfoSrc.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
+ const bool targetIsCompressed = (cbd.fileInfoTrg.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; //already set by CopyFileEx if target parent folder is compressed!
if (sourceIsCompressed && !targetIsCompressed)
{
USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
@@ -2026,7 +2022,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile,
if (lastError == ERROR_INVALID_PARAMETER &&
dst::isFatDrive(targetFile) &&
getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw FileError
- errorDescr += L"\nFAT volume cannot store files larger than 4 gigabyte!";
+ errorDescr += L"\nFAT volumes cannot store files larger than 4 gigabyte.";
//note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filename is of a restricted type.
}
@@ -2036,13 +2032,18 @@ void copyFileWindowsDefault(const Zstring& sourceFile,
}
if (newAttrib)
- *newAttrib = cbd.newAttrib;
+ {
+ newAttrib->fileSize = UInt64(cbd.fileInfoSrc.nFileSizeLow, cbd.fileInfoSrc.nFileSizeHigh);
+ newAttrib->modificationTime = toTimeT(cbd.fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
+ newAttrib->sourceFileId = extractFileID(cbd.fileInfoSrc);
+ newAttrib->targetFileId = extractFileID(cbd.fileInfoTrg);
+ }
{
//DST hack
const Int64 modTime = getFileTime(sourceFile, SYMLINK_FOLLOW); //throw FileError
setFileTime(targetFile, modTime, SYMLINK_FOLLOW); //throw FileError
- //caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we need to set again in order to catch such errors!
+ //caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we need to set it again but with proper error checking!
// - this sequence leads to a loss of precision of up to 1 sec!
// - perf-loss on USB sticks with many small files of about 30%! damn!
bgstack15