use crate::common::{single_mount, write_test_data};
use btrfs_uapi::{
fiemap::file_extents,
filesystem::sync,
subvolume::{snapshot_create, subvolume_create},
};
use std::{ffi::CStr, fs::File, os::unix::io::AsFd, process::Command};
#[test]
#[ignore = "requires elevated privileges"]
fn fiemap_basic() {
let (_td, mnt) = single_mount();
write_test_data(mnt.path(), "data.bin", 5_000_000);
sync(mnt.fd()).unwrap();
let file = File::open(mnt.path().join("data.bin")).expect("open failed");
let info = file_extents(file.as_fd()).expect("file_extents failed");
assert!(info.total_bytes > 0, "total_bytes should be > 0: {info:?}");
assert_eq!(
info.shared_bytes, 0,
"shared_bytes should be 0 without snapshots: {info:?}"
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn fiemap_shared_after_snapshot() {
let (_td, mnt) = single_mount();
let subvol_name = CStr::from_bytes_with_nul(b"origin\0").unwrap();
subvolume_create(mnt.fd(), subvol_name, &[])
.expect("subvolume_create failed");
write_test_data(&mnt.path().join("origin"), "data.bin", 5_000_000);
sync(mnt.fd()).unwrap();
let snap_name = CStr::from_bytes_with_nul(b"snap\0").unwrap();
let origin_dir =
File::open(mnt.path().join("origin")).expect("open origin failed");
snapshot_create(mnt.fd(), origin_dir.as_fd(), snap_name, false, &[])
.expect("snapshot_create failed");
sync(mnt.fd()).unwrap();
let file = File::open(mnt.path().join("origin").join("data.bin"))
.expect("open data failed");
let info = file_extents(file.as_fd()).expect("file_extents failed");
assert!(info.total_bytes > 0, "total_bytes should be > 0: {info:?}");
assert!(
info.shared_bytes > 0,
"shared_bytes should be > 0 after snapshot: {info:?}",
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn fiemap_shared_after_reflink() {
let (_td, mnt) = single_mount();
write_test_data(mnt.path(), "original.bin", 5_000_000);
sync(mnt.fd()).unwrap();
let original = mnt.path().join("original.bin");
let reflinked = mnt.path().join("reflinked.bin");
let output = Command::new("cp")
.args(["--reflink=always"])
.arg(&original)
.arg(&reflinked)
.output()
.expect("failed to run cp");
assert!(
output.status.success(),
"cp --reflink failed: {}",
String::from_utf8_lossy(&output.stderr)
);
sync(mnt.fd()).unwrap();
let file = File::open(&original).expect("open original failed");
let info = file_extents(file.as_fd()).expect("file_extents failed");
assert!(info.total_bytes > 0, "total_bytes should be > 0: {info:?}");
assert!(
info.shared_bytes > 0,
"shared_bytes should be > 0 after reflink: {info:?}",
);
}