Merge branch 'master' into stdenv-updates.

This commit is contained in:
Peter Simons
2013-01-04 21:00:53 +01:00
80 changed files with 1022 additions and 222 deletions
@@ -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;
}