1*55e6f0b6S火花 use core::ffi::{c_char, c_void};
2*55e6f0b6S火花 use libc::{
3*55e6f0b6S火花 chown, fchown, fchownat, getgrnam, getpwnam, gid_t, lchown, mount, uid_t, umount, AT_FDCWD,
4*55e6f0b6S火花 AT_SYMLINK_NOFOLLOW,
5*55e6f0b6S火花 };
6*55e6f0b6S火花 use nix::errno::Errno;
7*55e6f0b6S火花 use std::{
8*55e6f0b6S火花 ffi::CString,
9*55e6f0b6S火花 fs::{self, metadata, File},
10*55e6f0b6S火花 io::{self, Error, Write},
11*55e6f0b6S火花 os::unix::{
12*55e6f0b6S火花 fs::{MetadataExt, PermissionsExt},
13*55e6f0b6S火花 io::AsRawFd,
14*55e6f0b6S火花 },
15*55e6f0b6S火花 path::Path,
16*55e6f0b6S火花 };
17*55e6f0b6S火花
print_file_owner_group(filename: &str) -> Result<(), Error>18*55e6f0b6S火花 fn print_file_owner_group(filename: &str) -> Result<(), Error> {
19*55e6f0b6S火花 let metadata = std::fs::metadata(filename)?;
20*55e6f0b6S火花 let uid = metadata.uid();
21*55e6f0b6S火花 let gid = metadata.gid();
22*55e6f0b6S火花
23*55e6f0b6S火花 // 确保 UID 和 GID 打印正确
24*55e6f0b6S火花 assert!(uid > 0, "UID should be greater than 0");
25*55e6f0b6S火花 assert!(gid > 0, "GID should be greater than 0");
26*55e6f0b6S火花
27*55e6f0b6S火花 Ok(())
28*55e6f0b6S火花 }
29*55e6f0b6S火花
test_fchownat(filename: &str, new_uid: uid_t, new_gid: gid_t, flags: i32) -> Result<(), Error>30*55e6f0b6S火花 fn test_fchownat(filename: &str, new_uid: uid_t, new_gid: gid_t, flags: i32) -> Result<(), Error> {
31*55e6f0b6S火花 let c_filename = CString::new(filename)?;
32*55e6f0b6S火花 let result = unsafe { fchownat(AT_FDCWD, c_filename.as_ptr(), new_uid, new_gid, flags) };
33*55e6f0b6S火花
34*55e6f0b6S火花 // 确保 fchownat 成功
35*55e6f0b6S火花 assert!(result != -1, "fchownat failed");
36*55e6f0b6S火花
37*55e6f0b6S火花 print_file_owner_group(filename)?;
38*55e6f0b6S火花 Ok(())
39*55e6f0b6S火花 }
40*55e6f0b6S火花
test_chown(filename: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error>41*55e6f0b6S火花 fn test_chown(filename: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
42*55e6f0b6S火花 let c_filename = CString::new(filename)?;
43*55e6f0b6S火花 let result = unsafe { chown(c_filename.as_ptr(), new_uid, new_gid) };
44*55e6f0b6S火花
45*55e6f0b6S火花 // 确保 chown 成功
46*55e6f0b6S火花 assert!(result != -1, "chown failed");
47*55e6f0b6S火花
48*55e6f0b6S火花 print_file_owner_group(filename)?;
49*55e6f0b6S火花 Ok(())
50*55e6f0b6S火花 }
51*55e6f0b6S火花
test_fchown(fd: i32, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error>52*55e6f0b6S火花 fn test_fchown(fd: i32, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
53*55e6f0b6S火花 let result = unsafe { fchown(fd, new_uid, new_gid) };
54*55e6f0b6S火花
55*55e6f0b6S火花 // 确保 fchown 成功
56*55e6f0b6S火花 assert!(result != -1, "fchown failed");
57*55e6f0b6S火花
58*55e6f0b6S火花 Ok(())
59*55e6f0b6S火花 }
60*55e6f0b6S火花
test_lchown(symlink_name: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error>61*55e6f0b6S火花 fn test_lchown(symlink_name: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
62*55e6f0b6S火花 let c_symlink = CString::new(symlink_name)?;
63*55e6f0b6S火花 let result = unsafe { lchown(c_symlink.as_ptr(), new_uid, new_gid) };
64*55e6f0b6S火花
65*55e6f0b6S火花 // 确保 lchown 成功
66*55e6f0b6S火花 assert!(result != -1, "lchown failed");
67*55e6f0b6S火花
68*55e6f0b6S火花 print_file_owner_group(symlink_name)?;
69*55e6f0b6S火花 Ok(())
70*55e6f0b6S火花 }
71*55e6f0b6S火花
main() -> Result<(), Error>72*55e6f0b6S火花 fn main() -> Result<(), Error> {
73*55e6f0b6S火花 mount_test_ramfs();
74*55e6f0b6S火花
75*55e6f0b6S火花 let filename = "/mnt/myramfs/testfile.txt";
76*55e6f0b6S火花 let symlink_name = "/mnt/myramfs/testsymlink";
77*55e6f0b6S火花 let new_owner = "nobody"; // 替换为你测试系统中的有效用户名
78*55e6f0b6S火花 let new_group = "nogroup"; // 替换为你测试系统中的有效组名
79*55e6f0b6S火花
80*55e6f0b6S火花 // 获取新的 UID 和 GID
81*55e6f0b6S火花 let pw = unsafe { getpwnam(CString::new(new_owner)?.as_ptr()) };
82*55e6f0b6S火花 let gr = unsafe { getgrnam(CString::new(new_group)?.as_ptr()) };
83*55e6f0b6S火花
84*55e6f0b6S火花 assert!(!pw.is_null(), "Invalid user name");
85*55e6f0b6S火花 assert!(!gr.is_null(), "Invalid group name");
86*55e6f0b6S火花
87*55e6f0b6S火花 let new_uid = unsafe { (*pw).pw_uid };
88*55e6f0b6S火花 let new_gid = unsafe { (*gr).gr_gid };
89*55e6f0b6S火花
90*55e6f0b6S火花 // 创建测试文件
91*55e6f0b6S火花 let mut file = File::create(filename)?;
92*55e6f0b6S火花 println!("Created test file: {}", filename);
93*55e6f0b6S火花 writeln!(file, "This is a test file for chown system call")?;
94*55e6f0b6S火花
95*55e6f0b6S火花 // 创建符号链接
96*55e6f0b6S火花 std::os::unix::fs::symlink(filename, symlink_name)?;
97*55e6f0b6S火花 println!("Created symlink: {}", symlink_name);
98*55e6f0b6S火花
99*55e6f0b6S火花 // 打开文件以测试 fchown
100*55e6f0b6S火花 let fd = file.as_raw_fd();
101*55e6f0b6S火花
102*55e6f0b6S火花 // 测试 chown
103*55e6f0b6S火花 test_chown(filename, new_uid, new_gid)?;
104*55e6f0b6S火花
105*55e6f0b6S火花 // 测试 fchown
106*55e6f0b6S火花 test_fchown(fd, new_uid, new_gid)?;
107*55e6f0b6S火花
108*55e6f0b6S火花 // 测试 lchown
109*55e6f0b6S火花 test_lchown(symlink_name, new_uid, new_gid)?;
110*55e6f0b6S火花
111*55e6f0b6S火花 // 测试 fchownat,带 AT_SYMLINK_NOFOLLOW 标志(不会跟随符号链接)
112*55e6f0b6S火花 test_fchownat(symlink_name, new_uid, new_gid, AT_SYMLINK_NOFOLLOW)?;
113*55e6f0b6S火花
114*55e6f0b6S火花 // 清理测试文件
115*55e6f0b6S火花 std::fs::remove_file(filename)?;
116*55e6f0b6S火花
117*55e6f0b6S火花 umount_test_ramfs();
118*55e6f0b6S火花
119*55e6f0b6S火花 println!("All tests passed!");
120*55e6f0b6S火花
121*55e6f0b6S火花 Ok(())
122*55e6f0b6S火花 }
123*55e6f0b6S火花
mount_test_ramfs()124*55e6f0b6S火花 fn mount_test_ramfs() {
125*55e6f0b6S火花 let path = Path::new("mnt/myramfs");
126*55e6f0b6S火花 let dir = fs::create_dir_all(path);
127*55e6f0b6S火花 assert!(dir.is_ok(), "mkdir /mnt/myramfs failed");
128*55e6f0b6S火花
129*55e6f0b6S火花 let source = b"\0".as_ptr() as *const c_char;
130*55e6f0b6S火花 let target = b"/mnt/myramfs\0".as_ptr() as *const c_char;
131*55e6f0b6S火花 let fstype = b"ramfs\0".as_ptr() as *const c_char;
132*55e6f0b6S火花 // let flags = MS_BIND;
133*55e6f0b6S火花 let flags = 0;
134*55e6f0b6S火花 let data = std::ptr::null() as *const c_void;
135*55e6f0b6S火花 let result = unsafe { mount(source, target, fstype, flags, data) };
136*55e6f0b6S火花
137*55e6f0b6S火花 assert_eq!(
138*55e6f0b6S火花 result,
139*55e6f0b6S火花 0,
140*55e6f0b6S火花 "Mount myramfs failed, errno: {}",
141*55e6f0b6S火花 Errno::last().desc()
142*55e6f0b6S火花 );
143*55e6f0b6S火花 println!("Mount myramfs for test success!");
144*55e6f0b6S火花 }
145*55e6f0b6S火花
umount_test_ramfs()146*55e6f0b6S火花 fn umount_test_ramfs() {
147*55e6f0b6S火花 let path = b"/mnt/myramfs\0".as_ptr() as *const c_char;
148*55e6f0b6S火花 let result = unsafe { umount(path) };
149*55e6f0b6S火花 if result != 0 {
150*55e6f0b6S火花 let err = Errno::last();
151*55e6f0b6S火花 println!("Errno: {}", err);
152*55e6f0b6S火花 println!("Infomation: {}", err.desc());
153*55e6f0b6S火花 } else {
154*55e6f0b6S火花 // 删除mnt/myramfs
155*55e6f0b6S火花 let path = Path::new("mnt/myramfs");
156*55e6f0b6S火花 let _ = fs::remove_dir(path);
157*55e6f0b6S火花 }
158*55e6f0b6S火花 assert_eq!(result, 0, "Umount myramfs failed");
159*55e6f0b6S火花 println!("Umount myramfs for test success!");
160*55e6f0b6S火花 }
161