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 "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
|
#include <bits/atfile.h>
|
||||||
#include <bits/fcntl.h>
|
#include <bits/fcntl.h>
|
||||||
#include <bits/open-flags.h>
|
#include <bits/open-flags.h>
|
||||||
#include <bits/seek.h>
|
#include <bits/seek.h>
|
||||||
|
#include <bits/utime.h>
|
||||||
#include <luna/SafeArithmetic.h>
|
#include <luna/SafeArithmetic.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@ -262,3 +264,52 @@ Result<u64> sys_ftruncate(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
return 0;
|
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/scanf.cpp
|
||||||
src/signal.cpp
|
src/signal.cpp
|
||||||
src/termios.cpp
|
src/termios.cpp
|
||||||
|
src/utime.cpp
|
||||||
src/sys/stat.cpp
|
src/sys/stat.cpp
|
||||||
src/sys/mman.cpp
|
src/sys/mman.cpp
|
||||||
src/sys/wait.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/modes.h>
|
||||||
#include <bits/struct_stat.h>
|
#include <bits/struct_stat.h>
|
||||||
|
#include <bits/timespec.h>
|
||||||
|
#include <bits/utime.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -41,6 +43,12 @@ extern "C"
|
|||||||
/* Change the process's file creation mask. */
|
/* Change the process's file creation mask. */
|
||||||
mode_t umask(mode_t 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,6 +16,15 @@ extern "C"
|
|||||||
/* Get the current time of day. */
|
/* Get the current time of day. */
|
||||||
__deprecated int gettimeofday(struct timeval* tp, void* timezone);
|
__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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
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(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(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(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
|
enum Syscalls
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user