diff options
-rw-r--r-- | pkgs/tools/filesystems/btrfsprogs/btrfs-set-received-uuid.c | 109 | ||||
-rw-r--r-- | pkgs/tools/filesystems/btrfsprogs/default.nix | 12 |
2 files changed, 121 insertions, 0 deletions
diff --git a/pkgs/tools/filesystems/btrfsprogs/btrfs-set-received-uuid.c b/pkgs/tools/filesystems/btrfsprogs/btrfs-set-received-uuid.c new file mode 100644 index 00000000000..483ec5f8415 --- /dev/null +++ b/pkgs/tools/filesystems/btrfsprogs/btrfs-set-received-uuid.c @@ -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); +} diff --git a/pkgs/tools/filesystems/btrfsprogs/default.nix b/pkgs/tools/filesystems/btrfsprogs/default.nix index 37b83c2c9a2..a42c6aa7a7e 100644 --- a/pkgs/tools/filesystems/btrfsprogs/default.nix +++ b/pkgs/tools/filesystems/btrfsprogs/default.nix @@ -20,6 +20,18 @@ stdenv.mkDerivation { 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 = { |