Merge pull request #33825 from DaanDeMeyer/chattr

repart: Create disk image file with copy-on-write disabled on btrfs
This commit is contained in:
Luca Boccassi
2024-07-25 14:11:11 +01:00
committed by GitHub
14 changed files with 395 additions and 258 deletions
+4 -4
View File
@@ -148,15 +148,15 @@ int read_attr_fd(int fd, unsigned *ret) {
return RET_NERRNO(ioctl(fd, FS_IOC_GETFLAGS, ret));
}
int read_attr_path(const char *p, unsigned *ret) {
int read_attr_at(int dir_fd, const char *path, unsigned *ret) {
_cleanup_close_ int fd = -EBADF;
assert(p);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(ret);
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
return -errno;
return fd;
return read_attr_fd(fd, ret);
}
+1 -1
View File
@@ -52,7 +52,7 @@ static inline int chattr_path(const char *path, unsigned value, unsigned mask, u
}
int read_attr_fd(int fd, unsigned *ret);
int read_attr_path(const char *p, unsigned *ret);
int read_attr_at(int dir_fd, const char *path, unsigned *ret);
/* Combination of chattr flags, that should be appropriate for secrets stored on disk: Secure Remove +
* Exclusion from Dumping + Synchronous Writing (i.e. not caching in memory) + In-Place Updating (i.e. not
+39 -9
View File
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "btrfs.h"
#include "chattr-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -1114,8 +1115,27 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
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, hence put a limit on things */
/* Hmm, so now we got EEXIST? This can indicate two things. First, if the path points to a
* dangling symlink, the first openat() will fail with ENOENT because the symlink is resolved
* and the second openat() will fail with EEXIST because symlinks are not followed when
* O_CREAT|O_EXCL is specified. Let's check for this explicitly and fall back to opening with
* just O_CREAT and assume we're the ones that created the file. */
struct stat st;
if (fstatat(dirfd, pathname, &st, AT_SYMLINK_NOFOLLOW) < 0)
return -errno;
if (S_ISLNK(st.st_mode)) {
fd = openat(dirfd, pathname, flags | O_CREAT, mode);
if (fd < 0)
return -errno;
*ret_newly_created = true;
return fd;
}
/* If we're not operating on a symlink, someone might have created the file between the first
* and second call to openat(). Let's try again but with a limit so we don't spin forever. */
if (--attempts == 0) /* Give up eventually, somebody is playing with us */
return -EEXIST;
@@ -1124,7 +1144,7 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
_cleanup_close_ int fd = -EBADF;
bool made = false;
bool made_dir = false, made_file = false;
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@@ -1158,12 +1178,10 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
if (r == -EEXIST) {
if (FLAGS_SET(open_flags, O_EXCL))
return -EEXIST;
made = false;
} else if (r < 0)
return r;
else
made = true;
made_dir = true;
if (FLAGS_SET(xopen_flags, XO_LABEL)) {
r = label_ops_post(dir_fd, path);
@@ -1175,7 +1193,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
xopen_flags &= ~XO_LABEL;
}
fd = RET_NERRNO(openat(dir_fd, path, open_flags, mode));
fd = RET_NERRNO(openat_report_new(dir_fd, path, open_flags, mode, &made_file));
if (fd < 0) {
if (IN_SET(fd,
/* We got ENOENT? then someone else immediately removed it after we
@@ -1188,7 +1206,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
-ENOTDIR))
return fd;
if (made)
if (made_dir)
(void) unlinkat(dir_fd, path, AT_REMOVEDIR);
return fd;
@@ -1197,10 +1215,22 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
r = label_ops_post(dir_fd, path);
if (r < 0)
return r;
goto error;
}
if (FLAGS_SET(xopen_flags, XO_NOCOW)) {
r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
goto error;
}
return TAKE_FD(fd);
error:
if (made_dir || made_file)
(void) unlinkat(dir_fd, path, made_dir ? AT_REMOVEDIR : 0);
return r;
}
int xopenat_lock_full(
+1
View File
@@ -131,6 +131,7 @@ int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char
typedef enum XOpenFlags {
XO_LABEL = 1 << 0,
XO_SUBVOLUME = 1 << 1,
XO_NOCOW = 1 << 2,
} XOpenFlags;
int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode);