btrfsutil/subvolume/
iterator.rs1use crate::common;
2use crate::error::LibError;
3use crate::subvolume::Subvolume;
4use crate::Result;
5
6use std::convert::TryFrom;
7use std::convert::TryInto;
8use std::ffi::CString;
9use std::path::Path;
10
11use btrfsutil_sys::btrfs_util_create_subvolume_iterator;
12use btrfsutil_sys::btrfs_util_destroy_subvolume_iterator;
13use btrfsutil_sys::btrfs_util_subvolume_iterator;
14use btrfsutil_sys::btrfs_util_subvolume_iterator_next;
15
16bitflags! {
17 pub struct SubvolumeIteratorFlags: i32 {
19 const POST_ORDER = btrfsutil_sys::BTRFS_UTIL_SUBVOLUME_ITERATOR_POST_ORDER as i32;
21 }
22}
23
24pub struct SubvolumeIterator(*mut btrfs_util_subvolume_iterator);
26
27impl SubvolumeIterator {
28 pub fn new<'a, P, F>(path: P, flags: F) -> Result<Self>
30 where
31 P: Into<&'a Path>,
32 F: Into<Option<SubvolumeIteratorFlags>>,
33 {
34 Self::new_impl(path.into(), flags.into())
35 }
36
37 fn new_impl(path: &Path, flags: Option<SubvolumeIteratorFlags>) -> Result<Self> {
38 let path_cstr = common::path_to_cstr(path);
39 let flags_val = if let Some(val) = flags { val.bits() } else { 0 };
40
41 let raw_iterator_ptr: *mut btrfs_util_subvolume_iterator = {
42 let mut raw_iterator_ptr: *mut btrfs_util_subvolume_iterator = std::ptr::null_mut();
43 unsafe_wrapper!({
44 btrfs_util_create_subvolume_iterator(
45 path_cstr.as_ptr(),
46 0, flags_val,
48 &mut raw_iterator_ptr,
49 )
50 })?;
51 raw_iterator_ptr
57 };
58
59 Ok(Self(raw_iterator_ptr))
60 }
61}
62
63impl Iterator for SubvolumeIterator {
64 type Item = Result<Subvolume>;
65
66 fn next(&mut self) -> Option<Result<Subvolume>> {
67 let mut cstr_ptr: *mut std::os::raw::c_char = std::ptr::null_mut();
68 let mut id: u64 = 0;
69
70 if let Err(e) =
71 unsafe_wrapper!({ btrfs_util_subvolume_iterator_next(self.0, &mut cstr_ptr, &mut id) })
72 {
73 if e == LibError::StopIteration {
74 None
75 } else {
76 Err(e).into()
77 }
78 } else if !cstr_ptr.is_null() {
79 let path = common::cstr_to_path(unsafe { CString::from_raw(cstr_ptr).as_ref() });
80 Subvolume::get(path.as_path()).into()
81 } else if id != 0 {
82 Subvolume::try_from(id).into()
83 } else {
84 panic!("subvolume iterator returned both a null path")
85 }
86 }
87}
88
89impl Drop for SubvolumeIterator {
90 fn drop(&mut self) {
91 unsafe {
92 btrfs_util_destroy_subvolume_iterator(self.0);
93 }
94 }
95}
96
97impl TryFrom<&Subvolume> for SubvolumeIterator {
98 type Error = LibError;
99
100 #[inline]
102 fn try_from(src: &Subvolume) -> Result<SubvolumeIterator> {
103 SubvolumeIterator::new_impl(src.path(), None)
104 }
105}
106
107impl TryInto<Vec<Subvolume>> for SubvolumeIterator {
108 type Error = LibError;
109
110 #[inline]
112 fn try_into(self) -> Result<Vec<Subvolume>> {
113 self.collect::<Result<Vec<Subvolume>>>()
114 }
115}