return r;
/* Let's try to make a snapshot, if we can, so that the export is atomic */
- r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
+ r = btrfs_subvol_snapshot_at(sfd, NULL, AT_FDCWD, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
if (r < 0) {
log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path);
e->temp_path = mfree(e->temp_path);
BLOCK_SIGNALS(SIGINT, SIGTERM);
if (arg_btrfs_subvol)
- r = btrfs_subvol_snapshot_fd_full(
- fd,
- dest,
+ r = btrfs_subvol_snapshot_at_full(
+ fd, NULL,
+ AT_FDCWD, dest,
BTRFS_SNAPSHOT_FALLBACK_COPY|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
BTRFS_SNAPSHOT_RECURSIVE|
return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
if (i->flags & PULL_BTRFS_SUBVOL)
- r = btrfs_subvol_snapshot(
- i->final_path,
- t,
+ r = btrfs_subvol_snapshot_at(
+ AT_FDCWD, i->final_path,
+ AT_FDCWD, t,
(i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
BTRFS_SNAPSHOT_FALLBACK_COPY|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
{
BLOCK_SIGNALS(SIGINT);
- r = btrfs_subvol_snapshot(arg_directory, np,
- (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
- BTRFS_SNAPSHOT_FALLBACK_COPY |
- BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
- BTRFS_SNAPSHOT_RECURSIVE |
- BTRFS_SNAPSHOT_QUOTA |
- BTRFS_SNAPSHOT_SIGINT);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np,
+ (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA |
+ BTRFS_SNAPSHOT_SIGINT);
}
if (r == -EINTR) {
log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np);
{
BLOCK_SIGNALS(SIGINT);
- r = btrfs_subvol_snapshot(arg_template, arg_directory,
- (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
- BTRFS_SNAPSHOT_FALLBACK_COPY |
- BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
- BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
- BTRFS_SNAPSHOT_RECURSIVE |
- BTRFS_SNAPSHOT_QUOTA |
- BTRFS_SNAPSHOT_SIGINT);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_template, AT_FDCWD, arg_directory,
+ (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA |
+ BTRFS_SNAPSHOT_SIGINT);
}
if (r == -EEXIST)
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
return 0;
}
-int btrfs_subvol_snapshot_fd_full(
- int old_fd,
- const char *new_path,
+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) {
_cleanup_free_ char *subvolume = NULL;
- _cleanup_close_ int new_fd = -EBADF;
+ _cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
int r;
- assert(old_fd >= 0);
- assert(new_path);
+ assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
+ assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD);
+ assert(to);
+
+ old_fd = xopenat(dir_fdf, from, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0);
+ if (old_fd < 0)
+ return old_fd;
- r = btrfs_is_subvol_fd(old_fd);
+ new_fd = chase_and_openat(dir_fdt, to, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume);
+ if (new_fd < 0)
+ return new_fd;
+
+ r = validate_subvolume_name(subvolume);
+ if (r < 0)
+ return r;
+
+ r = btrfs_is_subvol_at(dir_fdf, from);
if (r < 0)
return r;
if (r == 0) {
if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
return -EISDIR;
- r = btrfs_subvol_make(new_path);
+ r = btrfs_subvol_make_fd(new_fd, subvolume);
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. */
- if (mkdir(new_path, 0755) < 0)
+ if (mkdirat(new_fd, subvolume, 0755) < 0)
return -errno;
plain_directory = true;
return r;
r = copy_directory_at_full(
- old_fd, NULL,
- AT_FDCWD, new_path,
+ dir_fdf, from,
+ new_fd, subvolume,
COPY_MERGE_EMPTY|
COPY_REFLINK|
COPY_SAME_MOUNT|
* it: the IMMUTABLE bit. Let's use this here, if this is requested. */
if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE)
- (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
+ (void) chattr_at(new_fd, subvolume, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
} else {
- r = btrfs_subvol_set_read_only(new_path, true);
+ r = btrfs_subvol_set_read_only_at(new_fd, subvolume, true);
if (r < 0)
goto fallback_fail;
}
return 0;
fallback_fail:
- (void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ (void) rm_rf_at(new_fd, subvolume, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
return r;
}
- r = extract_subvolume_name(new_path, &subvolume);
- if (r < 0)
- return r;
-
- new_fd = open_parent(new_path, O_CLOEXEC, 0);
- if (new_fd < 0)
- return new_fd;
-
return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
}
-int btrfs_subvol_snapshot_full(
- const char *old_path,
- const char *new_path,
- BtrfsSnapshotFlags flags,
- copy_progress_path_t progress_path,
- copy_progress_bytes_t progress_bytes,
- void *userdata) {
-
- _cleanup_close_ int old_fd = -EBADF;
-
- assert(old_path);
- assert(new_path);
-
- old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (old_fd < 0)
- return -errno;
-
- return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, progress_path, progress_bytes, userdata);
-}
-
int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
struct btrfs_ioctl_search_args args = {
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);
-}
-
-int btrfs_subvol_snapshot_full(const char *old_path, 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(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
- return btrfs_subvol_snapshot_full(old_path, new_path, flags, NULL, NULL, NULL);
+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);
}
int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags);
new_path = strjoina("/var/lib/machines/", new_name);
- r = btrfs_subvol_snapshot(i->path, new_path,
- (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
- BTRFS_SNAPSHOT_FALLBACK_COPY |
- BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
- BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
- BTRFS_SNAPSHOT_RECURSIVE |
- BTRFS_SNAPSHOT_QUOTA);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, new_path,
+ (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA);
if (r >= 0)
/* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
(void) btrfs_subvol_auto_qgroup(new_path, 0, true);
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
- r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", 0);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest2", 0);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_snapshot("/etc", "/etc2", BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, "/etc", AT_FDCWD, "/etc2",
+ BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
if (mkdir("/xxxrectest/mnt", 0755) < 0)
log_error_errno(errno, "Failed to make directory: %m");
- r = btrfs_subvol_snapshot("/xxxrectest", "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxrectest", AT_FDCWD, "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to snapshot subvolume: %m");
if (r < 0)
log_error_errno(r, "Failed to set up quota limit: %m");
- r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
+ r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxquotatest", AT_FDCWD, "/xxxquotatest2",
+ BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to set up snapshot: %m");