]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Implement BtrfsUtils::get_subvolume using libbtrfsutil 771/head
authorDavid Sterba <dsterba@suse.com>
Thu, 19 Jan 2023 16:10:44 +0000 (17:10 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 19 Jan 2023 18:40:03 +0000 (19:40 +0100)
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
snapper/BtrfsUtils.cc

index c05ec8dc09bc50f7f6c40c3b93fb5284b908af34..f5376b83bc0ab10558a2bba06efb20637df96d18 100644 (file)
@@ -1,3 +1,8 @@
+-------------------------------------------------------------------
+Thu Jan 19 12:00:00 PM CET 2023 - David Sterba <dsterba@suse.cz>
+
+- Use libbtrfsutil implementation for BtrfsUtil::get_subvolume
+
 -------------------------------------------------------------------
 Thu Jan 12 12:00:00 PM CET 2023 - David Sterba <dsterba@suse.cz>
 
index e104e916c441243c993b04d6261bccccec31b2e3..6d693533c220e79e341b6d420d183fb5af9df316 100644 (file)
@@ -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