From 877dc9bf2e79a0d926471bedf7204d8210eecf8f Mon Sep 17 00:00:00 2001 From: someone <40119497+some100@users.noreply.github.com> Date: Wed, 24 Dec 2025 06:08:16 +0000 Subject: [PATCH] Implement sys_truncate (#86) --- etc/syscalls_linux_aarch64.md | 2 +- src/arch/arm64/exceptions/syscall.rs | 3 +- src/fs/syscalls/trunc.rs | 32 +++++++++++++++- usertest/src/main.rs | 55 ++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index f4c6af5..239b90d 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -45,7 +45,7 @@ | 0x29 (41) | pivot_root | (const char *new_root, const char *put_old) | __arm64_sys_pivot_root | false | | 0x2b (43) | statfs | (const char *pathname, struct statfs *buf) | __arm64_sys_statfs | false | | 0x2c (44) | fstatfs | (unsigned int fd, struct statfs *buf) | __arm64_sys_fstatfs | false | -| 0x2d (45) | truncate | (const char *path, long length) | __arm64_sys_truncate | false | +| 0x2d (45) | truncate | (const char *path, long length) | __arm64_sys_truncate | true | | 0x2e (46) | ftruncate | (unsigned int fd, off_t length) | __arm64_sys_ftruncate | true | | 0x2f (47) | fallocate | (int fd, int mode, loff_t offset, loff_t len) | __arm64_sys_fallocate | false | | 0x30 (48) | faccessat | (int dfd, const char *filename, int mode) | __arm64_sys_faccessat | true | diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 5abc576..218cb45 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -26,7 +26,7 @@ use crate::{ splice::sys_sendfile, stat::sys_fstat, sync::sys_sync, - trunc::sys_ftruncate, + trunc::{sys_ftruncate, sys_truncate}, }, }, kernel::{power::sys_reboot, rand::sys_getrandom, sysinfo::sys_sysinfo, uname::sys_uname}, @@ -97,6 +97,7 @@ pub async fn handle_syscall() { 0x1d => sys_ioctl(arg1.into(), arg2 as _, arg3 as _).await, 0x22 => sys_mkdirat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x23 => sys_unlinkat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, + 0x2d => sys_truncate(TUA::from_value(arg1 as _), arg2 as _).await, 0x2e => sys_ftruncate(arg1.into(), arg2 as _).await, 0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x31 => sys_chdir(TUA::from_value(arg1 as _)).await, diff --git a/src/fs/syscalls/trunc.rs b/src/fs/syscalls/trunc.rs index 7c8ed39..3bc9755 100644 --- a/src/fs/syscalls/trunc.rs +++ b/src/fs/syscalls/trunc.rs @@ -1,5 +1,33 @@ -use crate::{process::fd_table::Fd, sched::current_task}; -use libkernel::error::{KernelError, Result}; +use core::ffi::c_char; + +use crate::{fs::VFS, memory::uaccess::cstr::UserCStr, process::fd_table::Fd, sched::current_task}; +use libkernel::{ + error::{KernelError, Result}, + fs::{OpenFlags, attr::FilePermissions, path::Path}, + memory::address::TUA, +}; + +pub async fn sys_truncate(path: TUA, new_size: usize) -> Result { + let mut buf = [0; 1024]; + + let task = current_task(); + let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); + + let root = task.root.lock_save_irq().0.clone(); + let file = VFS + .open( + path, + OpenFlags::O_WRONLY, + root, + FilePermissions::empty(), + task, + ) + .await?; + + let (ops, ctx) = &mut *file.lock().await; + + ops.truncate(ctx, new_size).await.map(|_| 0) +} pub async fn sys_ftruncate(fd: Fd, new_size: usize) -> Result { let fd = current_task() diff --git a/usertest/src/main.rs b/usertest/src/main.rs index c2c8380..44c9546 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -319,6 +319,59 @@ fn test_futex() { println!(" OK"); } +fn test_truncate() { + print!("Testing truncate syscall ..."); + use std::fs::{self, File}; + use std::io::{Read, Seek, Write}; + + let path = "/tmp/truncate_test.txt"; + let mut file = File::create_new(path).expect("Failed to create file"); + file.write_all(b"Hello, world!") + .expect("Failed to write to file"); + unsafe { + libc::truncate(std::ffi::CString::new(path).unwrap().as_ptr(), 5); + } + + let mut string = String::new(); + file.rewind().expect("Failed to rewind file"); + file.read_to_string(&mut string) + .expect("Failed to read from file"); + if string != "Hello" { + println!("{string}"); + panic!("truncate failed"); + } + + fs::remove_file(path).expect("Failed to delete file"); + println!(" OK"); +} + +fn test_ftruncate() { + print!("Testing ftruncate syscall ..."); + let file = "/tmp/ftruncate_test.txt"; + let c_file = std::ffi::CString::new(file).unwrap(); + let data = b"Hello, world!"; + let mut buffer = [1u8; 5]; + unsafe { + let fd = libc::open(c_file.as_ptr(), libc::O_RDWR | libc::O_CREAT, 0o777); + let ret = libc::write(fd, data.as_ptr() as *const libc::c_void, data.len()); + if ret < 0 || ret as usize != data.len() { + panic!("write failed"); + } + libc::ftruncate(fd, 5); + libc::lseek(fd, 0, libc::SEEK_SET); + let ret = libc::read(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()); + if ret < 0 || ret as usize != 5 { + panic!("read failed"); + } + if &buffer != b"Hello" { + panic!("ftruncate failed"); + } + libc::close(fd); + } + fs::remove_file(file).expect("Failed to delete file"); + println!(" OK"); +} + fn test_rust_file() { print!("Testing rust file operations ..."); use std::fs::{self, File}; @@ -436,6 +489,8 @@ fn main() { run_test(test_read); run_test(test_write); run_test(test_futex); + run_test(test_truncate); + run_test(test_ftruncate); run_test(test_rust_file); run_test(test_rust_dir); run_test(test_rust_thread);