fdutimensat: add an atflag parameter
authorEric Blake <eblake@redhat.com>
Thu, 16 Sep 2010 23:12:35 +0000 (17:12 -0600)
committerEric Blake <eblake@redhat.com>
Thu, 16 Sep 2010 23:28:55 +0000 (17:28 -0600)
* lib/fdutimensat.c (fdutimensat): Add new parameter.
* lib/utimens.h (fdutimensat): Update prototype.
* tests/test-fdutimensat.c: Adjust test to match.
* NEWS: Document the change.
Suggested by Paul Eggert.

Signed-off-by: Eric Blake <eblake@redhat.com>
ChangeLog
NEWS
lib/fdutimensat.c
lib/utimens.h
tests/test-fdutimensat.c

index a62894615506102be9d3bd2ede81c09dd5f75512..328f8dadac86a8cf05ce0c2d44d86073c9713d23 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-09-16  Eric Blake  <eblake@redhat.com>
+
+       fdutimensat: add an atflag parameter
+       * lib/fdutimensat.c (fdutimensat): Add new parameter.
+       * lib/utimens.h (fdutimensat): Update prototype.
+       * tests/test-fdutimensat.c: Adjust test to match.
+       * NEWS: Document the change.
+       Suggested by Paul Eggert.
+
 2010-09-16  Bruno Haible  <bruno@clisp.org>
 
        Fix typos in comments.
diff --git a/NEWS b/NEWS
index 712408f3d2a6860bee5c4cf9e9e6e14d628e97c5..7d01eef3a07e70f50c7f2bfcea0898fcb5574cf3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2010-09-16  fdutimensat     The function now takes a new parameter; old users
+                            can safely pass atflag=0 for no semantic change.
+
 2010-09-13  regex           The module is not guaranteeing anymore support for
                             64-bit regoff_t on 64-bit systems.  The size of
                             regoff_t will always be 32-bit unless the program
index 7c08a525a96e891bf0ae340aa4b41e821f5c25ba..77f893bb3b05ff25ffa117aff9142c13561afdb0 100644 (file)
    use just futimes (or equivalent) instead of utimes (or equivalent),
    and fail if on an old system without futimes (or equivalent).
    If TIMESPEC is null, set the time stamps to the current time.
+   ATFLAG must be 0 if FD is non-negative; otherwise it may be
+   AT_SYMLINK_NOFOLLOW to operate on FILE as a symlink.
    Return 0 on success, -1 (setting errno) on failure.  */
 
 int
