mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 07:06:47 +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 crate::mm::PhysAddr;
|
||||||
|
|
||||||
use acpi::mcfg::Mcfg;
|
use acpi::mcfg::Mcfg;
|
||||||
use log::{error, warn};
|
use log::warn;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
use unified_init::macros::unified_init;
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
|
@ -1472,6 +1472,16 @@ impl IndexNode for LockedFATInode {
|
|||||||
fn metadata(&self) -> Result<Metadata, SystemError> {
|
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||||
return Ok(self.0.lock().metadata.clone());
|
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> {
|
fn resize(&self, len: usize) -> Result<(), SystemError> {
|
||||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||||
|
@ -2,11 +2,6 @@ use alloc::sync::Arc;
|
|||||||
use log::warn;
|
use log::warn;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
driver::base::block::SeekFrom, process::ProcessManager,
|
|
||||||
syscall::user_access::check_and_clone_cstr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
fcntl::AtFlags,
|
fcntl::AtFlags,
|
||||||
file::{File, FileMode},
|
file::{File, FileMode},
|
||||||
@ -14,6 +9,13 @@ use super::{
|
|||||||
utils::{rsplit_path, user_path_at},
|
utils::{rsplit_path, user_path_at},
|
||||||
FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
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(
|
pub(super) fn do_faccessat(
|
||||||
dirfd: i32,
|
dirfd: i32,
|
||||||
@ -147,3 +149,84 @@ fn do_sys_openat2(
|
|||||||
|
|
||||||
return r;
|
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 system_error::SystemError;
|
||||||
|
|
||||||
use crate::producefs;
|
use crate::producefs;
|
||||||
|
use crate::syscall::user_access::UserBufferReader;
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
||||||
filesystem::vfs::{core as Vcore, file::FileDescriptorVec},
|
filesystem::vfs::{core as Vcore, file::FileDescriptorVec},
|
||||||
@ -17,14 +18,14 @@ use crate::{
|
|||||||
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
||||||
Syscall,
|
Syscall,
|
||||||
},
|
},
|
||||||
time::PosixTimeSpec,
|
time::{syscall::PosixTimeval, PosixTimeSpec},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
||||||
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||||
file::{File, FileMode},
|
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},
|
utils::{rsplit_path, user_path_at},
|
||||||
Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
|
Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
|
||||||
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||||
@ -323,6 +324,13 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct UtimensFlags: u32 {
|
||||||
|
/// 不需要解释符号链接
|
||||||
|
const AT_SYMLINK_NOFOLLOW = 0x100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct PosixStatfs {
|
pub struct PosixStatfs {
|
||||||
@ -1620,6 +1628,44 @@ impl Syscall {
|
|||||||
)?;
|
)?;
|
||||||
return Ok(());
|
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)]
|
#[repr(C)]
|
||||||
|
@ -29,7 +29,7 @@ use crate::{
|
|||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
fcntl::{AtFlags, FcntlCommand},
|
fcntl::{AtFlags, FcntlCommand},
|
||||||
file::FileMode,
|
file::FileMode,
|
||||||
syscall::{ModeType, PosixKstat},
|
syscall::{ModeType, PosixKstat, UtimensFlags},
|
||||||
MAX_PATHLEN,
|
MAX_PATHLEN,
|
||||||
},
|
},
|
||||||
libs::align::page_align_up,
|
libs::align::page_align_up,
|
||||||
@ -1103,7 +1103,24 @@ impl Syscall {
|
|||||||
|
|
||||||
Self::shmctl(id, cmd, user_buf, from_user)
|
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),
|
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::arch::CurrentTimeArch;
|
use crate::arch::CurrentTimeArch;
|
||||||
|
use crate::time::syscall::PosixTimeval;
|
||||||
|
|
||||||
use self::timekeeping::getnstimeofday;
|
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 {
|
impl From<PosixTimeSpec> for Duration {
|
||||||
fn from(val: PosixTimeSpec) -> Self {
|
fn from(val: PosixTimeSpec) -> Self {
|
||||||
Duration::from_micros(val.tv_sec as u64 * 1000000 + val.tv_nsec as u64 / 1000)
|
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