From aff3e37b378e18a37e7e219ee709bb0e0958d9db Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 19 Jan 2023 17:10:44 +0100 Subject: [PATCH] Implement BtrfsUtils::get_subvolume using libbtrfsutil The helper from btrfs_subvolid_resolve from libbtrfs can be reimplemented by means of libbtrfsutil. btrfs_util_subvolume_path_fd is practically equivalent to btrfs_subvolid_resolve i.e. requires the privileged ioctl. There's another way available to all users but is slow as it needs to iterate overall subvolumes. This is implemented as fallback. --- package/snapper.changes | 5 +++++ snapper/BtrfsUtils.cc | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/package/snapper.changes b/package/snapper.changes index c05ec8dc..f5376b83 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Thu Jan 19 12:00:00 PM CET 2023 - David Sterba + +- Use libbtrfsutil implementation for BtrfsUtil::get_subvolume + ------------------------------------------------------------------- Thu Jan 12 12:00:00 PM CET 2023 - David Sterba diff --git a/snapper/BtrfsUtils.cc b/snapper/BtrfsUtils.cc index e104e916..6d693533 100644 --- a/snapper/BtrfsUtils.cc +++ b/snapper/BtrfsUtils.cc @@ -279,6 +279,52 @@ namespace snapper string get_subvolume(int fd, subvolid_t id) { +#ifdef HAVE_LIBBTRFSUTIL + enum btrfs_util_error err; + char *tmp; + string path; + + /* This requires CAP_SYS_ADMIN as it uses the TREE_SEARCH ioctl but is fast. */ + err = btrfs_util_subvolume_path_fd(fd, id, &tmp); + if (err == BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) + throw runtime_error_with_errno("btrfs_util_subvolume_path_fd() failed", errno); + + /* Try slower iterative search but without restrictions. */ + if (err == BTRFS_UTIL_OK) { + path = tmp; + free(tmp); + } else if (err == BTRFS_UTIL_ERROR_SEARCH_FAILED || err == BTRFS_UTIL_ERROR_NO_MEMORY) { + struct btrfs_util_subvolume_iterator *iter; + + err = btrfs_util_create_subvolume_iterator_fd(fd, 0, 0, &iter); + if (err) + throw runtime_error_with_errno("btrfs_util_subvolume_path_fd() failed", errno); + + while (1) { + struct btrfs_util_subvolume_info subvol; + + err = btrfs_util_subvolume_iterator_next_info(iter, &tmp, &subvol); + if (err != BTRFS_UTIL_OK) { + /* Nothing found or other error */ + btrfs_util_destroy_subvolume_iterator(iter); + throw std::runtime_error("get_subvolume() failed"); + } + + if (subvol.id == id) { + btrfs_util_destroy_subvolume_iterator(iter); + path = tmp; + free(tmp); + break; + } + free(tmp); + } + } else { + /* Unknown error */ + throw std::runtime_error("get_subvolume() failed"); + } + + return path; +#else char path[BTRFS_PATH_NAME_MAX + 1]; if (btrfs_subvolid_resolve(fd, path, sizeof(path), id) != 0) @@ -286,6 +332,7 @@ namespace snapper path[BTRFS_PATH_NAME_MAX] = '\0'; return path; +#endif } #endif -- 2.47.3