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 | |
| 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
| -rw-r--r-- | ChangeLog | 20 | ||||
| -rw-r--r-- | admin/ChangeLog | 7 | ||||
| -rwxr-xr-x | admin/merge-gnulib | 8 | ||||
| -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 | ||||
| -rw-r--r-- | m4/dirent_h.m4 | 64 | ||||
| -rw-r--r-- | m4/fdopendir.m4 | 61 | ||||
| -rw-r--r-- | m4/fstatat.m4 | 60 | ||||
| -rw-r--r-- | m4/gnulib-comp.m4 | 78 | ||||
| -rw-r--r-- | m4/readlinkat.m4 | 19 | ||||
| -rw-r--r-- | nt/ChangeLog | 6 | ||||
| -rw-r--r-- | nt/inc/sys/stat.h | 3 | ||||
| -rw-r--r-- | nt/inc/unistd.h | 1 | ||||
| -rw-r--r-- | src/ChangeLog | 31 | ||||
| -rw-r--r-- | src/conf_post.h | 4 | ||||
| -rw-r--r-- | src/dired.c | 120 | ||||
| -rw-r--r-- | src/fileio.c | 40 | ||||
| -rw-r--r-- | src/filelock.c | 18 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/sysdep.c | 18 | ||||
| -rw-r--r-- | src/w32.c | 60 |
33 files changed, 1595 insertions, 140 deletions
| @@ -1,3 +1,23 @@ | |||
| 1 | 2013-02-01 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539). | ||
| 4 | On my host, this speeds up directory-files-and-attributes by a | ||
| 5 | factor of 3, when applied to Emacs's src directory. | ||
| 6 | These functions are standardized by POSIX and are common these | ||
| 7 | days; fall back on a (slower) gnulib implementation if the host | ||
| 8 | is too old to supply them. | ||
| 9 | * .bzrignore: Add lib/dirent.h. | ||
| 10 | * lib/Makefile.am (libgnu_a_SOURCES): Add openat-die.c, save-cwd.c. | ||
| 11 | * lib/careadlinkat.c, lib/careadlinkat.h: Merge from gnulib, | ||
| 12 | incorporating: 2013-01-29 careadlinkat: do not provide careadlinkatcwd. | ||
| 13 | * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. | ||
| 14 | * lib/dirent.in.h, lib/fdopendir.c, lib/fstatat.c, lib/openat-priv.h: | ||
| 15 | * lib/openat-proc.c, lib/openat.h, m4/dirent_h.m4, m4/fdopendir.m4: | ||
| 16 | * m4/fstatat.m4: New files, from gnulib. | ||
| 17 | * lib/openat-die.c, lib/save-cwd.c, lib/save-cwd.h: New files. | ||
| 18 | These last three are specific to Emacs and are not copied from gnulib. | ||
| 19 | They are simpler than the gnulib versions and are tuned for Emacs. | ||
| 20 | |||
| 1 | 2013-02-01 Glenn Morris <rgm@gnu.org> | 21 | 2013-02-01 Glenn Morris <rgm@gnu.org> |
| 2 | 22 | ||
| 3 | * make-dist: Only README files exist in lisp/ now, not README*. | 23 | * make-dist: Only README files exist in lisp/ now, not README*. |
diff --git a/admin/ChangeLog b/admin/ChangeLog index 5da0bf0c67d..76ac11446a3 100644 --- a/admin/ChangeLog +++ b/admin/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2013-02-01 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539). | ||
| 4 | * merge-gnulib (GNULIB_MODULES): Add fdopendir, fstatat, readlinkat. | ||
| 5 | (GNULIB_TOOL_FLAGS): Do not avoid at-internal, openat-h. | ||
| 6 | Avoid dup, open, opendir. | ||
| 7 | |||
| 1 | 2013-01-15 Dmitry Antipov <dmantipov@yandex.ru> | 8 | 2013-01-15 Dmitry Antipov <dmantipov@yandex.ru> |
| 2 | 9 | ||
| 3 | * coccinelle/xsave.cocci: Semantic patch to adjust users of | 10 | * coccinelle/xsave.cocci: Semantic patch to adjust users of |
diff --git a/admin/merge-gnulib b/admin/merge-gnulib index f3509d98b85..e90e2e23b29 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib | |||
| @@ -29,9 +29,9 @@ GNULIB_MODULES=' | |||
| 29 | alloca-opt c-ctype c-strcase | 29 | alloca-opt c-ctype c-strcase |
| 30 | careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 | 30 | careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 |
| 31 | dtoastr dtotimespec dup2 environ execinfo faccessat | 31 | dtoastr dtotimespec dup2 environ execinfo faccessat |
| 32 | fcntl-h filemode getloadavg getopt-gnu gettime gettimeofday | 32 | fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday |
| 33 | ignore-value intprops largefile lstat | 33 | ignore-value intprops largefile lstat |
| 34 | manywarnings mktime pselect pthread_sigmask putenv readlink | 34 | manywarnings mktime pselect pthread_sigmask putenv readlink readlinkat |
| 35 | sig2str socklen stat-time stdalign stdarg stdbool stdio | 35 | sig2str socklen stat-time stdalign stdarg stdbool stdio |
| 36 | strftime strtoimax strtoumax symlink sys_stat | 36 | strftime strtoimax strtoumax symlink sys_stat |
| 37 | sys_time time timer-time timespec-add timespec-sub unsetenv utimens | 37 | sys_time time timer-time timespec-add timespec-sub unsetenv utimens |
| @@ -39,10 +39,10 @@ GNULIB_MODULES=' | |||
| 39 | ' | 39 | ' |
| 40 | 40 | ||
| 41 | GNULIB_TOOL_FLAGS=' | 41 | GNULIB_TOOL_FLAGS=' |
| 42 | --avoid=at-internal | 42 | --avoid=dup |
| 43 | --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat | 43 | --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat |
| 44 | --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow | 44 | --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow |
| 45 | --avoid=openat-die --avoid=openat-h | 45 | --avoid=open --avoid=openat-die --avoid=opendir |
| 46 | --avoid=raise | 46 | --avoid=raise |
| 47 | --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types | 47 | --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types |
| 48 | --avoid=threadlib | 48 | --avoid=threadlib |
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 | ||
diff --git a/m4/dirent_h.m4 b/m4/dirent_h.m4 new file mode 100644 index 00000000000..54c16634314 --- /dev/null +++ b/m4/dirent_h.m4 | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | # dirent_h.m4 serial 16 | ||
| 2 | dnl Copyright (C) 2008-2013 Free Software Foundation, Inc. | ||
| 3 | dnl This file is free software; the Free Software Foundation | ||
| 4 | dnl gives unlimited permission to copy and/or distribute it, | ||
| 5 | dnl with or without modifications, as long as this notice is preserved. | ||
| 6 | |||
| 7 | dnl Written by Bruno Haible. | ||
| 8 | |||
| 9 | AC_DEFUN([gl_DIRENT_H], | ||
| 10 | [ | ||
| 11 | dnl Use AC_REQUIRE here, so that the default behavior below is expanded | ||
| 12 | dnl once only, before all statements that occur in other macros. | ||
| 13 | AC_REQUIRE([gl_DIRENT_H_DEFAULTS]) | ||
| 14 | |||
| 15 | dnl <dirent.h> is always overridden, because of GNULIB_POSIXCHECK. | ||
| 16 | gl_CHECK_NEXT_HEADERS([dirent.h]) | ||
| 17 | if test $ac_cv_header_dirent_h = yes; then | ||
| 18 | HAVE_DIRENT_H=1 | ||
| 19 | else | ||
| 20 | HAVE_DIRENT_H=0 | ||
| 21 | fi | ||
| 22 | AC_SUBST([HAVE_DIRENT_H]) | ||
| 23 | |||
| 24 | dnl Check for declarations of anything we want to poison if the | ||
| 25 | dnl corresponding gnulib module is not in use. | ||
| 26 | gl_WARN_ON_USE_PREPARE([[#include <dirent.h> | ||
| 27 | ]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir]) | ||
| 28 | ]) | ||
| 29 | |||
| 30 | AC_DEFUN([gl_DIRENT_MODULE_INDICATOR], | ||
| 31 | [ | ||
| 32 | dnl Use AC_REQUIRE here, so that the default settings are expanded once only. | ||
| 33 | AC_REQUIRE([gl_DIRENT_H_DEFAULTS]) | ||
| 34 | gl_MODULE_INDICATOR_SET_VARIABLE([$1]) | ||
| 35 | dnl Define it also as a C macro, for the benefit of the unit tests. | ||
| 36 | gl_MODULE_INDICATOR_FOR_TESTS([$1]) | ||
| 37 | ]) | ||
| 38 | |||
| 39 | AC_DEFUN([gl_DIRENT_H_DEFAULTS], | ||
| 40 | [ | ||
| 41 | AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR | ||
| 42 | GNULIB_OPENDIR=0; AC_SUBST([GNULIB_OPENDIR]) | ||
| 43 | GNULIB_READDIR=0; AC_SUBST([GNULIB_READDIR]) | ||
| 44 | GNULIB_REWINDDIR=0; AC_SUBST([GNULIB_REWINDDIR]) | ||
| 45 | GNULIB_CLOSEDIR=0; AC_SUBST([GNULIB_CLOSEDIR]) | ||
| 46 | GNULIB_DIRFD=0; AC_SUBST([GNULIB_DIRFD]) | ||
| 47 | GNULIB_FDOPENDIR=0; AC_SUBST([GNULIB_FDOPENDIR]) | ||
| 48 | GNULIB_SCANDIR=0; AC_SUBST([GNULIB_SCANDIR]) | ||
| 49 | GNULIB_ALPHASORT=0; AC_SUBST([GNULIB_ALPHASORT]) | ||
| 50 | dnl Assume proper GNU behavior unless another module says otherwise. | ||
| 51 | HAVE_OPENDIR=1; AC_SUBST([HAVE_OPENDIR]) | ||
| 52 | HAVE_READDIR=1; AC_SUBST([HAVE_READDIR]) | ||
| 53 | HAVE_REWINDDIR=1; AC_SUBST([HAVE_REWINDDIR]) | ||
| 54 | HAVE_CLOSEDIR=1; AC_SUBST([HAVE_CLOSEDIR]) | ||
| 55 | HAVE_DECL_DIRFD=1; AC_SUBST([HAVE_DECL_DIRFD]) | ||
| 56 | HAVE_DECL_FDOPENDIR=1;AC_SUBST([HAVE_DECL_FDOPENDIR]) | ||
| 57 | HAVE_FDOPENDIR=1; AC_SUBST([HAVE_FDOPENDIR]) | ||
| 58 | HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR]) | ||
| 59 | HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT]) | ||
| 60 | REPLACE_OPENDIR=0; AC_SUBST([REPLACE_OPENDIR]) | ||
| 61 | REPLACE_CLOSEDIR=0; AC_SUBST([REPLACE_CLOSEDIR]) | ||
| 62 | REPLACE_DIRFD=0; AC_SUBST([REPLACE_DIRFD]) | ||
| 63 | REPLACE_FDOPENDIR=0; AC_SUBST([REPLACE_FDOPENDIR]) | ||
| 64 | ]) | ||
diff --git a/m4/fdopendir.m4 b/m4/fdopendir.m4 new file mode 100644 index 00000000000..b7be78324dc --- /dev/null +++ b/m4/fdopendir.m4 | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | # serial 10 | ||
| 2 | # See if we need to provide fdopendir. | ||
| 3 | |||
| 4 | dnl Copyright (C) 2009-2013 Free Software Foundation, Inc. | ||
| 5 | dnl This file is free software; the Free Software Foundation | ||
| 6 | dnl gives unlimited permission to copy and/or distribute it, | ||
| 7 | dnl with or without modifications, as long as this notice is preserved. | ||
| 8 | |||
| 9 | # Written by Eric Blake. | ||
| 10 | |||
| 11 | AC_DEFUN([gl_FUNC_FDOPENDIR], | ||
| 12 | [ | ||
| 13 | AC_REQUIRE([gl_DIRENT_H_DEFAULTS]) | ||
| 14 | AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles | ||
| 15 | |||
| 16 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
| 17 | |||
| 18 | dnl FreeBSD 7.3 has the function, but failed to declare it. | ||
| 19 | AC_CHECK_DECLS([fdopendir], [], [HAVE_DECL_FDOPENDIR=0], [[ | ||
| 20 | #include <dirent.h> | ||
| 21 | ]]) | ||
| 22 | AC_CHECK_FUNCS_ONCE([fdopendir]) | ||
| 23 | if test $ac_cv_func_fdopendir = no; then | ||
| 24 | HAVE_FDOPENDIR=0 | ||
| 25 | else | ||
| 26 | AC_CACHE_CHECK([whether fdopendir works], | ||
| 27 | [gl_cv_func_fdopendir_works], | ||
| 28 | [AC_RUN_IFELSE([AC_LANG_PROGRAM([[ | ||
| 29 | #include <dirent.h> | ||
| 30 | #include <fcntl.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | #if !HAVE_DECL_FDOPENDIR | ||
| 33 | extern | ||
| 34 | # ifdef __cplusplus | ||
| 35 | "C" | ||
| 36 | # endif | ||
| 37 | DIR *fdopendir (int); | ||
| 38 | #endif | ||
| 39 | ]], [int result = 0; | ||
| 40 | int fd = open ("conftest.c", O_RDONLY); | ||
| 41 | if (fd < 0) result |= 1; | ||
| 42 | if (fdopendir (fd)) result |= 2; | ||
| 43 | if (close (fd)) result |= 4; | ||
| 44 | return result;])], | ||
| 45 | [gl_cv_func_fdopendir_works=yes], | ||
| 46 | [gl_cv_func_fdopendir_works=no], | ||
| 47 | [case "$host_os" in | ||
| 48 | # Guess yes on glibc systems. | ||
| 49 | *-gnu*) gl_cv_func_fdopendir_works="guessing yes" ;; | ||
| 50 | # If we don't know, assume the worst. | ||
| 51 | *) gl_cv_func_fdopendir_works="guessing no" ;; | ||
| 52 | esac | ||
| 53 | ])]) | ||
| 54 | case "$gl_cv_func_fdopendir_works" in | ||
| 55 | *yes) ;; | ||
| 56 | *) | ||
| 57 | REPLACE_FDOPENDIR=1 | ||
| 58 | ;; | ||
| 59 | esac | ||
| 60 | fi | ||
| 61 | ]) | ||
diff --git a/m4/fstatat.m4 b/m4/fstatat.m4 new file mode 100644 index 00000000000..adbc7e57f51 --- /dev/null +++ b/m4/fstatat.m4 | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | # fstatat.m4 serial 3 | ||
| 2 | dnl Copyright (C) 2004-2013 Free Software Foundation, Inc. | ||
| 3 | dnl This file is free software; the Free Software Foundation | ||
| 4 | dnl gives unlimited permission to copy and/or distribute it, | ||
| 5 | dnl with or without modifications, as long as this notice is preserved. | ||
| 6 | |||
| 7 | # Written by Jim Meyering. | ||
| 8 | |||
| 9 | # If we have the fstatat function, and it has the bug (in AIX 7.1) | ||
| 10 | # that it does not fill in st_size correctly, use the replacement function. | ||
| 11 | AC_DEFUN([gl_FUNC_FSTATAT], | ||
| 12 | [ | ||
| 13 | AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) | ||
| 14 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
| 15 | AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK]) | ||
| 16 | AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles | ||
| 17 | AC_CHECK_FUNCS_ONCE([fstatat]) | ||
| 18 | |||
| 19 | if test $ac_cv_func_fstatat = no; then | ||
| 20 | HAVE_FSTATAT=0 | ||
| 21 | else | ||
| 22 | dnl Test for an AIX 7.1 bug; see | ||
| 23 | dnl <http://lists.gnu.org/archive/html/bug-tar/2011-09/msg00015.html>. | ||
| 24 | AC_CACHE_CHECK([whether fstatat (..., 0) works], | ||
| 25 | [gl_cv_func_fstatat_zero_flag], | ||
| 26 | [AC_RUN_IFELSE( | ||
| 27 | [AC_LANG_SOURCE( | ||
| 28 | [[ | ||
| 29 | #include <fcntl.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | int | ||
| 32 | main (void) | ||
| 33 | { | ||
| 34 | struct stat a; | ||
| 35 | return fstatat (AT_FDCWD, ".", &a, 0) != 0; | ||
| 36 | } | ||
| 37 | ]])], | ||
| 38 | [gl_cv_func_fstatat_zero_flag=yes], | ||
| 39 | [gl_cv_func_fstatat_zero_flag=no], | ||
| 40 | [case "$host_os" in | ||
| 41 | aix*) gl_cv_func_fstatat_zero_flag="guessing no";; | ||
| 42 | *) gl_cv_func_fstatat_zero_flag="guessing yes";; | ||
| 43 | esac | ||
| 44 | ]) | ||
| 45 | ]) | ||
| 46 | |||
| 47 | case $gl_cv_func_fstatat_zero_flag+$gl_cv_func_lstat_dereferences_slashed_symlink in | ||
| 48 | *yes+*yes) ;; | ||
| 49 | *) REPLACE_FSTATAT=1 | ||
| 50 | case $gl_cv_func_fstatat_zero_flag in | ||
| 51 | *yes) | ||
| 52 | AC_DEFINE([HAVE_WORKING_FSTATAT_ZERO_FLAG], [1], | ||
| 53 | [Define to 1 if fstatat (..., 0) works. | ||
| 54 | For example, it does not work in AIX 7.1.]) | ||
| 55 | ;; | ||
| 56 | esac | ||
| 57 | ;; | ||
| 58 | esac | ||
| 59 | fi | ||
| 60 | ]) | ||
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index b7109c5f87f..8098a52e501 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 | |||
| @@ -40,6 +40,7 @@ AC_DEFUN([gl_EARLY], | |||
| 40 | AC_REQUIRE([gl_PROG_AR_RANLIB]) | 40 | AC_REQUIRE([gl_PROG_AR_RANLIB]) |
| 41 | # Code from module alloca-opt: | 41 | # Code from module alloca-opt: |
| 42 | # Code from module allocator: | 42 | # Code from module allocator: |
| 43 | # Code from module at-internal: | ||
| 43 | # Code from module c-ctype: | 44 | # Code from module c-ctype: |
| 44 | # Code from module c-strcase: | 45 | # Code from module c-strcase: |
| 45 | # Code from module careadlinkat: | 46 | # Code from module careadlinkat: |
| @@ -49,6 +50,7 @@ AC_DEFUN([gl_EARLY], | |||
| 49 | # Code from module crypto/sha1: | 50 | # Code from module crypto/sha1: |
| 50 | # Code from module crypto/sha256: | 51 | # Code from module crypto/sha256: |
| 51 | # Code from module crypto/sha512: | 52 | # Code from module crypto/sha512: |
| 53 | # Code from module dirent: | ||
| 52 | # Code from module dosname: | 54 | # Code from module dosname: |
| 53 | # Code from module dtoastr: | 55 | # Code from module dtoastr: |
| 54 | # Code from module dtotimespec: | 56 | # Code from module dtotimespec: |
| @@ -61,8 +63,10 @@ AC_DEFUN([gl_EARLY], | |||
| 61 | # Code from module extern-inline: | 63 | # Code from module extern-inline: |
| 62 | # Code from module faccessat: | 64 | # Code from module faccessat: |
| 63 | # Code from module fcntl-h: | 65 | # Code from module fcntl-h: |
| 66 | # Code from module fdopendir: | ||
| 64 | # Code from module filemode: | 67 | # Code from module filemode: |
| 65 | # Code from module fpending: | 68 | # Code from module fpending: |
| 69 | # Code from module fstatat: | ||
| 66 | # Code from module getgroups: | 70 | # Code from module getgroups: |
| 67 | # Code from module getloadavg: | 71 | # Code from module getloadavg: |
| 68 | # Code from module getopt-gnu: | 72 | # Code from module getopt-gnu: |
| @@ -82,11 +86,13 @@ AC_DEFUN([gl_EARLY], | |||
| 82 | # Code from module mktime: | 86 | # Code from module mktime: |
| 83 | # Code from module multiarch: | 87 | # Code from module multiarch: |
| 84 | # Code from module nocrash: | 88 | # Code from module nocrash: |
| 89 | # Code from module openat-h: | ||
| 85 | # Code from module pathmax: | 90 | # Code from module pathmax: |
| 86 | # Code from module pselect: | 91 | # Code from module pselect: |
| 87 | # Code from module pthread_sigmask: | 92 | # Code from module pthread_sigmask: |
| 88 | # Code from module putenv: | 93 | # Code from module putenv: |
| 89 | # Code from module readlink: | 94 | # Code from module readlink: |
| 95 | # Code from module readlinkat: | ||
| 90 | # Code from module root-uid: | 96 | # Code from module root-uid: |
| 91 | # Code from module sig2str: | 97 | # Code from module sig2str: |
| 92 | # Code from module signal-h: | 98 | # Code from module signal-h: |
| @@ -159,6 +165,7 @@ AC_DEFUN([gl_INIT], | |||
| 159 | gl_SHA1 | 165 | gl_SHA1 |
| 160 | gl_SHA256 | 166 | gl_SHA256 |
| 161 | gl_SHA512 | 167 | gl_SHA512 |
| 168 | gl_DIRENT_H | ||
| 162 | AC_REQUIRE([gl_C99_STRTOLD]) | 169 | AC_REQUIRE([gl_C99_STRTOLD]) |
| 163 | gl_FUNC_DUP2 | 170 | gl_FUNC_DUP2 |
| 164 | if test $HAVE_DUP2 = 0 || test $REPLACE_DUP2 = 1; then | 171 | if test $HAVE_DUP2 = 0 || test $REPLACE_DUP2 = 1; then |
| @@ -178,12 +185,23 @@ AC_DEFUN([gl_INIT], | |||
| 178 | gl_MODULE_INDICATOR([faccessat]) | 185 | gl_MODULE_INDICATOR([faccessat]) |
| 179 | gl_UNISTD_MODULE_INDICATOR([faccessat]) | 186 | gl_UNISTD_MODULE_INDICATOR([faccessat]) |
| 180 | gl_FCNTL_H | 187 | gl_FCNTL_H |
| 188 | gl_FUNC_FDOPENDIR | ||
| 189 | if test $HAVE_FDOPENDIR = 0 || test $REPLACE_FDOPENDIR = 1; then | ||
| 190 | AC_LIBOBJ([fdopendir]) | ||
| 191 | fi | ||
| 192 | gl_DIRENT_MODULE_INDICATOR([fdopendir]) | ||
| 193 | gl_MODULE_INDICATOR([fdopendir]) | ||
| 181 | gl_FILEMODE | 194 | gl_FILEMODE |
| 182 | gl_FUNC_FPENDING | 195 | gl_FUNC_FPENDING |
| 183 | if test $ac_cv_func___fpending = no; then | 196 | if test $ac_cv_func___fpending = no; then |
| 184 | AC_LIBOBJ([fpending]) | 197 | AC_LIBOBJ([fpending]) |
| 185 | gl_PREREQ_FPENDING | 198 | gl_PREREQ_FPENDING |
| 186 | fi | 199 | fi |
| 200 | gl_FUNC_FSTATAT | ||
| 201 | if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then | ||
| 202 | AC_LIBOBJ([fstatat]) | ||
| 203 | fi | ||
| 204 | gl_SYS_STAT_MODULE_INDICATOR([fstatat]) | ||
| 187 | gl_GETLOADAVG | 205 | gl_GETLOADAVG |
| 188 | if test $HAVE_GETLOADAVG = 0; then | 206 | if test $HAVE_GETLOADAVG = 0; then |
| 189 | AC_LIBOBJ([getloadavg]) | 207 | AC_LIBOBJ([getloadavg]) |
| @@ -253,6 +271,11 @@ AC_DEFUN([gl_INIT], | |||
| 253 | gl_PREREQ_READLINK | 271 | gl_PREREQ_READLINK |
| 254 | fi | 272 | fi |
| 255 | gl_UNISTD_MODULE_INDICATOR([readlink]) | 273 | gl_UNISTD_MODULE_INDICATOR([readlink]) |
| 274 | gl_FUNC_READLINKAT | ||
| 275 | if test $HAVE_READLINKAT = 0; then | ||
| 276 | AC_LIBOBJ([readlinkat]) | ||
| 277 | fi | ||
| 278 | gl_UNISTD_MODULE_INDICATOR([readlinkat]) | ||
| 256 | gl_FUNC_SIG2STR | 279 | gl_FUNC_SIG2STR |
| 257 | if test $ac_cv_func_sig2str = no; then | 280 | if test $ac_cv_func_sig2str = no; then |
| 258 | AC_LIBOBJ([sig2str]) | 281 | AC_LIBOBJ([sig2str]) |
| @@ -311,11 +334,13 @@ AC_DEFUN([gl_INIT], | |||
| 311 | fi | 334 | fi |
| 312 | gl_STDLIB_MODULE_INDICATOR([unsetenv]) | 335 | gl_STDLIB_MODULE_INDICATOR([unsetenv]) |
| 313 | gl_UTIMENS | 336 | gl_UTIMENS |
| 337 | gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false | ||
| 314 | gl_gnulib_enabled_dosname=false | 338 | gl_gnulib_enabled_dosname=false |
| 315 | gl_gnulib_enabled_euidaccess=false | 339 | gl_gnulib_enabled_euidaccess=false |
| 316 | gl_gnulib_enabled_getgroups=false | 340 | gl_gnulib_enabled_getgroups=false |
| 317 | gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false | 341 | gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false |
| 318 | gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false | 342 | gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false |
| 343 | gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false | ||
| 319 | gl_gnulib_enabled_pathmax=false | 344 | gl_gnulib_enabled_pathmax=false |
| 320 | gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false | 345 | gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false |
| 321 | gl_gnulib_enabled_stat=false | 346 | gl_gnulib_enabled_stat=false |
| @@ -323,6 +348,13 @@ AC_DEFUN([gl_INIT], | |||
| 323 | gl_gnulib_enabled_strtoull=false | 348 | gl_gnulib_enabled_strtoull=false |
| 324 | gl_gnulib_enabled_verify=false | 349 | gl_gnulib_enabled_verify=false |
| 325 | gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false | 350 | gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false |
| 351 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () | ||
| 352 | { | ||
| 353 | if ! $gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b; then | ||
| 354 | AC_LIBOBJ([openat-proc]) | ||
| 355 | gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=true | ||
| 356 | fi | ||
| 357 | } | ||
| 326 | func_gl_gnulib_m4code_dosname () | 358 | func_gl_gnulib_m4code_dosname () |
| 327 | { | 359 | { |
| 328 | if ! $gl_gnulib_enabled_dosname; then | 360 | if ! $gl_gnulib_enabled_dosname; then |
| @@ -385,6 +417,12 @@ AC_DEFUN([gl_INIT], | |||
| 385 | fi | 417 | fi |
| 386 | fi | 418 | fi |
| 387 | } | 419 | } |
| 420 | func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 () | ||
| 421 | { | ||
| 422 | if ! $gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7; then | ||
| 423 | gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=true | ||
| 424 | fi | ||
| 425 | } | ||
| 388 | func_gl_gnulib_m4code_pathmax () | 426 | func_gl_gnulib_m4code_pathmax () |
| 389 | { | 427 | { |
| 390 | if ! $gl_gnulib_enabled_pathmax; then | 428 | if ! $gl_gnulib_enabled_pathmax; then |
| @@ -456,11 +494,29 @@ AC_DEFUN([gl_INIT], | |||
| 456 | fi | 494 | fi |
| 457 | } | 495 | } |
| 458 | if test $HAVE_FACCESSAT = 0; then | 496 | if test $HAVE_FACCESSAT = 0; then |
| 497 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b | ||
| 498 | fi | ||
| 499 | if test $HAVE_FACCESSAT = 0; then | ||
| 459 | func_gl_gnulib_m4code_dosname | 500 | func_gl_gnulib_m4code_dosname |
| 460 | fi | 501 | fi |
| 461 | if test $HAVE_FACCESSAT = 0; then | 502 | if test $HAVE_FACCESSAT = 0; then |
| 462 | func_gl_gnulib_m4code_euidaccess | 503 | func_gl_gnulib_m4code_euidaccess |
| 463 | fi | 504 | fi |
| 505 | if test $HAVE_FACCESSAT = 0; then | ||
| 506 | func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 | ||
| 507 | fi | ||
| 508 | if test $HAVE_FDOPENDIR = 0; then | ||
| 509 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b | ||
| 510 | fi | ||
| 511 | if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then | ||
| 512 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b | ||
| 513 | fi | ||
| 514 | if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then | ||
| 515 | func_gl_gnulib_m4code_dosname | ||
| 516 | fi | ||
| 517 | if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then | ||
| 518 | func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 | ||
| 519 | fi | ||
| 464 | if test $REPLACE_GETOPT = 1; then | 520 | if test $REPLACE_GETOPT = 1; then |
| 465 | func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 | 521 | func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 |
| 466 | fi | 522 | fi |
| @@ -473,6 +529,15 @@ AC_DEFUN([gl_INIT], | |||
| 473 | if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then | 529 | if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then |
| 474 | func_gl_gnulib_m4code_stat | 530 | func_gl_gnulib_m4code_stat |
| 475 | fi | 531 | fi |
| 532 | if test $HAVE_READLINKAT = 0; then | ||
| 533 | func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b | ||
| 534 | fi | ||
| 535 | if test $HAVE_READLINKAT = 0; then | ||
| 536 | func_gl_gnulib_m4code_dosname | ||
| 537 | fi | ||
| 538 | if test $HAVE_READLINKAT = 0; then | ||
| 539 | func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 | ||
| 540 | fi | ||
| 476 | if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test $ac_cv_type_long_long_int = yes; then | 541 | if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test $ac_cv_type_long_long_int = yes; then |
| 477 | func_gl_gnulib_m4code_strtoll | 542 | func_gl_gnulib_m4code_strtoll |
| 478 | fi | 543 | fi |
| @@ -486,11 +551,13 @@ AC_DEFUN([gl_INIT], | |||
| 486 | func_gl_gnulib_m4code_verify | 551 | func_gl_gnulib_m4code_verify |
| 487 | fi | 552 | fi |
| 488 | m4_pattern_allow([^gl_GNULIB_ENABLED_]) | 553 | m4_pattern_allow([^gl_GNULIB_ENABLED_]) |
| 554 | AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b]) | ||
| 489 | AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname]) | 555 | AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname]) |
| 490 | AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess]) | 556 | AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess]) |
| 491 | AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups]) | 557 | AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups]) |
| 492 | AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36]) | 558 | AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36]) |
| 493 | AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1]) | 559 | AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1]) |
| 560 | AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7]) | ||
| 494 | AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax]) | 561 | AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax]) |
| 495 | AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) | 562 | AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) |
| 496 | AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat]) | 563 | AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat]) |
| @@ -656,6 +723,7 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 656 | lib/careadlinkat.h | 723 | lib/careadlinkat.h |
| 657 | lib/close-stream.c | 724 | lib/close-stream.c |
| 658 | lib/close-stream.h | 725 | lib/close-stream.h |
| 726 | lib/dirent.in.h | ||
| 659 | lib/dosname.h | 727 | lib/dosname.h |
| 660 | lib/dtoastr.c | 728 | lib/dtoastr.c |
| 661 | lib/dtotimespec.c | 729 | lib/dtotimespec.c |
| @@ -665,10 +733,12 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 665 | lib/execinfo.in.h | 733 | lib/execinfo.in.h |
| 666 | lib/faccessat.c | 734 | lib/faccessat.c |
| 667 | lib/fcntl.in.h | 735 | lib/fcntl.in.h |
| 736 | lib/fdopendir.c | ||
| 668 | lib/filemode.c | 737 | lib/filemode.c |
| 669 | lib/filemode.h | 738 | lib/filemode.h |
| 670 | lib/fpending.c | 739 | lib/fpending.c |
| 671 | lib/fpending.h | 740 | lib/fpending.h |
| 741 | lib/fstatat.c | ||
| 672 | lib/ftoastr.c | 742 | lib/ftoastr.c |
| 673 | lib/ftoastr.h | 743 | lib/ftoastr.h |
| 674 | lib/getgroups.c | 744 | lib/getgroups.c |
| @@ -689,11 +759,15 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 689 | lib/md5.h | 759 | lib/md5.h |
| 690 | lib/mktime-internal.h | 760 | lib/mktime-internal.h |
| 691 | lib/mktime.c | 761 | lib/mktime.c |
| 762 | lib/openat-priv.h | ||
| 763 | lib/openat-proc.c | ||
| 764 | lib/openat.h | ||
| 692 | lib/pathmax.h | 765 | lib/pathmax.h |
| 693 | lib/pselect.c | 766 | lib/pselect.c |
| 694 | lib/pthread_sigmask.c | 767 | lib/pthread_sigmask.c |
| 695 | lib/putenv.c | 768 | lib/putenv.c |
| 696 | lib/readlink.c | 769 | lib/readlink.c |
| 770 | lib/readlinkat.c | ||
| 697 | lib/root-uid.h | 771 | lib/root-uid.h |
| 698 | lib/sha1.c | 772 | lib/sha1.c |
| 699 | lib/sha1.h | 773 | lib/sha1.h |
| @@ -746,6 +820,7 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 746 | m4/c-strtod.m4 | 820 | m4/c-strtod.m4 |
| 747 | m4/clock_time.m4 | 821 | m4/clock_time.m4 |
| 748 | m4/close-stream.m4 | 822 | m4/close-stream.m4 |
| 823 | m4/dirent_h.m4 | ||
| 749 | m4/dup2.m4 | 824 | m4/dup2.m4 |
| 750 | m4/environ.m4 | 825 | m4/environ.m4 |
| 751 | m4/euidaccess.m4 | 826 | m4/euidaccess.m4 |
| @@ -755,8 +830,10 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 755 | m4/faccessat.m4 | 830 | m4/faccessat.m4 |
| 756 | m4/fcntl-o.m4 | 831 | m4/fcntl-o.m4 |
| 757 | m4/fcntl_h.m4 | 832 | m4/fcntl_h.m4 |
| 833 | m4/fdopendir.m4 | ||
| 758 | m4/filemode.m4 | 834 | m4/filemode.m4 |
| 759 | m4/fpending.m4 | 835 | m4/fpending.m4 |
| 836 | m4/fstatat.m4 | ||
| 760 | m4/getgroups.m4 | 837 | m4/getgroups.m4 |
| 761 | m4/getloadavg.m4 | 838 | m4/getloadavg.m4 |
| 762 | m4/getopt.m4 | 839 | m4/getopt.m4 |
| @@ -780,6 +857,7 @@ AC_DEFUN([gl_FILE_LIST], [ | |||
| 780 | m4/pthread_sigmask.m4 | 857 | m4/pthread_sigmask.m4 |
| 781 | m4/putenv.m4 | 858 | m4/putenv.m4 |
| 782 | m4/readlink.m4 | 859 | m4/readlink.m4 |
| 860 | m4/readlinkat.m4 | ||
| 783 | m4/setenv.m4 | 861 | m4/setenv.m4 |
| 784 | m4/sha1.m4 | 862 | m4/sha1.m4 |
| 785 | m4/sha256.m4 | 863 | m4/sha256.m4 |
diff --git a/m4/readlinkat.m4 b/m4/readlinkat.m4 new file mode 100644 index 00000000000..b2ff40dcb02 --- /dev/null +++ b/m4/readlinkat.m4 | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # serial 3 | ||
| 2 | # See if we need to provide readlinkat replacement. | ||
| 3 | |||
| 4 | dnl Copyright (C) 2009-2013 Free Software Foundation, Inc. | ||
| 5 | dnl This file is free software; the Free Software Foundation | ||
| 6 | dnl gives unlimited permission to copy and/or distribute it, | ||
| 7 | dnl with or without modifications, as long as this notice is preserved. | ||
| 8 | |||
| 9 | # Written by Eric Blake. | ||
| 10 | |||
| 11 | AC_DEFUN([gl_FUNC_READLINKAT], | ||
| 12 | [ | ||
| 13 | AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) | ||
| 14 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
| 15 | AC_CHECK_FUNCS_ONCE([readlinkat]) | ||
| 16 | if test $ac_cv_func_readlinkat = no; then | ||
| 17 | HAVE_READLINKAT=0 | ||
| 18 | fi | ||
| 19 | ]) | ||
diff --git a/nt/ChangeLog b/nt/ChangeLog index 8b8628db1e2..b2a481354bc 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2013-02-01 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539). | ||
| 4 | * inc/sys/stat.h (fstatat): | ||
| 5 | * inc/unistd.h (readlinkat): New decls. | ||
| 6 | |||
| 1 | 2013-01-28 Eli Zaretskii <eliz@gnu.org> | 7 | 2013-01-28 Eli Zaretskii <eliz@gnu.org> |
| 2 | 8 | ||
| 3 | * inc/dirent.h (opendir): Update prototype. | 9 | * inc/dirent.h (opendir): Update prototype. |
diff --git a/nt/inc/sys/stat.h b/nt/inc/sys/stat.h index 45689d24776..c356283c04b 100644 --- a/nt/inc/sys/stat.h +++ b/nt/inc/sys/stat.h | |||
| @@ -110,6 +110,7 @@ _CRTIMP int __cdecl __MINGW_NOTHROW fstat (int, struct stat*); | |||
| 110 | _CRTIMP int __cdecl __MINGW_NOTHROW chmod (const char*, int); | 110 | _CRTIMP int __cdecl __MINGW_NOTHROW chmod (const char*, int); |
| 111 | _CRTIMP int __cdecl __MINGW_NOTHROW stat (const char*, struct stat*); | 111 | _CRTIMP int __cdecl __MINGW_NOTHROW stat (const char*, struct stat*); |
| 112 | _CRTIMP int __cdecl __MINGW_NOTHROW lstat (const char*, struct stat*); | 112 | _CRTIMP int __cdecl __MINGW_NOTHROW lstat (const char*, struct stat*); |
| 113 | _CRTIMP int __cdecl __MINGW_NOTHROW fstatat (int, char const *, | ||
| 114 | struct stat *, int); | ||
| 113 | 115 | ||
| 114 | #endif /* INC_SYS_STAT_H_ */ | 116 | #endif /* INC_SYS_STAT_H_ */ |
| 115 | |||
diff --git a/nt/inc/unistd.h b/nt/inc/unistd.h index 9c8a64d5ed2..3fd9289d83d 100644 --- a/nt/inc/unistd.h +++ b/nt/inc/unistd.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | and whose prototypes are usually found in unistd.h on POSIX | 12 | and whose prototypes are usually found in unistd.h on POSIX |
| 13 | platforms. */ | 13 | platforms. */ |
| 14 | extern ssize_t readlink (const char *, char *, size_t); | 14 | extern ssize_t readlink (const char *, char *, size_t); |
| 15 | extern ssize_t readlinkat (int, const char *, char *, size_t); | ||
| 15 | extern int symlink (char const *, char const *); | 16 | extern int symlink (char const *, char const *); |
| 16 | extern int setpgid (pid_t, pid_t); | 17 | extern int setpgid (pid_t, pid_t); |
| 17 | extern pid_t getpgrp (void); | 18 | extern pid_t getpgrp (void); |
diff --git a/src/ChangeLog b/src/ChangeLog index 5c13e35306d..2156d7f19c9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,34 @@ | |||
| 1 | 2013-02-01 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539). | ||
| 4 | * conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): Remove. | ||
| 5 | * dired.c: Include <fcntl.h>. | ||
| 6 | (open_directory): New function, which uses open and fdopendir | ||
| 7 | rather than opendir. DOS_NT platforms still use opendir, though. | ||
| 8 | (directory_files_internal, file_name_completion): Use it. | ||
| 9 | (file_attributes): New function, with most of the old Ffile_attributes. | ||
| 10 | (directory_files_internal, Ffile_attributes): Use it. | ||
| 11 | (file_attributes, file_name_completion_stat): First arg is now fd, | ||
| 12 | not dir name. All uses changed. Use fstatat rather than lstat + | ||
| 13 | stat. | ||
| 14 | (file_attributes): Use emacs_readlinkat rather than Ffile_symlink_p. | ||
| 15 | * fileio.c: Include <allocator.h>, <careadlinkat.h>. | ||
| 16 | (emacs_readlinkat): New function, with much of the old | ||
| 17 | Ffile_symlink_p, but with an fd argument for speed. | ||
| 18 | It uses readlinkat rather than careadlinkatcwd, so that it | ||
| 19 | need not assume the working directory. | ||
| 20 | (Ffile_symlink_p): Use it. | ||
| 21 | * filelock.c (current_lock_owner): Use emacs_readlinkat | ||
| 22 | rather than emacs_readlink. | ||
| 23 | * lisp.h (emacs_readlinkat): New decl. | ||
| 24 | (READLINK_BUFSIZE, emacs_readlink): Remove. | ||
| 25 | * sysdep.c: Do not include <allocator.h>, <careadlinkat.h>. | ||
| 26 | (emacs_norealloc_allocator, emacs_readlink): Remove. | ||
| 27 | This stuff is moved to fileio.c. | ||
| 28 | * w32.c (fstatat, readlinkat): New functions. | ||
| 29 | (careadlinkat): Don't check that fd == AT_FDCWD. | ||
| 30 | (careadlinkatcwd): Remove; no longer needed. | ||
| 31 | |||
| 1 | 2013-01-31 Glenn Morris <rgm@gnu.org> | 32 | 2013-01-31 Glenn Morris <rgm@gnu.org> |
| 2 | 33 | ||
| 3 | * fileio.c (choose_write_coding_system): Make it callable from Lisp. | 34 | * fileio.c (choose_write_coding_system): Make it callable from Lisp. |
diff --git a/src/conf_post.h b/src/conf_post.h index cd1e35bea7a..6c9747a436c 100644 --- a/src/conf_post.h +++ b/src/conf_post.h | |||
| @@ -182,10 +182,6 @@ extern void _DebPrint (const char *fmt, ...); | |||
| 182 | #endif | 182 | #endif |
| 183 | #endif | 183 | #endif |
| 184 | 184 | ||
| 185 | /* Tell gnulib to omit support for openat-related functions having a | ||
| 186 | first argument other than AT_FDCWD. */ | ||
| 187 | #define GNULIB_SUPPORT_ONLY_AT_FDCWD | ||
| 188 | |||
| 189 | #include <string.h> | 185 | #include <string.h> |
| 190 | #include <stdlib.h> | 186 | #include <stdlib.h> |
| 191 | 187 | ||
diff --git a/src/dired.c b/src/dired.c index a4c8621e9c0..ed0571fe9fe 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 30 | #include <grp.h> | 30 | #include <grp.h> |
| 31 | 31 | ||
| 32 | #include <errno.h> | 32 | #include <errno.h> |
| 33 | #include <fcntl.h> | ||
| 33 | #include <unistd.h> | 34 | #include <unistd.h> |
| 34 | 35 | ||
| 35 | #include <dirent.h> | 36 | #include <dirent.h> |
| @@ -54,6 +55,7 @@ static Lisp_Object Qfile_attributes; | |||
| 54 | static Lisp_Object Qfile_attributes_lessp; | 55 | static Lisp_Object Qfile_attributes_lessp; |
| 55 | 56 | ||
| 56 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); | 57 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); |
| 58 | static Lisp_Object file_attributes (int, char const *, Lisp_Object); | ||
| 57 | 59 | ||
| 58 | /* Return the number of bytes in DP's name. */ | 60 | /* Return the number of bytes in DP's name. */ |
| 59 | static ptrdiff_t | 61 | static ptrdiff_t |
| @@ -66,6 +68,44 @@ dirent_namelen (struct dirent *dp) | |||
| 66 | #endif | 68 | #endif |
| 67 | } | 69 | } |
| 68 | 70 | ||
| 71 | static DIR * | ||
| 72 | open_directory (char const *name, int *fdp) | ||
| 73 | { | ||
| 74 | DIR *d; | ||
| 75 | int fd, opendir_errno; | ||
| 76 | |||
| 77 | block_input (); | ||
| 78 | |||
| 79 | #ifdef DOS_NT | ||
| 80 | /* Directories cannot be opened. The emulation assumes that any | ||
| 81 | file descriptor other than AT_FDCWD corresponds to the most | ||
| 82 | recently opened directory. This hack is good enough for Emacs. */ | ||
| 83 | fd = 0; | ||
| 84 | d = opendir (name); | ||
| 85 | opendir_errno = errno; | ||
| 86 | #else | ||
| 87 | fd = emacs_open (name, O_RDONLY | O_DIRECTORY, 0); | ||
| 88 | if (fd < 0) | ||
| 89 | { | ||
| 90 | opendir_errno = errno; | ||
| 91 | d = 0; | ||
| 92 | } | ||
| 93 | else | ||
| 94 | { | ||
| 95 | d = fdopendir (fd); | ||
| 96 | opendir_errno = errno; | ||
| 97 | if (! d) | ||
| 98 | close (fd); | ||
| 99 | } | ||
| 100 | #endif | ||
| 101 | |||
| 102 | unblock_input (); | ||
| 103 | |||
| 104 | *fdp = fd; | ||
| 105 | errno = opendir_errno; | ||
| 106 | return d; | ||
| 107 | } | ||
| 108 | |||
| 69 | #ifdef WINDOWSNT | 109 | #ifdef WINDOWSNT |
| 70 | Lisp_Object | 110 | Lisp_Object |
| 71 | directory_files_internal_w32_unwind (Lisp_Object arg) | 111 | directory_files_internal_w32_unwind (Lisp_Object arg) |
| @@ -96,6 +136,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 96 | Lisp_Object id_format) | 136 | Lisp_Object id_format) |
| 97 | { | 137 | { |
| 98 | DIR *d; | 138 | DIR *d; |
| 139 | int fd; | ||
| 99 | ptrdiff_t directory_nbytes; | 140 | ptrdiff_t directory_nbytes; |
| 100 | Lisp_Object list, dirfilename, encoded_directory; | 141 | Lisp_Object list, dirfilename, encoded_directory; |
| 101 | struct re_pattern_buffer *bufp = NULL; | 142 | struct re_pattern_buffer *bufp = NULL; |
| @@ -142,9 +183,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 142 | /* Now *bufp is the compiled form of MATCH; don't call anything | 183 | /* Now *bufp is the compiled form of MATCH; don't call anything |
| 143 | which might compile a new regexp until we're done with the loop! */ | 184 | which might compile a new regexp until we're done with the loop! */ |
| 144 | 185 | ||
| 145 | block_input (); | 186 | d = open_directory (SSDATA (dirfilename), &fd); |
| 146 | d = opendir (SSDATA (dirfilename)); | ||
| 147 | unblock_input (); | ||
| 148 | if (d == NULL) | 187 | if (d == NULL) |
| 149 | report_file_error ("Opening directory", Fcons (directory, Qnil)); | 188 | report_file_error ("Opening directory", Fcons (directory, Qnil)); |
| 150 | 189 | ||
| @@ -259,20 +298,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 259 | 298 | ||
| 260 | if (attrs) | 299 | if (attrs) |
| 261 | { | 300 | { |
| 262 | /* Construct an expanded filename for the directory entry. | 301 | Lisp_Object fileattrs |
| 263 | Use the decoded names for input to Ffile_attributes. */ | 302 | = file_attributes (fd, dp->d_name, id_format); |
| 264 | Lisp_Object decoded_fullname, fileattrs; | ||
| 265 | struct gcpro gcpro1, gcpro2; | ||
| 266 | |||
| 267 | decoded_fullname = fileattrs = Qnil; | ||
| 268 | GCPRO2 (decoded_fullname, fileattrs); | ||
| 269 | |||
| 270 | /* Both Fexpand_file_name and Ffile_attributes can GC. */ | ||
| 271 | decoded_fullname = Fexpand_file_name (name, directory); | ||
| 272 | fileattrs = Ffile_attributes (decoded_fullname, id_format); | ||
| 273 | |||
| 274 | list = Fcons (Fcons (finalname, fileattrs), list); | 303 | list = Fcons (Fcons (finalname, fileattrs), list); |
| 275 | UNGCPRO; | ||
| 276 | } | 304 | } |
| 277 | else | 305 | else |
| 278 | list = Fcons (finalname, list); | 306 | list = Fcons (finalname, list); |
| @@ -413,8 +441,7 @@ These are all file names in directory DIRECTORY which begin with FILE. */) | |||
| 413 | return file_name_completion (file, directory, 1, Qnil); | 441 | return file_name_completion (file, directory, 1, Qnil); |
| 414 | } | 442 | } |
| 415 | 443 | ||
| 416 | static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | 444 | static int file_name_completion_stat (int, struct dirent *, struct stat *); |
| 417 | struct stat *st_addr); | ||
| 418 | static Lisp_Object Qdefault_directory; | 445 | static Lisp_Object Qdefault_directory; |
| 419 | 446 | ||
| 420 | static Lisp_Object | 447 | static Lisp_Object |
| @@ -422,6 +449,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 422 | Lisp_Object predicate) | 449 | Lisp_Object predicate) |
| 423 | { | 450 | { |
| 424 | DIR *d; | 451 | DIR *d; |
| 452 | int fd; | ||
| 425 | ptrdiff_t bestmatchsize = 0; | 453 | ptrdiff_t bestmatchsize = 0; |
| 426 | int matchcount = 0; | 454 | int matchcount = 0; |
| 427 | /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. | 455 | /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. |
| @@ -458,9 +486,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 458 | 486 | ||
| 459 | encoded_dir = ENCODE_FILE (dirname); | 487 | encoded_dir = ENCODE_FILE (dirname); |
| 460 | 488 | ||
| 461 | block_input (); | 489 | d = open_directory (SSDATA (Fdirectory_file_name (encoded_dir)), &fd); |
| 462 | d = opendir (SSDATA (Fdirectory_file_name (encoded_dir))); | ||
| 463 | unblock_input (); | ||
| 464 | if (!d) | 490 | if (!d) |
| 465 | report_file_error ("Opening directory", Fcons (dirname, Qnil)); | 491 | report_file_error ("Opening directory", Fcons (dirname, Qnil)); |
| 466 | 492 | ||
| @@ -495,7 +521,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 495 | SCHARS (encoded_file))) | 521 | SCHARS (encoded_file))) |
| 496 | continue; | 522 | continue; |
| 497 | 523 | ||
| 498 | if (file_name_completion_stat (encoded_dir, dp, &st) < 0) | 524 | if (file_name_completion_stat (fd, dp, &st) < 0) |
| 499 | continue; | 525 | continue; |
| 500 | 526 | ||
| 501 | directoryp = S_ISDIR (st.st_mode) != 0; | 527 | directoryp = S_ISDIR (st.st_mode) != 0; |
| @@ -772,14 +798,9 @@ scmp (const char *s1, const char *s2, ptrdiff_t len) | |||
| 772 | } | 798 | } |
| 773 | 799 | ||
| 774 | static int | 800 | static int |
| 775 | file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | 801 | file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr) |
| 776 | struct stat *st_addr) | ||
| 777 | { | 802 | { |
| 778 | ptrdiff_t len = dirent_namelen (dp); | ||
| 779 | ptrdiff_t pos = SCHARS (dirname); | ||
| 780 | int value; | 803 | int value; |
| 781 | USE_SAFE_ALLOCA; | ||
| 782 | char *fullname = SAFE_ALLOCA (len + pos + 2); | ||
| 783 | 804 | ||
| 784 | #ifdef MSDOS | 805 | #ifdef MSDOS |
| 785 | /* Some fields of struct stat are *very* expensive to compute on MS-DOS, | 806 | /* Some fields of struct stat are *very* expensive to compute on MS-DOS, |
| @@ -792,23 +813,15 @@ file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | |||
| 792 | _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; | 813 | _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; |
| 793 | #endif /* MSDOS */ | 814 | #endif /* MSDOS */ |
| 794 | 815 | ||
| 795 | memcpy (fullname, SDATA (dirname), pos); | ||
| 796 | if (!IS_DIRECTORY_SEP (fullname[pos - 1])) | ||
| 797 | fullname[pos++] = DIRECTORY_SEP; | ||
| 798 | |||
| 799 | memcpy (fullname + pos, dp->d_name, len); | ||
| 800 | fullname[pos + len] = 0; | ||
| 801 | |||
| 802 | /* We want to return success if a link points to a nonexistent file, | 816 | /* We want to return success if a link points to a nonexistent file, |
| 803 | but we want to return the status for what the link points to, | 817 | but we want to return the status for what the link points to, |
| 804 | in case it is a directory. */ | 818 | in case it is a directory. */ |
| 805 | value = lstat (fullname, st_addr); | 819 | value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW); |
| 806 | if (value == 0 && S_ISLNK (st_addr->st_mode)) | 820 | if (value == 0 && S_ISLNK (st_addr->st_mode)) |
| 807 | stat (fullname, st_addr); | 821 | fstatat (fd, dp->d_name, st_addr, 0); |
| 808 | #ifdef MSDOS | 822 | #ifdef MSDOS |
| 809 | _djstat_flags = save_djstat_flags; | 823 | _djstat_flags = save_djstat_flags; |
| 810 | #endif /* MSDOS */ | 824 | #endif /* MSDOS */ |
| 811 | SAFE_FREE (); | ||
| 812 | return value; | 825 | return value; |
| 813 | } | 826 | } |
| 814 | 827 | ||
| @@ -886,18 +899,8 @@ On some FAT-based filesystems, only the date of last access is recorded, | |||
| 886 | so last access time will always be midnight of that day. */) | 899 | so last access time will always be midnight of that day. */) |
| 887 | (Lisp_Object filename, Lisp_Object id_format) | 900 | (Lisp_Object filename, Lisp_Object id_format) |
| 888 | { | 901 | { |
| 889 | Lisp_Object values[12]; | ||
| 890 | Lisp_Object encoded; | 902 | Lisp_Object encoded; |
| 891 | struct stat s; | ||
| 892 | int lstat_result; | ||
| 893 | |||
| 894 | /* An array to hold the mode string generated by filemodestring, | ||
| 895 | including its terminating space and null byte. */ | ||
| 896 | char modes[sizeof "-rwxr-xr-x "]; | ||
| 897 | |||
| 898 | Lisp_Object handler; | 903 | Lisp_Object handler; |
| 899 | struct gcpro gcpro1; | ||
| 900 | char *uname = NULL, *gname = NULL; | ||
| 901 | 904 | ||
| 902 | filename = Fexpand_file_name (filename, Qnil); | 905 | filename = Fexpand_file_name (filename, Qnil); |
| 903 | 906 | ||
| @@ -913,9 +916,22 @@ so last access time will always be midnight of that day. */) | |||
| 913 | return call3 (handler, Qfile_attributes, filename, id_format); | 916 | return call3 (handler, Qfile_attributes, filename, id_format); |
| 914 | } | 917 | } |
| 915 | 918 | ||
| 916 | GCPRO1 (filename); | ||
| 917 | encoded = ENCODE_FILE (filename); | 919 | encoded = ENCODE_FILE (filename); |
| 918 | UNGCPRO; | 920 | return file_attributes (AT_FDCWD, SSDATA (encoded), id_format); |
| 921 | } | ||
| 922 | |||
| 923 | static Lisp_Object | ||
| 924 | file_attributes (int fd, char const *name, Lisp_Object id_format) | ||
| 925 | { | ||
| 926 | Lisp_Object values[12]; | ||
| 927 | struct stat s; | ||
| 928 | int lstat_result; | ||
| 929 | |||
| 930 | /* An array to hold the mode string generated by filemodestring, | ||
| 931 | including its terminating space and null byte. */ | ||
| 932 | char modes[sizeof "-rwxr-xr-x "]; | ||
| 933 | |||
| 934 | char *uname = NULL, *gname = NULL; | ||
| 919 | 935 | ||
| 920 | #ifdef WINDOWSNT | 936 | #ifdef WINDOWSNT |
| 921 | /* We usually don't request accurate owner and group info, because | 937 | /* We usually don't request accurate owner and group info, because |
| @@ -925,7 +941,7 @@ so last access time will always be midnight of that day. */) | |||
| 925 | w32_stat_get_owner_group = 1; | 941 | w32_stat_get_owner_group = 1; |
| 926 | #endif | 942 | #endif |
| 927 | 943 | ||
| 928 | lstat_result = lstat (SSDATA (encoded), &s); | 944 | lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW); |
| 929 | 945 | ||
| 930 | #ifdef WINDOWSNT | 946 | #ifdef WINDOWSNT |
| 931 | w32_stat_get_owner_group = 0; | 947 | w32_stat_get_owner_group = 0; |
| @@ -934,7 +950,7 @@ so last access time will always be midnight of that day. */) | |||
| 934 | if (lstat_result < 0) | 950 | if (lstat_result < 0) |
| 935 | return Qnil; | 951 | return Qnil; |
| 936 | 952 | ||
| 937 | values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename) | 953 | values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name) |
| 938 | : S_ISDIR (s.st_mode) ? Qt : Qnil); | 954 | : S_ISDIR (s.st_mode) ? Qt : Qnil); |
| 939 | values[1] = make_number (s.st_nlink); | 955 | values[1] = make_number (s.st_nlink); |
| 940 | 956 | ||
diff --git a/src/fileio.c b/src/fileio.c index cd4bd4fa86e..a8218fcd797 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -82,6 +82,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 82 | #endif | 82 | #endif |
| 83 | 83 | ||
| 84 | #include "systime.h" | 84 | #include "systime.h" |
| 85 | #include <allocator.h> | ||
| 86 | #include <careadlinkat.h> | ||
| 85 | #include <stat-time.h> | 87 | #include <stat-time.h> |
| 86 | 88 | ||
| 87 | #ifdef HPUX | 89 | #ifdef HPUX |
| @@ -2759,6 +2761,29 @@ If there is no error, returns nil. */) | |||
| 2759 | return Qnil; | 2761 | return Qnil; |
| 2760 | } | 2762 | } |
| 2761 | 2763 | ||
| 2764 | /* Relative to directory FD, return the symbolic link value of FILENAME. | ||
| 2765 | On failure, return nil. */ | ||
| 2766 | Lisp_Object | ||
| 2767 | emacs_readlinkat (int fd, char const *filename) | ||
| 2768 | { | ||
| 2769 | static struct allocator const emacs_norealloc_allocator = | ||
| 2770 | { xmalloc, NULL, xfree, memory_full }; | ||
| 2771 | Lisp_Object val; | ||
| 2772 | char readlink_buf[1024]; | ||
| 2773 | char *buf = careadlinkat (fd, filename, readlink_buf, sizeof readlink_buf, | ||
| 2774 | &emacs_norealloc_allocator, readlinkat); | ||
| 2775 | if (!buf) | ||
| 2776 | return Qnil; | ||
| 2777 | |||
| 2778 | val = build_string (buf); | ||
| 2779 | if (buf[0] == '/' && strchr (buf, ':')) | ||
| 2780 | val = concat2 (build_string ("/:"), val); | ||
| 2781 | if (buf != readlink_buf) | ||
| 2782 | xfree (buf); | ||
| 2783 | val = DECODE_FILE (val); | ||
| 2784 | return val; | ||
| 2785 | } | ||
| 2786 | |||
| 2762 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, | 2787 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, |
| 2763 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. | 2788 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. |
| 2764 | The value is the link target, as a string. | 2789 | The value is the link target, as a string. |
| @@ -2769,9 +2794,6 @@ points to a nonexistent file. */) | |||
| 2769 | (Lisp_Object filename) | 2794 | (Lisp_Object filename) |
| 2770 | { | 2795 | { |
| 2771 | Lisp_Object handler; | 2796 | Lisp_Object handler; |
| 2772 | char *buf; | ||
| 2773 | Lisp_Object val; | ||
| 2774 | char readlink_buf[READLINK_BUFSIZE]; | ||
| 2775 | 2797 | ||
| 2776 | CHECK_STRING (filename); | 2798 | CHECK_STRING (filename); |
| 2777 | filename = Fexpand_file_name (filename, Qnil); | 2799 | filename = Fexpand_file_name (filename, Qnil); |
| @@ -2784,17 +2806,7 @@ points to a nonexistent file. */) | |||
| 2784 | 2806 | ||
| 2785 | filename = ENCODE_FILE (filename); | 2807 | filename = ENCODE_FILE (filename); |
| 2786 | 2808 | ||
| 2787 | buf = emacs_readlink (SSDATA (filename), readlink_buf); | 2809 | return emacs_readlinkat (AT_FDCWD, SSDATA (filename)); |
| 2788 | if (! buf) | ||
| 2789 | return Qnil; | ||
| 2790 | |||
| 2791 | val = build_string (buf); | ||
| 2792 | if (buf[0] == '/' && strchr (buf, ':')) | ||
| 2793 | val = concat2 (build_string ("/:"), val); | ||
| 2794 | if (buf != readlink_buf) | ||
| 2795 | xfree (buf); | ||
| 2796 | val = DECODE_FILE (val); | ||
| 2797 | return val; | ||
| 2798 | } | 2810 | } |
| 2799 | 2811 | ||
| 2800 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, | 2812 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, |
diff --git a/src/filelock.c b/src/filelock.c index f21240f8340..228fe98e8c7 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -390,12 +390,14 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 390 | lock_info_type local_owner; | 390 | lock_info_type local_owner; |
| 391 | intmax_t n; | 391 | intmax_t n; |
| 392 | char *at, *dot, *colon; | 392 | char *at, *dot, *colon; |
| 393 | char readlink_buf[READLINK_BUFSIZE]; | 393 | Lisp_Object lfinfo_object = emacs_readlinkat (AT_FDCWD, lfname); |
| 394 | char *lfinfo = emacs_readlink (lfname, readlink_buf); | 394 | char *lfinfo; |
| 395 | struct gcpro gcpro1; | ||
| 395 | 396 | ||
| 396 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | 397 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ |
| 397 | if (!lfinfo) | 398 | if (NILP (lfinfo_object)) |
| 398 | return errno == ENOENT ? 0 : -1; | 399 | return errno == ENOENT ? 0 : -1; |
| 400 | lfinfo = SSDATA (lfinfo_object); | ||
| 399 | 401 | ||
| 400 | /* Even if the caller doesn't want the owner info, we still have to | 402 | /* Even if the caller doesn't want the owner info, we still have to |
| 401 | read it to determine return value. */ | 403 | read it to determine return value. */ |
| @@ -407,12 +409,9 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 407 | at = strrchr (lfinfo, '@'); | 409 | at = strrchr (lfinfo, '@'); |
| 408 | dot = strrchr (lfinfo, '.'); | 410 | dot = strrchr (lfinfo, '.'); |
| 409 | if (!at || !dot) | 411 | if (!at || !dot) |
| 410 | { | 412 | return -1; |
| 411 | if (lfinfo != readlink_buf) | ||
| 412 | xfree (lfinfo); | ||
| 413 | return -1; | ||
| 414 | } | ||
| 415 | len = at - lfinfo; | 413 | len = at - lfinfo; |
| 414 | GCPRO1 (lfinfo_object); | ||
| 416 | owner->user = xmalloc (len + 1); | 415 | owner->user = xmalloc (len + 1); |
| 417 | memcpy (owner->user, lfinfo, len); | 416 | memcpy (owner->user, lfinfo, len); |
| 418 | owner->user[len] = 0; | 417 | owner->user[len] = 0; |
| @@ -445,8 +444,7 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 445 | owner->host[len] = 0; | 444 | owner->host[len] = 0; |
| 446 | 445 | ||
| 447 | /* We're done looking at the link info. */ | 446 | /* We're done looking at the link info. */ |
| 448 | if (lfinfo != readlink_buf) | 447 | UNGCPRO; |
| 449 | xfree (lfinfo); | ||
| 450 | 448 | ||
| 451 | /* On current host? */ | 449 | /* On current host? */ |
| 452 | if (STRINGP (Fsystem_name ()) | 450 | if (STRINGP (Fsystem_name ()) |
diff --git a/src/lisp.h b/src/lisp.h index 2e9088f1834..251b5e069ec 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3294,6 +3294,7 @@ extern Lisp_Object close_file_unwind (Lisp_Object); | |||
| 3294 | extern Lisp_Object restore_point_unwind (Lisp_Object); | 3294 | extern Lisp_Object restore_point_unwind (Lisp_Object); |
| 3295 | extern _Noreturn void report_file_error (const char *, Lisp_Object); | 3295 | extern _Noreturn void report_file_error (const char *, Lisp_Object); |
| 3296 | extern bool internal_delete_file (Lisp_Object); | 3296 | extern bool internal_delete_file (Lisp_Object); |
| 3297 | extern Lisp_Object emacs_readlinkat (int, const char *); | ||
| 3297 | extern bool file_directory_p (const char *); | 3298 | extern bool file_directory_p (const char *); |
| 3298 | extern bool file_accessible_directory_p (const char *); | 3299 | extern bool file_accessible_directory_p (const char *); |
| 3299 | extern void init_fileio (void); | 3300 | extern void init_fileio (void); |
| @@ -3566,8 +3567,6 @@ extern int emacs_open (const char *, int, int); | |||
| 3566 | extern int emacs_close (int); | 3567 | extern int emacs_close (int); |
| 3567 | extern ptrdiff_t emacs_read (int, char *, ptrdiff_t); | 3568 | extern ptrdiff_t emacs_read (int, char *, ptrdiff_t); |
| 3568 | extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t); | 3569 | extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t); |
| 3569 | enum { READLINK_BUFSIZE = 1024 }; | ||
| 3570 | extern char *emacs_readlink (const char *, char [READLINK_BUFSIZE]); | ||
| 3571 | 3570 | ||
| 3572 | extern void unlock_all_files (void); | 3571 | extern void unlock_all_files (void); |
| 3573 | extern void lock_file (Lisp_Object); | 3572 | extern void lock_file (Lisp_Object); |
diff --git a/src/sysdep.c b/src/sysdep.c index 0e9a6826005..57ca8265a65 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -30,9 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 30 | #include <limits.h> | 30 | #include <limits.h> |
| 31 | #include <unistd.h> | 31 | #include <unistd.h> |
| 32 | 32 | ||
| 33 | #include <allocator.h> | ||
| 34 | #include <c-ctype.h> | 33 | #include <c-ctype.h> |
| 35 | #include <careadlinkat.h> | ||
| 36 | #include <ignore-value.h> | 34 | #include <ignore-value.h> |
| 37 | #include <utimens.h> | 35 | #include <utimens.h> |
| 38 | 36 | ||
| @@ -2247,22 +2245,6 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) | |||
| 2247 | 2245 | ||
| 2248 | return (bytes_written); | 2246 | return (bytes_written); |
| 2249 | } | 2247 | } |
| 2250 | |||
| 2251 | static struct allocator const emacs_norealloc_allocator = | ||
| 2252 | { xmalloc, NULL, xfree, memory_full }; | ||
| 2253 | |||
| 2254 | /* Get the symbolic link value of FILENAME. Return a pointer to a | ||
| 2255 | NUL-terminated string. If readlink fails, return NULL and set | ||
| 2256 | errno. If the value fits in INITIAL_BUF, return INITIAL_BUF. | ||
| 2257 | Otherwise, allocate memory and return a pointer to that memory. If | ||
| 2258 | memory allocation fails, diagnose and fail without returning. If | ||
| 2259 | successful, store the length of the symbolic link into *LINKLEN. */ | ||
| 2260 | char * | ||
| 2261 | emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE]) | ||
| 2262 | { | ||
| 2263 | return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE, | ||
| 2264 | &emacs_norealloc_allocator, careadlinkatcwd); | ||
| 2265 | } | ||
| 2266 | 2248 | ||
| 2267 | /* Return a struct timeval that is roughly equivalent to T. | 2249 | /* Return a struct timeval that is roughly equivalent to T. |
| 2268 | Use the least timeval not less than T. | 2250 | Use the least timeval not less than T. |
| @@ -4274,6 +4274,30 @@ lstat (const char * path, struct stat * buf) | |||
| 4274 | return stat_worker (path, buf, 0); | 4274 | return stat_worker (path, buf, 0); |
| 4275 | } | 4275 | } |
| 4276 | 4276 | ||
| 4277 | int | ||
| 4278 | fstatat (int fd, char const *name, struct stat *st, int flags) | ||
| 4279 | { | ||
| 4280 | /* Rely on a hack: an open directory is modeled as file descriptor 0. | ||
| 4281 | This is good enough for the current usage in Emacs, but is fragile. | ||
| 4282 | |||
| 4283 | FIXME: Add proper support for fdopendir, fstatatat, readlinkat. | ||
| 4284 | Gnulib does this and can serve as a model. */ | ||
| 4285 | char fullname[MAX_PATH]; | ||
| 4286 | |||
| 4287 | if (fd != AT_FDCWD) | ||
| 4288 | { | ||
| 4289 | if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) | ||
| 4290 | < 0) | ||
| 4291 | { | ||
| 4292 | errno = ENAMETOOLONG; | ||
| 4293 | return -1; | ||
| 4294 | } | ||
| 4295 | name = fullname; | ||
| 4296 | } | ||
| 4297 | |||
| 4298 | return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); | ||
| 4299 | } | ||
| 4300 | |||
| 4277 | /* Provide fstat and utime as well as stat for consistent handling of | 4301 | /* Provide fstat and utime as well as stat for consistent handling of |
| 4278 | file timestamps. */ | 4302 | file timestamps. */ |
| 4279 | int | 4303 | int |
| @@ -4816,6 +4840,28 @@ readlink (const char *name, char *buf, size_t buf_size) | |||
| 4816 | return retval; | 4840 | return retval; |
| 4817 | } | 4841 | } |
| 4818 | 4842 | ||
| 4843 | ssize_t | ||
| 4844 | readlinkat (int fd, char const *name, char *buffer, | ||
| 4845 | size_t buffer_size) | ||
| 4846 | { | ||
| 4847 | /* Rely on a hack: an open directory is modeled as file descriptor 0, | ||
| 4848 | as in fstatat. FIXME: Add proper support for readlinkat. */ | ||
| 4849 | char fullname[MAX_PATH]; | ||
| 4850 | |||
| 4851 | if (fd != AT_FDCWD) | ||
| 4852 | { | ||
| 4853 | if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) | ||
| 4854 | < 0) | ||
| 4855 | { | ||
| 4856 | errno = ENAMETOOLONG; | ||
| 4857 | return -1; | ||
| 4858 | } | ||
| 4859 | name = fullname; | ||
| 4860 | } | ||
| 4861 | |||
| 4862 | return readlink (name, buffer, buffer_size); | ||
| 4863 | } | ||
| 4864 | |||
| 4819 | /* If FILE is a symlink, return its target (stored in a static | 4865 | /* If FILE is a symlink, return its target (stored in a static |
| 4820 | buffer); otherwise return FILE. | 4866 | buffer); otherwise return FILE. |
| 4821 | 4867 | ||
| @@ -5168,12 +5214,6 @@ careadlinkat (int fd, char const *filename, | |||
| 5168 | char linkname[MAX_PATH]; | 5214 | char linkname[MAX_PATH]; |
| 5169 | ssize_t link_size; | 5215 | ssize_t link_size; |
| 5170 | 5216 | ||
| 5171 | if (fd != AT_FDCWD) | ||
| 5172 | { | ||
| 5173 | errno = EINVAL; | ||
| 5174 | return NULL; | ||
| 5175 | } | ||
| 5176 | |||
| 5177 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); | 5217 | link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); |
| 5178 | 5218 | ||
| 5179 | if (link_size > 0) | 5219 | if (link_size > 0) |
| @@ -5191,14 +5231,6 @@ careadlinkat (int fd, char const *filename, | |||
| 5191 | return NULL; | 5231 | return NULL; |
| 5192 | } | 5232 | } |
| 5193 | 5233 | ||
| 5194 | ssize_t | ||
| 5195 | careadlinkatcwd (int fd, char const *filename, char *buffer, | ||
| 5196 | size_t buffer_size) | ||
| 5197 | { | ||
| 5198 | (void) fd; | ||
| 5199 | return readlink (filename, buffer, buffer_size); | ||
| 5200 | } | ||
| 5201 | |||
| 5202 | 5234 | ||
| 5203 | /* Support for browsing other processes and their attributes. See | 5235 | /* Support for browsing other processes and their attributes. See |
| 5204 | process.c for the Lisp bindings. */ | 5236 | process.c for the Lisp bindings. */ |