kernel+libc: Add all variants of utime
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
1481a4736a
commit
a92077d311
@ -4,9 +4,11 @@
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include <bits/atfile.h>
|
||||
#include <bits/fcntl.h>
|
||||
#include <bits/open-flags.h>
|
||||
#include <bits/seek.h>
|
||||
#include <bits/utime.h>
|
||||
#include <luna/SafeArithmetic.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -262,3 +264,52 @@ Result<u64> sys_ftruncate(Registers*, SyscallArgs args)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
||||
{
|
||||
int dirfd = (int)args[0];
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||
const auto* times = (const struct timespec*)args[2];
|
||||
int flags = (int)args[3];
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
||||
|
||||
struct timespec ktimes[2];
|
||||
ktimes[0].tv_sec = ktimes[1].tv_sec = 0;
|
||||
ktimes[0].tv_nsec = ktimes[1].tv_nsec = UTIME_NOW;
|
||||
|
||||
if (times && !MemoryManager::copy_from_user(times, ktimes, sizeof(ktimes))) return err(EFAULT);
|
||||
|
||||
// No permission checks are performed, since no actual modification is done, but the above checks are still
|
||||
// performed.
|
||||
if (ktimes[0].tv_nsec == UTIME_OMIT && ktimes[1].tv_nsec == UTIME_OMIT) return 0;
|
||||
|
||||
bool allow_write_access = ktimes[0].tv_nsec == UTIME_NOW && ktimes[1].tv_nsec == UTIME_NOW;
|
||||
|
||||
if (allow_write_access)
|
||||
{
|
||||
if (!VFS::can_write(inode, current->auth) && current->auth.euid != inode->metadata().uid &&
|
||||
current->auth.euid != 0)
|
||||
return err(EACCES);
|
||||
}
|
||||
else if (current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
||||
return err(EPERM);
|
||||
|
||||
auto metadata = inode->metadata();
|
||||
if (ktimes[0].tv_nsec != UTIME_OMIT)
|
||||
{
|
||||
if (ktimes[0].tv_nsec == UTIME_NOW) metadata.atime = *Timer::realtime_clock();
|
||||
if (ktimes[0].tv_nsec < 0 || ktimes[0].tv_nsec > 999'999'999) return err(EINVAL);
|
||||
metadata.atime = ktimes[0];
|
||||
}
|
||||
if (ktimes[1].tv_nsec != UTIME_OMIT)
|
||||
{
|
||||
if (ktimes[1].tv_nsec == UTIME_NOW) metadata.mtime = *Timer::realtime_clock();
|
||||
if (ktimes[1].tv_nsec < 0 || ktimes[1].tv_nsec > 999'999'999) return err(EINVAL);
|
||||
metadata.mtime = ktimes[1];
|
||||
}
|
||||
TRY(inode->set_metadata(metadata));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ set(SOURCES
|
||||
src/scanf.cpp
|
||||
src/signal.cpp
|
||||
src/termios.cpp
|
||||
src/utime.cpp
|
||||
src/sys/stat.cpp
|
||||
src/sys/mman.cpp
|
||||
src/sys/wait.cpp
|
||||
|
9
libc/include/bits/utime.h
Normal file
9
libc/include/bits/utime.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* bits/utime.h: Definitions for UTIME_NOW and UTIME_OMIT. */
|
||||
|
||||
#ifndef _BITS_UTIME_H
|
||||
#define _BITS_UTIME_H
|
||||
|
||||
#define UTIME_NOW -1
|
||||
#define UTIME_OMIT -2
|
||||
|
||||
#endif
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include <bits/modes.h>
|
||||
#include <bits/struct_stat.h>
|
||||
#include <bits/timespec.h>
|
||||
#include <bits/utime.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -41,6 +43,12 @@ extern "C"
|
||||
/* Change the process's file creation mask. */
|
||||
mode_t umask(mode_t mask);
|
||||
|
||||
/* Change a file's access and modification timestamps, with nanosecond precision. */
|
||||
int utimensat(int dirfd, const char* path, const struct timespec times[2], int flags);
|
||||
|
||||
/* Change a file's access and modification timestamps, with nanosecond precision. */
|
||||
int futimens(int fd, const struct timespec times[2], int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -16,6 +16,15 @@ extern "C"
|
||||
/* Get the current time of day. */
|
||||
__deprecated int gettimeofday(struct timeval* tp, void* timezone);
|
||||
|
||||
/* Change a file's access and modification timestamps, with microsecond precision. */
|
||||
int utimes(const char* path, const struct timeval buf[2]);
|
||||
|
||||
/* Change a file descriptor's access and modification timestamps, with microsecond precision. */
|
||||
int futimes(int fd, const struct timeval buf[2]);
|
||||
|
||||
/* Change a symlink's access and modification timestamps, with microsecond precision. */
|
||||
int lutimes(const char* path, const struct timeval buf[2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
26
libc/include/utime.h
Normal file
26
libc/include/utime.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* utime.h: The utime function. */
|
||||
|
||||
#ifndef _UTIME_H
|
||||
#define _UTIME_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct utimbuf
|
||||
{
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Change a file's access and modification timestamps. */
|
||||
int utime(const char* path, const struct utimbuf* buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -52,4 +52,15 @@ extern "C"
|
||||
{
|
||||
return (mode_t)syscall(SYS_umask, mask);
|
||||
}
|
||||
|
||||
int utimensat(int dirfd, const char* path, const struct timespec* times, int flags)
|
||||
{
|
||||
long rc = syscall(SYS_utimensat, dirfd, path, times, flags);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
|
||||
int futimens(int fd, const struct timespec* times, int flags)
|
||||
{
|
||||
return utimensat(fd, "", times, flags | AT_EMPTY_PATH);
|
||||
}
|
||||
}
|
||||
|
55
libc/src/utime.cpp
Normal file
55
libc/src/utime.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int utime(const char* path, const struct utimbuf* buf)
|
||||
{
|
||||
if (!buf) return utimensat(AT_FDCWD, path, nullptr, 0);
|
||||
|
||||
struct timespec times[2] = {
|
||||
{ .tv_sec = buf->actime, .tv_nsec = 0 },
|
||||
{ .tv_sec = buf->modtime, .tv_nsec = 0 },
|
||||
};
|
||||
|
||||
return utimensat(AT_FDCWD, path, times, 0);
|
||||
}
|
||||
|
||||
int utimes(const char* path, const struct timeval* buf)
|
||||
{
|
||||
if (!buf) return utimensat(AT_FDCWD, path, nullptr, 0);
|
||||
|
||||
struct timespec times[2] = {
|
||||
{ .tv_sec = buf[0].tv_sec, .tv_nsec = buf[0].tv_usec * 1000 },
|
||||
{ .tv_sec = buf[1].tv_sec, .tv_nsec = buf[1].tv_usec * 1000 },
|
||||
};
|
||||
|
||||
return utimensat(AT_FDCWD, path, times, 0);
|
||||
}
|
||||
|
||||
int futimes(int fd, const struct timeval* buf)
|
||||
{
|
||||
if (!buf) return utimensat(fd, "", nullptr, AT_EMPTY_PATH);
|
||||
|
||||
struct timespec times[2] = {
|
||||
{ .tv_sec = buf[0].tv_sec, .tv_nsec = buf[0].tv_usec * 1000 },
|
||||
{ .tv_sec = buf[1].tv_sec, .tv_nsec = buf[1].tv_usec * 1000 },
|
||||
};
|
||||
|
||||
return utimensat(fd, "", times, AT_EMPTY_PATH);
|
||||
}
|
||||
|
||||
int lutimes(const char* path, const struct timeval* buf)
|
||||
{
|
||||
if (!buf) return utimensat(AT_FDCWD, path, nullptr, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
struct timespec times[2] = {
|
||||
{ .tv_sec = buf[0].tv_sec, .tv_nsec = buf[0].tv_usec * 1000 },
|
||||
{ .tv_sec = buf[1].tv_sec, .tv_nsec = buf[1].tv_usec * 1000 },
|
||||
};
|
||||
|
||||
return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
|
||||
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
||||
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
|
||||
_e(truncate) _e(ftruncate)
|
||||
_e(truncate) _e(ftruncate) _e(utimensat)
|
||||
|
||||
enum Syscalls
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user