diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-03-21 18:11:26 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-03-21 18:23:44 +0100 |
commit | ca8503f168d0632c606110da909aba3057777395 (patch) | |
tree | 30ec3c83f14440afe195fb747712bde52b2832ed /src/basic/fs-util.c | |
parent | f5d0f21c3721d8788e96add470630cd1cd91c34c (diff) | |
download | systemd-ca8503f168d0632c606110da909aba3057777395.tar.gz |
fs-util: add openat_report_new() wrapper around openat()
This is a wrapper around openat(). It works mostly the same, except for
one thing: it race-freely reports whether we just created the indicated
file in case O_CREAT is passed without O_EXCL.
Diffstat (limited to 'src/basic/fs-util.c')
-rw-r--r-- | src/basic/fs-util.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 11039fd75d..14aea54e26 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1083,3 +1083,42 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) { return TAKE_FD(fd); } + +int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created) { + unsigned attempts = 7; + + /* Just like openat(), but adds one thing: optionally returns whether we created the file anew or if + * it already existed before. This is only relevant of O_CREAT is set without O_EXCL, and thus will + * shortcut to openat() otherwise */ + + if (!FLAGS_SET(flags, O_CREAT) || FLAGS_SET(flags, O_EXCL) || !ret_newly_created) + return RET_NERRNO(openat(dirfd, pathname, flags, mode)); + + for (;;) { + int fd; + + /* First, attempt to open without O_CREAT/O_EXCL, i.e. open existing file */ + fd = openat(dirfd, pathname, flags & ~(O_CREAT | O_EXCL), mode); + if (fd >= 0) { + *ret_newly_created = false; + return fd; + } + if (errno != ENOENT) + return -errno; + + /* So the file didn't exist yet, hence create it with O_CREAT/O_EXCL. */ + fd = openat(dirfd, pathname, flags | O_CREAT | O_EXCL, mode); + if (fd >= 0) { + *ret_newly_created = true; + return fd; + } + if (errno != EEXIST) + return -errno; + + /* Hmm, so now we got EEXIST? So it apparently exists now? If so, let's try to open again + * without the two flags. But let's not spin forever, hnce put a limit on things */ + + if (--attempts == 0) /* Give up eventually, somebody is playing with us */ + return -EEXIST; + } +} |