diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2023-03-22 17:04:36 +0100 |
---|---|---|
committer | Daan De Meyer <daan.j.demeyer@gmail.com> | 2023-03-22 21:54:20 +0100 |
commit | 2646b86dd6a84f2e7ebc625203d44e6d1923c5bd (patch) | |
tree | 835cc1aa3aa41a91508a33e2dde76de745735a06 /src/basic/fs-util.c | |
parent | a3b00f91bb985fa10bc33db5c7883e33dbdf83d0 (diff) | |
download | systemd-2646b86dd6a84f2e7ebc625203d44e6d1923c5bd.tar.gz |
fs-util: Add xopenat_lock()
open/create a file/directory and lock it using the given lock type.
Diffstat (limited to 'src/basic/fs-util.c')
-rw-r--r-- | src/basic/fs-util.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 19ada73af5..06bd5705f2 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -3,6 +3,7 @@ #include <errno.h> #include <stddef.h> #include <stdlib.h> +#include <sys/file.h> #include <linux/falloc.h> #include <linux/magic.h> #include <unistd.h> @@ -13,6 +14,7 @@ #include "fileio.h" #include "fs-util.h" #include "hostname-util.h" +#include "lock-util.h" #include "log.h" #include "macro.h" #include "missing_fcntl.h" @@ -1099,6 +1101,9 @@ int xopenat(int dir_fd, const char *path, int flags, mode_t mode) { bool made = false; int r; + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(path); + if (FLAGS_SET(flags, O_DIRECTORY|O_CREAT)) { r = RET_NERRNO(mkdirat(dir_fd, path, mode)); if (r == -EEXIST) { @@ -1135,3 +1140,42 @@ int xopenat(int dir_fd, const char *path, int flags, mode_t mode) { return TAKE_FD(fd); } + +int xopenat_lock(int dir_fd, const char *path, int flags, mode_t mode, LockType locktype, int operation) { + _cleanup_close_ int fd = -EBADF; + int r; + + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(path); + assert(IN_SET(operation & ~LOCK_NB, LOCK_EX, LOCK_SH)); + + /* POSIX/UNPOSIX locks don't work on directories (errno is set to -EBADF so let's return early with + * the same error here). */ + if (FLAGS_SET(flags, O_DIRECTORY) && locktype != LOCK_BSD) + return -EBADF; + + for (;;) { + struct stat st; + + fd = xopenat(dir_fd, path, flags, mode); + if (fd < 0) + return fd; + + r = lock_generic(fd, locktype, operation); + if (r < 0) + return r; + + /* If we acquired the lock, let's check if the file/directory still exists in the file + * system. If not, then the previous exclusive owner removed it and then closed it. In such a + * case our acquired lock is worthless, hence try again. */ + + if (fstat(fd, &st) < 0) + return -errno; + if (st.st_nlink > 0) + break; + + fd = safe_close(fd); + } + + return TAKE_FD(fd); +} |