fileio: port write_string_file() to LabelOps, and thus add WRITE_STRING_FILE_LABEL flag
Given that we have the LabelOps abstraction these days, we can teach write_string_file() to use it, which means we can get rid of fileio-label.[ch] as a separate concept. (The only reason that fileio-label.[ch] exists independently of fileio.[ch] was that the former linekd to libselinux potentially, and thus had to be in src/shared/ while the other always was in src/basic/. But the LabelOps vtable provides us with a nice work-around)
This commit is contained in:
+60
-17
@@ -18,6 +18,7 @@
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "label.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "mkdir.h"
|
||||
@@ -230,22 +231,40 @@ static int write_string_file_atomic_at(
|
||||
/* 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. */
|
||||
|
||||
mode_t mode = write_string_file_flags_to_mode(flags);
|
||||
|
||||
bool call_label_ops_post = false;
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) {
|
||||
r = label_ops_pre(dir_fd, fn, mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
call_label_ops_post = true;
|
||||
}
|
||||
|
||||
r = fopen_temporary_at(dir_fd, fn, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto fail;
|
||||
|
||||
if (call_label_ops_post) {
|
||||
call_label_ops_post = false;
|
||||
|
||||
r = label_ops_post(fileno(f), /* path= */ NULL, /* created= */ true);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = write_string_stream_full(f, line, flags, ts);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fchmod_umask(fileno(f), write_string_file_flags_to_mode(flags));
|
||||
r = fchmod_umask(fileno(f), mode);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (renameat(dir_fd, p, dir_fd, fn) < 0) {
|
||||
r = -errno;
|
||||
r = RET_NERRNO(renameat(dir_fd, p, dir_fd, fn));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
|
||||
/* Sync the rename, too */
|
||||
@@ -257,7 +276,11 @@ static int write_string_file_atomic_at(
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void) unlinkat(dir_fd, p, 0);
|
||||
if (call_label_ops_post)
|
||||
(void) label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f);
|
||||
|
||||
if (f)
|
||||
(void) unlinkat(dir_fd, p, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -268,9 +291,10 @@ int write_string_file_full(
|
||||
WriteStringFileFlags flags,
|
||||
const struct timespec *ts) {
|
||||
|
||||
bool call_label_ops_post = false;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int q, r;
|
||||
int r;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
@@ -292,8 +316,17 @@ int write_string_file_full(
|
||||
goto fail;
|
||||
|
||||
return r;
|
||||
} else
|
||||
assert(!ts);
|
||||
}
|
||||
|
||||
mode_t mode = write_string_file_flags_to_mode(flags);
|
||||
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
|
||||
r = label_ops_pre(dir_fd, fn, mode);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
call_label_ops_post = true;
|
||||
}
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
|
||||
fd = openat(dir_fd, fn, O_CLOEXEC|O_NOCTTY |
|
||||
@@ -301,12 +334,20 @@ int write_string_file_full(
|
||||
(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),
|
||||
write_string_file_flags_to_mode(flags));
|
||||
mode);
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (call_label_ops_post) {
|
||||
call_label_ops_post = false;
|
||||
|
||||
r = label_ops_post(fd, /* path= */ NULL, /* created= */ true);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = take_fdopen_unlocked(&fd, "w", &f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@@ -321,19 +362,21 @@ int write_string_file_full(
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (call_label_ops_post)
|
||||
(void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, /* created= */ true);
|
||||
|
||||
if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
|
||||
return r;
|
||||
|
||||
f = safe_fclose(f);
|
||||
fd = safe_close(fd);
|
||||
|
||||
/* OK, the operation failed, but let's see if the right
|
||||
* contents in place already. If so, eat up the error. */
|
||||
/* OK, the operation failed, but let's see if the right contents in place already. If so, eat up the
|
||||
* error. */
|
||||
if (verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0)
|
||||
return 0;
|
||||
|
||||
q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE));
|
||||
if (q <= 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int write_string_filef(
|
||||
|
||||
+1
-5
@@ -28,11 +28,7 @@ typedef enum {
|
||||
WRITE_STRING_FILE_MODE_0600 = 1 << 10,
|
||||
WRITE_STRING_FILE_MODE_0444 = 1 << 11,
|
||||
WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL = 1 << 12,
|
||||
|
||||
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
||||
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
||||
and friends. */
|
||||
|
||||
WRITE_STRING_FILE_LABEL = 1 << 13,
|
||||
} WriteStringFileFlags;
|
||||
|
||||
typedef enum {
|
||||
|
||||
Reference in New Issue
Block a user