diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 2c4ba89a15..a5c44f184a 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -43,16 +43,17 @@ * can detect EOFs. */ #define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U) -int fopen_unlocked(const char *path, const char *options, FILE **ret) { +int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) { + int r; + assert(ret); - FILE *f = fopen(path, options); - if (!f) - return -errno; + r = xfopenat(dir_fd, path, options, flags, ret); + if (r < 0) + return r; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + (void) __fsetlocking(*ret, FSETLOCKING_BYCALLER); - *ret = f; return 0; } @@ -209,7 +210,8 @@ int write_string_stream_ts( return 0; } -static int write_string_file_atomic( +static int write_string_file_atomic_at( + int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, @@ -225,7 +227,7 @@ static int write_string_file_atomic( /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */ - r = fopen_temporary(fn, &f, &p); + r = fopen_temporary_at(dir_fd, fn, &f, &p); if (r < 0) return r; @@ -237,7 +239,7 @@ static int write_string_file_atomic( if (r < 0) goto fail; - if (rename(p, fn) < 0) { + if (renameat(dir_fd, p, dir_fd, fn) < 0) { r = -errno; goto fail; } @@ -252,11 +254,12 @@ static int write_string_file_atomic( return 0; fail: - (void) unlink(p); + (void) unlinkat(dir_fd, p, 0); return r; } -int write_string_file_ts( +int write_string_file_ts_at( + int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, @@ -272,7 +275,7 @@ int write_string_file_ts( assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC))); if (flags & WRITE_STRING_FILE_MKDIR_0755) { - r = mkdir_parents(fn, 0755); + r = mkdirat_parents(dir_fd, fn, 0755); if (r < 0) return r; } @@ -280,7 +283,7 @@ int write_string_file_ts( if (flags & WRITE_STRING_FILE_ATOMIC) { assert(flags & WRITE_STRING_FILE_CREATE); - r = write_string_file_atomic(fn, line, flags, ts); + r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts); if (r < 0) goto fail; @@ -289,12 +292,12 @@ int write_string_file_ts( assert(!ts); /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */ - fd = open(fn, O_CLOEXEC|O_NOCTTY | - (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY), - (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666)); + fd = openat(dir_fd, fn, O_CLOEXEC|O_NOCTTY | + (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY), + (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666)); if (fd < 0) { r = -errno; goto fail; @@ -364,7 +367,7 @@ int read_one_line_file(const char *fn, char **line) { return read_line(f, LONG_LINE_MAX, line); } -int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { +int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *buf = NULL; size_t l, k; @@ -382,7 +385,7 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { if (!buf) return -ENOMEM; - r = fopen_unlocked(fn, "re", &f); + r = fopen_unlocked_at(dir_fd, fn, "re", 0, &f); if (r < 0) return r; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 9151d8237a..7da3ee33e0 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -43,7 +43,10 @@ typedef enum { READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */ } ReadFullFileFlags; -int fopen_unlocked(const char *path, const char *options, FILE **ret); +int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret); +static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) { + return fopen_unlocked_at(AT_FDCWD, path, options, 0, ret); +} int fdopen_unlocked(int fd, const char *options, FILE **ret); int take_fdopen_unlocked(int *fd, const char *options, FILE **ret); FILE* take_fdopen(int *fd, const char *options); @@ -55,7 +58,13 @@ int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) { return write_string_stream_ts(f, line, flags, NULL); } -int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts); +int write_string_file_ts_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts); +static inline int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts) { + return write_string_file_ts_at(AT_FDCWD, fn, line, flags, ts); +} +static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) { + return write_string_file_ts_at(dir_fd, fn, line, flags, NULL); +} static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { return write_string_file_ts(fn, line, flags, NULL); } @@ -64,6 +73,9 @@ int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *f int read_one_line_file(const char *filename, char **line); int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size); +static inline int read_full_file_at(int dir_fd, const char *filename, char **ret_contents, size_t *ret_size) { + return read_full_file_full(dir_fd, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size); +} static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) { return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size); } @@ -82,7 +94,10 @@ static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_siz return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size); } -int verify_file(const char *fn, const char *blob, bool accept_extra_nl); +int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl); +static inline int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { + return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl); +} int executable_is_script(const char *path, char **interpreter);