mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat(time): Add syscall support for utime* (#838)
* feat(vfs): Add syscall support for utime* impl sys_utimensat impl sys_utimes add utimensat test fix some warning * fix(vfs): Verify pointer validity * fix: remove bad cfg
This commit is contained in:
parent
03746da3d9
commit
6f189d2743
@ -11,7 +11,7 @@ use crate::init::initcall::INITCALL_SUBSYS;
|
||||
use crate::mm::PhysAddr;
|
||||
|
||||
use acpi::mcfg::Mcfg;
|
||||
use log::{error, warn};
|
||||
use log::warn;
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
|
@ -1472,6 +1472,16 @@ impl IndexNode for LockedFATInode {
|
||||
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||
return Ok(self.0.lock().metadata.clone());
|
||||
}
|
||||
fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError> {
|
||||
let inode = &mut self.0.lock();
|
||||
inode.metadata.atime = metadata.atime;
|
||||
inode.metadata.mtime = metadata.mtime;
|
||||
inode.metadata.ctime = metadata.ctime;
|
||||
inode.metadata.mode = metadata.mode;
|
||||
inode.metadata.uid = metadata.uid;
|
||||
inode.metadata.gid = metadata.gid;
|
||||
Ok(())
|
||||
}
|
||||
fn resize(&self, len: usize) -> Result<(), SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||
|
@ -2,11 +2,6 @@ use alloc::sync::Arc;
|
||||
use log::warn;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::block::SeekFrom, process::ProcessManager,
|
||||
syscall::user_access::check_and_clone_cstr,
|
||||
};
|
||||
|
||||
use super::{
|
||||
fcntl::AtFlags,
|
||||
file::{File, FileMode},
|
||||
@ -14,6 +9,13 @@ use super::{
|
||||
utils::{rsplit_path, user_path_at},
|
||||
FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
};
|
||||
use crate::filesystem::vfs::syscall::UtimensFlags;
|
||||
use crate::time::{syscall::PosixTimeval, PosixTimeSpec};
|
||||
use crate::{
|
||||
driver::base::block::SeekFrom, process::ProcessManager,
|
||||
syscall::user_access::check_and_clone_cstr,
|
||||
};
|
||||
use alloc::string::String;
|
||||
|
||||
pub(super) fn do_faccessat(
|
||||
dirfd: i32,
|
||||
@ -147,3 +149,84 @@ fn do_sys_openat2(
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/// On Linux, futimens() is a library function implemented on top of
|
||||
/// the utimensat() system call. To support this, the Linux
|
||||
/// utimensat() system call implements a nonstandard feature: if
|
||||
/// pathname is NULL, then the call modifies the timestamps of the
|
||||
/// file referred to by the file descriptor dirfd (which may refer to
|
||||
/// any type of file).
|
||||
pub fn do_utimensat(
|
||||
dirfd: i32,
|
||||
pathname: Option<String>,
|
||||
times: Option<[PosixTimeSpec; 2]>,
|
||||
flags: UtimensFlags,
|
||||
) -> Result<usize, SystemError> {
|
||||
const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
|
||||
const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
|
||||
// log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
|
||||
let inode = match pathname {
|
||||
Some(path) => {
|
||||
let (inode_begin, path) =
|
||||
user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
|
||||
let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
|
||||
inode_begin.lookup(path.as_str())?
|
||||
} else {
|
||||
inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
|
||||
};
|
||||
inode
|
||||
}
|
||||
None => {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.write();
|
||||
let file = fd_table_guard
|
||||
.get_file_by_fd(dirfd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
file.inode()
|
||||
}
|
||||
};
|
||||
let now = PosixTimeSpec::now();
|
||||
let mut meta = inode.metadata()?;
|
||||
|
||||
if let Some([atime, mtime]) = times {
|
||||
if atime.tv_nsec == UTIME_NOW {
|
||||
meta.atime = now;
|
||||
} else if atime.tv_nsec != UTIME_OMIT {
|
||||
meta.atime = atime;
|
||||
}
|
||||
if mtime.tv_nsec == UTIME_NOW {
|
||||
meta.mtime = now;
|
||||
} else if mtime.tv_nsec != UTIME_OMIT {
|
||||
meta.mtime = mtime;
|
||||
}
|
||||
inode.set_metadata(&meta).unwrap();
|
||||
} else {
|
||||
meta.atime = now;
|
||||
meta.mtime = now;
|
||||
inode.set_metadata(&meta).unwrap();
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
|
||||
// log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
|
||||
let (inode_begin, path) = user_path_at(
|
||||
&ProcessManager::current_pcb(),
|
||||
AtFlags::AT_FDCWD.bits(),
|
||||
path,
|
||||
)?;
|
||||
let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
let mut meta = inode.metadata()?;
|
||||
|
||||
if let Some([atime, mtime]) = times {
|
||||
meta.atime = PosixTimeSpec::from(atime);
|
||||
meta.mtime = PosixTimeSpec::from(mtime);
|
||||
inode.set_metadata(&meta)?;
|
||||
} else {
|
||||
let now = PosixTimeSpec::now();
|
||||
meta.atime = now;
|
||||
meta.mtime = now;
|
||||
inode.set_metadata(&meta)?;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use log::warn;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::producefs;
|
||||
use crate::syscall::user_access::UserBufferReader;
|
||||
use crate::{
|
||||
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
||||
filesystem::vfs::{core as Vcore, file::FileDescriptorVec},
|
||||
@ -17,14 +18,14 @@ use crate::{
|
||||
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
||||
Syscall,
|
||||
},
|
||||
time::PosixTimeSpec,
|
||||
time::{syscall::PosixTimeval, PosixTimeSpec},
|
||||
};
|
||||
|
||||
use super::{
|
||||
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
||||
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||
file::{File, FileMode},
|
||||
open::{do_faccessat, do_fchmodat, do_sys_open},
|
||||
open::{do_faccessat, do_fchmodat, do_sys_open, do_utimensat, do_utimes},
|
||||
utils::{rsplit_path, user_path_at},
|
||||
Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
|
||||
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
@ -323,6 +324,13 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct UtimensFlags: u32 {
|
||||
/// 不需要解释符号链接
|
||||
const AT_SYMLINK_NOFOLLOW = 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PosixStatfs {
|
||||
@ -1620,6 +1628,44 @@ impl Syscall {
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn sys_utimensat(
|
||||
dirfd: i32,
|
||||
pathname: *const u8,
|
||||
times: *const PosixTimeSpec,
|
||||
flags: u32,
|
||||
) -> Result<usize, SystemError> {
|
||||
let pathname = if pathname.is_null() {
|
||||
None
|
||||
} else {
|
||||
let pathname = check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?;
|
||||
Some(pathname)
|
||||
};
|
||||
let flags = UtimensFlags::from_bits(flags).ok_or(SystemError::EINVAL)?;
|
||||
let times = if times.is_null() {
|
||||
None
|
||||
} else {
|
||||
let times_reader = UserBufferReader::new(times, size_of::<PosixTimeSpec>() * 2, true)?;
|
||||
let times = times_reader.read_from_user::<PosixTimeSpec>(0)?;
|
||||
Some([times[0], times[1]])
|
||||
};
|
||||
do_utimensat(dirfd, pathname, times, flags)
|
||||
}
|
||||
|
||||
pub fn sys_utimes(
|
||||
pathname: *const u8,
|
||||
times: *const PosixTimeval,
|
||||
) -> Result<usize, SystemError> {
|
||||
let pathname = check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?;
|
||||
let times = if times.is_null() {
|
||||
None
|
||||
} else {
|
||||
let times_reader = UserBufferReader::new(times, size_of::<PosixTimeval>() * 2, true)?;
|
||||
let times = times_reader.read_from_user::<PosixTimeval>(0)?;
|
||||
Some([times[0], times[1]])
|
||||
};
|
||||
do_utimes(&pathname, times)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -29,7 +29,7 @@ use crate::{
|
||||
filesystem::vfs::{
|
||||
fcntl::{AtFlags, FcntlCommand},
|
||||
file::FileMode,
|
||||
syscall::{ModeType, PosixKstat},
|
||||
syscall::{ModeType, PosixKstat, UtimensFlags},
|
||||
MAX_PATHLEN,
|
||||
},
|
||||
libs::align::page_align_up,
|
||||
@ -1103,7 +1103,24 @@ impl Syscall {
|
||||
|
||||
Self::shmctl(id, cmd, user_buf, from_user)
|
||||
}
|
||||
|
||||
SYS_UTIMENSAT => Self::sys_utimensat(
|
||||
args[0] as i32,
|
||||
args[1] as *const u8,
|
||||
args[2] as *const PosixTimeSpec,
|
||||
args[3] as u32,
|
||||
),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
SYS_FUTIMESAT => {
|
||||
let flags = UtimensFlags::empty();
|
||||
Self::sys_utimensat(
|
||||
args[0] as i32,
|
||||
args[1] as *const u8,
|
||||
args[2] as *const PosixTimeSpec,
|
||||
flags.bits(),
|
||||
)
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
SYS_UTIMES => Self::sys_utimes(args[0] as *const u8, args[1] as *const PosixTimeval),
|
||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ use core::{
|
||||
};
|
||||
|
||||
use crate::arch::CurrentTimeArch;
|
||||
use crate::time::syscall::PosixTimeval;
|
||||
|
||||
use self::timekeeping::getnstimeofday;
|
||||
|
||||
@ -114,6 +115,15 @@ impl From<Duration> for PosixTimeSpec {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PosixTimeval> for PosixTimeSpec {
|
||||
fn from(value: PosixTimeval) -> Self {
|
||||
PosixTimeSpec {
|
||||
tv_sec: value.tv_sec,
|
||||
tv_nsec: value.tv_usec as i64 * 1000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PosixTimeSpec> for Duration {
|
||||
fn from(val: PosixTimeSpec) -> Self {
|
||||
Duration::from_micros(val.tv_sec as u64 * 1000000 + val.tv_nsec as u64 / 1000)
|
||||
|
1
user/apps/test_utimensat/.gitignore
vendored
Normal file
1
user/apps/test_utimensat/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test_utimensat
|
20
user/apps/test_utimensat/Makefile
Normal file
20
user/apps/test_utimensat/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
ifeq ($(ARCH), x86_64)
|
||||
CROSS_COMPILE=x86_64-linux-musl-
|
||||
else ifeq ($(ARCH), riscv64)
|
||||
CROSS_COMPILE=riscv64-linux-musl-
|
||||
endif
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
.PHONY: all
|
||||
all: main.c
|
||||
$(CC) -static -o test_utimensat main.c
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
mv test_utimensat $(DADK_CURRENT_BUILD_DIR)/test_utimensat
|
||||
|
||||
clean:
|
||||
rm test_utimensat *.o
|
||||
|
||||
fmt:
|
12
user/apps/test_utimensat/main.c
Normal file
12
user/apps/test_utimensat/main.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int main(){
|
||||
int res = utimensat(AT_FDCWD, "/bin/about.elf", NULL, 0);
|
||||
printf("utimensat res = %d\n", res);
|
||||
}
|
23
user/dadk/config/test_utimensat_0_1_0.dadk
Normal file
23
user/dadk/config/test_utimensat_0_1_0.dadk
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "test_utimensat",
|
||||
"version": "0.1.0",
|
||||
"description": "test_utimensat",
|
||||
"task_type": {
|
||||
"BuildFromSource": {
|
||||
"Local": {
|
||||
"path": "apps/test_utimensat"
|
||||
}
|
||||
}
|
||||
},
|
||||
"depends": [],
|
||||
"build": {
|
||||
"build_command": "make install"
|
||||
},
|
||||
"install": {
|
||||
"in_dragonos_path": "/bin"
|
||||
},
|
||||
"clean": {
|
||||
"clean_command": "make clean"
|
||||
},
|
||||
"target_arch": ["x86_64"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user