Skip to content

Commit

Permalink
unix,fs: use utimes & friends for uv_fs_utime
Browse files Browse the repository at this point in the history
This should improve uv_fs_utime resolution and reliability, as
utime(2)'s precision is left more to the implementing platform than the
newer but well supported alternatives.

Related to nodejs/node#22070
PR-URL: libuv#1940
  • Loading branch information
Fishrock123 committed Aug 24, 2018
1 parent 90891b4 commit 67256b0
Showing 1 changed file with 85 additions and 2 deletions.
87 changes: 85 additions & 2 deletions src/unix/fs.c
Expand Up @@ -43,7 +43,6 @@
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
#include <poll.h>

#if defined(__DragonFly__) || \
Expand All @@ -67,6 +66,10 @@
# define FICLONE _IOW(0x94, 9, int)
#endif

#if defined(_AIX) && !defined(_AIX71)
# include <utime.h>
#endif

#define INIT(subtype) \
do { \
if (req == NULL) \
Expand Down Expand Up @@ -702,10 +705,90 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {


static ssize_t uv__fs_utime(uv_fs_t* req) {
#if defined(__linux__)
/* utimesat() has nanosecond resolution but we stick to microseconds
* for the sake of consistency with other platforms.
*/
static int no_utimesat;
struct timespec ts[2];
struct timeval tv[2];
int r;

if (no_utimesat)
goto skip;

ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;

r = uv__utimesat(AT_FDCWD, req->path, ts, 0);
if (r == 0)
return r;

if (errno != ENOSYS)
return r;

no_utimesat = 1;

skip:

tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;

r = utimes(req->path, tv);
if (r == 0)
return r;

switch (errno) {
case EACCES:
case ENOTDIR:
errno = ENOSYS;
break;
}

return r;

#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
return utimes(req->path, tv);
#elif defined(_AIX) \
&& !defined(_AIX71)
struct utimbuf buf;
buf.actime = req->atime;
buf.modtime = req->mtime;
return utime(req->path, &buf); /* TODO use utimes() where available */
return utime(req->path, &buf);
#elif defined(_AIX71) \
|| defined(__sun)
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
return utimensat(AT_FDCWD, req->path, ts, 0);
#elif defined(__MVS__)
attrib_t atr;
memset(&atr, 0, sizeof(atr));
atr.att_mtimechg = 1;
atr.att_atimechg = 1;
atr.att_mtime = req->mtime;
atr.att_atime = req->atime;
return __lchattr(req->path, &atr, sizeof(atr));
#else
errno = ENOSYS;
return -1;
#endif
}


Expand Down

0 comments on commit 67256b0

Please sign in to comment.