-fdutimensat (int dir, char const *file, int fd, struct timespec const ts[2])
+fdutimensat (int dir, char const *file, int fd, struct timespec const ts[2],
+             int atflag)
 {
   int result = 1;
+  if (atflag & ~AT_SYMLINK_NOFOLLOW)
+    {
+      errno = EINVAL;
+      return -1;
+    }
   if (0 <= fd)
-    result = futimens (fd, ts);
+    {
+      if (atflag)
+        {
+          errno = EINVAL;
+          return -1;
+        }
+      result = futimens (fd, ts);
+    }
   if (file && (fd < 0 || (result == -1 && errno == ENOSYS)))
-    result = utimensat (dir, file, ts, 0);
+    result = utimensat (dir, file, ts, atflag);
   if (result == 1)
     {
       errno = EBADF;
index bb0326da5fc23b00cffba7081410f09f4df960f3..f651beebaded642d83080dc92de6c834672d9435 100644 (file)
@@ -8,7 +8,8 @@ int lutimens (char const *, struct timespec const [2]);
 # include <fcntl.h>
 # include <sys/stat.h>
 
-int fdutimensat (int dir, char const *name, int fd, struct timespec const [2]);
+int fdutimensat (int dir, char const *name, int fd, struct timespec const [2],
+                 int atflag);
 
 /* Using this function makes application code slightly more readable.  */
 static inline int
index 949ca47aa33eed660cd2d85478000bc42cb17174..67f03bbb507b27b62e856d993761772bc28845be 100644 (file)
@@ -40,7 +40,7 @@ static int dfd = AT_FDCWD;
 static int
 do_futimens (int fd, struct timespec const times[2])
 {
-  return fdutimensat (dfd, NULL, fd, times);
+  return fdutimensat (dfd, NULL, fd, times, 0);
 }
 
 /* Test the use of file descriptors alongside a name.  */
@@ -52,7 +52,7 @@ do_fdutimens (char const *name, struct timespec const times[2])
   if (fd < 0)
     fd = openat (dfd, name, O_RDONLY);
   errno = 0;
-  result = fdutimensat (dfd, name, fd, times);
+  result = fdutimensat (dfd, name, fd, times, 0);
   if (0 <= fd)
     {
       int saved_errno = errno;
@@ -69,11 +69,18 @@ do_lutimens (const char *name, struct timespec const times[2])
   return lutimensat (dfd, name, times);
 }
 
+/* Wrap fdutimensat to behave like lutimens.  */
+static int
+do_lutimens1 (const char *name, struct timespec const times[2])
+{
+  return fdutimensat (dfd, name, -1, times, AT_SYMLINK_NOFOLLOW);
+}
+
 /* Wrap fdutimensat to behave like utimens.  */
 static int
 do_utimens (const char *name, struct timespec const times[2])
 {
-  return fdutimensat (dfd, name, -1, times);
+  return fdutimensat (dfd, name, -1, times, 0);
 }
 
 int
@@ -94,12 +101,14 @@ main (void)
   result3 = test_lutimens (do_lutimens, (result1 + result2) == 0);
   /* We expect 0/0, 0/77, or 77/77, but not 77/0.  */
   ASSERT (result1 <= result3);
+  ASSERT (test_lutimens (do_lutimens1, (result1 + result2) == 0) == result3);
   dfd = open (".", O_RDONLY);
   ASSERT (0 <= dfd);
   ASSERT (test_utimens (do_utimens, false) == result1);
   ASSERT (test_utimens (do_fdutimens, false) == result1);
   ASSERT (test_futimens (do_futimens, false) == result2);
   ASSERT (test_lutimens (do_lutimens, false) == result3);
+  ASSERT (test_lutimens (do_lutimens1, false) == result3);
 
   /* Directory relative tests.  */
   ASSERT (mkdir (BASE "dir", 0700) == 0);
@@ -107,12 +116,15 @@ main (void)
   fd = creat ("file", 0600);
   ASSERT (0 <= fd);
   errno = 0;
-  ASSERT (fdutimensat (fd, ".", AT_FDCWD, NULL) == -1);
+  ASSERT (fdutimensat (fd, ".", fd, NULL, AT_SYMLINK_NOFOLLOW) == -1);
+  ASSERT (errno == EINVAL);
+  errno = 0;
+  ASSERT (fdutimensat (fd, ".", AT_FDCWD, NULL, 0) == -1);
   ASSERT (errno == ENOTDIR);
   {
     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
     struct stat st;
-    ASSERT (fdutimensat (dfd, BASE "dir/file", fd, ts) == 0);
+    ASSERT (fdutimensat (dfd, BASE "dir/file", fd, ts, 0) == 0);
     ASSERT (stat ("file", &st) == 0);
     ASSERT (st.st_atime == Y2K);
     ASSERT (get_stat_atime_ns (&st) == 0);
@@ -122,7 +134,7 @@ main (void)
   ASSERT (close (fd) == 0);
   ASSERT (close (dfd) == 0);
   errno = 0;
-  ASSERT (fdutimensat (dfd, ".", -1, NULL) == -1);
+  ASSERT (fdutimensat (dfd, ".", -1, NULL, 0) == -1);
   ASSERT (errno == EBADF);
 
   /* Cleanup.  */