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 | 30c932a3098146128acfd839589f308ec1bb116d (patch) | |
tree | 1a97d2f26bbb5f1a00ae827a5da65167d5c6b5cb | |
parent | 52139fd69034446695af60c8064a38e5e795227c (diff) | |
download | coreutils-30c932a3098146128acfd839589f308ec1bb116d.tar.gz |
cp,mv,install: modularize targetdir
Move target directory code out of system.h to a new targetdir module.
This doesn’t change functionality.
* bootstrap.conf (gnulib_modules): Add targetdir.
* src/cp.c, src/install.c, src/mv.c: Include targetdir.h.
* src/system.h (must_be_working_directory, target_directory_operand)
(targetdir_dirfd_valid): Move from here ...
* gl/lib/targetdir.c, gl/lib/targetdir.h, gl/modules/targetdir:
... to these new files.
-rw-r--r-- | bootstrap.conf | 1 | ||||
-rw-r--r-- | gl/lib/targetdir.c | 100 | ||||
-rw-r--r-- | gl/lib/targetdir.h | 42 | ||||
-rw-r--r-- | gl/modules/targetdir | 25 | ||||
-rw-r--r-- | src/cp.c | 1 | ||||
-rw-r--r-- | src/install.c | 1 | ||||
-rw-r--r-- | src/mv.c | 1 | ||||
-rw-r--r-- | src/system.h | 74 |
8 files changed, 171 insertions, 74 deletions
diff --git a/bootstrap.conf b/bootstrap.conf index c1399e30c..756df00f6 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -262,6 +262,7 @@ gnulib_modules=" sys_resource sys_stat sys_wait + targetdir tempname termios time_rz diff --git a/gl/lib/targetdir.c b/gl/lib/targetdir.c new file mode 100644 index 000000000..79d888887 --- /dev/null +++ b/gl/lib/targetdir.c @@ -0,0 +1,100 @@ +/* Target directory operands for coreutils + + Copyright 2004-2022 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 <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#define TARGETDIR_INLINE _GL_EXTERN_INLINE +#include <targetdir.h> + +#include <attribute.h> + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#ifdef O_PATH +enum { O_PATHSEARCH = O_PATH }; +#else +enum { O_PATHSEARCH = O_SEARCH }; +#endif + +/* Must F designate the working directory? */ + +ATTRIBUTE_PURE static inline bool +must_be_working_directory (char const *f) +{ + /* Return true for ".", "./.", ".///./", etc. */ + while (*f++ == '.') + { + if (*f != '/') + return !*f; + while (*++f == '/') + continue; + if (!*f) + return true; + } + return false; +} + +/* Return a file descriptor open to FILE, for use in openat. + As an optimization, return AT_FDCWD if FILE must be the working directory. + 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) +{ + 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. + Also check on systems with O_PATHSEARCH == O_SEARCH, like Solaris 11, + where open() was seen to return EACCES for non executable non dirs. + */ + if ((!O_DIRECTORY || (O_PATHSEARCH == O_SEARCH)) + && stat (file, &st) == 0) + { + maybe_dir = S_ISDIR (st.st_mode); + if (! maybe_dir) + errno = ENOTDIR; + } + + if (maybe_dir) + fd = open (file, O_PATHSEARCH | O_DIRECTORY); + + if (!O_DIRECTORY && 0 <= fd) + { + /* 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)) + { + close (fd); + errno = err; + fd = -1; + } + } + + return fd - (AT_FDCWD == -1 && fd < 0); +} diff --git a/gl/lib/targetdir.h b/gl/lib/targetdir.h new file mode 100644 index 000000000..be34d4981 --- /dev/null +++ b/gl/lib/targetdir.h @@ -0,0 +1,42 @@ +/* Target directory operands for coreutils + + Copyright 2022 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 <https://www.gnu.org/licenses/>. */ + +#include <fcntl.h> +#include <stdbool.h> + +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef TARGETDIR_INLINE +# define TARGETDIR_INLINE _GL_INLINE +#endif + +/* Return a file descriptor open to FILE, for use in openat. + As an optimization, return AT_FDCWD if FILE must be the working directory. + 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); + +/* Return true if FD represents success for target_directory_operand. */ +TARGETDIR_INLINE _GL_ATTRIBUTE_PURE bool +target_dirfd_valid (int fd) +{ + return fd != -1 - (AT_FDCWD == -1); +} + +_GL_INLINE_HEADER_END diff --git a/gl/modules/targetdir b/gl/modules/targetdir new file mode 100644 index 000000000..25ccfb899 --- /dev/null +++ b/gl/modules/targetdir @@ -0,0 +1,25 @@ +Description: +Target directory operands + +Files: +lib/targetdir.c +lib/targetdir.h + +Depends-on: +attribute +fcntl-h +stdbool + +configure.ac: + +Makefile.am: +lib_SOURCES += targetdir.c targetdir.h + +Include: +"targetdir.h" + +License: +GPL + +Maintainer: +all @@ -33,6 +33,7 @@ #include "ignore-value.h" #include "quote.h" #include "stat-time.h" +#include "targetdir.h" #include "utimens.h" #include "acl.h" diff --git a/src/install.c b/src/install.c index 079ce1f70..4b06f9639 100644 --- a/src/install.c +++ b/src/install.c @@ -42,6 +42,7 @@ #include "savewd.h" #include "selinux.h" #include "stat-time.h" +#include "targetdir.h" #include "utimens.h" #include "xstrtol.h" @@ -33,6 +33,7 @@ #include "remove.h" #include "renameatu.h" #include "root-dev-ino.h" +#include "targetdir.h" #include "priv-set.h" /* The official name of this program (e.g., no 'g' prefix). */ diff --git a/src/system.h b/src/system.h index 768c3a1f2..0c5c9b900 100644 --- a/src/system.h +++ b/src/system.h @@ -107,80 +107,6 @@ enum { O_PATHSEARCH = O_PATH }; enum { O_PATHSEARCH = O_SEARCH }; #endif -/* Must F designate the working directory? */ - -ATTRIBUTE_PURE static inline bool -must_be_working_directory (char const *f) -{ - /* Return true for ".", "./.", ".///./", etc. */ - while (*f++ == '.') - { - if (*f != '/') - return !*f; - while (*++f == '/') - continue; - if (!*f) - return true; - } - return false; -} - -/* Return a file descriptor open to FILE, for use in openat. - As an optimization, return AT_FDCWD if FILE must be the working directory. - Fail if FILE is not a directory. - On failure return a negative value; this is -1 unless AT_FDCWD == -1. */ - -static inline int -target_directory_operand (char const *file) -{ - 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. - Also check on systems with O_PATHSEARCH == O_SEARCH, like Solaris 11, - where open() was seen to return EACCES for non executable non dirs. - */ - if ((!O_DIRECTORY || (O_PATHSEARCH == O_SEARCH)) - && stat (file, &st) == 0) - { - maybe_dir = S_ISDIR (st.st_mode); - if (! maybe_dir) - errno = ENOTDIR; - } - - if (maybe_dir) - fd = open (file, O_PATHSEARCH | O_DIRECTORY); - - if (!O_DIRECTORY && 0 <= fd) - { - /* 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)) - { - close (fd); - errno = err; - fd = -1; - } - } - - return fd - (AT_FDCWD == -1 && fd < 0); -} - -/* Return true if FD represents success for target_directory_operand. */ - -static inline bool -target_dirfd_valid (int fd) -{ - return fd != -1 - (AT_FDCWD == -1); -} - #include <dirent.h> #ifndef _D_EXACT_NAMLEN # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name) |