Files
DragonOS/user/apps/test-chown/src/main.rs
火花 55e6f0b65f feat:添加chown系统调用 (#962)
* 添加chown系统调用

---------

Co-authored-by: sparkzky <sparkhhhhhhhhh@outlook.com>
Co-authored-by: longjin <longjin@DragonOS.org>
2024-10-26 18:13:25 +08:00

161 lines
4.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::ffi::{c_char, c_void};
use libc::{
chown, fchown, fchownat, getgrnam, getpwnam, gid_t, lchown, mount, uid_t, umount, AT_FDCWD,
AT_SYMLINK_NOFOLLOW,
};
use nix::errno::Errno;
use std::{
ffi::CString,
fs::{self, metadata, File},
io::{self, Error, Write},
os::unix::{
fs::{MetadataExt, PermissionsExt},
io::AsRawFd,
},
path::Path,
};
fn print_file_owner_group(filename: &str) -> Result<(), Error> {
let metadata = std::fs::metadata(filename)?;
let uid = metadata.uid();
let gid = metadata.gid();
// 确保 UID 和 GID 打印正确
assert!(uid > 0, "UID should be greater than 0");
assert!(gid > 0, "GID should be greater than 0");
Ok(())
}
fn test_fchownat(filename: &str, new_uid: uid_t, new_gid: gid_t, flags: i32) -> Result<(), Error> {
let c_filename = CString::new(filename)?;
let result = unsafe { fchownat(AT_FDCWD, c_filename.as_ptr(), new_uid, new_gid, flags) };
// 确保 fchownat 成功
assert!(result != -1, "fchownat failed");
print_file_owner_group(filename)?;
Ok(())
}
fn test_chown(filename: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
let c_filename = CString::new(filename)?;
let result = unsafe { chown(c_filename.as_ptr(), new_uid, new_gid) };
// 确保 chown 成功
assert!(result != -1, "chown failed");
print_file_owner_group(filename)?;
Ok(())
}
fn test_fchown(fd: i32, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
let result = unsafe { fchown(fd, new_uid, new_gid) };
// 确保 fchown 成功
assert!(result != -1, "fchown failed");
Ok(())
}
fn test_lchown(symlink_name: &str, new_uid: uid_t, new_gid: gid_t) -> Result<(), Error> {
let c_symlink = CString::new(symlink_name)?;
let result = unsafe { lchown(c_symlink.as_ptr(), new_uid, new_gid) };
// 确保 lchown 成功
assert!(result != -1, "lchown failed");
print_file_owner_group(symlink_name)?;
Ok(())
}
fn main() -> Result<(), Error> {
mount_test_ramfs();
let filename = "/mnt/myramfs/testfile.txt";
let symlink_name = "/mnt/myramfs/testsymlink";
let new_owner = "nobody"; // 替换为你测试系统中的有效用户名
let new_group = "nogroup"; // 替换为你测试系统中的有效组名
// 获取新的 UID 和 GID
let pw = unsafe { getpwnam(CString::new(new_owner)?.as_ptr()) };
let gr = unsafe { getgrnam(CString::new(new_group)?.as_ptr()) };
assert!(!pw.is_null(), "Invalid user name");
assert!(!gr.is_null(), "Invalid group name");
let new_uid = unsafe { (*pw).pw_uid };
let new_gid = unsafe { (*gr).gr_gid };
// 创建测试文件
let mut file = File::create(filename)?;
println!("Created test file: {}", filename);
writeln!(file, "This is a test file for chown system call")?;
// 创建符号链接
std::os::unix::fs::symlink(filename, symlink_name)?;
println!("Created symlink: {}", symlink_name);
// 打开文件以测试 fchown
let fd = file.as_raw_fd();
// 测试 chown
test_chown(filename, new_uid, new_gid)?;
// 测试 fchown
test_fchown(fd, new_uid, new_gid)?;
// 测试 lchown
test_lchown(symlink_name, new_uid, new_gid)?;
// 测试 fchownat带 AT_SYMLINK_NOFOLLOW 标志(不会跟随符号链接)
test_fchownat(symlink_name, new_uid, new_gid, AT_SYMLINK_NOFOLLOW)?;
// 清理测试文件
std::fs::remove_file(filename)?;
umount_test_ramfs();
println!("All tests passed!");
Ok(())
}
fn mount_test_ramfs() {
let path = Path::new("mnt/myramfs");
let dir = fs::create_dir_all(path);
assert!(dir.is_ok(), "mkdir /mnt/myramfs failed");
let source = b"\0".as_ptr() as *const c_char;
let target = b"/mnt/myramfs\0".as_ptr() as *const c_char;
let fstype = b"ramfs\0".as_ptr() as *const c_char;
// let flags = MS_BIND;
let flags = 0;
let data = std::ptr::null() as *const c_void;
let result = unsafe { mount(source, target, fstype, flags, data) };
assert_eq!(
result,
0,
"Mount myramfs failed, errno: {}",
Errno::last().desc()
);
println!("Mount myramfs for test success!");
}
fn umount_test_ramfs() {
let path = b"/mnt/myramfs\0".as_ptr() as *const c_char;
let result = unsafe { umount(path) };
if result != 0 {
let err = Errno::last();
println!("Errno: {}", err);
println!("Infomation: {}", err.desc());
} else {
// 删除mnt/myramfs
let path = Path::new("mnt/myramfs");
let _ = fs::remove_dir(path);
}
assert_eq!(result, 0, "Umount myramfs failed");
println!("Umount myramfs for test success!");
}