diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2022-04-12 23:56:41 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2022-04-12 23:57:15 -0700 |
commit | 197a570ff0a17db5c8e003645d154e57bddc70ce (patch) | |
tree | d24b9e3a13402b4bfbbf4b89721813d2ca1b6754 | |
parent | 30c932a3098146128acfd839589f308ec1bb116d (diff) | |
download | coreutils-197a570ff0a17db5c8e003645d154e57bddc70ce.tar.gz |
cp,mv,install: avoid excess stat calls on non-GNU
* gl/lib/targetdir.c (target_directory_operand): New arg ST.
All callers changed.
* src/cp.c (do_copy):
* src/mv.c (main):
Avoid unnecessary stat call if target_directory_operand already
got the status.
-rw-r--r-- | gl/lib/targetdir.c | 12 | ||||
-rw-r--r-- | gl/lib/targetdir.h | 4 | ||||
-rw-r--r-- | src/cp.c | 7 | ||||
-rw-r--r-- | src/install.c | 5 | ||||
-rw-r--r-- | src/mv.c | 10 |
5 files changed, 22 insertions, 16 deletions
diff --git a/gl/lib/targetdir.c b/gl/lib/targetdir.c index 79d888887..a966e1ea1 100644 --- a/gl/lib/targetdir.c +++ b/gl/lib/targetdir.c @@ -53,18 +53,18 @@ must_be_working_directory (char const *f) /* Return a file descriptor open to FILE, for use in openat. As an optimization, return AT_FDCWD if FILE must be the working directory. + As a side effect, possibly set *ST to the file's status. Fail and set errno if FILE is not a directory. On failure return -2 if AT_FDCWD is -1, -1 otherwise. */ int -target_directory_operand (char const *file) +target_directory_operand (char const *file, struct stat *st) { if (must_be_working_directory (file)) return AT_FDCWD; int fd = -1; int maybe_dir = -1; - struct stat st; /* On old systems without O_DIRECTORY, like Solaris 10, check with stat first lest we try to open a fifo for example and hang. @@ -72,9 +72,9 @@ target_directory_operand (char const *file) where open() was seen to return EACCES for non executable non dirs. */ if ((!O_DIRECTORY || (O_PATHSEARCH == O_SEARCH)) - && stat (file, &st) == 0) + && stat (file, st) == 0) { - maybe_dir = S_ISDIR (st.st_mode); + maybe_dir = S_ISDIR (st->st_mode); if (! maybe_dir) errno = ENOTDIR; } @@ -87,8 +87,8 @@ target_directory_operand (char const *file) /* On old systems like Solaris 10 double check type, to ensure we've opened a directory. */ int err; - if (fstat (fd, &st) != 0 ? (err = errno, true) - : !S_ISDIR (st.st_mode) && (err = ENOTDIR, true)) + if (fstat (fd, st) != 0 ? (err = errno, true) + : !S_ISDIR (st->st_mode) && (err = ENOTDIR, true)) { close (fd); errno = err; diff --git a/gl/lib/targetdir.h b/gl/lib/targetdir.h index be34d4981..cb6b06835 100644 --- a/gl/lib/targetdir.h +++ b/gl/lib/targetdir.h @@ -17,6 +17,7 @@ #include <fcntl.h> #include <stdbool.h> +#include <sys/stat.h> #ifndef _GL_INLINE_HEADER_BEGIN #error "Please include config.h first." @@ -28,9 +29,10 @@ _GL_INLINE_HEADER_BEGIN /* Return a file descriptor open to FILE, for use in openat. As an optimization, return AT_FDCWD if FILE must be the working directory. + As a side effect, possibly set *ST to the file's status. Fail and set errno if FILE is not a directory. On failure return -2 if AT_FDCWD is -1, -1 otherwise. */ -extern int target_directory_operand (char const *file); +extern int target_directory_operand (char const *file, struct stat *st); /* Return true if FD represents success for target_directory_operand. */ TARGETDIR_INLINE _GL_ATTRIBUTE_PURE bool @@ -602,7 +602,7 @@ do_copy (int n_files, char **file, char const *target_directory, } else if (target_directory) { - target_dirfd = target_directory_operand (target_directory); + target_dirfd = target_directory_operand (target_directory, &sb); if (! target_dirfd_valid (target_dirfd)) die (EXIT_FAILURE, errno, _("target directory %s"), quoteaf (target_directory)); @@ -610,7 +610,7 @@ do_copy (int n_files, char **file, char const *target_directory, else { char const *lastfile = file[n_files - 1]; - int fd = target_directory_operand (lastfile); + int fd = target_directory_operand (lastfile, &sb); if (target_dirfd_valid (fd)) { target_dirfd = fd; @@ -634,7 +634,8 @@ do_copy (int n_files, char **file, char const *target_directory, | O_DIRECTORY) failed with EACCES not ENOTDIR. */ if (2 < n_files || (O_PATHSEARCH == O_SEARCH && err == EACCES - && stat (lastfile, &sb) == 0 && S_ISDIR (sb.st_mode))) + && (sb.st_mode || stat (lastfile, &sb) == 0) + && S_ISDIR (sb.st_mode))) die (EXIT_FAILURE, err, _("target %s"), quoteaf (lastfile)); } } diff --git a/src/install.c b/src/install.c index 4b06f9639..5c4baf7d4 100644 --- a/src/install.c +++ b/src/install.c @@ -931,6 +931,7 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + struct stat sb; int target_dirfd = AT_FDCWD; if (no_target_directory) { @@ -946,7 +947,7 @@ main (int argc, char **argv) } else if (target_directory) { - target_dirfd = target_directory_operand (target_directory); + target_dirfd = target_directory_operand (target_directory, &sb); if (! (target_dirfd_valid (target_dirfd) || (mkdir_and_install && errno == ENOENT))) die (EXIT_FAILURE, errno, _("failed to access %s"), @@ -955,7 +956,7 @@ main (int argc, char **argv) else if (!dir_arg) { char const *lastfile = file[n_files - 1]; - int fd = target_directory_operand (lastfile); + int fd = target_directory_operand (lastfile, &sb); if (target_dirfd_valid (fd)) { target_dirfd = fd; @@ -382,6 +382,8 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + struct stat sb; + sb.st_mode = 0; int target_dirfd = AT_FDCWD; if (no_target_directory) { @@ -397,7 +399,7 @@ main (int argc, char **argv) } else if (target_directory) { - target_dirfd = target_directory_operand (target_directory); + target_dirfd = target_directory_operand (target_directory, &sb); if (! target_dirfd_valid (target_dirfd)) die (EXIT_FAILURE, errno, _("target directory %s"), quoteaf (target_directory)); @@ -411,7 +413,7 @@ main (int argc, char **argv) ? errno : 0); if (x.rename_errno != 0) { - int fd = target_directory_operand (lastfile); + int fd = target_directory_operand (lastfile, &sb); if (target_dirfd_valid (fd)) { x.rename_errno = -1; @@ -431,10 +433,10 @@ main (int argc, char **argv) directory, in case opening a non-directory with (O_SEARCH | O_DIRECTORY) failed with EACCES not ENOTDIR. */ int err = errno; - struct stat st; if (2 < n_files || (O_PATHSEARCH == O_SEARCH && err == EACCES - && stat (lastfile, &st) == 0 && S_ISDIR (st.st_mode))) + && (sb.st_mode != 0 || stat (lastfile, &sb) == 0) + && S_ISDIR (sb.st_mode))) die (EXIT_FAILURE, err, _("target %s"), quoteaf (lastfile)); } } |