changeset 13686:f7caccc03505

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. Signed-off-by: Eric Blake <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Thu, 16 Sep 2010 17:12:35 -0600
parents b370816ef4c2
children b3e909bb673a
files ChangeLog NEWS lib/fdutimensat.c lib/utimens.h tests/test-fdutimensat.c
diffstat 5 files changed, 50 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@
 
 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
--- a/lib/fdutimensat.c
+++ b/lib/fdutimensat.c
@@ -35,16 +35,31 @@
    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;
--- a/lib/utimens.h
+++ b/lib/utimens.h
@@ -8,7 +8,8 @@
 # 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
--- a/tests/test-fdutimensat.c
+++ b/tests/test-fdutimensat.c
@@ -40,7 +40,7 @@
 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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.  */