[libos] Add support for UTIME

This commit is contained in:
zhubojun 2022-03-16 15:59:11 +08:00 committed by Zongmin.Gu
parent 66d1ebe918
commit 4fab368127
6 changed files with 266 additions and 16 deletions

@ -29,6 +29,9 @@ pub use self::stat::{do_fstat, do_fstatat, Stat, StatFlags};
pub use self::symlink::{do_readlinkat, do_symlinkat};
pub use self::truncate::{do_ftruncate, do_truncate};
pub use self::unlink::{do_unlinkat, UnlinkFlags};
pub use self::utimes::{
do_utimes_fd, do_utimes_path, get_utimes, utimbuf_t, Utime, UtimeFlags, UTIME_OMIT,
};
pub use self::write::{do_pwrite, do_write, do_writev};
mod access;
@ -56,4 +59,5 @@ mod stat;
mod symlink;
mod truncate;
mod unlink;
mod utimes;
mod write;

@ -0,0 +1,138 @@
use crate::util::mem_util::from_user;
use super::time::{timespec_t, OcclumTimeProvider};
use super::*;
use rcore_fs::dev::TimeProvider;
const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
pub const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
bitflags! {
pub struct UtimeFlags: i32 {
const AT_SYMLINK_NOFOLLOW = 1 << 8;
}
}
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct utimbuf_t {
atime: time_t,
mtime: time_t,
}
impl utimbuf_t {
pub fn atime(&self) -> time_t {
self.atime
}
pub fn mtime(&self) -> time_t {
self.mtime
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum Utime {
UTIME_OMIT,
UTIME_NOW,
UTIME(Timespec),
}
pub fn get_utimes(times: Option<(timespec_t, timespec_t)>) -> Result<(Utime, Utime)> {
let now = OcclumTimeProvider.current_time();
if let Some(times) = times {
let (atime, mtime) = times;
if (!timespec_valid(atime)) || (!timespec_valid(mtime)) {
return_errno!(EINVAL, "parameter: times is invalid")
}
let atime = if atime.nsec() == UTIME_OMIT {
Utime::UTIME_OMIT
} else if atime.nsec() == UTIME_NOW {
Utime::UTIME(now)
} else {
Utime::UTIME(Timespec {
sec: atime.sec(),
nsec: atime.nsec(),
})
};
let mtime = if mtime.nsec() == UTIME_OMIT {
Utime::UTIME_OMIT
} else if mtime.nsec() == UTIME_NOW {
Utime::UTIME(now)
} else {
Utime::UTIME(Timespec {
sec: mtime.sec(),
nsec: mtime.nsec(),
})
};
Ok((atime, mtime))
} else {
Ok((Utime::UTIME(now), Utime::UTIME(now)))
}
}
fn timespec_valid(time: timespec_t) -> bool {
if (time.nsec() == UTIME_NOW || time.nsec() == UTIME_OMIT) {
true
} else {
time.sec() >= 0 && time.nsec() >= 0 && time.nsec() < 1_000_000_000
}
}
pub fn do_utimes_fd(fd: FileDesc, atime: Utime, mtime: Utime, flags: i32) -> Result<isize> {
debug!(
"utimes_fd: fd: {:?}, atime: {:?}, mtime: {:?}, flags: {:?}",
fd, atime, mtime, flags
);
if flags != 0 {
return_errno!(EINVAL, "parameter: flags is invalid");
}
let file_ref = current!().file(fd)?;
let mut info = file_ref.metadata()?;
if let Utime::UTIME(atime) = atime {
info.atime = atime;
}
if let Utime::UTIME(mtime) = mtime {
info.mtime = mtime;
}
file_ref.set_metadata(&info)?;
Ok(0)
}
pub fn do_utimes_path(
fs_path: &FsPath,
atime: Utime,
mtime: Utime,
flags: UtimeFlags,
) -> Result<isize> {
debug!(
"utimes_path: fs_path: {:?}, atime: {:?}, mtime: {:?}, flags: {:?}",
fs_path, atime, mtime, flags
);
let inode = {
let path = fs_path.to_abs_path()?;
let current = current!();
let fs = current.fs().read().unwrap();
if flags.contains(UtimeFlags::AT_SYMLINK_NOFOLLOW) {
fs.lookup_inode_no_follow(&path)?
} else {
fs.lookup_inode(&path)?
}
};
let mut info = inode.metadata()?;
if let Utime::UTIME(atime) = atime {
info.atime = atime;
}
if let Utime::UTIME(mtime) = mtime {
info.mtime = mtime;
}
inode.set_metadata(&info)?;
Ok(0)
}

@ -19,8 +19,8 @@ pub use self::event_file::{AsEvent, EventCreationFlags, EventFile};
pub use self::events::{AtomicIoEvents, IoEvents, IoNotifier};
pub use self::file::{File, FileRef};
pub use self::file_ops::{
occlum_ocall_ioctl, AccessMode, BuiltinIoctlNum, CreationFlags, FallocateFlags, FileMode,
IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
occlum_ocall_ioctl, utimbuf_t, AccessMode, BuiltinIoctlNum, CreationFlags, FallocateFlags,
FileMode, IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
};
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
pub use self::fs_ops::Statfs;

@ -1,12 +1,12 @@
use super::event_file::EventCreationFlags;
use super::file_ops;
use super::file_ops::{
get_abs_path_by_fd, AccessibilityCheckFlags, AccessibilityCheckMode, ChownFlags, FcntlCmd,
FsPath, LinkFlags, StatFlags, UnlinkFlags, AT_FDCWD,
get_abs_path_by_fd, get_utimes, AccessibilityCheckFlags, AccessibilityCheckMode, ChownFlags,
FcntlCmd, FsPath, LinkFlags, StatFlags, UnlinkFlags, Utime, UtimeFlags, AT_FDCWD, UTIME_OMIT,
};
use super::fs_ops;
use super::fs_ops::{MountFlags, MountOptions, UmountFlags};
use super::time::{clockid_t, itimerspec_t, ClockID};
use super::time::{clockid_t, itimerspec_t, timespec_t, timeval_t, ClockID};
use super::timer_file::{TimerCreationFlags, TimerSetFlags};
use super::*;
use config::ConfigMountFsType;
@ -700,3 +700,87 @@ pub fn do_flock(fd: FileDesc, operation: i32) -> Result<isize> {
file_ops::do_flock(fd, flock_ops)?;
Ok(0)
}
pub fn do_utime(path: *const i8, times_u: *const utimbuf_t) -> Result<isize> {
let times = if !times_u.is_null() {
from_user::check_ptr(times_u)?;
let utimbuf = unsafe { *times_u };
let atime = timespec_t::from(utimbuf.atime());
atime.validate()?;
let mtime = timespec_t::from(utimbuf.mtime());
mtime.validate()?;
Some((atime, mtime))
} else {
None
};
let (atime, mtime) = file_ops::get_utimes(times)?;
self::do_utimes_wrapper(AT_FDCWD, path, atime, mtime, 0)
}
pub fn do_utimes(path: *const i8, times: *const timeval_t) -> Result<isize> {
self::do_futimesat(AT_FDCWD, path, times)
}
pub fn do_futimesat(dirfd: i32, path: *const i8, times_u: *const timeval_t) -> Result<isize> {
let times = if !times_u.is_null() {
from_user::check_array(times_u, 2)?;
let atime_ptr = unsafe { times_u.offset(0) };
let atime = unsafe { *atime_ptr };
let atime = timespec_t::from(atime);
atime.validate()?;
let mtime_ptr = unsafe { times_u.offset(1) };
let mtime = unsafe { *mtime_ptr };
let mtime = timespec_t::from(mtime);
mtime.validate()?;
Some((atime, mtime))
} else {
None
};
let (atime, mtime) = file_ops::get_utimes(times)?;
self::do_utimes_wrapper(dirfd, path, atime, mtime, 0)
}
pub fn do_utimensat(
dirfd: i32,
path: *const i8,
times_u: *const timespec_t,
flags: i32,
) -> Result<isize> {
let times = if !times_u.is_null() {
from_user::check_array(times_u, 2)?;
let atime_ptr = unsafe { times_u.offset(0) };
let atime = unsafe { *atime_ptr };
let mtime_ptr = unsafe { times_u.offset(1) };
let mtime = unsafe { *mtime_ptr };
if atime.nsec() == UTIME_OMIT && mtime.nsec() == UTIME_OMIT {
return Ok(0);
}
Some((atime, mtime))
} else {
None
};
let (atime, mtime) = file_ops::get_utimes(times)?;
self::do_utimes_wrapper(dirfd, path, atime, mtime, flags)
}
fn do_utimes_wrapper(
dirfd: i32,
path: *const i8,
atime: Utime,
mtime: Utime,
flags: i32,
) -> Result<isize> {
if path.is_null() && dirfd != AT_FDCWD {
file_ops::do_utimes_fd(dirfd as FileDesc, atime, mtime, flags)
} else {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
let flags = UtimeFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL, "invalid flags"))?;
let fs_path = FsPath::new(&path, dirfd, false)?;
file_ops::do_utimes_path(&fs_path, atime, mtime, flags)
}
}

