aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/src/vfs/mo2filesystem.cpp16
1 files changed, 13 insertions, 3 deletions
diff --git a/src/src/vfs/mo2filesystem.cpp b/src/src/vfs/mo2filesystem.cpp
index dd701df..1127072 100644
--- a/src/src/vfs/mo2filesystem.cpp
+++ b/src/src/vfs/mo2filesystem.cpp
@@ -917,7 +917,7 @@ std::vector<char> buildReaddirBlob(
} else {
// Use cached mode bits (populated during tree snapshot) — no stat() needed.
mode_t mode = entry.cached_mode != 0 ? entry.cached_mode : static_cast<mode_t>(0644);
- st.st_mode = S_IFREG | mode;
+ st.st_mode = S_IFREG | regularFileVfsMode(mode);
}
const size_t entSize =
@@ -1070,6 +1070,16 @@ void fillStatForDir(struct stat* st, fuse_ino_t ino, uid_t uid, gid_t gid)
st->st_ctim.tv_sec = kVirtualDirTime;
}
+mode_t regularFileVfsMode(mode_t sourceMode)
+{
+ mode_t mode = sourceMode != 0 ? sourceMode : static_cast<mode_t>(0644);
+ // The merged VFS is copy-on-write. Existing files from the base game or mods
+ // must still pass the kernel's default_permissions write check so mo2_open()
+ // can materialize them into staging instead of failing before userspace.
+ mode |= S_IRUSR | S_IWUSR;
+ return mode;
+}
+
void fillStatForFile(struct stat* st, fuse_ino_t ino, uid_t uid, gid_t gid,
uint64_t size,
const std::chrono::system_clock::time_point& mtime,
@@ -1093,7 +1103,7 @@ void fillStatForFile(struct stat* st, fuse_ino_t ino, uid_t uid, gid_t gid,
mode = real_st.st_mode & 0777;
}
}
- st->st_mode = S_IFREG | mode;
+ st->st_mode = S_IFREG | regularFileVfsMode(mode);
const auto secs = std::chrono::duration_cast<std::chrono::seconds>(
mtime.time_since_epoch());
@@ -1821,7 +1831,7 @@ void mo2_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
} else {
mode_t mode = (*entries)[i].cached_mode != 0 ? (*entries)[i].cached_mode
: static_cast<mode_t>(0644);
- st.st_mode = S_IFREG | mode;
+ st.st_mode = S_IFREG | regularFileVfsMode(mode);
}
const size_t ent = fuse_add_direntry(req, buf.data() + used, size - used,