diff options
Diffstat (limited to 'libbtrfsutil/subvolume.c')
-rw-r--r-- | libbtrfsutil/subvolume.c | 89 |
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; +} |