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
  • Loading branch information
Fishrock123 committed Aug 7, 2018
1 parent 27ba662 commit cfe3745
Showing 1 changed file with 88 additions and 4 deletions.
92 changes: 88 additions & 4 deletions src/unix/fs.c
Expand Up @@ -698,10 +698,94 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {


static ssize_t uv__fs_utime(uv_fs_t* req) {
struct utimbuf buf;
buf.actime = req->atime;
buf.modtime = req->mtime;
return utime(req->path, &buf); /* TODO use utimes() where available */
#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(NULL, 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;
snprintf(req->path, sizeof(req->path));

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

switch (errno) {
case ENOENT:
// if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
break;
/* Fall through. */

case EACCES:
case ENOTDIR:
errno = ENOSYS;
break;
}

return r;

#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__sun)
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;
# if defined(__sun)
return utimesat(NULL, req->path, tv);
# else
return utimes(req->path, tv);
# endif
#elif defined(_AIX71)
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 utimens(req->path, ts);
#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 cfe3745

Please sign in to comment.