summaryrefslogtreecommitdiff
path: root/libbtrfsutil/subvolume.c
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2018-01-24 12:48:59 -0800
committerDavid Sterba <dsterba@suse.com>2018-03-06 11:28:37 +0100
commitf23918016238a67b98740bdcb2509e290715977a (patch)
tree086a0297dc788c9536c934f32d43c9f990aa4486 /libbtrfsutil/subvolume.c
parent678da5a7f71ed7fbc887e40cc8ef91008c6fe843 (diff)
libbtrfsutil: add btrfs_util_deleted_subvolumes()
Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'libbtrfsutil/subvolume.c')
-rw-r--r--libbtrfsutil/subvolume.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/libbtrfsutil/subvolume.c b/libbtrfsutil/subvolume.c
index 56cd2c6d..d9728281 100644
--- a/libbtrfsutil/subvolume.c
+++ b/libbtrfsutil/subvolume.c
@@ -1279,3 +1279,92 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrf
return btrfs_util_subvolume_info_fd(iter->fd, id, subvol);
}
+
+PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes(const char *path,
+ uint64_t **ids,
+ size_t *n)
+{
+ enum btrfs_util_error err;
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return BTRFS_UTIL_ERROR_OPEN_FAILED;
+
+ err = btrfs_util_deleted_subvolumes_fd(fd, ids, n);
+ SAVE_ERRNO_AND_CLOSE(fd);
+ return err;
+}
+
+PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd,
+ uint64_t **ids,
+ size_t *n)
+{
+ size_t capacity = 0;
+ struct btrfs_ioctl_search_args search = {
+ .key = {
+ .tree_id = BTRFS_ROOT_TREE_OBJECTID,
+ .min_objectid = BTRFS_ORPHAN_OBJECTID,
+ .max_objectid = BTRFS_ORPHAN_OBJECTID,
+ .min_type = BTRFS_ORPHAN_ITEM_KEY,
+ .max_type = BTRFS_ORPHAN_ITEM_KEY,
+ .min_offset = 0,
+ .max_offset = UINT64_MAX,
+ .min_transid = 0,
+ .max_transid = UINT64_MAX,
+ .nr_items = 0,
+ },
+ };
+ enum btrfs_util_error err;
+ size_t items_pos = 0, buf_off = 0;
+ int ret;
+
+ *ids = NULL;
+ *n = 0;
+ for (;;) {
+ const struct btrfs_ioctl_search_header *header;
+
+ if (items_pos >= search.key.nr_items) {
+ search.key.nr_items = 4096;
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search);
+ if (ret == -1) {
+ err = BTRFS_UTIL_ERROR_SEARCH_FAILED;
+ goto out;
+ }
+ items_pos = 0;
+ buf_off = 0;
+
+ if (search.key.nr_items == 0)
+ break;
+ }
+
+ header = (struct btrfs_ioctl_search_header *)(search.buf + buf_off);
+ if (*n >= capacity) {
+ size_t new_capacity = capacity ? capacity * 2 : 1;
+ uint64_t *new_ids;
+
+ new_ids = reallocarray(*ids, new_capacity,
+ sizeof(**ids));
+ if (!new_ids)
+ return BTRFS_UTIL_ERROR_NO_MEMORY;
+
+ *ids = new_ids;
+ capacity = new_capacity;
+ }
+
+ (*ids)[(*n)++] = header->offset;
+
+ items_pos++;
+ buf_off += sizeof(*header) + header->len;
+ search.key.min_offset = header->offset + 1;
+ }
+
+ err = BTRFS_UTIL_OK;
+out:
+ if (err) {
+ free(*ids);
+ *ids = NULL;
+ *n = 0;
+ }
+ return err;
+}