xref: /DragonOS/user/apps/test-chown/src/main.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
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