Merge branch 'master' into stdenv-updates.
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
diff --git a/cmds-receive.c b/cmds-receive.c
|
||||
index a8be6fa..6b7cf12 100644
|
||||
--- a/cmds-receive.c
|
||||
+++ b/cmds-receive.c
|
||||
@@ -52,11 +52,13 @@ static int g_verbose = 0;
|
||||
struct btrfs_receive
|
||||
{
|
||||
int mnt_fd;
|
||||
+ int dest_dir_fd;
|
||||
|
||||
int write_fd;
|
||||
char *write_path;
|
||||
|
||||
char *root_path;
|
||||
+ char *dest_dir_path; /* relative to root_path */
|
||||
char *full_subvol_path;
|
||||
|
||||
struct subvol_info *cur_subvol;
|
||||
@@ -150,8 +152,11 @@ static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
|
||||
r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
|
||||
r->parent_subvol = NULL;
|
||||
|
||||
- r->cur_subvol->path = strdup(path);
|
||||
- r->full_subvol_path = path_cat(r->root_path, path);
|
||||
+ if (strlen(r->dest_dir_path) == 0)
|
||||
+ r->cur_subvol->path = strdup(path);
|
||||
+ else
|
||||
+ r->cur_subvol->path = path_cat(r->dest_dir_path, path);
|
||||
+ r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
|
||||
|
||||
fprintf(stderr, "At subvol %s\n", path);
|
||||
|
||||
@@ -167,7 +172,7 @@ static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
|
||||
|
||||
memset(&args_v1, 0, sizeof(args_v1));
|
||||
strcpy(args_v1.name, path);
|
||||
- ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
|
||||
+ ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "ERROR: creating subvolume %s failed. "
|
||||
@@ -195,8 +200,11 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
|
||||
r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
|
||||
r->parent_subvol = NULL;
|
||||
|
||||
- r->cur_subvol->path = strdup(path);
|
||||
- r->full_subvol_path = path_cat(r->root_path, path);
|
||||
+ if (strlen(r->dest_dir_path) == 0)
|
||||
+ r->cur_subvol->path = strdup(path);
|
||||
+ else
|
||||
+ r->cur_subvol->path = path_cat(r->dest_dir_path, path);
|
||||
+ r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
|
||||
|
||||
fprintf(stderr, "At snapshot %s\n", path);
|
||||
|
||||
@@ -243,7 +251,7 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
|
||||
+ ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
|
||||
close(args_v2.fd);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
@@ -790,17 +798,48 @@ struct btrfs_send_ops send_ops = {
|
||||
int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
|
||||
{
|
||||
int ret;
|
||||
+ char *dest_dir_full_path;
|
||||
int end = 0;
|
||||
|
||||
- r->root_path = strdup(tomnt);
|
||||
- r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
|
||||
+ dest_dir_full_path = realpath(tomnt, NULL);
|
||||
+ if (!dest_dir_full_path) {
|
||||
+ ret = -errno;
|
||||
+ fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
|
||||
+ strerror(-ret));
|
||||
+ goto out;
|
||||
+ }
|
||||
+ r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
|
||||
+ if (r->dest_dir_fd < 0) {
|
||||
+ ret = -errno;
|
||||
+ fprintf(stderr, "ERROR: failed to open destination directory %s. %s\n",
|
||||
+ dest_dir_full_path, strerror(-ret));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ret = find_mount_root(dest_dir_full_path, &r->root_path);
|
||||
+ if (ret < 0) {
|
||||
+ ret = -EINVAL;
|
||||
+ fprintf(stderr, "ERROR: failed to determine mount point "
|
||||
+ "for %s\n", dest_dir_full_path);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
|
||||
if (r->mnt_fd < 0) {
|
||||
ret = -errno;
|
||||
- fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
|
||||
+ fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
|
||||
strerror(-ret));
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * find_mount_root returns a root_path that is a subpath of
|
||||
+ * dest_dir_full_path. Now get the other part of root_path,
|
||||
+ * which is the destination dir relative to root_path.
|
||||
+ */
|
||||
+ r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
|
||||
+ if (r->dest_dir_path[0] == '/')
|
||||
+ r->dest_dir_path++;
|
||||
+
|
||||
ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
diff --git a/cmds-send.c b/cmds-send.c
|
||||
index 9b47e70..c408bc7 100644
|
||||
--- a/cmds-send.c
|
||||
+++ b/cmds-send.c
|
||||
@@ -81,6 +81,14 @@ int find_mount_root(const char *path, char **mount_root)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!longest_match) {
|
||||
+ fprintf(stderr, "ERROR: Failed to find mount root for path %s.\n",
|
||||
+ path);
|
||||
+ fprintf(stderr, "Please make sure that you have a valid \
|
||||
+ /etc/mtab file.\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
*mount_root = realpath(longest_match, NULL);
|
||||
free(longest_match);
|
||||
|
||||
diff --git a/send-utils.h b/send-utils.h
|
||||
index da407eb..a3e038b 100644
|
||||
--- a/send-utils.h
|
||||
+++ b/send-utils.h
|
||||
@@ -65,5 +65,6 @@ void subvol_uuid_search_add(struct subvol_uuid_search *s,
|
||||
char *path_cat(const char *p1, const char *p2);
|
||||
char *path_cat3(const char *p1, const char *p2, const char *p3);
|
||||
|
||||
+int find_mount_root(const char *path, char **mount_root);
|
||||
|
||||
#endif /* SEND_UTILS_H_ */
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/cmds-receive.c b/cmds-receive.c
|
||||
index a8be6fa..c182175 100644
|
||||
--- a/cmds-receive.c
|
||||
+++ b/cmds-receive.c
|
||||
@@ -880,7 +880,7 @@ static const char * const receive_cmd_group_usage[] = {
|
||||
};
|
||||
|
||||
static const char * const cmd_receive_usage[] = {
|
||||
- "btrfs receive [-v] [-i <infile>] <mount>",
|
||||
+ "btrfs receive [-v] [-f <infile>] <mount>",
|
||||
"Receive subvolumes from stdin.",
|
||||
"Receives one or more subvolumes that were previously ",
|
||||
"sent with btrfs send. The received subvolumes are stored",
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/cmds-receive.c b/cmds-receive.c
|
||||
index 6b7cf12..a6a6a5b 100644
|
||||
--- a/cmds-receive.c
|
||||
+++ b/cmds-receive.c
|
||||
@@ -731,7 +731,7 @@ static int process_chown(const char *path, u64 uid, u64 gid, void *user)
|
||||
fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
|
||||
uid, gid);
|
||||
|
||||
- ret = chown(full_path, uid, gid);
|
||||
+ ret = lchown(full_path, uid, gid);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
btrfs receive currently mandates that incremental receives can only be performed on a parent subvolume
|
||||
that was also received. This means you cannot apply it to (snapshotted) subvolumes you still have on disk,
|
||||
as they were not received themselves.
|
||||
|
||||
This small utility allows you to set the received_uuid of a subvolume, tricking btrfs receive into using it.
|
||||
|
||||
found on btrfs mailing list
|
||||
read the discussion here: http://comments.gmane.org/gmane.comp.file-systems.btrfs/21922
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "ctree.h"
|
||||
#include "ioctl.h"
|
||||
#include "send-utils.h"
|
||||
|
||||
#define CLEAR(var) memset(&var, 0, sizeof(var))
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret, fd;
|
||||
struct subvol_uuid_search sus;
|
||||
struct btrfs_ioctl_received_subvol_args rs_args;
|
||||
struct subvol_info *si;
|
||||
char uuidbuf[37], parent_uuidbuf[37], received_uuidbuf[37];
|
||||
|
||||
|
||||
if (argc != 3 && argc != 4) {
|
||||
printf("usage: btrfs-set-received-uuid btrfs-mountpoint src-subvolume-path-relative-to-mountpoint [dest-absolute-subvolume-path]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("opening srcmnt %s\n", argv[1]);
|
||||
fd = open(argv[1], O_RDONLY | O_NOATIME);
|
||||
if (fd < 0) {
|
||||
printf("failed to open srcmnt %s! %s\n", argv[1], strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
puts("initializing sub search");
|
||||
CLEAR(sus);
|
||||
ret = subvol_uuid_search_init(fd, &sus);
|
||||
if (ret < 0) {
|
||||
printf("failed to initialize sub search! %s\n", strerror(-ret));
|
||||
exit(3);
|
||||
}
|
||||
|
||||
printf("searching srcsub %s\n", argv[2]);
|
||||
si = subvol_uuid_search(&sus, 0, NULL, 0, argv[2], subvol_search_by_path);
|
||||
if (!si) {
|
||||
puts("srcsub not found!");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
uuid_unparse(si->uuid, uuidbuf);
|
||||
uuid_unparse(si->parent_uuid, parent_uuidbuf);
|
||||
uuid_unparse(si->received_uuid, received_uuidbuf);
|
||||
|
||||
printf("\nsrcsub found:\n"
|
||||
" uuid=%s\n"
|
||||
" parent_uuid=%s\n"
|
||||
"received_uuid=%s\n"
|
||||
"ctransid=%Lu otransid=%Lu stransid=%Lu rtransid=%Lu\n\n",
|
||||
uuidbuf, parent_uuidbuf, received_uuidbuf,
|
||||
(unsigned long long)(si->ctransid),
|
||||
(unsigned long long)(si->otransid),
|
||||
(unsigned long long)(si->stransid),
|
||||
(unsigned long long)(si->rtransid));
|
||||
|
||||
if (argc == 3)
|
||||
goto done;
|
||||
|
||||
printf("opening dst subvol %s\n", argv[3]);
|
||||
fd = open(argv[3], O_RDONLY | O_NOATIME);
|
||||
if (fd < 0) {
|
||||
printf("failed to open dst subvol %s. %s\n", argv[3], strerror(errno));
|
||||
exit(5);
|
||||
}
|
||||
|
||||
printf("\nhere we go with BTRFS_IOC_SET_RECEIVED_SUBVOL:\n"
|
||||
"dstsub.received_uuid = srcsub.uuid == %s\n"
|
||||
"dstsub.stransid = srcsub.ctransid == %Lu\n\n",
|
||||
uuidbuf, (unsigned long long)(si->ctransid));
|
||||
|
||||
CLEAR(rs_args);
|
||||
memcpy(rs_args.uuid, si->uuid, BTRFS_UUID_SIZE);
|
||||
rs_args.stransid = si->ctransid;
|
||||
|
||||
ret = ioctl(fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
|
||||
if (ret < 0) {
|
||||
printf("BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s", strerror(-ret));
|
||||
exit(6);
|
||||
}
|
||||
|
||||
done:
|
||||
printf("done.\n");
|
||||
exit(0);
|
||||
}
|
||||
@@ -11,8 +11,27 @@ stdenv.mkDerivation {
|
||||
sha256 = "72d4cd4fb23d876a17146d6231ad40a2151fa47c648485c54cf7478239b43764";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./subvol-listing.patch
|
||||
./btrfs-receive-help-text.patch
|
||||
./btrfs-progs-Fix-the-receive-code-pathing.patch
|
||||
./btrfs-receive-lchown.patch
|
||||
];
|
||||
|
||||
buildInputs = [ zlib libuuid acl attr e2fsprogs ];
|
||||
|
||||
postPatch = ''
|
||||
cp ${./btrfs-set-received-uuid.c} btrfs-set-received-uuid.c
|
||||
'';
|
||||
|
||||
postBuild = ''
|
||||
gcc -O2 -luuid -o btrfs-set-received-uuid send-utils.o rbtree.o btrfs-list.o btrfs-set-received-uuid.c
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
cp btrfs-set-received-uuid $out/bin
|
||||
'';
|
||||
|
||||
makeFlags = "prefix=$(out)";
|
||||
|
||||
meta = {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/btrfs-list.c 2012-12-30 12:20:01.394137593 +0100
|
||||
+++ b/btrfs-list.c 2012-12-30 12:22:47.242452906 +0100
|
||||
@@ -1004,6 +1004,23 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void __drop_deleting_roots(struct root_lookup *root_lookup)
|
||||
+{
|
||||
+ struct rb_node *n;
|
||||
+
|
||||
+again:
|
||||
+ n = rb_first(&root_lookup->root);
|
||||
+ while (n) {
|
||||
+ struct root_info *entry = rb_entry(n, struct root_info, rb_node);
|
||||
+ if (!entry->ref_tree) {
|
||||
+ rb_erase(n, &root_lookup->root);
|
||||
+ free(entry);
|
||||
+ goto again;
|
||||
+ }
|
||||
+ n = rb_next(n);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
|
||||
{
|
||||
int ret;
|
||||
@@ -1123,6 +1140,8 @@
|
||||
break;
|
||||
}
|
||||
|
||||
+ __drop_deleting_roots(root_lookup);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user