aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/src/vfs/mo2filesystem.cpp21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/src/vfs/mo2filesystem.cpp b/src/src/vfs/mo2filesystem.cpp
index 5fe6be5..d5a9201 100644
--- a/src/src/vfs/mo2filesystem.cpp
+++ b/src/src/vfs/mo2filesystem.cpp
@@ -1583,7 +1583,15 @@ void mo2_rename(fuse_req_t req, fuse_ino_t parent, const char* name,
fuse_ino_t newparent, const char* newname, unsigned int flags)
{
Mo2FsContext* ctx = getContext(req);
- if (ctx == nullptr || name == nullptr || newname == nullptr || flags != 0) {
+ if (ctx == nullptr || name == nullptr || newname == nullptr) {
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
+
+ // Reject unsupported flags (only RENAME_NOREPLACE is supported).
+ // Wine uses renameat2(RENAME_NOREPLACE) for MoveFileW() calls where
+ // ReplaceIfExists is FALSE (e.g. xEdit saving plugins).
+ if (flags & ~(unsigned int)RENAME_NOREPLACE) {
fuse_reply_err(req, EINVAL);
return;
}
@@ -1606,7 +1614,18 @@ void mo2_rename(fuse_req_t req, fuse_ino_t parent, const char* name,
return;
}
+ // RENAME_NOREPLACE: fail if destination already exists in the VFS
+ if (flags & RENAME_NOREPLACE) {
+ const auto destSnap = snapshotForPath(ctx, newRelative);
+ if (destSnap.found) {
+ fuse_reply_err(req, EEXIST);
+ return;
+ }
+ }
+
if (!ctx->overwrite->rename(oldRelative, newRelative)) {
+ std::fprintf(stderr, "[VFS] rename EACCES: '%s' -> '%s' (flags=%u, backing=%d)\n",
+ oldRelative.c_str(), newRelative.c_str(), flags, oldSnap.is_backing);
fuse_reply_err(req, EACCES);
return;
}