1use crate::{
9 raw::{
10 self, btrfs_ioc_clone_range, btrfs_ioc_encoded_write, btrfs_ioc_set_received_subvol,
11 btrfs_ioctl_clone_range_args, btrfs_ioctl_encoded_io_args,
12 btrfs_ioctl_received_subvol_args,
13 },
14 tree_search::{SearchKey, tree_search},
15};
16use nix::libc::c_int;
17use std::os::fd::{AsRawFd, BorrowedFd};
18use uuid::Uuid;
19
20#[derive(Debug, Clone)]
22pub struct SubvolSearchResult {
23 pub root_id: u64,
25}
26
27pub fn received_subvol_set(fd: BorrowedFd<'_>, uuid: &Uuid, stransid: u64) -> nix::Result<u64> {
33 let mut args: btrfs_ioctl_received_subvol_args = unsafe { std::mem::zeroed() };
34
35 let uuid_bytes = uuid.as_bytes();
36 for (i, &b) in uuid_bytes.iter().enumerate() {
38 args.uuid[i] = b as std::os::raw::c_char;
39 }
40 args.stransid = stransid;
41
42 unsafe {
44 btrfs_ioc_set_received_subvol(fd.as_raw_fd() as c_int, &mut args)?;
45 }
46
47 Ok(args.rtransid)
48}
49
50pub fn clone_range(
55 dest_fd: BorrowedFd<'_>,
56 src_fd: BorrowedFd<'_>,
57 src_offset: u64,
58 src_length: u64,
59 dest_offset: u64,
60) -> nix::Result<()> {
61 let args = btrfs_ioctl_clone_range_args {
62 src_fd: src_fd.as_raw_fd() as i64,
63 src_offset,
64 src_length,
65 dest_offset,
66 };
67
68 unsafe {
70 btrfs_ioc_clone_range(dest_fd.as_raw_fd() as c_int, &args)?;
71 }
72
73 Ok(())
74}
75
76#[allow(clippy::too_many_arguments)]
84pub fn encoded_write(
85 fd: BorrowedFd<'_>,
86 data: &[u8],
87 offset: u64,
88 unencoded_file_len: u64,
89 unencoded_len: u64,
90 unencoded_offset: u64,
91 compression: u32,
92 encryption: u32,
93) -> nix::Result<()> {
94 let iov = nix::libc::iovec {
95 iov_base: data.as_ptr() as *mut _,
96 iov_len: data.len(),
97 };
98
99 let mut args: btrfs_ioctl_encoded_io_args = unsafe { std::mem::zeroed() };
100 args.iov = &iov as *const _ as *mut _;
101 args.iovcnt = 1;
102 args.offset = offset as i64;
103 args.len = unencoded_file_len;
104 args.unencoded_len = unencoded_len;
105 args.unencoded_offset = unencoded_offset;
106 args.compression = compression;
107 args.encryption = encryption;
108
109 unsafe {
113 btrfs_ioc_encoded_write(fd.as_raw_fd() as c_int, &args)?;
114 }
115
116 Ok(())
117}
118
119pub fn subvolume_search_by_uuid(fd: BorrowedFd<'_>, uuid: &Uuid) -> nix::Result<u64> {
124 search_uuid_tree(fd, uuid, raw::BTRFS_UUID_KEY_SUBVOL as u32)
125}
126
127pub fn subvolume_search_by_received_uuid(fd: BorrowedFd<'_>, uuid: &Uuid) -> nix::Result<u64> {
132 search_uuid_tree(fd, uuid, raw::BTRFS_UUID_KEY_RECEIVED_SUBVOL as u32)
133}
134
135fn search_uuid_tree(fd: BorrowedFd<'_>, uuid: &Uuid, item_type: u32) -> nix::Result<u64> {
142 let bytes = uuid.as_bytes();
143 let objectid = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
144 let offset = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
145
146 let mut key = SearchKey::for_type(raw::BTRFS_UUID_TREE_OBJECTID as u64, item_type);
147 key.min_objectid = objectid;
148 key.max_objectid = objectid;
149 key.min_offset = offset;
150 key.max_offset = offset;
151
152 let mut result: Option<u64> = None;
153
154 tree_search(fd, key, |_hdr, data| {
155 if data.len() >= 8 {
156 result = Some(u64::from_le_bytes(data[0..8].try_into().unwrap()));
157 }
158 Ok(())
159 })?;
160
161 result.ok_or(nix::errno::Errno::ENOENT)
162}