Re: [PATCH] utimensat implementation

From: Ulrich Drepper
Date: Thu Apr 26 2007 - 20:54:42 EST


Andrew Morton wrote:
> Does the spec say what the OS should do if (ts_nsec => 1e9)?

Yes, return EINVAL. We already do this. It's just that now we have to
recognize two special values.


> OK, so there's no collision on ts_nsec if unnormalised timespecs are
> disallowed.

Indeed, that's the basis of using the special values.

I chose the values of the constants so that they are a) out of the way
of valid values and b) don't have to be adjusted for 32-bit compat code.


> But there's a potential collision on ts_sec? Do we know what date that
> corresponds to?

No, there is no collision. The tv_sec value is relevant. The
UTIME_OMIT and UTIME_NOW value refers to the atime/mtime respectively,
not just the tv_nsec field of either. It makes no sense to just set
tv_sec, the tv_nsec value would be basically random.

In my patch I'm testing that tv_sec is zero in case any of the special
values is used in the corresponding tv_nsec field. That's more than the
standard currently requires but I think it's better and I try to get the
standard proposal changed. If this doesn't happen I'll make appropriate
changes at userlevel for the "strictly POSIX" mode.


> Do you have a testcase app which can be used by arch maintainers?

Attached here.

--
â Ulrich Drepper â Red Hat, Inc. â 444 Castro St â Mountain View, CA â
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
#include <syscall.h>

#define UTIME_NOW ((1l << 30) - 1l)
#define UTIME_OMIT ((1l << 30) - 2l)


int
main(void)
{
int status = 0;

int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
if (fd == -1)
error (1, errno, "failed to create test file \"ttt\"");

struct stat64 st1;
if (fstat64 (fd, &st1) != 0)
error (1, errno, "fstat failed");

struct timespec t[2];
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(280, AT_FDCWD, "ttt", t) != 0)
error (1, errno, "utimensat failed");

struct stat64 st2;
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");

if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;

t[0] = st1.st_atim;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_OMIT;
if (syscall(280, AT_FDCWD, "ttt", t) != 0)
error (1, errno, "utimensat failed");

if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");

if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("atim not set");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim changed from zero");
status = 1;
}
if (status != 0)
goto out;

t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_OMIT;
t[1] = st1.st_mtim;
if (syscall(280, AT_FDCWD, "ttt", t) != 0)
error (1, errno, "utimensat failed");

if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");

if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("mtim changed from original time");
status = 1;
}
if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
|| st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
{
puts ("mtim not set");
status = 1;
}
if (status != 0)
goto out;

sleep (2);

t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_NOW;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_NOW;
if (syscall(280, AT_FDCWD, "ttt", t) != 0)
error (1, errno, "utimensat failed");

if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");

struct timeval tv;
gettimeofday(&tv,NULL);

if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
|| st2.st_atim.tv_sec > tv.tv_sec)
{
puts ("atim not set to NOW");
status = 1;
}
if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
|| st2.st_mtim.tv_sec > tv.tv_sec)
{
puts ("mtim not set to NOW");
status = 1;
}

if (status == 0)
puts ("all OK");

out:
close (fd);
unlink ("ttt");

return status;
}

Attachment: signature.asc
Description: OpenPGP digital signature