@ -25,13 +25,14 @@ use crate::fs::{
do_access, do_chdir, do_chmod, do_chown, do_close, do_creat, do_dup, do_dup2, do_dup3,
do_eventfd, do_eventfd2, do_faccessat, do_fallocate, do_fchdir, do_fchmod, do_fchmodat,
do_fchown, do_fchownat, do_fcntl, do_fdatasync, do_flock, do_fstat, do_fstatat, do_fstatfs,
do_fsync, do_ftruncate, do_getcwd, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link,
do_linkat, do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount, do_mount_rootfs, do_open,
do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat,
do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink,
do_symlinkat, do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate,
do_umask, do_umount, do_unlink, do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File,
FileDesc, FileRef, HostStdioFds, Stat, Statfs,
do_fsync, do_ftruncate, do_futimesat, do_getcwd, do_getdents, do_getdents64, do_ioctl,
do_lchown, do_link, do_linkat, do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount,
do_mount_rootfs, do_open, do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, do_read,
do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_stat,
do_statfs, do_symlink, do_symlinkat, do_sync, do_timerfd_create, do_timerfd_gettime,
do_timerfd_settime, do_truncate, do_umask, do_umount, do_unlink, do_unlinkat, do_utime,
do_utimensat, do_utimes, do_write, do_writev, iovec_t, utimbuf_t, AsTimer, File, FileDesc,
FileRef, HostStdioFds, Stat, Statfs,
};
use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t};
use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t, RandFlags};
@ -220,7 +221,7 @@ macro_rules! process_syscall_table_with_callback {
(RtSigqueueinfo = 129) => handle_unsupported(),
(RtSigsuspend = 130) => handle_unsupported(),
(Sigaltstack = 131) => do_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t, context: *const CpuContext),
(Utime = 132) => handle_unsupported(),
(Utime = 132) => do_utime(path: *const i8, times: *const utimbuf_t),
(Mknod = 133) => handle_unsupported(),
(Uselib = 134) => handle_unsupported(),
(Personality = 135) => handle_unsupported(),
@ -323,7 +324,7 @@ macro_rules! process_syscall_table_with_callback {
(EpollWait = 232) => do_epoll_wait(epfd: c_int, events: *mut libc::epoll_event, maxevents: c_int, timeout: c_int),
(EpollCtl = 233) => do_epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const libc::epoll_event),
(Tgkill = 234) => do_tgkill(pid: i32, tid: pid_t, sig: c_int),
(Utimes = 235) => handle_unsupported(),
(Utimes = 235) => do_utimes(path: *const i8, times: *const timeval_t),
(Vserver = 236) => handle_unsupported(),
(Mbind = 237) => handle_unsupported(),
(SetMempolicy = 238) => handle_unsupported(),
@ -349,7 +350,7 @@ macro_rules! process_syscall_table_with_callback {
(Mkdirat = 258) => do_mkdirat(dirfd: i32, path: *const i8, mode: u16),
(Mknodat = 259) => handle_unsupported(),
(Fchownat = 260) => do_fchownat(dirfd: i32, path: *const i8, uid: u32, gid: u32, flags: i32),
(Futimesat = 261) => handle_unsupported(),
(Futimesat = 261) => do_futimesat(dirfd: i32, path: *const i8, times: *const timeval_t),
(Fstatat = 262) => do_fstatat(dirfd: i32, path: *const i8, stat_buf: *mut Stat, flags: u32),
(Unlinkat = 263) => do_unlinkat(dirfd: i32, path: *const i8, flags: i32),
(Renameat = 264) => do_renameat(olddirfd: i32, oldpath: *const i8, newdirfd: i32, newpath: *const i8),
@ -368,7 +369,7 @@ macro_rules! process_syscall_table_with_callback {
(SyncFileRange = 277) => handle_unsupported(),
(Vmsplice = 278) => handle_unsupported(),
(MovePages = 279) => handle_unsupported(),
(Utimensat = 280) => handle_unsupported(),
(Utimensat = 280) => do_utimensat(dirfd: i32, path: *const i8, times: *const timespec_t, flags: i32),
(EpollPwait = 281) => do_epoll_pwait(epfd: c_int, events: *mut libc::epoll_event, maxevents: c_int, timeout: c_int, sigmask: *const usize),
(Signalfd = 282) => handle_unsupported(),
(TimerfdCreate = 283) => do_timerfd_create(clockid: clockid_t, flags: i32 ),

@ -48,6 +48,14 @@ impl timeval_t {
}
}
pub fn sec(&self) -> time_t {
self.sec
}
pub fn usec(&self) -> suseconds_t {
self.usec
}
pub fn as_duration(&self) -> Duration {
Duration::new(self.sec as u64, (self.usec * 1_000) as u32)
}
@ -92,6 +100,21 @@ impl From<Duration> for timespec_t {
}
}
impl From<timeval_t> for timespec_t {
fn from(timval: timeval_t) -> timespec_t {
timespec_t {
sec: timval.sec(),
nsec: timval.usec() * 1_000,
}
}
}
impl From<time_t> for timespec_t {
fn from(time: time_t) -> timespec_t {
timespec_t { sec: time, nsec: 0 }
}
}
impl timespec_t {
pub fn from_raw_ptr(ptr: *const timespec_t) -> Result<timespec_t> {
let ts = unsafe { *ptr };