Skip to content

Commit 408d49e

Browse files
committed
mnt: consolidate EROFS fallbacks into errno-preserving helpers
1 parent f1a9dc6 commit 408d49e

5 files changed

Lines changed: 60 additions & 17 deletions

File tree

mnt.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ namespace fs = std::filesystem;
140140

141141
static bool tryCreateDir(const std::string& path, bool log_errors = true) {
142142
if (mkdir(path.c_str(), 0755) == -1 && errno != EEXIST) {
143-
struct stat st;
144-
if (errno != EROFS || stat(path.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
143+
if (errno != EROFS || !util::existsAsDir(path.c_str())) {
145144
if (log_errors) {
146145
PLOG_D("mkdir('%s')", path.c_str());
147146
}

mnt_legacy.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,7 @@ static int tryMountRW(mount_t* mpt, const char* src, const char* dst) {
126126
static bool createMountTarget(const std::string& path, bool is_dir) {
127127
if (is_dir) {
128128
if (mkdir(path.c_str(), 0711) == -1 && errno != EEXIST) {
129-
struct stat st;
130-
if (errno != EROFS || stat(path.c_str(), &st) != 0 ||
131-
!S_ISDIR(st.st_mode)) {
129+
if (errno != EROFS || !util::existsAsDir(path.c_str())) {
132130
PLOG_W("mkdir('%s')", path.c_str());
133131
return false;
134132
}
@@ -137,9 +135,7 @@ static bool createMountTarget(const std::string& path, bool is_dir) {
137135
int fd =
138136
TEMP_FAILURE_RETRY(open(path.c_str(), O_CREAT | O_RDONLY | O_CLOEXEC, 0644));
139137
if (fd == -1) {
140-
struct stat st;
141-
if (errno != EROFS || stat(path.c_str(), &st) != 0 ||
142-
!S_ISREG(st.st_mode)) {
138+
if (errno != EROFS || !util::existsAsReg(path.c_str())) {
143139
PLOG_W("open('%s', O_CREAT)", path.c_str());
144140
return false;
145141
}

mnt_newapi.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,7 @@ static bool createDirAt(int dir_fd, const char* path, mode_t mode) {
212212
cumulative += component;
213213

214214
if (mkdirat(dir_fd, cumulative.c_str(), mode) == -1 && errno != EEXIST) {
215-
struct stat st;
216-
if (errno != EROFS || fstatat(dir_fd, cumulative.c_str(), &st, 0) != 0 ||
217-
!S_ISDIR(st.st_mode)) {
215+
if (errno != EROFS || !util::existsAsDirAt(dir_fd, cumulative.c_str())) {
218216
PLOG_W("mkdirat(%d, '%s')", dir_fd, cumulative.c_str());
219217
return false;
220218
}
@@ -433,14 +431,16 @@ static bool mountSinglePointAt(mount_t* mpt, int root_fd) {
433431

434432
if (mpt->is_dir) {
435433
if (strcmp(rel_dst, ".") != 0 && mkdirat(root_fd, rel_dst, 0711) == -1 &&
436-
errno != EEXIST && errno != EROFS) {
437-
PLOG_W("mkdirat(root_fd, '%s')", rel_dst);
434+
errno != EEXIST) {
435+
if (errno != EROFS || !util::existsAsDirAt(root_fd, rel_dst)) {
436+
PLOG_W("mkdirat(root_fd, '%s')", rel_dst);
437+
}
438438
}
439439
} else {
440440
int fd = openat(root_fd, rel_dst, O_CREAT | O_RDONLY | O_CLOEXEC, 0644);
441441
if (fd >= 0) {
442442
close(fd);
443-
} else if (errno != EROFS) {
443+
} else if (errno != EROFS || !util::existsAsRegAt(root_fd, rel_dst)) {
444444
PLOG_W("openat(root_fd, '%s', O_CREAT)", rel_dst);
445445
}
446446
}

util.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,7 @@ bool createDirRecursively(const char* dir) {
225225
*next = '\0';
226226

227227
if (mkdirat(prev_dir_fd, curr, 0755) == -1 && errno != EEXIST) {
228-
struct stat st;
229-
if (errno != EROFS || fstatat(prev_dir_fd, curr, &st, 0) != 0 ||
230-
!S_ISDIR(st.st_mode)) {
228+
if (errno != EROFS || !util::existsAsDirAt(prev_dir_fd, curr)) {
231229
PLOG_W("mkdir(%s, 0755)", QC(curr));
232230
close(prev_dir_fd);
233231
return false;

util.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
#ifndef NS_UTIL_H
2323
#define NS_UTIL_H
2424

25+
#include <errno.h>
2526
#include <inttypes.h>
2627
#include <stdbool.h>
2728
#include <stdint.h>
2829
#include <stdlib.h>
2930
#include <sys/resource.h>
31+
#include <sys/stat.h>
3032

3133
#include <string>
3234
#include <vector>
@@ -80,6 +82,54 @@ bool makeRangeCOE(unsigned int first, unsigned int last);
8082
const char* stripLeadingSlashes(const char* path);
8183
bool kernelVersionAtLeast(int major, int minor, int patch);
8284

85+
/*
86+
* EROFS fallback helpers for read-only filesystems (e.g. NFS).
87+
*
88+
* On NFSv3/v4 with a cold dentry cache, mkdir()/open(O_CREAT) can return
89+
* EROFS instead of EEXIST for entries that already exist. These helpers
90+
* verify the entry exists with the expected type, preserving the original
91+
* errno for accurate PLOG logging on failure.
92+
*/
93+
inline bool existsAsDir(const char* path) {
94+
int saved = errno;
95+
struct stat st;
96+
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
97+
return true;
98+
}
99+
errno = saved;
100+
return false;
101+
}
102+
103+
inline bool existsAsDirAt(int dir_fd, const char* path) {
104+
int saved = errno;
105+
struct stat st;
106+
if (fstatat(dir_fd, path, &st, 0) == 0 && S_ISDIR(st.st_mode)) {
107+
return true;
108+
}
109+
errno = saved;
110+
return false;
111+
}
112+
113+
inline bool existsAsReg(const char* path) {
114+
int saved = errno;
115+
struct stat st;
116+
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
117+
return true;
118+
}
119+
errno = saved;
120+
return false;
121+
}
122+
123+
inline bool existsAsRegAt(int dir_fd, const char* path) {
124+
int saved = errno;
125+
struct stat st;
126+
if (fstatat(dir_fd, path, &st, 0) == 0 && S_ISREG(st.st_mode)) {
127+
return true;
128+
}
129+
errno = saved;
130+
return false;
131+
}
132+
83133
} // namespace util
84134

85135
#endif /* NS_UTIL_H */

0 commit comments

Comments
 (0)