Mercurial > hg > octave-lojdl > gnulib-hg
changeset 12193:d1ea4269ac6f
fdutimensat: new module
Needed for coreutils copy.c to be rewritten to use fts.
* modules/fdutimensat: New file.
* lib/fdutimensat.c (fdutimensat): Likewise.
* lib/utimens.h (fdutimensat, lutimensat): Declare new functions.
* MODULES.html.sh (File system functions): Mention module.
* modules/fdutimensat-tests: New test.
* tests/test-fdutimensat.c: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Tue, 20 Oct 2009 06:09:29 -0600 |
parents | b0d3e25d7cdc |
children | 16c7c4fa9754 |
files | ChangeLog MODULES.html.sh lib/fdutimensat.c lib/utimens.h modules/fdutimensat modules/fdutimensat-tests tests/test-fdutimensat.c |
diffstat | 7 files changed, 268 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2009-10-20 Eric Blake <ebb9@byu.net> + fdutimensat: new module + * modules/fdutimensat: New file. + * lib/fdutimensat.c (fdutimensat): Likewise. + * lib/utimens.h (fdutimensat, lutimensat): Declare new functions. + * MODULES.html.sh (File system functions): Mention module. + * modules/fdutimensat-tests: New test. + * tests/test-fdutimensat.c: Likewise. + doc: regenerate INSTALL * doc/INSTALL: Reflect recent autoconf update. * doc/INSTALL.ISO: Likewise.
--- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2464,6 +2464,7 @@ func_module euidaccess func_module faccessat func_module fdopendir + func_module fdutimensat func_module file-type func_module fileblocks func_module filemode
new file mode 100644 --- /dev/null +++ b/lib/fdutimensat.c @@ -0,0 +1,54 @@ +/* Set file access and modification times. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake. */ + +/* derived from a function in utimens.c */ + +#include <config.h> + +#include "utimens.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +/* Set the access and modification time stamps of FD (a.k.a. FILE) to be + TIMESPEC[0] and TIMESPEC[1], respectively; relative to directory DIR. + FD must be either negative -- in which case it is ignored -- + or a file descriptor that is open on FILE. + If FD is nonnegative, then FILE can be NULL, which means + 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. + Return 0 on success, -1 (setting errno) on failure. */ + +int +fdutimensat (int dir, char const *file, int fd, struct timespec const ts[2]) +{ + int result = 1; + if (0 <= fd) + result = futimens (fd, ts); + if (file && (fd < 0 || (result == -1 && errno == ENOSYS))) + result = utimensat (dir, file, ts, 0); + if (result == 1) + { + errno = EBADF; + result = -1; + } + return result; +}
--- a/lib/utimens.h +++ b/lib/utimens.h @@ -3,3 +3,17 @@ int gl_futimens (int, char const *, struct timespec const [2]); int utimens (char const *, struct timespec const [2]); int lutimens (char const *, struct timespec const [2]); + +#if GNULIB_FDUTIMENSAT +# include <fcntl.h> +# include <sys/stat.h> + +int fdutimensat (int dir, char const *name, int fd, struct timespec const [2]); + +/* Using this function makes application code slightly more readable. */ +static inline int +lutimensat (int fd, char const *file, struct timespec const times[2]) +{ + return utimensat (fd, file, times, AT_SYMLINK_NOFOLLOW); +} +#endif
new file mode 100644 --- /dev/null +++ b/modules/fdutimensat @@ -0,0 +1,30 @@ +Description: +Set file access and modification times, relative to a directory. + +Files: +lib/fdutimensat.c +lib/utimens.h + +Depends-on: +futimens +inline +utimensat + +configure.ac: +gl_MODULE_INDICATOR([fdutimensat]) + +Makefile.am: +lib_SOURCES += fdutimensat.c + +Include: +<fcntl.h> +"utimens.h" + +Link: +$(LIB_CLOCK_GETTIME) + +License: +GPL + +Maintainer: +Paul Eggert, Jim Meyering, Eric Blake
new file mode 100644 --- /dev/null +++ b/modules/fdutimensat-tests @@ -0,0 +1,19 @@ +Files: +tests/test-futimens.h +tests/test-lutimens.h +tests/test-utimens.h +tests/test-utimens-common.h +tests/test-fdutimensat.c + +Depends-on: +progname +timespec +utimecmp + +configure.ac: +AC_CHECK_FUNCS_ONCE([usleep]) + +Makefile.am: +TESTS += test-fdutimensat +check_PROGRAMS += test-fdutimensat +test_fdutimensat_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBINTL@
new file mode 100644 --- /dev/null +++ b/tests/test-fdutimensat.c @@ -0,0 +1,142 @@ +/* Tests of fdutimensat. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include "utimens.h" + +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +#define BASE "test-fdutimensat.t" + +#include "test-futimens.h" +#include "test-lutimens.h" +#include "test-utimens.h" + +static int dfd = AT_FDCWD; + +/* Wrap fdutimensat to behave like futimens. */ +static int +do_futimens (int fd, struct timespec const times[2]) +{ + return fdutimensat (dfd, NULL, fd, times); +} + +/* Test the use of file descriptors alongside a name. */ +static int +do_fdutimens (char const *name, struct timespec const times[2]) +{ + int result; + int fd = openat (dfd, name, O_WRONLY); + if (fd < 0) + fd = openat (dfd, name, O_RDONLY); + errno = 0; + result = fdutimensat (dfd, name, fd, times); + if (0 <= fd) + { + int saved_errno = errno; + close (fd); + errno = saved_errno; + } + return result; +} + +/* Wrap lutimensat to behave like lutimens. */ +static int +do_lutimens (const char *name, struct timespec const times[2]) +{ + return lutimensat (dfd, name, times); +} + +/* Wrap fdutimensat to behave like utimens. */ +static int +do_utimens (const char *name, struct timespec const times[2]) +{ + return fdutimensat (dfd, name, -1, times); +} + +int +main () +{ + int result1; /* Skip because of no symlink support. */ + int result2; /* Skip because of no futimens support. */ + int result3; /* Skip because of no lutimens support. */ + int fd; + + /* Clean up any trash from prior testsuite runs. */ + ASSERT (system ("rm -rf " BASE "*") == 0); + + /* Basic tests. */ + result1 = test_utimens (do_utimens, true); + ASSERT (test_utimens (do_fdutimens, false) == result1); + result2 = test_futimens (do_futimens, result1 == 0); + result3 = test_lutimens (do_lutimens, (result1 + result2) == 0); + /* We expect 0/0, 0/77, or 77/77, but not 77/0. */ + ASSERT (result1 <= 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); + + /* Directory relative tests. */ + ASSERT (mkdir (BASE "dir", 0700) == 0); + ASSERT (chdir (BASE "dir") == 0); + fd = creat ("file", 0600); + ASSERT (0 <= fd); + errno = 0; + ASSERT (fdutimensat (fd, ".", AT_FDCWD, NULL) == -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 (stat ("file", &st) == 0); + ASSERT (st.st_atime == Y2K); + ASSERT (get_stat_atime_ns (&st) == 0); + ASSERT (st.st_mtime == Y2K); + ASSERT (get_stat_mtime_ns (&st) == 0); + } + ASSERT (close (fd) == 0); + ASSERT (close (dfd) == 0); + errno = 0; + ASSERT (fdutimensat (dfd, ".", -1, NULL) == -1); + ASSERT (errno == EBADF); + + /* Cleanup. */ + ASSERT (chdir ("..") == 0); + ASSERT (unlink (BASE "dir/file") == 0); + ASSERT (rmdir (BASE "dir") == 0); + return result1 | result2 | result3; +}