summaryrefslogtreecommitdiffstats
path: root/src/basic
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-03-14 09:55:04 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2023-03-14 09:55:04 +0100
commit7486f9c3421a5cd011c72a8c8d9c8b1cf62410ca (patch)
tree1a1fabfe61fa795fe8a3a9efae4d327fd1f3c2f4 /src/basic
parentsystemctl: refuse to acquire dbus connection with --global (diff)
downloadsystemd-7486f9c3421a5cd011c72a8c8d9c8b1cf62410ca.tar.xz
systemd-7486f9c3421a5cd011c72a8c8d9c8b1cf62410ca.zip
fs-util: Add xopenat()
xopenat() will create directories if O_DIRECTORY and O_CREAT are specified. Note that this is not an atomic operation.
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/fs-util.c73
-rw-r--r--src/basic/fs-util.h2
2 files changed, 48 insertions, 27 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index a895f4f2df..5007a829ea 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -993,7 +993,6 @@ int parse_cifs_service(
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
_cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
_cleanup_free_ char *fname = NULL;
- bool made;
int r;
/* Creates a directory with mkdirat() and then opens it, in the "most atomic" fashion we can
@@ -1033,33 +1032,11 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
path = fname;
}
- r = RET_NERRNO(mkdirat(dirfd, path, mode));
- if (r == -EEXIST) {
- if (FLAGS_SET(flags, O_EXCL))
- return -EEXIST;
-
- made = false;
- } else if (r < 0)
- return r;
- else
- made = true;
-
- fd = RET_NERRNO(openat(dirfd, path, (flags & ~O_EXCL)|O_DIRECTORY|O_NOFOLLOW));
- if (fd < 0) {
- if (fd == -ENOENT) /* We got ENOENT? then someone else immediately removed it after we
- * created it. In that case let's return immediately without unlinking
- * anything, because there simply isn't anything to unlink anymore. */
- return -ENOENT;
- if (fd == -ELOOP) /* is a symlink? exists already → created by someone else, don't unlink */
- return -EEXIST;
- if (fd == -ENOTDIR) /* not a directory? exists already → created by someone else, don't unlink */
- return -EEXIST;
-
- if (made)
- (void) unlinkat(dirfd, path, AT_REMOVEDIR);
-
+ fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, mode);
+ if (IN_SET(fd, -ELOOP, -ENOTDIR))
+ return -EEXIST;
+ if (fd < 0)
return fd;
- }
return TAKE_FD(fd);
}
@@ -1110,3 +1087,45 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
return -EEXIST;
}
}
+
+int xopenat(int dir_fd, const char *path, int flags, mode_t mode) {
+ _cleanup_close_ int fd = -EBADF;
+ bool made = false;
+ int r;
+
+ if (FLAGS_SET(flags, O_DIRECTORY|O_CREAT)) {
+ r = RET_NERRNO(mkdirat(dir_fd, path, mode));
+ if (r == -EEXIST) {
+ if (FLAGS_SET(flags, O_EXCL))
+ return -EEXIST;
+
+ made = false;
+ } else if (r < 0)
+ return r;
+ else
+ made = true;
+
+ flags &= ~(O_EXCL|O_CREAT);
+ }
+
+ fd = RET_NERRNO(openat(dir_fd, path, flags, mode));
+ if (fd < 0) {
+ if (IN_SET(fd,
+ /* We got ENOENT? then someone else immediately removed it after we
+ * created it. In that case let's return immediately without unlinking
+ * anything, because there simply isn't anything to unlink anymore. */
+ -ENOENT,
+ /* is a symlink? exists already → created by someone else, don't unlink */
+ -ELOOP,
+ /* not a directory? exists already → created by someone else, don't unlink */
+ -ENOTDIR))
+ return fd;
+
+ if (made)
+ (void) unlinkat(dir_fd, path, AT_REMOVEDIR);
+
+ return fd;
+ }
+
+ return TAKE_FD(fd);
+}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 932d003f19..3db9df2224 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -129,3 +129,5 @@ int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
+
+int xopenat(int dir_fd, const char *path, int flags, mode_t mode);