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.cpp133
1 files changed, 56 insertions, 77 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index c2072a26..d8a1f3b7 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -1,8 +1,8 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
+// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
#include "file_access.h"
#include <map>
@@ -810,7 +810,7 @@ void setFileTimeByHandle(HANDLE hFile, //throw FileError
}
-void setWriteTimeNative(const Zstring& filePath,
+void setWriteTimeNative(const Zstring& itemPath,
const FILETIME& lastWriteTime,
const FILETIME* creationTime, //optional
ProcSymlink procSl) //throw FileError
@@ -839,21 +839,21 @@ void setWriteTimeNative(const Zstring& filePath,
DWORD attribs = INVALID_FILE_ATTRIBUTES;
ZEN_ON_SCOPE_EXIT(
if (attribs != INVALID_FILE_ATTRIBUTES)
- ::SetFileAttributes(applyLongPathPrefix(filePath).c_str(), attribs);
+ ::SetFileAttributes(applyLongPathPrefix(itemPath).c_str(), attribs);
);
auto removeReadonly = [&]() -> bool //throw FileError; may need to remove the readonly-attribute (e.g. on FAT usb drives)
{
if (attribs == INVALID_FILE_ATTRIBUTES)
{
- const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filePath).c_str());
+ const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(itemPath).c_str());
if (tmpAttr == INVALID_FILE_ATTRIBUTES)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileAttributes");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"GetFileAttributes");
if (tmpAttr & FILE_ATTRIBUTE_READONLY)
{
- if (!::SetFileAttributes(applyLongPathPrefix(filePath).c_str(), FILE_ATTRIBUTE_NORMAL))
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(filePath)), L"SetFileAttributes");
+ if (!::SetFileAttributes(applyLongPathPrefix(itemPath).c_str(), FILE_ATTRIBUTE_NORMAL))
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(itemPath)), L"SetFileAttributes");
attribs = tmpAttr; //reapplied on scope exit
return true;
@@ -864,7 +864,7 @@ void setWriteTimeNative(const Zstring& filePath,
auto openFile = [&](bool conservativeApproach)
{
- return ::CreateFile(applyLongPathPrefix(filePath).c_str(), //_In_ LPCTSTR lpFileName,
+ return ::CreateFile(applyLongPathPrefix(itemPath).c_str(), //_In_ LPCTSTR lpFileName,
(conservativeApproach ?
//some NAS seem to have issues with FILE_WRITE_ATTRIBUTES, even worse, they may fail silently!
//http://sourceforge.net/tracker/?func=detail&atid=1093081&aid=3536680&group_id=234430
@@ -906,20 +906,20 @@ void setWriteTimeNative(const Zstring& filePath,
continue;
//3. after these herculean stunts we give up...
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), formatSystemError(L"CreateFile", ec));
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), formatSystemError(L"CreateFile", ec));
}
}
break;
}
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
- setFileTimeByHandle(hFile, creationTime, lastWriteTime, filePath); //throw FileError
+ setFileTimeByHandle(hFile, creationTime, lastWriteTime, itemPath); //throw FileError
}
#ifndef NDEBUG //verify written data
FILETIME creationTimeDbg = {};
FILETIME lastWriteTimeDbg = {};
- HANDLE hFile = ::CreateFile(applyLongPathPrefix(filePath).c_str(), //_In_ LPCTSTR lpFileName,
+ HANDLE hFile = ::CreateFile(applyLongPathPrefix(itemPath).c_str(), //_In_ LPCTSTR lpFileName,
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, //_In_ DWORD dwDesiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode,
nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
@@ -942,26 +942,7 @@ void setWriteTimeNative(const Zstring& filePath,
#elif defined ZEN_LINUX
-void setWriteTimeFallback(const Zstring& filePath, std::int64_t modTime, ProcSymlink procSl) //throw FileError
-{
- struct ::timeval writeTime[2] = {};
- writeTime[0].tv_sec = ::time(nullptr); //access time (seconds)
- writeTime[1].tv_sec = modTime; //modification time (seconds)
-
- if (procSl == ProcSymlink::FOLLOW)
- {
- if (::utimes(filePath.c_str(), writeTime) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimes");
- }
- else
- {
- if (::lutimes(filePath.c_str(), writeTime) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"lutimes");
- }
-}
-
-
-void setWriteTimeNative(const Zstring& filePath, std::int64_t modTime, ProcSymlink procSl) //throw FileError
+void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTime, ProcSymlink procSl) //throw FileError
{
/*
[2013-05-01] sigh, we can't use utimensat() on NTFS volumes on Ubuntu: silent failure!!! what morons are programming this shit???
@@ -970,36 +951,33 @@ void setWriteTimeNative(const Zstring& filePath, std::int64_t modTime, ProcSymli
[2015-03-09]
- cannot reproduce issues with NTFS and utimensat() on Ubuntu
- utimensat() is supposed to obsolete utime/utimes and is also used by "cp" and "touch"
- - solves utimes() EINVAL bug for certain CIFS/NTFS drives: http://www.freefilesync.org/forum/viewtopic.php?t=387
- => don't use utimensat() directly, but open file descriptor manually, else EINVAL, again!
-
- => let's give utimensat another chance:
+ => let's give utimensat another chance:
+ using open()/futimens() for regular files and utimensat(AT_SYMLINK_NOFOLLOW) for symlinks is consistent with "cp" and "touch"!
*/
struct ::timespec newTimes[2] = {};
- newTimes[0].tv_sec = ::time(nullptr); //access time; using UTIME_OMIT for tv_nsec would trigger even more bugs!!
- //http://www.freefilesync.org/forum/viewtopic.php?t=1701
- newTimes[1].tv_sec = modTime; //modification time
+ newTimes[0].tv_sec = ::time(nullptr); //access time; using UTIME_OMIT for tv_nsec would trigger even more bugs: http://www.freefilesync.org/forum/viewtopic.php?t=1701
+ newTimes[1] = modTime; //modification time
- //=> using open()/futimens() for regular files and utimensat(AT_SYMLINK_NOFOLLOW) for symlinks is consistent with "cp" and "touch"!
if (procSl == ProcSymlink::FOLLOW)
{
- const int fdFile = ::open(filePath.c_str(), O_WRONLY);
- if (fdFile == -1)
- {
- if (errno == EACCES) //bullshit, access denied even with 0777 permissions! => utimes should work!
- return setWriteTimeFallback(filePath, modTime, procSl); //throw FileError
+ //hell knows why files on gvfs-mounted Samba shares fail to open(O_WRONLY) returning EOPNOTSUPP:
+ //http://www.freefilesync.org/forum/viewtopic.php?t=2803 => utimensat() works
+ if (::utimensat(AT_FDCWD, itemPath.c_str(), newTimes, 0) == 0)
+ return;
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"open");
- }
+ //in other cases utimensat() returns EINVAL for CIFS/NTFS drives, but open+futimens works: http://www.freefilesync.org/forum/viewtopic.php?t=387
+ const int fdFile = ::open(itemPath.c_str(), O_WRONLY);
+ if (fdFile == -1)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), L"open");
ZEN_ON_SCOPE_EXIT(::close(fdFile));
if (::futimens(fdFile, newTimes) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"futimens");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), L"futimens");
}
else
{
- if (::utimensat(AT_FDCWD, filePath.c_str(), newTimes, AT_SYMLINK_NOFOLLOW) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimensat");
+ if (::utimensat(AT_FDCWD, itemPath.c_str(), newTimes, AT_SYMLINK_NOFOLLOW) != 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), L"utimensat");
}
}
@@ -1013,7 +991,7 @@ struct AttrBufFileTimes
} __attribute__((aligned(4), packed));
-void setWriteTimeNative(const Zstring& filePath,
+void setWriteTimeNative(const Zstring& itemPath,
const struct ::timespec& writeTime,
const struct ::timespec* createTime, //optional
ProcSymlink procSl) //throw FileError
@@ -1035,18 +1013,18 @@ void setWriteTimeNative(const Zstring& filePath,
attrBuf.writeTime.tv_sec = writeTime.tv_sec;
attrBuf.writeTime.tv_nsec = writeTime.tv_nsec;
- const int rv = ::setattrlist(filePath.c_str(), //const char* path,
+ const int rv = ::setattrlist(itemPath.c_str(), //const char* path,
&attribs, //struct ::attrlist* attrList,
createTime ? &attrBuf.createTime : &attrBuf.writeTime, //void* attrBuf,
(createTime ? sizeof(attrBuf.createTime) : 0) + sizeof(attrBuf.writeTime), //size_t attrBufSize,
procSl == ProcSymlink::DIRECT ? FSOPT_NOFOLLOW : 0); //unsigned long options
if (rv != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"setattrlist");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), L"setattrlist");
}
/*
void getFileTimeRaw(int fd, //throw FileError
- const Zstring& filePath, //for error reporting only
+ const Zstring& itemPath, //for error reporting only
struct ::timespec& createTime, //out
struct ::timespec& writeTime) //
{
@@ -1063,7 +1041,7 @@ void getFileTimeRaw(int fd, //throw FileError
sizeof(attrBuf), //size_t attrBufSize,
0); //unsigned long options
if (rv != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"fgetattrlist");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"fgetattrlist");
createTime.tv_sec = attrBuf.createTime.tv_sec;
createTime.tv_nsec = attrBuf.createTime.tv_nsec;
@@ -1111,7 +1089,9 @@ void zen::setFileTime(const Zstring& filePath, std::int64_t modTime, ProcSymlink
setWriteTimeNative(filePath, timetToFileTime(modTime), nullptr, procSl); //throw FileError
#elif defined ZEN_LINUX
- setWriteTimeNative(filePath, modTime, procSl); //throw FileError
+ struct ::timespec writeTime = {};
+ writeTime.tv_sec = modTime;
+ setWriteTimeNative(filePath, writeTime, procSl); //throw FileError
#elif defined ZEN_MAC
struct ::timespec writeTime = {};
@@ -1217,15 +1197,15 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
try
{
//enable privilege: required to read/write SACL information (only)
- activatePrivilege(SE_SECURITY_NAME); //throw FileError
+ activatePrivilege(PrivilegeName::SECURITY); //throw FileError
//Note: trying to copy SACL (SACL_SECURITY_INFORMATION) may return ERROR_PRIVILEGE_NOT_HELD (1314) on Samba shares. This is not due to missing privileges!
//However, this is okay, since copying NTFS permissions doesn't make sense in this case anyway
//the following privilege may be required according to https://msdn.microsoft.com/en-us/library/aa364399 (although not needed nor active in my tests)
- activatePrivilege(SE_BACKUP_NAME); //throw FileError
+ activatePrivilege(PrivilegeName::BACKUP); //throw FileError
//enable privilege: required to copy owner information
- activatePrivilege(SE_RESTORE_NAME); //throw FileError
+ activatePrivilege(PrivilegeName::RESTORE); //throw FileError
}
catch (const FileError& e)//add some more context description (e.g. user is not an admin)
{
@@ -1674,22 +1654,21 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
setWriteTimeNative(targetLink, sourceAttr.ftLastWriteTime, &sourceAttr.ftCreationTime, ProcSymlink::DIRECT); //throw FileError
-#elif defined ZEN_LINUX
+#else
struct ::stat sourceInfo = {};
if (::lstat(sourceLink.c_str(), &sourceInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat");
- setWriteTimeNative(targetLink, sourceInfo.st_mtime, ProcSymlink::DIRECT); //throw FileError
-
+#ifdef ZEN_LINUX
+ setWriteTimeNative(targetLink, sourceInfo.st_mtim, ProcSymlink::DIRECT); //throw FileError
#elif defined ZEN_MAC
- struct ::stat sourceInfo = {};
- if (::lstat(sourceLink.c_str(), &sourceInfo) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat");
-
if (hasNativeSupportForExtendedAtrributes(targetLink)) //throw FileError
::copyfile(sourceLink.c_str(), targetLink.c_str(), nullptr, COPYFILE_XATTR | COPYFILE_NOFOLLOW); //ignore errors, see related comments in copyFileOsSpecific()
setWriteTimeNative(targetLink, sourceInfo.st_mtimespec, &sourceInfo.st_birthtimespec, ProcSymlink::DIRECT); //throw FileError
+#else
+#error WTF
+#endif
#endif
if (copyFilePermissions)
@@ -1835,9 +1814,9 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
{
//try to get backup read and write privileges: help solve most "access denied" errors with FILE_FLAG_BACKUP_SEMANTICS:
//http://www.freefilesync.org/forum/viewtopic.php?t=1714
- try { activatePrivilege(SE_BACKUP_NAME); }
+ try { activatePrivilege(PrivilegeName::BACKUP); }
catch (const FileError&) {}
- try { activatePrivilege(SE_RESTORE_NAME); }
+ try { activatePrivilege(PrivilegeName::RESTORE); }
catch (const FileError&) {}
//open sourceFile for reading
@@ -1903,8 +1882,8 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
CREATE_NEW, //_In_ DWORD dwCreationDisposition,
//FILE_FLAG_OVERLAPPED must not be used! FILE_FLAG_NO_BUFFERING should not be used!
(fileInfoSource.dwFileAttributes & validAttribs) |
- FILE_FLAG_SEQUENTIAL_SCAN |
- FILE_FLAG_BACKUP_SEMANTICS, //_In_ DWORD dwFlagsAndAttributes,
+ FILE_FLAG_SEQUENTIAL_SCAN | //_In_ DWORD dwFlagsAndAttributes,
+ FILE_FLAG_BACKUP_SEMANTICS, //-> also required by FSCTL_SET_SPARSE
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFileTarget == INVALID_HANDLE_VALUE)
{
@@ -2186,9 +2165,9 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
{
//try to get backup read and write privileges: may help solve some "access denied" errors
bool backupPrivilegesActive = true;
- try { activatePrivilege(SE_BACKUP_NAME); }
+ try { activatePrivilege(PrivilegeName::BACKUP); }
catch (const FileError&) { backupPrivilegesActive = false; }
- try { activatePrivilege(SE_RESTORE_NAME); }
+ try { activatePrivilege(PrivilegeName::RESTORE); }
catch (const FileError&) { backupPrivilegesActive = false; }
auto guardTarget = zen::makeGuard<ScopeGuardRunMode::ON_FAIL>([&] { try { removeFile(targetFile); } catch (FileError&) {} });
@@ -2402,7 +2381,7 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
//sourceInfo.st_birthtime; -> only seconds-precision
//sourceInfo.st_mtime; ->
#else
- setWriteTimeNative(targetFile, sourceInfo.st_mtime, ProcSymlink::FOLLOW); //throw FileError
+ setWriteTimeNative(targetFile, sourceInfo.st_mtim, ProcSymlink::FOLLOW); //throw FileError
#endif
InSyncAttributes newAttrib;
@@ -2410,7 +2389,7 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
#ifdef ZEN_MAC
newAttrib.modificationTime = sourceInfo.st_mtimespec.tv_sec; //use same time variable like setWriteTimeNative() for consistency
#else
- newAttrib.modificationTime = sourceInfo.st_mtime;
+ newAttrib.modificationTime = sourceInfo.st_mtim.tv_sec; //
#endif
newAttrib.sourceFileId = extractFileId(sourceInfo);
newAttrib.targetFileId = extractFileId(targetInfo);
bgstack15