Merge pull request #28833 from DaanDeMeyer/copy-subvolume
repart: Add Subvolumes= setting
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/* 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 */
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* 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);
|
||||
+5
-1
@@ -9,6 +9,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@@ -1110,7 +1111,10 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
|
||||
}
|
||||
|
||||
if (FLAGS_SET(open_flags, O_DIRECTORY|O_CREAT)) {
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (FLAGS_SET(xopen_flags, XO_SUBVOLUME))
|
||||
r = btrfs_subvol_make_fallback(dir_fd, path, mode);
|
||||
else
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(open_flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
||||
+2
-1
@@ -133,7 +133,8 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
|
||||
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
|
||||
|
||||
typedef enum XOpenFlags {
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_SUBVOLUME = 1 << 1,
|
||||
} XOpenFlags;
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
|
||||
@@ -8,6 +8,7 @@ basic_sources = files(
|
||||
'argv-util.c',
|
||||
'arphrd-util.c',
|
||||
'audit-util.c',
|
||||
'btrfs.c',
|
||||
'build.c',
|
||||
'bus-label.c',
|
||||
'cap-list.c',
|
||||
|
||||
+10
-5
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs.h"
|
||||
#include "chase.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
@@ -209,7 +210,7 @@ int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, g
|
||||
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
|
||||
}
|
||||
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m) {
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
|
||||
_cleanup_free_ char *pp = NULL, *bn = NULL;
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
int r;
|
||||
@@ -227,7 +228,7 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
|
||||
return r;
|
||||
else {
|
||||
/* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
|
||||
r = mkdir_p_root(root, pp, uid, gid, m);
|
||||
r = mkdir_p_root(root, pp, uid, gid, m, subvolumes);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -242,11 +243,15 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mkdirat(dfd, bn, m) < 0) {
|
||||
if (errno == EEXIST)
|
||||
if (path_strv_contains(subvolumes, p))
|
||||
r = btrfs_subvol_make_fallback(dfd, bn, m);
|
||||
else
|
||||
r = RET_NERRNO(mkdirat(dfd, bn, m));
|
||||
if (r < 0) {
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uid_is_valid(uid) || gid_is_valid(gid)) {
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ static inline int mkdir_parents(const char *path, mode_t mode) {
|
||||
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
int mkdir_p(const char *path, mode_t mode);
|
||||
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m);
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes);
|
||||
|
||||
/* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */
|
||||
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode);
|
||||
|
||||
@@ -1116,7 +1116,9 @@ int path_extract_directory(const char *path, char **ret) {
|
||||
if (!path_is_valid(a))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(a);
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user