#25474 Added read-only warnings when saving documents (#25532)

* #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:
Andrew Burks
2025-11-23 00:09:32 -05:00
committed by GitHub
parent 147810c9de
commit b32c224f09
2 changed files with 44 additions and 0 deletions

View File

@@ -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.

View File

@@ -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;