mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-07 19:58:30 +00:00
Add x86_64-linux-gnu emulator
I wanted a tiny scriptable meltdown proof way to run userspace programs and visualize how program execution impacts memory. It helps to explain how things like Actually Portable Executable works. It can show you how the GCC generated code is going about manipulating matrices and more. I didn't feel fully comfortable with Qemu and Bochs because I'm not smart enough to understand them. I wanted something like gVisor but with much stronger levels of assurances. I wanted a single binary that'll run, on all major operating systems with an embedded GPL barrier ZIP filesystem that is tiny enough to transpile to JavaScript and run in browsers too. https://justine.storage.googleapis.com/emulator625.mp4
This commit is contained in:
parent
467504308a
commit
f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions
|
@ -44,7 +44,7 @@
|
|||
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. noting
|
||||
* that on Linux CLOCK_MONOTONIC is redefined to use the monotonic
|
||||
* clock that's actually monotonic lool
|
||||
* @param out_ts is where the nanoseconds are stored
|
||||
* @param out_ts is where the nanoseconds are stored if non-NULL
|
||||
* @return 0 on success or -1 w/ errno on error
|
||||
* @error ENOSYS if clockid isn't available; in which case this function
|
||||
* guarantees an ordinary timestamp is still stored to out_ts; and
|
||||
|
@ -56,21 +56,28 @@ int clock_gettime(int clockid, struct timespec *out_ts) {
|
|||
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */
|
||||
if (!IsWindows()) {
|
||||
if (!IsXnu()) {
|
||||
out_ts->tv_sec = 0;
|
||||
out_ts->tv_nsec = 0;
|
||||
if (out_ts) {
|
||||
out_ts->tv_sec = 0;
|
||||
out_ts->tv_nsec = 0;
|
||||
}
|
||||
return clock_gettime$sysv(clockid, out_ts);
|
||||
} else {
|
||||
int rc;
|
||||
static_assert(sizeof(struct timeval) == sizeof(struct timespec));
|
||||
out_ts->tv_sec = 0;
|
||||
out_ts->tv_nsec = 0;
|
||||
int rc = gettimeofday$sysv((struct timeval *)out_ts, NULL);
|
||||
out_ts->tv_nsec *= 1000;
|
||||
if (out_ts) {
|
||||
out_ts->tv_sec = 0;
|
||||
out_ts->tv_nsec = 0;
|
||||
}
|
||||
rc = gettimeofday$sysv((struct timeval *)out_ts, NULL);
|
||||
if (out_ts) {
|
||||
out_ts->tv_nsec *= 1000;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
struct NtFileTime ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
filetimetotimespec(out_ts, ft);
|
||||
*out_ts = filetimetotimespec(ft);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ long double dsleep(long double secs) {
|
|||
struct timespec dur, rem;
|
||||
dur.tv_sec = secs;
|
||||
dur.tv_nsec = secs * 1e9;
|
||||
dur.tv_nsec = mod1000000000int64(dur.tv_nsec);
|
||||
dur.tv_nsec = rem1000000000int64(dur.tv_nsec);
|
||||
if (secs > 1e-6) {
|
||||
nanosleep(&dur, &rem);
|
||||
secs = rem.tv_nsec;
|
||||
|
|
31
libc/time/futimens.c
Normal file
31
libc/time/futimens.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Sets atime/mtime on file descriptor.
|
||||
*
|
||||
* @param ts is atime/mtime, or null for current time
|
||||
* @note better than microsecond precision on most platforms
|
||||
* @see fstat() for reading timestamps
|
||||
*/
|
||||
int futimens(int fd, const struct timespec ts[hasatleast 2]) {
|
||||
return utimensat(fd, NULL, ts, 0);
|
||||
}
|
40
libc/time/futimes.c
Normal file
40
libc/time/futimes.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Sets atime/mtime on file descriptor.
|
||||
*
|
||||
* @param ts is atime/mtime, or null for current time
|
||||
* @note better than microsecond precision on most platforms
|
||||
* @see fstat() for reading timestamps
|
||||
*/
|
||||
int futimes(int fd, const struct timeval tv[hasatleast 2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
return utimensat(fd, NULL, ts, 0);
|
||||
} else {
|
||||
return utimensat(fd, NULL, NULL, 0);
|
||||
}
|
||||
}
|
40
libc/time/futimesat.c
Normal file
40
libc/time/futimesat.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Changes last accessed/modified times on file.
|
||||
*
|
||||
* @param times is access/modified and NULL means now
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see utimensat() which uses nanos
|
||||
*/
|
||||
int futimesat(int dirfd, const char *pathname, const struct timeval tv[2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
return utimensat(dirfd, pathname, ts, 0);
|
||||
} else {
|
||||
return utimensat(dirfd, pathname, NULL, 0);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
/**
|
||||
* Returns system wall time in microseconds.
|
||||
*
|
||||
* @param tv points to timeval that receives result
|
||||
* @param tv points to timeval that receives result if non-NULL
|
||||
* @param tz receives UTC timezone if non-NULL
|
||||
* @return always zero
|
||||
* @see clock_gettime() for nanosecond precision
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "libc/bits/initializer.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -871,9 +873,9 @@ const int32_t offset;
|
|||
*/
|
||||
m1 = (rulep->r_mon + 9) % 12 + 1;
|
||||
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
|
||||
yy1 = yy0 / 100;
|
||||
yy2 = yy0 % 100;
|
||||
dow = ((26 * m1 - 2) / 10 +
|
||||
yy1 = div100int64(yy0);
|
||||
yy2 = rem100int64(yy0);
|
||||
dow = (div10int64(26 * m1 - 2) +
|
||||
1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
|
||||
if (dow < 0)
|
||||
dow += DAYSPERWEEK;
|
||||
|
@ -1440,7 +1442,7 @@ pureconst static int
|
|||
leaps_thru_end_of(y)
|
||||
register const int y;
|
||||
{
|
||||
return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
|
||||
return (y >= 0) ? (y / 4 - div100int64(y) + y / 400) :
|
||||
-(leaps_thru_end_of(-(y + 1)) + 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,13 @@
|
|||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nt/enum/status.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/nt/time.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -35,24 +37,28 @@
|
|||
*/
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
long res, millis, hectonanos;
|
||||
if (!req) return efault();
|
||||
if (!IsWindows()) {
|
||||
if (!IsXnu()) {
|
||||
return nanosleep$sysv(req, rem);
|
||||
} else {
|
||||
return select$sysv(0, 0, 0, 0, /* lool */
|
||||
&(struct timeval){req->tv_sec, req->tv_nsec / 1000});
|
||||
return select$sysv(
|
||||
0, 0, 0, 0, /* lool */
|
||||
&(struct timeval){req->tv_sec, div1000int64(req->tv_nsec)});
|
||||
}
|
||||
} else {
|
||||
if (rem) memcpy(rem, req, sizeof(*rem));
|
||||
if (req->tv_sec && req->tv_nsec) {
|
||||
hectonanos = MAX(1, req->tv_sec * 10000000L + req->tv_nsec / 100L);
|
||||
hectonanos = MAX(1, req->tv_sec * 10000000L + div100int64(req->tv_nsec));
|
||||
} else {
|
||||
hectonanos = 1;
|
||||
}
|
||||
if (NtError(NtDelayExecution(true, &hectonanos))) {
|
||||
millis = hectonanos / 10000;
|
||||
millis = div10000int64(hectonanos);
|
||||
res = SleepEx(millis, true);
|
||||
if (res == kNtWaitIoCompletion) return eintr();
|
||||
}
|
||||
if (rem) memset(rem, 0, sizeof(*rem));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "libc/time/time.h"
|
||||
|
||||
static struct Now {
|
||||
bool once;
|
||||
uint64_t k0;
|
||||
long double r0, cpn;
|
||||
} now_;
|
||||
|
@ -37,25 +39,7 @@ static struct Now {
|
|||
*/
|
||||
long double (*nowl)(void);
|
||||
|
||||
long double converttickstonanos(uint64_t ticks) {
|
||||
return ticks * now_.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
long double converttickstoseconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * converttickstonanos(ticks);
|
||||
}
|
||||
|
||||
static long double nowl$sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
static long double nowl$art(void) {
|
||||
uint64_t ticks;
|
||||
ticks = unsignedsubtract(rdtsc(), now_.k0);
|
||||
return now_.r0 + converttickstoseconds(ticks);
|
||||
}
|
||||
|
||||
static long double GetSample(void) {
|
||||
static long double GetTimeSample(void) {
|
||||
uint64_t tick1, tick2;
|
||||
long double time1, time2;
|
||||
sched_yield();
|
||||
|
@ -71,17 +55,41 @@ static long double MeasureNanosPerCycle(void) {
|
|||
int i;
|
||||
long double avg, samp;
|
||||
for (avg = 1.0L, i = 1; i < 5; ++i) {
|
||||
samp = GetSample();
|
||||
samp = GetTimeSample();
|
||||
avg += (samp - avg) / i;
|
||||
}
|
||||
return avg;
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_time, {
|
||||
static void InitTime(void) {
|
||||
now_.cpn = MeasureNanosPerCycle();
|
||||
now_.r0 = dtime(CLOCK_REALTIME);
|
||||
now_.k0 = rdtsc();
|
||||
now_.once = true;
|
||||
}
|
||||
|
||||
long double converttickstonanos(uint64_t ticks) {
|
||||
if (!now_.once) InitTime();
|
||||
return ticks * now_.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
long double converttickstoseconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * converttickstonanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl$sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
long double nowl$art(void) {
|
||||
uint64_t ticks;
|
||||
if (!now_.once) InitTime();
|
||||
ticks = unsignedsubtract(rdtsc(), now_.k0);
|
||||
return now_.r0 + converttickstoseconds(ticks);
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_nowl, {
|
||||
if (X86_HAVE(INVTSC)) {
|
||||
now_.cpn = MeasureNanosPerCycle();
|
||||
now_.r0 = dtime(CLOCK_REALTIME);
|
||||
now_.k0 = rdtsc();
|
||||
nowl = nowl$art;
|
||||
} else {
|
||||
nowl = nowl$sys;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/tzfile.h"
|
||||
|
@ -100,7 +101,7 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
|
|||
** something completely different.
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
pt = strftime_conv(pt, ptlim, (t->tm_year + TM_YEAR_BASE) / 100,
|
||||
pt = strftime_conv(pt, ptlim, div100int64(t->tm_year + TM_YEAR_BASE),
|
||||
"%02d");
|
||||
continue;
|
||||
case 'D':
|
||||
|
|
11
libc/time/struct/utimbuf.h
Normal file
11
libc/time/struct/utimbuf.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_TIME_STRUCT_UTIMBUF_H_
|
||||
#define COSMOPOLITAN_LIBC_TIME_STRUCT_UTIMBUF_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct utimbuf {
|
||||
int64_t actime; /* access time */
|
||||
int64_t modtime; /* modified time */
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_TIME_STRUCT_UTIMBUF_H_ */
|
|
@ -1,13 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_
|
||||
#define COSMOPOLITAN_LIBC_TIME_TIME_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct itimerval;
|
||||
struct timespec;
|
||||
struct timeval;
|
||||
struct timezone;
|
||||
struct tm;
|
||||
struct utimbuf;
|
||||
|
||||
extern const char kWeekdayNameShort[7][4];
|
||||
extern const char kWeekdayName[7][10];
|
||||
|
@ -20,12 +21,12 @@ extern long CLOCKS_PER_SEC;
|
|||
int64_t clock(void);
|
||||
int64_t time(int64_t *);
|
||||
int gettimeofday(struct timeval *, struct timezone *);
|
||||
int clock_gettime(int, struct timespec *) paramsnonnull();
|
||||
int clock_gettime(int, struct timespec *);
|
||||
int clock_getres(int, struct timespec *);
|
||||
|
||||
int sleep(uint32_t);
|
||||
int usleep(uint32_t);
|
||||
int nanosleep(const struct timespec *, struct timespec *) paramsnonnull((1));
|
||||
int nanosleep(const struct timespec *, struct timespec *);
|
||||
unsigned alarm(unsigned);
|
||||
int getitimer(int, struct itimerval *) paramsnonnull();
|
||||
int setitimer(int, const struct itimerval *, struct itimerval *)
|
||||
|
@ -51,7 +52,12 @@ char *asctime_r(const struct tm *, char * /*[64]*/);
|
|||
char *ctime(const int64_t *);
|
||||
char *ctime_r(const int64_t *, char * /*[64]*/);
|
||||
|
||||
int utimes(const char *, const struct timeval *);
|
||||
int futimens(int, const struct timespec[2]);
|
||||
int utimensat(int, const char *, const struct timespec[2], int);
|
||||
int utimes(const char *, const struct timeval[2]);
|
||||
int utime(const char *, const struct utimbuf *);
|
||||
int futimes(int, const struct timeval[2]);
|
||||
int futimesat(int, const char *, const struct timeval[2]);
|
||||
|
||||
long double dtime(int);
|
||||
long double dsleep(long double);
|
||||
|
|
|
@ -25,39 +25,31 @@
|
|||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
* Returns accounting data for process on time-sharing system.
|
||||
*/
|
||||
long times(struct tms *out_times) {
|
||||
static noinline long times2(struct tms *out_times, struct rusage *ru) {
|
||||
long tick;
|
||||
struct timeval tv;
|
||||
long tick = sysconf(_SC_CLK_TCK);
|
||||
tick = sysconf(_SC_CLK_TCK);
|
||||
if (!IsWindows()) {
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_SELF, &ru) == -1) return -1;
|
||||
out_times->tms_utime = convertmicros(&ru.ru_utime, tick);
|
||||
out_times->tms_stime = convertmicros(&ru.ru_stime, tick);
|
||||
if (getrusage(RUSAGE_CHILDREN, &ru) == -1) return -1;
|
||||
out_times->tms_cutime = convertmicros(&ru.ru_utime, tick);
|
||||
out_times->tms_cstime = convertmicros(&ru.ru_stime, tick);
|
||||
if (getrusage(RUSAGE_SELF, ru) == -1) return -1;
|
||||
out_times->tms_utime = convertmicros(&ru->ru_utime, tick);
|
||||
out_times->tms_stime = convertmicros(&ru->ru_stime, tick);
|
||||
if (getrusage(RUSAGE_CHILDREN, ru) == -1) return -1;
|
||||
out_times->tms_cutime = convertmicros(&ru->ru_utime, tick);
|
||||
out_times->tms_cstime = convertmicros(&ru->ru_stime, tick);
|
||||
} else {
|
||||
struct NtFileTime CreationFileTime;
|
||||
struct NtFileTime ExitFileTime;
|
||||
struct NtFileTime KernelFileTime;
|
||||
struct NtFileTime UserFileTime;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &CreationFileTime, &ExitFileTime,
|
||||
&KernelFileTime, &UserFileTime)) {
|
||||
struct NtFileTime CreationTime, ExitTime, KernelTime, UserTime;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime,
|
||||
&KernelTime, &UserTime)) {
|
||||
return winerr();
|
||||
}
|
||||
filetimetotimeval(&tv, UserFileTime);
|
||||
filetimetotimeval(&tv, UserTime);
|
||||
out_times->tms_utime = convertmicros(&tv, tick);
|
||||
filetimetotimeval(&tv, KernelFileTime);
|
||||
filetimetotimeval(&tv, KernelTime);
|
||||
out_times->tms_stime = convertmicros(&tv, tick);
|
||||
out_times->tms_cutime = 0;
|
||||
out_times->tms_cstime = 0;
|
||||
|
@ -65,3 +57,11 @@ long times(struct tms *out_times) {
|
|||
if (gettimeofday(&tv, NULL) == -1) return -1;
|
||||
return convertmicros(&tv, tick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns accounting data for process on time-sharing system.
|
||||
*/
|
||||
long times(struct tms *out_times) {
|
||||
struct rusage ru;
|
||||
return times2(out_times, &ru);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/time/struct/utimbuf.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time/utime.h"
|
||||
|
||||
/**
|
||||
* Changes last accessed/modified times on file.
|
||||
|
@ -29,11 +29,14 @@
|
|||
* @return 0 on success or -1 w/ errno
|
||||
*/
|
||||
int utime(const char *path, const struct utimbuf *times) {
|
||||
struct timeval tv[2];
|
||||
memset(tv, 0, sizeof(tv));
|
||||
struct timespec ts[2];
|
||||
if (times) {
|
||||
tv[0].tv_sec = times->actime;
|
||||
tv[1].tv_sec = times->modtime;
|
||||
ts[0].tv_sec = times->actime;
|
||||
ts[0].tv_nsec = 0;
|
||||
ts[1].tv_sec = times->modtime;
|
||||
ts[1].tv_nsec = 0;
|
||||
return utimensat(AT_FDCWD, path, ts, 0);
|
||||
} else {
|
||||
return utimensat(AT_FDCWD, path, NULL, 0);
|
||||
}
|
||||
return utimes(path, times ? tv : NULL);
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_UTIME_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_UTIME_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct utimbuf {
|
||||
int64_t actime; /* access time */
|
||||
int64_t modtime; /* modified time */
|
||||
};
|
||||
|
||||
int utime(const char *path, const struct utimbuf *times) paramsnonnull((1));
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_UTIME_H_ */
|
86
libc/time/utimensat-nt.c
Normal file
86
libc/time/utimensat-nt.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/utime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
textwindows int utimensat$nt(int dirfd, const char *path,
|
||||
const struct timespec ts[2], int flags) {
|
||||
int i, rc;
|
||||
int64_t fh;
|
||||
bool closeme;
|
||||
uint16_t path16[PATH_MAX];
|
||||
struct NtFileTime ft[2], *ftp[2];
|
||||
if (flags) return einval();
|
||||
if (path) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead,
|
||||
NULL, kNtOpenExisting, kNtFileAttributeNormal, 0)) !=
|
||||
-1) {
|
||||
closeme = true;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else if (isfdindex(dirfd)) {
|
||||
fh = g_fds.p[dirfd].handle;
|
||||
closeme = false;
|
||||
} else {
|
||||
return ebadf();
|
||||
}
|
||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||
GetSystemTimeAsFileTime(ft);
|
||||
}
|
||||
if (ts) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (ts[i].tv_nsec == UTIME_NOW) {
|
||||
ftp[i] = ft;
|
||||
} else if (ts[i].tv_nsec == UTIME_OMIT) {
|
||||
ftp[i] = NULL;
|
||||
} else {
|
||||
ft[i] = timespectofiletime(ts[i]);
|
||||
ftp[i] = &ft[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ftp[0] = ft;
|
||||
ftp[1] = ft;
|
||||
}
|
||||
if (SetFileTime(fh, NULL, ftp[0], ftp[1])) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = winerr();
|
||||
}
|
||||
if (closeme) {
|
||||
CloseHandle(fh);
|
||||
}
|
||||
return rc;
|
||||
}
|
30
libc/time/utimensat-sysv.c
Normal file
30
libc/time/utimensat-sysv.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
int utimensat$sysv(int dirfd, const char *path, const struct timespec ts[2],
|
||||
int flags) {
|
||||
if (!IsXnu()) {
|
||||
return __utimensat$sysv(dirfd, path, ts, flags);
|
||||
} else {
|
||||
return utimensat$xnu(dirfd, path, ts, flags);
|
||||
}
|
||||
}
|
63
libc/time/utimensat-xnu.c
Normal file
63
libc/time/utimensat-xnu.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/utime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
int utimensat$xnu(int dirfd, const char *path, const struct timespec ts[2],
|
||||
int flags) {
|
||||
int i;
|
||||
struct timeval now, tv[2];
|
||||
if (flags) return einval();
|
||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||
gettimeofday(&now, NULL);
|
||||
}
|
||||
if (ts) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (ts[i].tv_nsec == UTIME_NOW) {
|
||||
tv[i] = now;
|
||||
} else if (ts[i].tv_nsec == UTIME_OMIT) {
|
||||
return einval();
|
||||
} else {
|
||||
tv[i].tv_sec = ts[i].tv_sec;
|
||||
tv[i].tv_usec = div1000int64(ts[i].tv_nsec);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tv[0] = now;
|
||||
tv[1] = now;
|
||||
}
|
||||
if (path) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return utimes$sysv(path, tv);
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
} else {
|
||||
if (dirfd != AT_FDCWD) {
|
||||
return futimes$sysv(dirfd, tv);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
}
|
37
libc/time/utimensat.c
Normal file
37
libc/time/utimensat.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
/**
|
||||
* Sets atime/mtime on file, the modern way.
|
||||
*
|
||||
* @param ts is atime/mtime, or null for current time
|
||||
* @param flags can have AT_SYMLINK_NOFOLLOW
|
||||
* @note no rhel5 support
|
||||
*/
|
||||
int utimensat(int dirfd, const char *path,
|
||||
const struct timespec ts[hasatleast 2], int flags) {
|
||||
if (!IsWindows()) {
|
||||
return utimensat$sysv(dirfd, path, ts, flags);
|
||||
} else {
|
||||
return utimensat$nt(dirfd, path, ts, flags);
|
||||
}
|
||||
}
|
|
@ -17,57 +17,25 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static int utimes$nt(const char *path, const struct timeval times[2]) {
|
||||
int rc;
|
||||
int64_t fh;
|
||||
struct timeval tv;
|
||||
struct NtFileTime accessed;
|
||||
struct NtFileTime modified;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
if (times) {
|
||||
accessed = timevaltofiletime(×[0]);
|
||||
modified = timevaltofiletime(×[1]);
|
||||
} else {
|
||||
gettimeofday(&tv, NULL);
|
||||
accessed = timevaltofiletime(&tv);
|
||||
modified = timevaltofiletime(&tv);
|
||||
}
|
||||
if ((fh = CreateFile(path16, kNtGenericWrite, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0)) != -1 &&
|
||||
SetFileTime(fh, NULL, &accessed, &modified)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = winerr();
|
||||
}
|
||||
CloseHandle(fh);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes last accessed/modified times on file.
|
||||
*
|
||||
* @param times is access/modified and NULL means now
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see stat()
|
||||
*/
|
||||
int utimes(const char *path, const struct timeval times[hasatleast 2]) {
|
||||
if (!IsWindows()) {
|
||||
return utimes$sysv(path, times);
|
||||
int utimes(const char *path, const struct timeval tv[hasatleast 2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
return utimensat(AT_FDCWD, path, ts, 0);
|
||||
} else {
|
||||
return utimes$nt(path, times);
|
||||
return utimensat(AT_FDCWD, path, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue