diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index b48e7371f6..62f4fca947 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -160,6 +160,31 @@ int btrfs_subvol_make(const char *path) { return btrfs_subvol_make_fd(fd, subvolume); } +int btrfs_subvol_make_fallback(const char *path, mode_t mode) { + mode_t old, combined; + int r; + + assert(path); + + /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */ + old = umask(~mode); + combined = old | ~mode; + if (combined != ~mode) + umask(combined); + r = btrfs_subvol_make(path); + umask(old); + + if (r >= 0) + return 1; /* subvol worked */ + if (r != -ENOTTY) + return r; + + if (mkdir(path, mode) < 0) + return -errno; + + return 0; /* plain directory */ +} + int btrfs_subvol_set_read_only_fd(int fd, bool b) { uint64_t flags, nflags; struct stat st; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index b15667bf2f..c1bbb42ca1 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -66,6 +66,8 @@ int btrfs_quota_scan_ongoing(int fd); int btrfs_subvol_make(const char *path); int btrfs_subvol_make_fd(int fd, const char *subvolume); +int btrfs_subvol_make_fallback(const char *path, mode_t); + int btrfs_subvol_snapshot_fd_full(int old_fd, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); static inline int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) { return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, NULL, NULL, NULL); diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index de7535fc60..5eb67bc2b3 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -8,6 +8,7 @@ #include "blkid-util.h" #include "blockdev-util.h" +#include "btrfs-util.h" #include "chattr-util.h" #include "dm-util.h" #include "errno-util.h" @@ -2037,8 +2038,10 @@ int home_create_luks( goto fail; } - if (mkdir(subdir, 0700) < 0) { - r = log_error_errno(errno, "Failed to create user directory in mounted image file: %m"); + /* Prefer using a btrfs subvolume if we can, fall back to directory otherwise */ + r = btrfs_subvol_make_fallback(subdir, 0700); + if (r < 0) { + log_error_errno(r, "Failed to create user directory in mounted image file: %m"); goto fail; } diff --git a/src/import/import-tar.c b/src/import/import-tar.c index 1e50d31bc2..5d2bf22fb2 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -220,13 +220,10 @@ static int tar_import_fork_tar(TarImport *i) { (void) mkdir_parents_label(i->temp_path, 0700); - r = btrfs_subvol_make(i->temp_path); - if (r == -ENOTTY) { - if (mkdir(i->temp_path, 0755) < 0) - return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); - } else if (r < 0) - return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); - else + r = btrfs_subvol_make_fallback(i->temp_path, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create directory/subvolume %s: %m", i->temp_path); + if (r > 0) /* actually btrfs subvol */ (void) import_assign_pool_quota_and_warn(i->temp_path); i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 3930578a8c..ede28bee1b 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -415,13 +415,10 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) { mkdir_parents_label(i->temp_path, 0700); - r = btrfs_subvol_make(i->temp_path); - if (r == -ENOTTY) { - if (mkdir(i->temp_path, 0755) < 0) - return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); - } else if (r < 0) - return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); - else + r = btrfs_subvol_make_fallback(i->temp_path, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create directory/subvolume %s: %m", i->temp_path); + if (r > 0) /* actually btrfs subvol */ (void) import_assign_pool_quota_and_warn(i->temp_path); j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);