main.rs 4.6 KB

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