* #25474 Added read-only warnings when saving documents Block saving a file and notify user if windows is unable to save to the file for any reason, or the read-only attribute is checked. Also check std::filesystem::perms for write permission and other checks in FileInfo::isWritable(), although it doesn't seem to matter on windows. Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
This commit is contained in:
@@ -1792,6 +1792,12 @@ bool Document::saveToFile(const char* filename) const
|
||||
// realpath is canonical filename i.e. without symlink
|
||||
std::string nativePath = canonical_path(filename);
|
||||
|
||||
// check if file is writeable, then block the save if it is not.
|
||||
Base::FileInfo originalFileInfo(nativePath);
|
||||
if (originalFileInfo.exists() && !originalFileInfo.isWritable()) {
|
||||
throw Base::FileException("Unable to save document because file is marked as read-only or write permission is not available.", originalFileInfo);
|
||||
}
|
||||
|
||||
// make a tmp. file where to save the project data first and then rename to
|
||||
// the actual file name. This may be useful if overwriting an existing file
|
||||
// fails so that the data of the work up to now isn't lost.
|
||||
|
||||
@@ -336,6 +336,44 @@ bool FileInfo::isWritable() const
|
||||
if (fs::is_directory(path)) {
|
||||
return directoryIsWritable(path);
|
||||
}
|
||||
#ifdef FC_OS_WIN32
|
||||
// convert filename from UTF-8 to windows WSTRING
|
||||
std::wstring fileNameWstring = toStdWString();
|
||||
// requires import of <windows.h>
|
||||
DWORD attributes = GetFileAttributes(fileNameWstring.c_str());
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// Log the error?
|
||||
std::clog << "GetFileAttributes failed for file: " << FileName << '\n';
|
||||
// usually indicates some kind of network file issue, so the file is probably not writable
|
||||
return false;
|
||||
}
|
||||
if ((attributes & FILE_ATTRIBUTE_READONLY) != 0) {
|
||||
return false;
|
||||
}
|
||||
// TEST if file is truly writable, because windows ACL does not map well to POSIX perms,
|
||||
// and there are other potential blockers (app or shared file locks, etc)
|
||||
HANDLE hFile = CreateFileW(
|
||||
fileNameWstring.c_str(),
|
||||
GENERIC_WRITE,
|
||||
0, // ----> no sharing: fail if anyone else has it open
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!CloseHandle(hFile)) {
|
||||
std::clog << "CloseHandle failed for file: " << FileName
|
||||
<< " while checking for write access." << '\n';
|
||||
}
|
||||
#endif
|
||||
fs::file_status stat = fs::status(path);
|
||||
fs::perms perms = stat.permissions();
|
||||
return (perms & fs::perms::owner_write) == fs::perms::owner_write;
|
||||
|
||||
Reference in New Issue
Block a user