diff options
| author | Paul Eggert | 2013-01-31 22:30:51 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-01-31 22:30:51 -0800 |
| commit | 8654f9d7d6d7c3ee97232a34a40250dcbc57af8e (patch) | |
| tree | ff488081b57dabdfe7e85c11a34e8ac522b5bdb4 /lib | |
| parent | 44b12dd6994a6214b9d6f73539b441080611369b (diff) | |
| download | emacs-8654f9d7d6d7c3ee97232a34a40250dcbc57af8e.tar.gz emacs-8654f9d7d6d7c3ee97232a34a40250dcbc57af8e.zip | |
Use fdopendir, fstatat and readlinkat, for efficiency.
On my host, this speeds up directory-files-and-attributes by a
factor of 3, when applied to Emacs's src directory.
These functions are standardized by POSIX and are common these
days; fall back on a (slower) gnulib implementation if the host
is too old to supply them.
* .bzrignore: Add lib/dirent.h.
* lib/Makefile.am (libgnu_a_SOURCES): Add openat-die.c, save-cwd.c.
* lib/careadlinkat.c, lib/careadlinkat.h: Merge from gnulib,
incorporating: 2013-01-29 careadlinkat: do not provide careadlinkatcwd.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* lib/dirent.in.h, lib/fdopendir.c, lib/fstatat.c, lib/openat-priv.h:
* lib/openat-proc.c, lib/openat.h, m4/dirent_h.m4, m4/fdopendir.m4:
* m4/fstatat.m4: New files, from gnulib.
* lib/openat-die.c, lib/save-cwd.c, lib/save-cwd.h: New files.
These last three are specific to Emacs and are not copied from gnulib.
They are simpler than the gnulib versions and are tuned for Emacs.
* admin/merge-gnulib (GNULIB_MODULES): Add fdopendir, fstatat, readlinkat.
(GNULIB_TOOL_FLAGS): Do not avoid at-internal, openat-h.
Avoid dup, open, opendir.
* nt/inc/sys/stat.h (fstatat):
* nt/inc/unistd.h (readlinkat): New decls.
* src/conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): Remove.
* src/dired.c: Include <fcntl.h>.
(open_directory): New function, which uses open and fdopendir
rather than opendir. DOS_NT platforms still use opendir, though.
(directory_files_internal, file_name_completion): Use it.
(file_attributes): New function, with most of the old Ffile_attributes.
(directory_files_internal, Ffile_attributes): Use it.
(file_attributes, file_name_completion_stat): First arg is now fd,
not dir name. All uses changed. Use fstatat rather than lstat +
stat.
(file_attributes): Use emacs_readlinkat rather than Ffile_symlink_p.
* src/fileio.c: Include <allocator.h>, <careadlinkat.h>.
(emacs_readlinkat): New function, with much of the old
Ffile_symlink_p, but with an fd argument for speed.
It uses readlinkat rather than careadlinkatcwd, so that it
need not assume the working directory.
(Ffile_symlink_p): Use it.
* src/filelock.c (current_lock_owner): Use emacs_readlinkat
rather than emacs_readlink.
* src/lisp.h (emacs_readlinkat): New decl.
(READLINK_BUFSIZE, emacs_readlink): Remove.
* src/sysdep.c: Do not include <allocator.h>, <careadlinkat.h>.
(emacs_norealloc_allocator, emacs_readlink): Remove.
This stuff is moved to fileio.c.
* src/w32.c (fstatat, readlinkat): New functions.
(careadlinkat): Don't check that fd == AT_FDCWD.
(careadlinkatcwd): Remove; no longer needed.
Fixes: debbugs:13539
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.am | 2 | ||||
| -rw-r--r-- | lib/careadlinkat.c | 16 | ||||
| -rw-r--r-- | lib/careadlinkat.h | 6 | ||||
| -rw-r--r-- | lib/dirent.in.h | 258 | ||||
| -rw-r--r-- | lib/fdopendir.c | 204 | ||||
| -rw-r--r-- | lib/fstatat.c | 135 | ||||
| -rw-r--r-- | lib/gnulib.mk | 97 | ||||
| -rw-r--r-- | lib/openat-die.c | 6 | ||||
| -rw-r--r-- | lib/openat-priv.h | 64 | ||||
| -rw-r--r-- | lib/openat-proc.c | 110 | ||||
| -rw-r--r-- | lib/openat.h | 120 | ||||
| -rw-r--r-- | lib/readlinkat.c | 47 | ||||
| -rw-r--r-- | lib/save-cwd.c | 3 | ||||
| -rw-r--r-- | lib/save-cwd.h | 46 |
14 files changed, 1093 insertions, 21 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 28fdafd4b45..a341609e895 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
| @@ -8,3 +8,5 @@ AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) | |||
| 8 | DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src | 8 | DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src |
| 9 | 9 | ||
| 10 | include gnulib.mk | 10 | include gnulib.mk |
| 11 | |||
| 12 | libgnu_a_SOURCES += openat-die.c save-cwd.c | ||
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index 1a759be7caf..d242ffaac7d 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include <errno.h> | 25 | #include <errno.h> |
| 26 | #include <limits.h> | 26 | #include <limits.h> |
| 27 | #include <stdlib.h> | ||
| 28 | #include <string.h> | 27 | #include <string.h> |
| 29 | #include <unistd.h> | ||
| 30 | 28 | ||
| 31 | /* Define this independently so that stdint.h is not a prerequisite. */ | 29 | /* Define this independently so that stdint.h is not a prerequisite. */ |
| 32 | #ifndef SIZE_MAX | 30 | #ifndef SIZE_MAX |
| @@ -39,20 +37,6 @@ | |||
| 39 | 37 | ||
| 40 | #include "allocator.h" | 38 | #include "allocator.h" |
| 41 | 39 | ||
| 42 | /* Get the symbolic link value of FILENAME and put it into BUFFER, with | ||
| 43 | size BUFFER_SIZE. This function acts like readlink but has | ||
| 44 | readlinkat's signature. */ | ||
| 45 | ssize_t | ||
| 46 | careadlinkatcwd (int fd, char const *filename, char *buffer, | ||
| 47 | size_t buffer_size) | ||
| 48 | { | ||
| 49 | /* FD must be AT_FDCWD here, otherwise the caller is using this | ||
| 50 | function in contexts for which it was not meant for. */ | ||
| 51 | if (fd != AT_FDCWD) | ||
| 52 | abort (); | ||
| 53 | return readlink (filename, buffer, buffer_size); | ||
| 54 | } | ||
| 55 | |||
| 56 | /* Assuming the current directory is FD, get the symbolic link value | 40 | /* Assuming the current directory is FD, get the symbolic link value |
| 57 | of FILENAME as a null-terminated string and put it into a buffer. | 41 | of FILENAME as a null-terminated string and put it into a buffer. |
| 58 | If FD is AT_FDCWD, FILENAME is interpreted relative to the current | 42 | If FD is AT_FDCWD, FILENAME is interpreted relative to the current |
diff --git a/lib/careadlinkat.h b/lib/careadlinkat.h index 5cdb813fedd..965573bef3a 100644 --- a/lib/careadlinkat.h +++ b/lib/careadlinkat.h | |||
| @@ -52,9 +52,9 @@ char *careadlinkat (int fd, char const *filename, | |||
| 52 | ssize_t (*preadlinkat) (int, char const *, | 52 | ssize_t (*preadlinkat) (int, char const *, |
| 53 | char *, size_t)); | 53 | char *, size_t)); |
| 54 | 54 | ||
| 55 | /* Suitable values for careadlinkat's FD and PREADLINKAT arguments, | 55 | /* Suitable value for careadlinkat's FD argument, |
| 56 | when doing a plain readlink: | 56 | when doing a plain readlink: |
| 57 | Pass FD = AT_FDCWD and PREADLINKAT = careadlinkatcwd. */ | 57 | Pass FD = AT_FDCWD. */ |
| 58 | #if HAVE_READLINKAT | 58 | #if HAVE_READLINKAT |
| 59 | /* AT_FDCWD is declared in <fcntl.h>. */ | 59 | /* AT_FDCWD is declared in <fcntl.h>. */ |
| 60 | #else | 60 | #else |
| @@ -66,7 +66,5 @@ char *careadlinkat (int fd, char const *filename, | |||
| 66 | # define AT_FDCWD (-3041965) | 66 | # define AT_FDCWD (-3041965) |
| 67 | # endif | 67 | # endif |
| 68 | #endif | 68 | #endif |
| 69 | ssize_t careadlinkatcwd (int fd, char const *filename, | ||
| 70 | char *buffer, size_t buffer_size); | ||
| 71 | 69 | ||
| 72 | #endif /* _GL_CAREADLINKAT_H */ | 70 | #endif /* _GL_CAREADLINKAT_H */ |
diff --git a/lib/dirent.in.h b/lib/dirent.in.h new file mode 100644 index 00000000000..fad3797b8ba --- /dev/null +++ b/lib/dirent.in.h | |||
| @@ -0,0 +1,258 @@ | |||
| 1 | /* A GNU-like <dirent.h>. | ||
| 2 | Copyright (C) 2006-2013 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | #ifndef _@GUARD_PREFIX@_DIRENT_H | ||
| 18 | |||
| 19 | #if __GNUC__ >= 3 | ||
| 20 | @PRAGMA_SYSTEM_HEADER@ | ||
| 21 | #endif | ||
| 22 | @PRAGMA_COLUMNS@ | ||
| 23 | |||
| 24 | /* The include_next requires a split double-inclusion guard. */ | ||
| 25 | #if @HAVE_DIRENT_H@ | ||
| 26 | # @INCLUDE_NEXT@ @NEXT_DIRENT_H@ | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #ifndef _@GUARD_PREFIX@_DIRENT_H | ||
| 30 | #define _@GUARD_PREFIX@_DIRENT_H | ||
| 31 | |||
| 32 | /* Get ino_t. Needed on some systems, including glibc 2.8. */ | ||
| 33 | #include <sys/types.h> | ||
| 34 | |||
| 35 | #if !@HAVE_DIRENT_H@ | ||
| 36 | /* Define types DIR and 'struct dirent'. */ | ||
| 37 | # if !GNULIB_defined_struct_dirent | ||
| 38 | struct dirent | ||
| 39 | { | ||
| 40 | char d_type; | ||
| 41 | char d_name[1]; | ||
| 42 | }; | ||
| 43 | /* Possible values for 'd_type'. */ | ||
| 44 | # define DT_UNKNOWN 0 | ||
| 45 | # define DT_FIFO 1 /* FIFO */ | ||
| 46 | # define DT_CHR 2 /* character device */ | ||
| 47 | # define DT_DIR 4 /* directory */ | ||
| 48 | # define DT_BLK 6 /* block device */ | ||
| 49 | # define DT_REG 8 /* regular file */ | ||
| 50 | # define DT_LNK 10 /* symbolic link */ | ||
| 51 | # define DT_SOCK 12 /* socket */ | ||
| 52 | # define DT_WHT 14 /* whiteout */ | ||
| 53 | typedef struct gl_directory DIR; | ||
| 54 | # define GNULIB_defined_struct_dirent 1 | ||
| 55 | # endif | ||
| 56 | #endif | ||
| 57 | |||
| 58 | /* The __attribute__ feature is available in gcc versions 2.5 and later. | ||
| 59 | The attribute __pure__ was added in gcc 2.96. */ | ||
| 60 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) | ||
| 61 | # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) | ||
| 62 | #else | ||
| 63 | # define _GL_ATTRIBUTE_PURE /* empty */ | ||
| 64 | #endif | ||
| 65 | |||
| 66 | /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ | ||
| 67 | |||
| 68 | /* The definition of _GL_ARG_NONNULL is copied here. */ | ||
| 69 | |||
| 70 | /* The definition of _GL_WARN_ON_USE is copied here. */ | ||
| 71 | |||
| 72 | |||
| 73 | /* Declare overridden functions. */ | ||
| 74 | |||
| 75 | #if @GNULIB_OPENDIR@ | ||
| 76 | # if @REPLACE_OPENDIR@ | ||
| 77 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 78 | # undef opendir | ||
| 79 | # define opendir rpl_opendir | ||
| 80 | # endif | ||
| 81 | _GL_FUNCDECL_RPL (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1))); | ||
| 82 | _GL_CXXALIAS_RPL (opendir, DIR *, (const char *dir_name)); | ||
| 83 | # else | ||
| 84 | # if !@HAVE_OPENDIR@ | ||
| 85 | _GL_FUNCDECL_SYS (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1))); | ||
| 86 | # endif | ||
| 87 | _GL_CXXALIAS_SYS (opendir, DIR *, (const char *dir_name)); | ||
| 88 | # endif | ||
| 89 | _GL_CXXALIASWARN (opendir); | ||
| 90 | #elif defined GNULIB_POSIXCHECK | ||
| 91 | # undef opendir | ||
| 92 | # if HAVE_RAW_DECL_OPENDIR | ||
| 93 | _GL_WARN_ON_USE (opendir, "opendir is not portable - " | ||
| 94 | "use gnulib module opendir for portability"); | ||
| 95 | # endif | ||
| 96 | #endif | ||
| 97 | |||
| 98 | #if @GNULIB_READDIR@ | ||
| 99 | # if !@HAVE_READDIR@ | ||
| 100 | _GL_FUNCDECL_SYS (readdir, struct dirent *, (DIR *dirp) _GL_ARG_NONNULL ((1))); | ||
| 101 | # endif | ||
| 102 | _GL_CXXALIAS_SYS (readdir, struct dirent *, (DIR *dirp)); | ||
| 103 | _GL_CXXALIASWARN (readdir); | ||
| 104 | #elif defined GNULIB_POSIXCHECK | ||
| 105 | # undef readdir | ||
| 106 | # if HAVE_RAW_DECL_READDIR | ||
| 107 | _GL_WARN_ON_USE (readdir, "readdir is not portable - " | ||
| 108 | "use gnulib module readdir for portability"); | ||
| 109 | # endif | ||
| 110 | #endif | ||
| 111 | |||
| 112 | #if @GNULIB_REWINDDIR@ | ||
| 113 | # if !@HAVE_REWINDDIR@ | ||
| 114 | _GL_FUNCDECL_SYS (rewinddir, void, (DIR *dirp) _GL_ARG_NONNULL ((1))); | ||
| 115 | # endif | ||
| 116 | _GL_CXXALIAS_SYS (rewinddir, void, (DIR *dirp)); | ||
| 117 | _GL_CXXALIASWARN (rewinddir); | ||
| 118 | #elif defined GNULIB_POSIXCHECK | ||
| 119 | # undef rewinddir | ||
| 120 | # if HAVE_RAW_DECL_REWINDDIR | ||
| 121 | _GL_WARN_ON_USE (rewinddir, "rewinddir is not portable - " | ||
| 122 | "use gnulib module rewinddir for portability"); | ||
| 123 | # endif | ||
| 124 | #endif | ||
| 125 | |||
| 126 | #if @GNULIB_CLOSEDIR@ | ||
| 127 | # if @REPLACE_CLOSEDIR@ | ||
| 128 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 129 | # undef closedir | ||
| 130 | # define closedir rpl_closedir | ||
| 131 | # endif | ||
| 132 | _GL_FUNCDECL_RPL (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1))); | ||
| 133 | _GL_CXXALIAS_RPL (closedir, int, (DIR *dirp)); | ||
| 134 | # else | ||
| 135 | # if !@HAVE_CLOSEDIR@ | ||
| 136 | _GL_FUNCDECL_SYS (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1))); | ||
| 137 | # endif | ||
| 138 | _GL_CXXALIAS_SYS (closedir, int, (DIR *dirp)); | ||
| 139 | # endif | ||
| 140 | _GL_CXXALIASWARN (closedir); | ||
| 141 | #elif defined GNULIB_POSIXCHECK | ||
| 142 | # undef closedir | ||
| 143 | # if HAVE_RAW_DECL_CLOSEDIR | ||
| 144 | _GL_WARN_ON_USE (closedir, "closedir is not portable - " | ||
| 145 | "use gnulib module closedir for portability"); | ||
| 146 | # endif | ||
| 147 | #endif | ||
| 148 | |||
| 149 | #if @GNULIB_DIRFD@ | ||
| 150 | /* Return the file descriptor associated with the given directory stream, | ||
| 151 | or -1 if none exists. */ | ||
| 152 | # if @REPLACE_DIRFD@ | ||
| 153 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 154 | # undef dirfd | ||
| 155 | # define dirfd rpl_dirfd | ||
| 156 | # endif | ||
| 157 | _GL_FUNCDECL_RPL (dirfd, int, (DIR *) _GL_ARG_NONNULL ((1))); | ||
| 158 | _GL_CXXALIAS_RPL (dirfd, int, (DIR *)); | ||
| 159 | # else | ||
| 160 | # if defined __cplusplus && defined GNULIB_NAMESPACE && defined dirfd | ||
| 161 | /* dirfd is defined as a macro and not as a function. | ||
| 162 | Turn it into a function and get rid of the macro. */ | ||
| 163 | static inline int (dirfd) (DIR *dp) { return dirfd (dp); } | ||
| 164 | # undef dirfd | ||
| 165 | # endif | ||
| 166 | # if !(@HAVE_DECL_DIRFD@ || defined dirfd) | ||
| 167 | _GL_FUNCDECL_SYS (dirfd, int, (DIR *) _GL_ARG_NONNULL ((1))); | ||
| 168 | # endif | ||
| 169 | _GL_CXXALIAS_SYS (dirfd, int, (DIR *)); | ||
| 170 | # endif | ||
| 171 | _GL_CXXALIASWARN (dirfd); | ||
| 172 | #elif defined GNULIB_POSIXCHECK | ||
| 173 | # undef dirfd | ||
| 174 | # if HAVE_RAW_DECL_DIRFD | ||
| 175 | _GL_WARN_ON_USE (dirfd, "dirfd is unportable - " | ||
| 176 | "use gnulib module dirfd for portability"); | ||
| 177 | # endif | ||
| 178 | #endif | ||
| 179 | |||
| 180 | #if @GNULIB_FDOPENDIR@ | ||
| 181 | /* Open a directory stream visiting the given directory file | ||
| 182 | descriptor. Return NULL and set errno if fd is not visiting a | ||
| 183 | directory. On success, this function consumes fd (it will be | ||
| 184 | implicitly closed either by this function or by a subsequent | ||
| 185 | closedir). */ | ||
| 186 | # if @REPLACE_FDOPENDIR@ | ||
| 187 | # if !(defined __cplusplus && defined GNULIB_NAMESPACE) | ||
| 188 | # undef fdopendir | ||
| 189 | # define fdopendir rpl_fdopendir | ||
| 190 | # endif | ||
| 191 | _GL_FUNCDECL_RPL (fdopendir, DIR *, (int fd)); | ||
| 192 | _GL_CXXALIAS_RPL (fdopendir, DIR *, (int fd)); | ||
| 193 | # else | ||
| 194 | # if !@HAVE_FDOPENDIR@ || !@HAVE_DECL_FDOPENDIR@ | ||
| 195 | _GL_FUNCDECL_SYS (fdopendir, DIR *, (int fd)); | ||
| 196 | # endif | ||
| 197 | _GL_CXXALIAS_SYS (fdopendir, DIR *, (int fd)); | ||
| 198 | # endif | ||
| 199 | _GL_CXXALIASWARN (fdopendir); | ||
| 200 | #elif defined GNULIB_POSIXCHECK | ||
| 201 | # undef fdopendir | ||
| 202 | # if HAVE_RAW_DECL_FDOPENDIR | ||
| 203 | _GL_WARN_ON_USE (fdopendir, "fdopendir is unportable - " | ||
| 204 | "use gnulib module fdopendir for portability"); | ||
| 205 | # endif | ||
| 206 | #endif | ||
| 207 | |||
| 208 | #if @GNULIB_SCANDIR@ | ||
| 209 | /* Scan the directory DIR, calling FILTER on each directory entry. | ||
| 210 | Entries for which FILTER returns nonzero are individually malloc'd, | ||
| 211 | sorted using qsort with CMP, and collected in a malloc'd array in | ||
| 212 | *NAMELIST. Returns the number of entries selected, or -1 on error. */ | ||
| 213 | # if !@HAVE_SCANDIR@ | ||
| 214 | _GL_FUNCDECL_SYS (scandir, int, | ||
| 215 | (const char *dir, struct dirent ***namelist, | ||
| 216 | int (*filter) (const struct dirent *), | ||
| 217 | int (*cmp) (const struct dirent **, const struct dirent **)) | ||
| 218 | _GL_ARG_NONNULL ((1, 2, 4))); | ||
| 219 | # endif | ||
| 220 | /* Need to cast, because on glibc systems, the fourth parameter is | ||
| 221 | int (*cmp) (const void *, const void *). */ | ||
| 222 | _GL_CXXALIAS_SYS_CAST (scandir, int, | ||
| 223 | (const char *dir, struct dirent ***namelist, | ||
| 224 | int (*filter) (const struct dirent *), | ||
| 225 | int (*cmp) (const struct dirent **, const struct dirent **))); | ||
| 226 | _GL_CXXALIASWARN (scandir); | ||
| 227 | #elif defined GNULIB_POSIXCHECK | ||
| 228 | # undef scandir | ||
| 229 | # if HAVE_RAW_DECL_SCANDIR | ||
| 230 | _GL_WARN_ON_USE (scandir, "scandir is unportable - " | ||
| 231 | "use gnulib module scandir for portability"); | ||
| 232 | # endif | ||
| 233 | #endif | ||
| 234 | |||
| 235 | #if @GNULIB_ALPHASORT@ | ||
| 236 | /* Compare two 'struct dirent' entries alphabetically. */ | ||
| 237 | # if !@HAVE_ALPHASORT@ | ||
| 238 | _GL_FUNCDECL_SYS (alphasort, int, | ||
| 239 | (const struct dirent **, const struct dirent **) | ||
| 240 | _GL_ATTRIBUTE_PURE | ||
| 241 | _GL_ARG_NONNULL ((1, 2))); | ||
| 242 | # endif | ||
| 243 | /* Need to cast, because on glibc systems, the parameters are | ||
| 244 | (const void *, const void *). */ | ||
| 245 | _GL_CXXALIAS_SYS_CAST (alphasort, int, | ||
| 246 | (const struct dirent **, const struct dirent **)); | ||
| 247 | _GL_CXXALIASWARN (alphasort); | ||
| 248 | #elif defined GNULIB_POSIXCHECK | ||
| 249 | # undef alphasort | ||
| 250 | # if HAVE_RAW_DECL_ALPHASORT | ||
| 251 | _GL_WARN_ON_USE (alphasort, "alphasort is unportable - " | ||
| 252 | "use gnulib module alphasort for portability"); | ||
| 253 | # endif | ||
| 254 | #endif | ||
| 255 | |||
| 256 | |||
| 257 | #endif /* _@GUARD_PREFIX@_DIRENT_H */ | ||
| 258 | #endif /* _@GUARD_PREFIX@_DIRENT_H */ | ||
diff --git a/lib/fdopendir.c b/lib/fdopendir.c new file mode 100644 index 00000000000..63e06b92ae8 --- /dev/null +++ b/lib/fdopendir.c | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | /* provide a replacement fdopendir function | ||
| 2 | Copyright (C) 2004-2013 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | /* written by Jim Meyering */ | ||
| 18 | |||
| 19 | #include <config.h> | ||
| 20 | |||
| 21 | #include <dirent.h> | ||
| 22 | |||
| 23 | #include <stdlib.h> | ||
| 24 | #include <unistd.h> | ||
| 25 | |||
| 26 | #if !HAVE_FDOPENDIR | ||
| 27 | |||
| 28 | # include "openat.h" | ||
| 29 | # include "openat-priv.h" | ||
| 30 | # include "save-cwd.h" | ||
| 31 | |||
| 32 | # if GNULIB_DIRENT_SAFER | ||
| 33 | # include "dirent--.h" | ||
| 34 | # endif | ||
| 35 | |||
| 36 | # ifndef REPLACE_FCHDIR | ||
| 37 | # define REPLACE_FCHDIR 0 | ||
| 38 | # endif | ||
| 39 | |||
| 40 | static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *); | ||
| 41 | static DIR *fd_clone_opendir (int, struct saved_cwd const *); | ||
| 42 | |||
| 43 | /* Replacement for POSIX fdopendir. | ||
| 44 | |||
| 45 | First, try to simulate it via opendir ("/proc/self/fd/..."). Failing | ||
| 46 | that, simulate it by using fchdir metadata, or by doing | ||
| 47 | save_cwd/fchdir/opendir(".")/restore_cwd. | ||
| 48 | If either the save_cwd or the restore_cwd fails (relatively unlikely), | ||
| 49 | then give a diagnostic and exit nonzero. | ||
| 50 | |||
| 51 | If successful, the resulting stream is based on FD in | ||
| 52 | implementations where streams are based on file descriptors and in | ||
| 53 | applications where no other thread or signal handler allocates or | ||
| 54 | frees file descriptors. In other cases, consult dirfd on the result | ||
| 55 | to find out whether FD is still being used. | ||
| 56 | |||
| 57 | Otherwise, this function works just like POSIX fdopendir. | ||
| 58 | |||
| 59 | W A R N I N G: | ||
| 60 | |||
| 61 | Unlike other fd-related functions, this one places constraints on FD. | ||
| 62 | If this function returns successfully, FD is under control of the | ||
| 63 | dirent.h system, and the caller should not close or modify the state of | ||
| 64 | FD other than by the dirent.h functions. */ | ||
| 65 | DIR * | ||
| 66 | fdopendir (int fd) | ||
| 67 | { | ||
| 68 | DIR *dir = fdopendir_with_dup (fd, -1, NULL); | ||
| 69 | |||
| 70 | if (! REPLACE_FCHDIR && ! dir) | ||
| 71 | { | ||
| 72 | int saved_errno = errno; | ||
| 73 | if (EXPECTED_ERRNO (saved_errno)) | ||
| 74 | { | ||
| 75 | struct saved_cwd cwd; | ||
| 76 | if (save_cwd (&cwd) != 0) | ||
| 77 | openat_save_fail (errno); | ||
| 78 | dir = fdopendir_with_dup (fd, -1, &cwd); | ||
| 79 | saved_errno = errno; | ||
| 80 | free_cwd (&cwd); | ||
| 81 | errno = saved_errno; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | return dir; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known | ||
| 89 | to be a dup of FD which is less than FD - 1 and which will be | ||
| 90 | closed by the caller and not otherwise used by the caller. This | ||
| 91 | function makes sure that FD is closed and all file descriptors less | ||
| 92 | than FD are open, and then calls fd_clone_opendir on a dup of FD. | ||
| 93 | That way, barring race conditions, fd_clone_opendir returns a | ||
| 94 | stream whose file descriptor is FD. | ||
| 95 | |||
| 96 | If REPLACE_CHDIR or CWD is null, use opendir ("/proc/self/fd/...", | ||
| 97 | falling back on fchdir metadata. Otherwise, CWD is a saved version | ||
| 98 | of the working directory; use fchdir/opendir(".")/restore_cwd(CWD). */ | ||
| 99 | static DIR * | ||
| 100 | fdopendir_with_dup (int fd, int older_dupfd, struct saved_cwd const *cwd) | ||
| 101 | { | ||
| 102 | int dupfd = dup (fd); | ||
| 103 | if (dupfd < 0 && errno == EMFILE) | ||
| 104 | dupfd = older_dupfd; | ||
| 105 | if (dupfd < 0) | ||
| 106 | return NULL; | ||
| 107 | else | ||
| 108 | { | ||
| 109 | DIR *dir; | ||
| 110 | int saved_errno; | ||
| 111 | if (dupfd < fd - 1 && dupfd != older_dupfd) | ||
| 112 | { | ||
| 113 | dir = fdopendir_with_dup (fd, dupfd, cwd); | ||
| 114 | saved_errno = errno; | ||
| 115 | } | ||
| 116 | else | ||
| 117 | { | ||
| 118 | close (fd); | ||
| 119 | dir = fd_clone_opendir (dupfd, cwd); | ||
| 120 | saved_errno = errno; | ||
| 121 | if (! dir) | ||
| 122 | { | ||
| 123 | int fd1 = dup (dupfd); | ||
| 124 | if (fd1 != fd) | ||
| 125 | openat_save_fail (fd1 < 0 ? errno : EBADF); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | if (dupfd != older_dupfd) | ||
| 130 | close (dupfd); | ||
| 131 | errno = saved_errno; | ||
| 132 | return dir; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Like fdopendir, except the result controls a clone of FD. It is | ||
| 137 | the caller's responsibility both to close FD and (if the result is | ||
| 138 | not null) to closedir the result. */ | ||
| 139 | static DIR * | ||
| 140 | fd_clone_opendir (int fd, struct saved_cwd const *cwd) | ||
| 141 | { | ||
| 142 | if (REPLACE_FCHDIR || ! cwd) | ||
| 143 | { | ||
| 144 | DIR *dir = NULL; | ||
| 145 | int saved_errno = EOPNOTSUPP; | ||
| 146 | char buf[OPENAT_BUFFER_SIZE]; | ||
| 147 | char *proc_file = openat_proc_name (buf, fd, "."); | ||
| 148 | if (proc_file) | ||
| 149 | { | ||
| 150 | dir = opendir (proc_file); | ||
| 151 | saved_errno = errno; | ||
| 152 | if (proc_file != buf) | ||
| 153 | free (proc_file); | ||
| 154 | } | ||
| 155 | # if REPLACE_FCHDIR | ||
| 156 | if (! dir && EXPECTED_ERRNO (saved_errno)) | ||
| 157 | { | ||
| 158 | char const *name = _gl_directory_name (fd); | ||
| 159 | return (name ? opendir (name) : NULL); | ||
| 160 | } | ||
| 161 | # endif | ||
| 162 | errno = saved_errno; | ||
| 163 | return dir; | ||
| 164 | } | ||
| 165 | else | ||
| 166 | { | ||
| 167 | if (fchdir (fd) != 0) | ||
| 168 | return NULL; | ||
| 169 | else | ||
| 170 | { | ||
| 171 | DIR *dir = opendir ("."); | ||
| 172 | int saved_errno = errno; | ||
| 173 | if (restore_cwd (cwd) != 0) | ||
| 174 | openat_restore_fail (errno); | ||
| 175 | errno = saved_errno; | ||
| 176 | return dir; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | #else /* HAVE_FDOPENDIR */ | ||
| 182 | |||
| 183 | # include <errno.h> | ||
| 184 | # include <sys/stat.h> | ||
| 185 | |||
| 186 | # undef fdopendir | ||
| 187 | |||
| 188 | /* Like fdopendir, but work around GNU/Hurd bug by validating FD. */ | ||
| 189 | |||
| 190 | DIR * | ||
| 191 | rpl_fdopendir (int fd) | ||
| 192 | { | ||
| 193 | struct stat st; | ||
| 194 | if (fstat (fd, &st)) | ||
| 195 | return NULL; | ||
| 196 | if (!S_ISDIR (st.st_mode)) | ||
| 197 | { | ||
| 198 | errno = ENOTDIR; | ||
| 199 | return NULL; | ||
| 200 | } | ||
| 201 | return fdopendir (fd); | ||
| 202 | } | ||
| 203 | |||
| 204 | #endif /* HAVE_FDOPENDIR */ | ||
diff --git a/lib/fstatat.c b/lib/fstatat.c new file mode 100644 index 00000000000..845c171fb45 --- /dev/null +++ b/lib/fstatat.c | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | /* Work around an fstatat bug on Solaris 9. | ||
| 2 | |||
| 3 | Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert and Jim Meyering. */ | ||
| 19 | |||
| 20 | /* If the user's config.h happens to include <sys/stat.h>, let it include only | ||
| 21 | the system's <sys/stat.h> here, so that orig_fstatat doesn't recurse to | ||
| 22 | rpl_fstatat. */ | ||
| 23 | #define __need_system_sys_stat_h | ||
| 24 | #include <config.h> | ||
| 25 | |||
| 26 | /* Get the original definition of fstatat. It might be defined as a macro. */ | ||
| 27 | #include <sys/types.h> | ||
| 28 | #include <sys/stat.h> | ||
| 29 | #undef __need_system_sys_stat_h | ||
| 30 | |||
| 31 | #if HAVE_FSTATAT | ||
| 32 | static int | ||
| 33 | orig_fstatat (int fd, char const *filename, struct stat *buf, int flags) | ||
| 34 | { | ||
| 35 | return fstatat (fd, filename, buf, flags); | ||
| 36 | } | ||
| 37 | #endif | ||
| 38 | |||
| 39 | /* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc | ||
| 40 | eliminates this include because of the preliminary #include <sys/stat.h> | ||
| 41 | above. */ | ||
| 42 | #include "sys/stat.h" | ||
| 43 | |||
| 44 | #include <errno.h> | ||
| 45 | #include <fcntl.h> | ||
| 46 | #include <string.h> | ||
| 47 | |||
| 48 | #if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG | ||
| 49 | |||
| 50 | # ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK | ||
| 51 | # define LSTAT_FOLLOWS_SLASHED_SYMLINK 0 | ||
| 52 | # endif | ||
| 53 | |||
| 54 | /* fstatat should always follow symbolic links that end in /, but on | ||
| 55 | Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified. | ||
| 56 | Likewise, trailing slash on a non-directory should be an error. | ||
| 57 | These are the same problems that lstat.c and stat.c address, so | ||
| 58 | solve it in a similar way. | ||
| 59 | |||
| 60 | AIX 7.1 fstatat (AT_FDCWD, ..., 0) always fails, which is a bug. | ||
| 61 | Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero. */ | ||
| 62 | |||
| 63 | int | ||
| 64 | rpl_fstatat (int fd, char const *file, struct stat *st, int flag) | ||
| 65 | { | ||
| 66 | int result = orig_fstatat (fd, file, st, flag); | ||
| 67 | size_t len; | ||
| 68 | |||
| 69 | if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0) | ||
| 70 | return result; | ||
| 71 | len = strlen (file); | ||
| 72 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
| 73 | { | ||
| 74 | /* Fix lstat behavior. */ | ||
| 75 | if (file[len - 1] != '/' || S_ISDIR (st->st_mode)) | ||
| 76 | return 0; | ||
| 77 | if (!S_ISLNK (st->st_mode)) | ||
| 78 | { | ||
| 79 | errno = ENOTDIR; | ||
| 80 | return -1; | ||
| 81 | } | ||
| 82 | result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); | ||
| 83 | } | ||
| 84 | /* Fix stat behavior. */ | ||
| 85 | if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/') | ||
| 86 | { | ||
| 87 | errno = ENOTDIR; | ||
| 88 | return -1; | ||
| 89 | } | ||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 93 | #else /* ! (HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG) */ | ||
| 94 | |||
| 95 | /* On mingw, the gnulib <sys/stat.h> defines 'stat' as a function-like | ||
| 96 | macro; but using it in AT_FUNC_F2 causes compilation failure | ||
| 97 | because the preprocessor sees a use of a macro that requires two | ||
| 98 | arguments but is only given one. Hence, we need an inline | ||
| 99 | forwarder to get past the preprocessor. */ | ||
| 100 | static int | ||
| 101 | stat_func (char const *name, struct stat *st) | ||
| 102 | { | ||
| 103 | return stat (name, st); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* Likewise, if there is no native 'lstat', then the gnulib | ||
| 107 | <sys/stat.h> defined it as stat, which also needs adjustment. */ | ||
| 108 | # if !HAVE_LSTAT | ||
| 109 | # undef lstat | ||
| 110 | # define lstat stat_func | ||
| 111 | # endif | ||
| 112 | |||
| 113 | /* Replacement for Solaris' function by the same name. | ||
| 114 | <http://www.google.com/search?q=fstatat+site:docs.sun.com> | ||
| 115 | First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE"). | ||
| 116 | Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd. | ||
| 117 | If either the save_cwd or the restore_cwd fails (relatively unlikely), | ||
| 118 | then give a diagnostic and exit nonzero. | ||
| 119 | Otherwise, this function works just like Solaris' fstatat. */ | ||
| 120 | |||
| 121 | # define AT_FUNC_NAME fstatat | ||
| 122 | # define AT_FUNC_F1 lstat | ||
| 123 | # define AT_FUNC_F2 stat_func | ||
| 124 | # define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW | ||
| 125 | # define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag | ||
| 126 | # define AT_FUNC_POST_FILE_ARGS , st | ||
| 127 | # include "at-func.c" | ||
| 128 | # undef AT_FUNC_NAME | ||
| 129 | # undef AT_FUNC_F1 | ||
| 130 | # undef AT_FUNC_F2 | ||
| 131 | # undef AT_FUNC_USE_F1_COND | ||
| 132 | # undef AT_FUNC_POST_FILE_PARAM_DECLS | ||
| 133 | # undef AT_FUNC_POST_FILE_ARGS | ||
| 134 | |||
| 135 | #endif /* !HAVE_FSTATAT */ | ||
diff --git a/lib/gnulib.mk b/lib/gnulib.mk index 2347d84448d..89317fd2088 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | # the same distribution terms as the rest of that program. | 21 | # the same distribution terms as the rest of that program. |
| 22 | # | 22 | # |
| 23 | # Generated by gnulib-tool. | 23 | # Generated by gnulib-tool. |
| 24 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=at-internal --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=openat-h --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask putenv readlink sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings | 24 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask putenv readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -64,6 +64,17 @@ EXTRA_DIST += allocator.h | |||
| 64 | 64 | ||
| 65 | ## end gnulib module allocator | 65 | ## end gnulib module allocator |
| 66 | 66 | ||
| 67 | ## begin gnulib module at-internal | ||
| 68 | |||
| 69 | if gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b | ||
| 70 | |||
| 71 | endif | ||
| 72 | EXTRA_DIST += openat-priv.h openat-proc.c | ||
| 73 | |||
| 74 | EXTRA_libgnu_a_SOURCES += openat-proc.c | ||
| 75 | |||
| 76 | ## end gnulib module at-internal | ||
| 77 | |||
| 67 | ## begin gnulib module c-ctype | 78 | ## begin gnulib module c-ctype |
| 68 | 79 | ||
| 69 | libgnu_a_SOURCES += c-ctype.h c-ctype.c | 80 | libgnu_a_SOURCES += c-ctype.h c-ctype.c |
| @@ -124,6 +135,54 @@ EXTRA_DIST += sha512.h | |||
| 124 | 135 | ||
| 125 | ## end gnulib module crypto/sha512 | 136 | ## end gnulib module crypto/sha512 |
| 126 | 137 | ||
| 138 | ## begin gnulib module dirent | ||
| 139 | |||
| 140 | BUILT_SOURCES += dirent.h | ||
| 141 | |||
| 142 | # We need the following in order to create <dirent.h> when the system | ||
| 143 | # doesn't have one that works with the given compiler. | ||
| 144 | dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) | ||
| 145 | $(AM_V_GEN)rm -f $@-t $@ && \ | ||
| 146 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
| 147 | sed -e 's|@''GUARD_PREFIX''@|GL|g' \ | ||
| 148 | -e 's|@''HAVE_DIRENT_H''@|$(HAVE_DIRENT_H)|g' \ | ||
| 149 | -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ | ||
| 150 | -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ | ||
| 151 | -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ | ||
| 152 | -e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \ | ||
| 153 | -e 's/@''GNULIB_OPENDIR''@/$(GNULIB_OPENDIR)/g' \ | ||
| 154 | -e 's/@''GNULIB_READDIR''@/$(GNULIB_READDIR)/g' \ | ||
| 155 | -e 's/@''GNULIB_REWINDDIR''@/$(GNULIB_REWINDDIR)/g' \ | ||
| 156 | -e 's/@''GNULIB_CLOSEDIR''@/$(GNULIB_CLOSEDIR)/g' \ | ||
| 157 | -e 's/@''GNULIB_DIRFD''@/$(GNULIB_DIRFD)/g' \ | ||
| 158 | -e 's/@''GNULIB_FDOPENDIR''@/$(GNULIB_FDOPENDIR)/g' \ | ||
| 159 | -e 's/@''GNULIB_SCANDIR''@/$(GNULIB_SCANDIR)/g' \ | ||
| 160 | -e 's/@''GNULIB_ALPHASORT''@/$(GNULIB_ALPHASORT)/g' \ | ||
| 161 | -e 's/@''HAVE_OPENDIR''@/$(HAVE_OPENDIR)/g' \ | ||
| 162 | -e 's/@''HAVE_READDIR''@/$(HAVE_READDIR)/g' \ | ||
| 163 | -e 's/@''HAVE_REWINDDIR''@/$(HAVE_REWINDDIR)/g' \ | ||
| 164 | -e 's/@''HAVE_CLOSEDIR''@/$(HAVE_CLOSEDIR)/g' \ | ||
| 165 | -e 's|@''HAVE_DECL_DIRFD''@|$(HAVE_DECL_DIRFD)|g' \ | ||
| 166 | -e 's|@''HAVE_DECL_FDOPENDIR''@|$(HAVE_DECL_FDOPENDIR)|g' \ | ||
| 167 | -e 's|@''HAVE_FDOPENDIR''@|$(HAVE_FDOPENDIR)|g' \ | ||
| 168 | -e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \ | ||
| 169 | -e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \ | ||
| 170 | -e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \ | ||
| 171 | -e 's|@''REPLACE_CLOSEDIR''@|$(REPLACE_CLOSEDIR)|g' \ | ||
| 172 | -e 's|@''REPLACE_DIRFD''@|$(REPLACE_DIRFD)|g' \ | ||
| 173 | -e 's|@''REPLACE_FDOPENDIR''@|$(REPLACE_FDOPENDIR)|g' \ | ||
| 174 | -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ | ||
| 175 | -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ | ||
| 176 | -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ | ||
| 177 | < $(srcdir)/dirent.in.h; \ | ||
| 178 | } > $@-t && \ | ||
| 179 | mv $@-t $@ | ||
| 180 | MOSTLYCLEANFILES += dirent.h dirent.h-t | ||
| 181 | |||
| 182 | EXTRA_DIST += dirent.in.h | ||
| 183 | |||
| 184 | ## end gnulib module dirent | ||
| 185 | |||
| 127 | ## begin gnulib module dosname | 186 | ## begin gnulib module dosname |
| 128 | 187 | ||
| 129 | if gl_GNULIB_ENABLED_dosname | 188 | if gl_GNULIB_ENABLED_dosname |
| @@ -238,6 +297,15 @@ EXTRA_DIST += fcntl.in.h | |||
| 238 | 297 | ||
| 239 | ## end gnulib module fcntl-h | 298 | ## end gnulib module fcntl-h |
| 240 | 299 | ||
| 300 | ## begin gnulib module fdopendir | ||
| 301 | |||
| 302 | |||
| 303 | EXTRA_DIST += fdopendir.c | ||
| 304 | |||
| 305 | EXTRA_libgnu_a_SOURCES += fdopendir.c | ||
| 306 | |||
| 307 | ## end gnulib module fdopendir | ||
| 308 | |||
| 241 | ## begin gnulib module filemode | 309 | ## begin gnulib module filemode |
| 242 | 310 | ||
| 243 | libgnu_a_SOURCES += filemode.c | 311 | libgnu_a_SOURCES += filemode.c |
| @@ -255,6 +323,15 @@ EXTRA_libgnu_a_SOURCES += fpending.c | |||
| 255 | 323 | ||
| 256 | ## end gnulib module fpending | 324 | ## end gnulib module fpending |
| 257 | 325 | ||
| 326 | ## begin gnulib module fstatat | ||
| 327 | |||
| 328 | |||
| 329 | EXTRA_DIST += at-func.c fstatat.c | ||
| 330 | |||
| 331 | EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c | ||
| 332 | |||
| 333 | ## end gnulib module fstatat | ||
| 334 | |||
| 258 | ## begin gnulib module getgroups | 335 | ## begin gnulib module getgroups |
| 259 | 336 | ||
| 260 | if gl_GNULIB_ENABLED_getgroups | 337 | if gl_GNULIB_ENABLED_getgroups |
| @@ -412,6 +489,15 @@ EXTRA_libgnu_a_SOURCES += mktime.c | |||
| 412 | 489 | ||
| 413 | ## end gnulib module mktime | 490 | ## end gnulib module mktime |
| 414 | 491 | ||
| 492 | ## begin gnulib module openat-h | ||
| 493 | |||
| 494 | if gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7 | ||
| 495 | |||
| 496 | endif | ||
| 497 | EXTRA_DIST += openat.h | ||
| 498 | |||
| 499 | ## end gnulib module openat-h | ||
| 500 | |||
| 415 | ## begin gnulib module pathmax | 501 | ## begin gnulib module pathmax |
| 416 | 502 | ||
| 417 | if gl_GNULIB_ENABLED_pathmax | 503 | if gl_GNULIB_ENABLED_pathmax |
| @@ -457,6 +543,15 @@ EXTRA_libgnu_a_SOURCES += readlink.c | |||
| 457 | 543 | ||
| 458 | ## end gnulib module readlink | 544 | ## end gnulib module readlink |
| 459 | 545 | ||
| 546 | ## begin gnulib module readlinkat | ||
| 547 | |||
| 548 | |||
| 549 | EXTRA_DIST += at-func.c readlinkat.c | ||
| 550 | |||
| 551 | EXTRA_libgnu_a_SOURCES += at-func.c readlinkat.c | ||
| 552 | |||
| 553 | ## end gnulib module readlinkat | ||
| 554 | |||
| 460 | ## begin gnulib module root-uid | 555 | ## begin gnulib module root-uid |
| 461 | 556 | ||
| 462 | if gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c | 557 | if gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c |
diff --git a/lib/openat-die.c b/lib/openat-die.c new file mode 100644 index 00000000000..f09123ea785 --- /dev/null +++ b/lib/openat-die.c | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | /* Respond to a save- or restore-cwd failure. | ||
| 2 | This should never happen with Emacs. */ | ||
| 3 | #include <config.h> | ||
| 4 | #include "openat.h" | ||
| 5 | void openat_save_fail (int errnum) { abort (); } | ||
| 6 | void openat_restore_fail (int errnum) { abort (); } | ||
diff --git a/lib/openat-priv.h b/lib/openat-priv.h new file mode 100644 index 00000000000..829cf7d0855 --- /dev/null +++ b/lib/openat-priv.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* Internals for openat-like functions. | ||
| 2 | |||
| 3 | Copyright (C) 2005-2006, 2009-2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* written by Jim Meyering */ | ||
| 19 | |||
| 20 | #ifndef _GL_HEADER_OPENAT_PRIV | ||
| 21 | #define _GL_HEADER_OPENAT_PRIV | ||
| 22 | |||
| 23 | #include <errno.h> | ||
| 24 | #include <limits.h> | ||
| 25 | #include <stdlib.h> | ||
| 26 | |||
| 27 | /* Maximum number of bytes that it is safe to allocate as a single | ||
| 28 | array on the stack, and that is known as a compile-time constant. | ||
| 29 | The assumption is that we'll touch the array very quickly, or a | ||
| 30 | temporary very near the array, provoking an out-of-memory trap. On | ||
| 31 | some operating systems, there is only one guard page for the stack, | ||
| 32 | and a page size can be as small as 4096 bytes. Subtract 64 in the | ||
| 33 | hope that this will let the compiler touch a nearby temporary and | ||
| 34 | provoke a trap. */ | ||
| 35 | #define SAFER_ALLOCA_MAX (4096 - 64) | ||
| 36 | |||
| 37 | #define SAFER_ALLOCA(m) ((m) < SAFER_ALLOCA_MAX ? (m) : SAFER_ALLOCA_MAX) | ||
| 38 | |||
| 39 | #if defined PATH_MAX | ||
| 40 | # define OPENAT_BUFFER_SIZE SAFER_ALLOCA (PATH_MAX) | ||
| 41 | #elif defined _XOPEN_PATH_MAX | ||
| 42 | # define OPENAT_BUFFER_SIZE SAFER_ALLOCA (_XOPEN_PATH_MAX) | ||
| 43 | #else | ||
| 44 | # define OPENAT_BUFFER_SIZE SAFER_ALLOCA (1024) | ||
| 45 | #endif | ||
| 46 | |||
| 47 | char *openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file); | ||
| 48 | |||
| 49 | /* Trying to access a BUILD_PROC_NAME file will fail on systems without | ||
| 50 | /proc support, and even on systems *with* ProcFS support. Return | ||
| 51 | nonzero if the failure may be legitimate, e.g., because /proc is not | ||
| 52 | readable, or the particular .../fd/N directory is not present. */ | ||
| 53 | #define EXPECTED_ERRNO(Errno) \ | ||
| 54 | ((Errno) == ENOTDIR || (Errno) == ENOENT \ | ||
| 55 | || (Errno) == EPERM || (Errno) == EACCES \ | ||
| 56 | || (Errno) == ENOSYS /* Solaris 8 */ \ | ||
| 57 | || (Errno) == EOPNOTSUPP /* FreeBSD */) | ||
| 58 | |||
| 59 | /* Wrapper function shared among linkat and renameat. */ | ||
| 60 | int at_func2 (int fd1, char const *file1, | ||
| 61 | int fd2, char const *file2, | ||
| 62 | int (*func) (char const *file1, char const *file2)); | ||
| 63 | |||
| 64 | #endif /* _GL_HEADER_OPENAT_PRIV */ | ||
diff --git a/lib/openat-proc.c b/lib/openat-proc.c new file mode 100644 index 00000000000..d7a68e26d0b --- /dev/null +++ b/lib/openat-proc.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* Create /proc/self/fd-related names for subfiles of open directories. | ||
| 2 | |||
| 3 | Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Written by Paul Eggert. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include "openat-priv.h" | ||
| 23 | |||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/stat.h> | ||
| 26 | #include <fcntl.h> | ||
| 27 | |||
| 28 | #include <stdio.h> | ||
| 29 | #include <stdlib.h> | ||
| 30 | #include <string.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | |||
| 33 | #include "intprops.h" | ||
| 34 | |||
| 35 | /* The results of open() in this file are not used with fchdir, | ||
| 36 | and we do not leak fds to any single-threaded code that could use stdio, | ||
| 37 | therefore save some unnecessary work in fchdir.c. | ||
| 38 | FIXME - if the kernel ever adds support for multi-thread safety for | ||
| 39 | avoiding standard fds, then we should use open_safer. */ | ||
| 40 | #undef open | ||
| 41 | #undef close | ||
| 42 | |||
| 43 | #define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/%s" | ||
| 44 | |||
| 45 | #define PROC_SELF_FD_NAME_SIZE_BOUND(len) \ | ||
| 46 | (sizeof PROC_SELF_FD_FORMAT - sizeof "%d%s" \ | ||
| 47 | + INT_STRLEN_BOUND (int) + (len) + 1) | ||
| 48 | |||
| 49 | |||
| 50 | /* Set BUF to the expansion of PROC_SELF_FD_FORMAT, using FD and FILE | ||
| 51 | respectively for %d and %s. If successful, return BUF if the | ||
| 52 | result fits in BUF, dynamically allocated memory otherwise. But | ||
| 53 | return NULL if /proc is not reliable, either because the operating | ||
| 54 | system support is lacking or because memory is low. */ | ||
| 55 | char * | ||
| 56 | openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file) | ||
| 57 | { | ||
| 58 | static int proc_status = 0; | ||
| 59 | |||
| 60 | /* Make sure the caller gets ENOENT when appropriate. */ | ||
| 61 | if (!*file) | ||
| 62 | { | ||
| 63 | buf[0] = '\0'; | ||
| 64 | return buf; | ||
| 65 | } | ||
| 66 | |||
| 67 | if (! proc_status) | ||
| 68 | { | ||
| 69 | /* Set PROC_STATUS to a positive value if /proc/self/fd is | ||
| 70 | reliable, and a negative value otherwise. Solaris 10 | ||
| 71 | /proc/self/fd mishandles "..", and any file name might expand | ||
| 72 | to ".." after symbolic link expansion, so avoid /proc/self/fd | ||
| 73 | if it mishandles "..". Solaris 10 has openat, but this | ||
| 74 | problem is exhibited on code that built on Solaris 8 and | ||
| 75 | running on Solaris 10. */ | ||
| 76 | |||
| 77 | int proc_self_fd = open ("/proc/self/fd", | ||
| 78 | O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK); | ||
| 79 | if (proc_self_fd < 0) | ||
| 80 | proc_status = -1; | ||
| 81 | else | ||
| 82 | { | ||
| 83 | /* Detect whether /proc/self/fd/%i/../fd exists, where %i is the | ||
| 84 | number of a file descriptor open on /proc/self/fd. On Linux, | ||
| 85 | that name resolves to /proc/self/fd, which was opened above. | ||
| 86 | However, on Solaris, it may resolve to /proc/self/fd/fd, which | ||
| 87 | cannot exist, since all names in /proc/self/fd are numeric. */ | ||
| 88 | char dotdot_buf[PROC_SELF_FD_NAME_SIZE_BOUND (sizeof "../fd" - 1)]; | ||
| 89 | sprintf (dotdot_buf, PROC_SELF_FD_FORMAT, proc_self_fd, "../fd"); | ||
| 90 | proc_status = access (dotdot_buf, F_OK) ? -1 : 1; | ||
| 91 | close (proc_self_fd); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | if (proc_status < 0) | ||
| 96 | return NULL; | ||
| 97 | else | ||
| 98 | { | ||
| 99 | size_t bufsize = PROC_SELF_FD_NAME_SIZE_BOUND (strlen (file)); | ||
| 100 | char *result = buf; | ||
| 101 | if (OPENAT_BUFFER_SIZE < bufsize) | ||
| 102 | { | ||
| 103 | result = malloc (bufsize); | ||
| 104 | if (! result) | ||
| 105 | return NULL; | ||
| 106 | } | ||
| 107 | sprintf (result, PROC_SELF_FD_FORMAT, fd, file); | ||
| 108 | return result; | ||
| 109 | } | ||
| 110 | } | ||
diff --git a/lib/openat.h b/lib/openat.h new file mode 100644 index 00000000000..eb90990da1d --- /dev/null +++ b/lib/openat.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* provide a replacement openat function | ||
| 2 | Copyright (C) 2004-2006, 2008-2013 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | /* written by Jim Meyering */ | ||
| 18 | |||
| 19 | #ifndef _GL_HEADER_OPENAT | ||
| 20 | #define _GL_HEADER_OPENAT | ||
| 21 | |||
| 22 | #include <fcntl.h> | ||
| 23 | |||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/stat.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | #include <stdbool.h> | ||
| 28 | |||
| 29 | _GL_INLINE_HEADER_BEGIN | ||
| 30 | |||
| 31 | #if !HAVE_OPENAT | ||
| 32 | |||
| 33 | int openat_permissive (int fd, char const *file, int flags, mode_t mode, | ||
| 34 | int *cwd_errno); | ||
| 35 | bool openat_needs_fchdir (void); | ||
| 36 | |||
| 37 | #else | ||
| 38 | |||
| 39 | # define openat_permissive(Fd, File, Flags, Mode, Cwd_errno) \ | ||
| 40 | openat (Fd, File, Flags, Mode) | ||
| 41 | # define openat_needs_fchdir() false | ||
| 42 | |||
| 43 | #endif | ||
| 44 | |||
| 45 | _Noreturn void openat_restore_fail (int); | ||
| 46 | _Noreturn void openat_save_fail (int); | ||
| 47 | |||
| 48 | /* Using these function names makes application code | ||
| 49 | slightly more readable than it would be with | ||
| 50 | fchownat (..., 0) or fchownat (..., AT_SYMLINK_NOFOLLOW). */ | ||
| 51 | |||
| 52 | #if GNULIB_FCHOWNAT | ||
| 53 | |||
| 54 | # ifndef FCHOWNAT_INLINE | ||
| 55 | # define FCHOWNAT_INLINE _GL_INLINE | ||
| 56 | # endif | ||
| 57 | |||
| 58 | FCHOWNAT_INLINE int | ||
| 59 | chownat (int fd, char const *file, uid_t owner, gid_t group) | ||
| 60 | { | ||
| 61 | return fchownat (fd, file, owner, group, 0); | ||
| 62 | } | ||
| 63 | |||
| 64 | FCHOWNAT_INLINE int | ||
| 65 | lchownat (int fd, char const *file, uid_t owner, gid_t group) | ||
| 66 | { | ||
| 67 | return fchownat (fd, file, owner, group, AT_SYMLINK_NOFOLLOW); | ||
| 68 | } | ||
| 69 | |||
| 70 | #endif | ||
| 71 | |||
| 72 | #if GNULIB_FCHMODAT | ||
| 73 | |||
| 74 | # ifndef FCHMODAT_INLINE | ||
| 75 | # define FCHMODAT_INLINE _GL_INLINE | ||
| 76 | # endif | ||
| 77 | |||
| 78 | FCHMODAT_INLINE int | ||
| 79 | chmodat (int fd, char const *file, mode_t mode) | ||
| 80 | { | ||
| 81 | return fchmodat (fd, file, mode, 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | FCHMODAT_INLINE int | ||
| 85 | lchmodat (int fd, char const *file, mode_t mode) | ||
| 86 | { | ||
| 87 | return fchmodat (fd, file, mode, AT_SYMLINK_NOFOLLOW); | ||
| 88 | } | ||
| 89 | |||
| 90 | #endif | ||
| 91 | |||
| 92 | #if GNULIB_STATAT | ||
| 93 | |||
| 94 | # ifndef STATAT_INLINE | ||
| 95 | # define STATAT_INLINE _GL_INLINE | ||
| 96 | # endif | ||
| 97 | |||
| 98 | STATAT_INLINE int | ||
| 99 | statat (int fd, char const *name, struct stat *st) | ||
| 100 | { | ||
| 101 | return fstatat (fd, name, st, 0); | ||
| 102 | } | ||
| 103 | |||
| 104 | STATAT_INLINE int | ||
| 105 | lstatat (int fd, char const *name, struct stat *st) | ||
| 106 | { | ||
| 107 | return fstatat (fd, name, st, AT_SYMLINK_NOFOLLOW); | ||
| 108 | } | ||
| 109 | |||
| 110 | #endif | ||
| 111 | |||
| 112 | /* For now, there are no wrappers named laccessat or leuidaccessat, | ||
| 113 | since gnulib doesn't support faccessat(,AT_SYMLINK_NOFOLLOW) and | ||
| 114 | since access rights on symlinks are of limited utility. Likewise, | ||
| 115 | wrappers are not provided for accessat or euidaccessat, so as to | ||
| 116 | avoid dragging in -lgen on some platforms. */ | ||
| 117 | |||
| 118 | _GL_INLINE_HEADER_END | ||
| 119 | |||
| 120 | #endif /* _GL_HEADER_OPENAT */ | ||
diff --git a/lib/readlinkat.c b/lib/readlinkat.c new file mode 100644 index 00000000000..504e6ebbc49 --- /dev/null +++ b/lib/readlinkat.c | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* Read a symlink relative to an open directory. | ||
| 2 | Copyright (C) 2009-2013 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 3 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 16 | |||
| 17 | /* written by Eric Blake */ | ||
| 18 | |||
| 19 | #include <config.h> | ||
| 20 | |||
| 21 | #include <unistd.h> | ||
| 22 | |||
| 23 | /* Gnulib provides a readlink stub for mingw; use it for distinction | ||
| 24 | between EINVAL and ENOENT, rather than always failing with ENOSYS. */ | ||
| 25 | |||
| 26 | /* POSIX 2008 says that unlike readlink, readlinkat returns 0 for | ||
| 27 | success instead of the buffer length. But this would render | ||
| 28 | readlinkat worthless since readlink does not guarantee a | ||
| 29 | NUL-terminated buffer. Assume this was a bug in POSIX. */ | ||
| 30 | |||
| 31 | /* Read the contents of symlink FILE into buffer BUF of size LEN, in the | ||
| 32 | directory open on descriptor FD. If possible, do it without changing | ||
| 33 | the working directory. Otherwise, resort to using save_cwd/fchdir, | ||
| 34 | then readlink/restore_cwd. If either the save_cwd or the restore_cwd | ||
| 35 | fails, then give a diagnostic and exit nonzero. */ | ||
| 36 | |||
| 37 | #define AT_FUNC_NAME readlinkat | ||
| 38 | #define AT_FUNC_F1 readlink | ||
| 39 | #define AT_FUNC_POST_FILE_PARAM_DECLS , char *buf, size_t len | ||
| 40 | #define AT_FUNC_POST_FILE_ARGS , buf, len | ||
| 41 | #define AT_FUNC_RESULT ssize_t | ||
| 42 | #include "at-func.c" | ||
| 43 | #undef AT_FUNC_NAME | ||
| 44 | #undef AT_FUNC_F1 | ||
| 45 | #undef AT_FUNC_POST_FILE_PARAM_DECLS | ||
| 46 | #undef AT_FUNC_POST_FILE_ARGS | ||
| 47 | #undef AT_FUNC_RESULT | ||
diff --git a/lib/save-cwd.c b/lib/save-cwd.c new file mode 100644 index 00000000000..b8dae34ca02 --- /dev/null +++ b/lib/save-cwd.c | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #include <config.h> | ||
| 2 | #define SAVE_CWD_INLINE _GL_EXTERN_INLINE | ||
| 3 | #include "save-cwd.h" | ||
diff --git a/lib/save-cwd.h b/lib/save-cwd.h new file mode 100644 index 00000000000..bd0cd8d5707 --- /dev/null +++ b/lib/save-cwd.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* Do not save and restore the current working directory. | ||
| 2 | |||
| 3 | Copyright 2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Gnulib needs to save and restore the current working directory to | ||
| 19 | fully emulate functions like fstatat. But Emacs doesn't care what | ||
| 20 | the current working directory is; it always uses absolute file | ||
| 21 | names. This module replaces the Gnulib module by omitting the code | ||
| 22 | that Emacs does not need. */ | ||
| 23 | |||
| 24 | #ifndef SAVE_CWD_H | ||
| 25 | #define SAVE_CWD_H 1 | ||
| 26 | |||
| 27 | _GL_INLINE_HEADER_BEGIN | ||
| 28 | #ifndef SAVE_CWD_INLINE | ||
| 29 | # define SAVE_CWD_INLINE _GL_INLINE | ||
| 30 | #endif | ||
| 31 | |||
| 32 | struct saved_cwd { int desc; }; | ||
| 33 | |||
| 34 | SAVE_CWD_INLINE int | ||
| 35 | save_cwd (struct saved_cwd *cwd) | ||
| 36 | { | ||
| 37 | cwd->desc = -1; | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | SAVE_CWD_INLINE int restore_cwd (struct saved_cwd const *cwd) { return 0; } | ||
| 42 | SAVE_CWD_INLINE void free_cwd (struct saved_cwd *cwd) { } | ||
| 43 | |||
| 44 | _GL_INLINE_HEADER_END | ||
| 45 | |||
| 46 | #endif | ||