Skip to content

Commit

Permalink
feat(time): Add syscall support for utime* (DragonOS-Community#838)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Godones authored Jun 27, 2024
1 parent 03746da commit 6f189d2
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 10 deletions.
2 changes: 1 addition & 1 deletion kernel/src/arch/x86_64/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
10 changes: 10 additions & 0 deletions kernel/src/filesystem/fat/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
93 changes: 88 additions & 5 deletions kernel/src/filesystem/vfs/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ 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},
syscall::{ModeType, OpenHow, OpenHowResolve},
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,
Expand Down Expand Up @@ -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);
}
50 changes: 48 additions & 2 deletions kernel/src/filesystem/vfs/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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,
Expand Down Expand Up @@ -323,6 +324,13 @@ bitflags! {
}
}

bitflags! {
pub struct UtimensFlags: u32 {
/// 不需要解释符号链接
const AT_SYMLINK_NOFOLLOW = 0x100;
}
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PosixStatfs {
Expand Down Expand Up @@ -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)]
Expand Down
21 changes: 19 additions & 2 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand 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),
};

Expand Down
10 changes: 10 additions & 0 deletions kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use core::{
};

use crate::arch::CurrentTimeArch;
use crate::time::syscall::PosixTimeval;

use self::timekeeping::getnstimeofday;

Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions user/apps/test_utimensat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_utimensat
20 changes: 20 additions & 0 deletions user/apps/test_utimensat/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions user/apps/test_utimensat/main.c
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions user/dadk/config/test_utimensat_0_1_0.dadk
Original file line number Diff line number Diff line change
@@ -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"]
}

0 comments on commit 6f189d2

Please sign in to comment.