Also make btrfs_subvol_make() an openat style function.
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/btrfs.h>
+#include <sys/ioctl.h>
+
+#include "btrfs.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "path-util.h"
+
+int btrfs_validate_subvolume_name(const char *name) {
+
+ if (!filename_is_valid(name))
+ return -EINVAL;
+
+ if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
+ return -E2BIG;
+
+ return 0;
+}
+
+static int extract_subvolume_name(const char *path, char **ret) {
+ _cleanup_free_ char *fn = NULL;
+ int r;
+
+ assert(path);
+ assert(ret);
+
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return r;
+
+ r = btrfs_validate_subvolume_name(fn);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(fn);
+ return 0;
+}
+
+int btrfs_subvol_make(int dir_fd, const char *path) {
+ struct btrfs_ioctl_vol_args args = {};
+ _cleanup_free_ char *subvolume = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(!isempty(path));
+
+ r = extract_subvolume_name(path, &subvolume);
+ if (r < 0)
+ return r;
+
+ r = path_extract_directory(path, NULL);
+ if (r >= 0) {
+ fd = open_parent_at(dir_fd, path, O_RDONLY|O_CLOEXEC|O_CLOEXEC, 0);
+ if (fd < 0)
+ return fd;
+
+ dir_fd = fd;
+ }
+
+ strncpy(args.name, subvolume, sizeof(args.name)-1);
+
+ return RET_NERRNO(ioctl(dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args));
+}
+
+int btrfs_subvol_make_fallback(int dir_fd, 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(dir_fd, path);
+ umask(old);
+
+ if (r >= 0)
+ return 1; /* subvol worked */
+ if (r != -ENOTTY)
+ return r;
+
+ if (mkdirat(dir_fd, path, mode) < 0)
+ return -errno;
+
+ return 0; /* plain directory */
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+
+int btrfs_validate_subvolume_name(const char *name);
+
+int btrfs_subvol_make(int dir_fd, const char *path);
+
+int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode);
'argv-util.c',
'arphrd-util.c',
'audit-util.c',
+ 'btrfs.c',
'build.c',
'bus-label.c',
'cap-list.c',
case USER_SUBVOLUME:
WITH_UMASK(0077)
- r = btrfs_subvol_make(d);
+ r = btrfs_subvol_make(AT_FDCWD, d);
if (r >= 0) {
log_info("Subvolume created.");
return log_oom();
/* Prefer using a btrfs subvolume if we can, fall back to directory otherwise */
- r = btrfs_subvol_make_fallback(subdir, 0700);
+ r = btrfs_subvol_make_fallback(AT_FDCWD, subdir, 0700);
if (r < 0)
return log_error_errno(r, "Failed to create user directory in mounted image file: %m");
(void) rm_rf(d, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (i->flags & IMPORT_BTRFS_SUBVOL)
- r = btrfs_subvol_make_fallback(d, 0755);
+ r = btrfs_subvol_make_fallback(AT_FDCWD, d, 0755);
else
r = RET_NERRNO(mkdir(d, 0755));
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (i->flags & PULL_BTRFS_SUBVOL)
- r = btrfs_subvol_make_fallback(where, 0755);
+ r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
else
r = RET_NERRNO(mkdir(where, 0755));
if (r == -EEXIST && (i->flags & PULL_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
* device nodes (that reference drivers) rather than fds to normal
* files or directories. */
-static int validate_subvolume_name(const char *name) {
-
- if (!filename_is_valid(name))
- return -EINVAL;
-
- if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
- return -E2BIG;
-
- return 0;
-}
-
-static int extract_subvolume_name(const char *path, char **ret) {
- _cleanup_free_ char *fn = NULL;
- int r;
-
- assert(path);
- assert(ret);
-
- r = path_extract_filename(path, &fn);
- if (r < 0)
- return r;
-
- r = validate_subvolume_name(fn);
- if (r < 0)
- return r;
-
- *ret = TAKE_PTR(fn);
- return 0;
-}
-
int btrfs_is_subvol_at(int dir_fd, const char *path) {
struct stat st;
return is_fs_type_at(dir_fd, path, BTRFS_SUPER_MAGIC);
}
-int btrfs_subvol_make_fd(int fd, const char *subvolume) {
- struct btrfs_ioctl_vol_args args = {};
- _cleanup_close_ int real_fd = -EBADF;
- int r;
-
- assert(subvolume);
-
- r = validate_subvolume_name(subvolume);
- if (r < 0)
- return r;
-
- /* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
- * with O_PATH. */
- fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
- if (fd < 0)
- return fd;
-
- strncpy(args.name, subvolume, sizeof(args.name)-1);
-
- return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args));
-}
-
-int btrfs_subvol_make(const char *path) {
- _cleanup_free_ char *subvolume = NULL;
- _cleanup_close_ int fd = -EBADF;
- int r;
-
- assert(path);
-
- r = extract_subvolume_name(path, &subvolume);
- if (r < 0)
- return r;
-
- fd = open_parent(path, O_CLOEXEC, 0);
- if (fd < 0)
- return fd;
-
- 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_at(int dir_fd, const char *path, bool b) {
_cleanup_close_ int fd = -EBADF;
uint64_t flags, nflags;
if (fd < 0)
return fd;
- r = validate_subvolume_name(subvolume);
+ r = btrfs_validate_subvolume_name(subvolume);
if (r < 0)
return r;
if (new_fd < 0)
return new_fd;
- r = validate_subvolume_name(subvolume);
+ r = btrfs_validate_subvolume_name(subvolume);
if (r < 0)
return r;
if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
return -EISDIR;
- r = btrfs_subvol_make_fd(new_fd, subvolume);
+ r = btrfs_subvol_make(new_fd, subvolume);
if (r < 0) {
if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
#include "sd-id128.h"
+#include "btrfs.h"
#include "copy.h"
#include "time-util.h"
int btrfs_quota_scan_wait(int fd);
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_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int btrfs_subvol_snapshot_at(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags) {
return btrfs_subvol_snapshot_at_full(dir_fdf, from, dir_fdt, to, flags, NULL, NULL, NULL);
if (r < 0)
return r;
- r = btrfs_subvol_make(path);
+ r = btrfs_subvol_make(AT_FDCWD, path);
mac_selinux_create_file_clear();
if (r < 0)
safe_close(fd);
}
- r = btrfs_subvol_make("/xxxtest");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxtest");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_make("/xxxrectest");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
- r = btrfs_subvol_make("/xxxrectest/xxxrectest2");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest2");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
- r = btrfs_subvol_make("/xxxrectest/xxxrectest3");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
- r = btrfs_subvol_make("/xxxrectest/xxxrectest3/sub");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3/sub");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
if (mkdir("/xxxrectest/dir", 0755) < 0)
log_error_errno(errno, "Failed to make directory: %m");
- r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
if (mkdir("/xxxrectest/dir/xxxrectest4/dir", 0755) < 0)
log_error_errno(errno, "Failed to make directory: %m");
- r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
if (r < 0)
log_error_errno(r, "Failed to recursively remove subvolume: %m");
- r = btrfs_subvol_make("/xxxquotatest");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
if (r < 0)
log_error_errno(r, "Failed to set up auto qgroup: %m");
- r = btrfs_subvol_make("/xxxquotatest/beneath");
+ r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest/beneath");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
subvol = false;
else {
WITH_UMASK((~mode) & 0777)
- r = btrfs_subvol_make_fd(pfd, bn);
+ r = btrfs_subvol_make(pfd, bn);
}
} else
r = 0;