mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-02 11:21:42 +00:00
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
This commit is contained in:
parent
44b12dd699
commit
8654f9d7d6
20
ChangeLog
20
ChangeLog
@ -1,3 +1,23 @@
|
||||
2013-02-01 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).
|
||||
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.
|
||||
|
||||
2013-02-01 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* make-dist: Only README files exist in lisp/ now, not README*.
|
||||
|
@ -1,3 +1,10 @@
|
||||
2013-02-01 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).
|
||||
* merge-gnulib (GNULIB_MODULES): Add fdopendir, fstatat, readlinkat.
|
||||
(GNULIB_TOOL_FLAGS): Do not avoid at-internal, openat-h.
|
||||
Avoid dup, open, opendir.
|
||||
|
||||
2013-01-15 Dmitry Antipov <dmantipov@yandex.ru>
|
||||
|
||||
* coccinelle/xsave.cocci: Semantic patch to adjust users of
|
||||
|
@ -29,9 +29,9 @@ GNULIB_MODULES='
|
||||
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
|
||||
fcntl-h fdopendir filemode fstatat getloadavg getopt-gnu gettime gettimeofday
|
||||
ignore-value intprops largefile lstat
|
||||
manywarnings mktime pselect pthread_sigmask putenv readlink
|
||||
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
|
||||
@ -39,10 +39,10 @@ GNULIB_MODULES='
|
||||
'
|
||||
|
||||
GNULIB_TOOL_FLAGS='
|
||||
--avoid=at-internal
|
||||
--avoid=dup
|
||||
--avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat
|
||||
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
|
||||
--avoid=openat-die --avoid=openat-h
|
||||
--avoid=open --avoid=openat-die --avoid=opendir
|
||||
--avoid=raise
|
||||
--avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types
|
||||
--avoid=threadlib
|
||||
|
@ -8,3 +8,5 @@ AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src
|
||||
|
||||
include gnulib.mk
|
||||
|
||||
libgnu_a_SOURCES += openat-die.c save-cwd.c
|
||||
|
@ -24,9 +24,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Define this independently so that stdint.h is not a prerequisite. */
|
||||
#ifndef SIZE_MAX
|
||||
@ -39,20 +37,6 @@
|
||||
|
||||
#include "allocator.h"
|
||||
|
||||
/* Get the symbolic link value of FILENAME and put it into BUFFER, with
|
||||
size BUFFER_SIZE. This function acts like readlink but has
|
||||
readlinkat's signature. */
|
||||
ssize_t
|
||||
careadlinkatcwd (int fd, char const *filename, char *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
/* FD must be AT_FDCWD here, otherwise the caller is using this
|
||||
function in contexts for which it was not meant for. */
|
||||
if (fd != AT_FDCWD)
|
||||
abort ();
|
||||
return readlink (filename, buffer, buffer_size);
|
||||
}
|
||||
|
||||
/* Assuming the current directory is FD, get the symbolic link value
|
||||
of FILENAME as a null-terminated string and put it into a buffer.
|
||||
If FD is AT_FDCWD, FILENAME is interpreted relative to the current
|
||||
|
@ -52,9 +52,9 @@ char *careadlinkat (int fd, char const *filename,
|
||||
ssize_t (*preadlinkat) (int, char const *,
|
||||
char *, size_t));
|
||||
|
||||
/* Suitable values for careadlinkat's FD and PREADLINKAT arguments,
|
||||
/* Suitable value for careadlinkat's FD argument,
|
||||
when doing a plain readlink:
|
||||
Pass FD = AT_FDCWD and PREADLINKAT = careadlinkatcwd. */
|
||||
Pass FD = AT_FDCWD. */
|
||||
#if HAVE_READLINKAT
|
||||
/* AT_FDCWD is declared in <fcntl.h>. */
|
||||
#else
|
||||
@ -66,7 +66,5 @@ char *careadlinkat (int fd, char const *filename,
|
||||
# define AT_FDCWD (-3041965)
|
||||
# endif
|
||||
#endif
|
||||
ssize_t careadlinkatcwd (int fd, char const *filename,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
#endif /* _GL_CAREADLINKAT_H */
|
||||
|
258
lib/dirent.in.h
Normal file
258
lib/dirent.in.h
Normal file
@ -0,0 +1,258 @@
|
||||
/* A GNU-like <dirent.h>.
|
||||
Copyright (C) 2006-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_DIRENT_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@PRAGMA_SYSTEM_HEADER@
|
||||
#endif
|
||||
@PRAGMA_COLUMNS@
|
||||
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
#if @HAVE_DIRENT_H@
|
||||
# @INCLUDE_NEXT@ @NEXT_DIRENT_H@
|
||||
#endif
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_DIRENT_H
|
||||
#define _@GUARD_PREFIX@_DIRENT_H
|
||||
|
||||
/* Get ino_t. Needed on some systems, including glibc 2.8. */
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !@HAVE_DIRENT_H@
|
||||
/* Define types DIR and 'struct dirent'. */
|
||||
# if !GNULIB_defined_struct_dirent
|
||||
struct dirent
|
||||
{
|
||||
char d_type;
|
||||
char d_name[1];
|
||||
};
|
||||
/* Possible values for 'd_type'. */
|
||||
# define DT_UNKNOWN 0
|
||||
# define DT_FIFO 1 /* FIFO */
|
||||
# define DT_CHR 2 /* character device */
|
||||
# define DT_DIR 4 /* directory */
|
||||
# define DT_BLK 6 /* block device */
|
||||
# define DT_REG 8 /* regular file */
|
||||
# define DT_LNK 10 /* symbolic link */
|
||||
# define DT_SOCK 12 /* socket */
|
||||
# define DT_WHT 14 /* whiteout */
|
||||
typedef struct gl_directory DIR;
|
||||
# define GNULIB_defined_struct_dirent 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The __attribute__ feature is available in gcc versions 2.5 and later.
|
||||
The attribute __pure__ was added in gcc 2.96. */
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
|
||||
# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
|
||||
#else
|
||||
# define _GL_ATTRIBUTE_PURE /* empty */
|
||||
#endif
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
|
||||
/* The definition of _GL_ARG_NONNULL is copied here. */
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
|
||||
|
||||
/* Declare overridden functions. */
|
||||
|
||||
#if @GNULIB_OPENDIR@
|
||||
# if @REPLACE_OPENDIR@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef opendir
|
||||
# define opendir rpl_opendir
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1)));
|
||||
_GL_CXXALIAS_RPL (opendir, DIR *, (const char *dir_name));
|
||||
# else
|
||||
# if !@HAVE_OPENDIR@
|
||||
_GL_FUNCDECL_SYS (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL ((1)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (opendir, DIR *, (const char *dir_name));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (opendir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef opendir
|
||||
# if HAVE_RAW_DECL_OPENDIR
|
||||
_GL_WARN_ON_USE (opendir, "opendir is not portable - "
|
||||
"use gnulib module opendir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_READDIR@
|
||||
# if !@HAVE_READDIR@
|
||||
_GL_FUNCDECL_SYS (readdir, struct dirent *, (DIR *dirp) _GL_ARG_NONNULL ((1)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (readdir, struct dirent *, (DIR *dirp));
|
||||
_GL_CXXALIASWARN (readdir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef readdir
|
||||
# if HAVE_RAW_DECL_READDIR
|
||||
_GL_WARN_ON_USE (readdir, "readdir is not portable - "
|
||||
"use gnulib module readdir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_REWINDDIR@
|
||||
# if !@HAVE_REWINDDIR@
|
||||
_GL_FUNCDECL_SYS (rewinddir, void, (DIR *dirp) _GL_ARG_NONNULL ((1)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (rewinddir, void, (DIR *dirp));
|
||||
_GL_CXXALIASWARN (rewinddir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef rewinddir
|
||||
# if HAVE_RAW_DECL_REWINDDIR
|
||||
_GL_WARN_ON_USE (rewinddir, "rewinddir is not portable - "
|
||||
"use gnulib module rewinddir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_CLOSEDIR@
|
||||
# if @REPLACE_CLOSEDIR@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef closedir
|
||||
# define closedir rpl_closedir
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
|
||||
_GL_CXXALIAS_RPL (closedir, int, (DIR *dirp));
|
||||
# else
|
||||
# if !@HAVE_CLOSEDIR@
|
||||
_GL_FUNCDECL_SYS (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (closedir, int, (DIR *dirp));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (closedir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef closedir
|
||||
# if HAVE_RAW_DECL_CLOSEDIR
|
||||
_GL_WARN_ON_USE (closedir, "closedir is not portable - "
|
||||
"use gnulib module closedir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_DIRFD@
|
||||
/* Return the file descriptor associated with the given directory stream,
|
||||
or -1 if none exists. */
|
||||
# if @REPLACE_DIRFD@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef dirfd
|
||||
# define dirfd rpl_dirfd
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (dirfd, int, (DIR *) _GL_ARG_NONNULL ((1)));
|
||||
_GL_CXXALIAS_RPL (dirfd, int, (DIR *));
|
||||
# else
|
||||
# if defined __cplusplus && defined GNULIB_NAMESPACE && defined dirfd
|
||||
/* dirfd is defined as a macro and not as a function.
|
||||
Turn it into a function and get rid of the macro. */
|
||||
static inline int (dirfd) (DIR *dp) { return dirfd (dp); }
|
||||
# undef dirfd
|
||||
# endif
|
||||
# if !(@HAVE_DECL_DIRFD@ || defined dirfd)
|
||||
_GL_FUNCDECL_SYS (dirfd, int, (DIR *) _GL_ARG_NONNULL ((1)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (dirfd, int, (DIR *));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (dirfd);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef dirfd
|
||||
# if HAVE_RAW_DECL_DIRFD
|
||||
_GL_WARN_ON_USE (dirfd, "dirfd is unportable - "
|
||||
"use gnulib module dirfd for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_FDOPENDIR@
|
||||
/* Open a directory stream visiting the given directory file
|
||||
descriptor. Return NULL and set errno if fd is not visiting a
|
||||
directory. On success, this function consumes fd (it will be
|
||||
implicitly closed either by this function or by a subsequent
|
||||
closedir). */
|
||||
# if @REPLACE_FDOPENDIR@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef fdopendir
|
||||
# define fdopendir rpl_fdopendir
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (fdopendir, DIR *, (int fd));
|
||||
_GL_CXXALIAS_RPL (fdopendir, DIR *, (int fd));
|
||||
# else
|
||||
# if !@HAVE_FDOPENDIR@ || !@HAVE_DECL_FDOPENDIR@
|
||||
_GL_FUNCDECL_SYS (fdopendir, DIR *, (int fd));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (fdopendir, DIR *, (int fd));
|
||||
# endif
|
||||
_GL_CXXALIASWARN (fdopendir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef fdopendir
|
||||
# if HAVE_RAW_DECL_FDOPENDIR
|
||||
_GL_WARN_ON_USE (fdopendir, "fdopendir is unportable - "
|
||||
"use gnulib module fdopendir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_SCANDIR@
|
||||
/* Scan the directory DIR, calling FILTER on each directory entry.
|
||||
Entries for which FILTER returns nonzero are individually malloc'd,
|
||||
sorted using qsort with CMP, and collected in a malloc'd array in
|
||||
*NAMELIST. Returns the number of entries selected, or -1 on error. */
|
||||
# if !@HAVE_SCANDIR@
|
||||
_GL_FUNCDECL_SYS (scandir, int,
|
||||
(const char *dir, struct dirent ***namelist,
|
||||
int (*filter) (const struct dirent *),
|
||||
int (*cmp) (const struct dirent **, const struct dirent **))
|
||||
_GL_ARG_NONNULL ((1, 2, 4)));
|
||||
# endif
|
||||
/* Need to cast, because on glibc systems, the fourth parameter is
|
||||
int (*cmp) (const void *, const void *). */
|
||||
_GL_CXXALIAS_SYS_CAST (scandir, int,
|
||||
(const char *dir, struct dirent ***namelist,
|
||||
int (*filter) (const struct dirent *),
|
||||
int (*cmp) (const struct dirent **, const struct dirent **)));
|
||||
_GL_CXXALIASWARN (scandir);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef scandir
|
||||
# if HAVE_RAW_DECL_SCANDIR
|
||||
_GL_WARN_ON_USE (scandir, "scandir is unportable - "
|
||||
"use gnulib module scandir for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_ALPHASORT@
|
||||
/* Compare two 'struct dirent' entries alphabetically. */
|
||||
# if !@HAVE_ALPHASORT@
|
||||
_GL_FUNCDECL_SYS (alphasort, int,
|
||||
(const struct dirent **, const struct dirent **)
|
||||
_GL_ATTRIBUTE_PURE
|
||||
_GL_ARG_NONNULL ((1, 2)));
|
||||
# endif
|
||||
/* Need to cast, because on glibc systems, the parameters are
|
||||
(const void *, const void *). */
|
||||
_GL_CXXALIAS_SYS_CAST (alphasort, int,
|
||||
(const struct dirent **, const struct dirent **));
|
||||
_GL_CXXALIASWARN (alphasort);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef alphasort
|
||||
# if HAVE_RAW_DECL_ALPHASORT
|
||||
_GL_WARN_ON_USE (alphasort, "alphasort is unportable - "
|
||||
"use gnulib module alphasort for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _@GUARD_PREFIX@_DIRENT_H */
|
||||
#endif /* _@GUARD_PREFIX@_DIRENT_H */
|
204
lib/fdopendir.c
Normal file
204
lib/fdopendir.c
Normal file
@ -0,0 +1,204 @@
|
||||
/* provide a replacement fdopendir function
|
||||
Copyright (C) 2004-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !HAVE_FDOPENDIR
|
||||
|
||||
# include "openat.h"
|
||||
# include "openat-priv.h"
|
||||
# include "save-cwd.h"
|
||||
|
||||
# if GNULIB_DIRENT_SAFER
|
||||
# include "dirent--.h"
|
||||
# endif
|
||||
|
||||
# ifndef REPLACE_FCHDIR
|
||||
# define REPLACE_FCHDIR 0
|
||||
# endif
|
||||
|
||||
static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *);
|
||||
static DIR *fd_clone_opendir (int, struct saved_cwd const *);
|
||||
|
||||
/* Replacement for POSIX fdopendir.
|
||||
|
||||
First, try to simulate it via opendir ("/proc/self/fd/..."). Failing
|
||||
that, simulate it by using fchdir metadata, or by doing
|
||||
save_cwd/fchdir/opendir(".")/restore_cwd.
|
||||
If either the save_cwd or the restore_cwd fails (relatively unlikely),
|
||||
then give a diagnostic and exit nonzero.
|
||||
|
||||
If successful, the resulting stream is based on FD in
|
||||
implementations where streams are based on file descriptors and in
|
||||
applications where no other thread or signal handler allocates or
|
||||
frees file descriptors. In other cases, consult dirfd on the result
|
||||
to find out whether FD is still being used.
|
||||
|
||||
Otherwise, this function works just like POSIX fdopendir.
|
||||
|
||||
W A R N I N G:
|
||||
|
||||
Unlike other fd-related functions, this one places constraints on FD.
|
||||
If this function returns successfully, FD is under control of the
|
||||
dirent.h system, and the caller should not close or modify the state of
|
||||
FD other than by the dirent.h functions. */
|
||||
DIR *
|
||||
fdopendir (int fd)
|
||||
{
|
||||
DIR *dir = fdopendir_with_dup (fd, -1, NULL);
|
||||
|
||||
if (! REPLACE_FCHDIR && ! dir)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
if (EXPECTED_ERRNO (saved_errno))
|
||||
{
|
||||
struct saved_cwd cwd;
|
||||
if (save_cwd (&cwd) != 0)
|
||||
openat_save_fail (errno);
|
||||
dir = fdopendir_with_dup (fd, -1, &cwd);
|
||||
saved_errno = errno;
|
||||
free_cwd (&cwd);
|
||||
errno = saved_errno;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known
|
||||
to be a dup of FD which is less than FD - 1 and which will be
|
||||
closed by the caller and not otherwise used by the caller. This
|
||||
function makes sure that FD is closed and all file descriptors less
|
||||
than FD are open, and then calls fd_clone_opendir on a dup of FD.
|
||||
That way, barring race conditions, fd_clone_opendir returns a
|
||||
stream whose file descriptor is FD.
|
||||
|
||||
If REPLACE_CHDIR or CWD is null, use opendir ("/proc/self/fd/...",
|
||||
falling back on fchdir metadata. Otherwise, CWD is a saved version
|
||||
of the working directory; use fchdir/opendir(".")/restore_cwd(CWD). */
|
||||
static DIR *
|
||||
fdopendir_with_dup (int fd, int older_dupfd, struct saved_cwd const *cwd)
|
||||
{
|
||||
int dupfd = dup (fd);
|
||||
if (dupfd < 0 && errno == EMFILE)
|
||||
dupfd = older_dupfd;
|
||||
if (dupfd < 0)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
DIR *dir;
|
||||
int saved_errno;
|
||||
if (dupfd < fd - 1 && dupfd != older_dupfd)
|
||||
{
|
||||
dir = fdopendir_with_dup (fd, dupfd, cwd);
|
||||
saved_errno = errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
close (fd);
|
||||
dir = fd_clone_opendir (dupfd, cwd);
|
||||
saved_errno = errno;
|
||||
if (! dir)
|
||||
{
|
||||
int fd1 = dup (dupfd);
|
||||
if (fd1 != fd)
|
||||
openat_save_fail (fd1 < 0 ? errno : EBADF);
|
||||
}
|
||||
}
|
||||
|
||||
if (dupfd != older_dupfd)
|
||||
close (dupfd);
|
||||
errno = saved_errno;
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
/* Like fdopendir, except the result controls a clone of FD. It is
|
||||
the caller's responsibility both to close FD and (if the result is
|
||||
not null) to closedir the result. */
|
||||
static DIR *
|
||||
fd_clone_opendir (int fd, struct saved_cwd const *cwd)
|
||||
{
|
||||
if (REPLACE_FCHDIR || ! cwd)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
int saved_errno = EOPNOTSUPP;
|
||||
char buf[OPENAT_BUFFER_SIZE];
|
||||
char *proc_file = openat_proc_name (buf, fd, ".");
|
||||
if (proc_file)
|
||||
{
|
||||
dir = opendir (proc_file);
|
||||
saved_errno = errno;
|
||||
if (proc_file != buf)
|
||||
free (proc_file);
|
||||
}
|
||||
# if REPLACE_FCHDIR
|
||||
if (! dir && EXPECTED_ERRNO (saved_errno))
|
||||
{
|
||||
char const *name = _gl_directory_name (fd);
|
||||
return (name ? opendir (name) : NULL);
|
||||
}
|
||||
# endif
|
||||
errno = saved_errno;
|
||||
return dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fchdir (fd) != 0)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
DIR *dir = opendir (".");
|
||||
int saved_errno = errno;
|
||||
if (restore_cwd (cwd) != 0)
|
||||
openat_restore_fail (errno);
|
||||
errno = saved_errno;
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_FDOPENDIR */
|
||||
|
||||
# include <errno.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
# undef fdopendir
|
||||
|
||||
/* Like fdopendir, but work around GNU/Hurd bug by validating FD. */
|
||||
|
||||
DIR *
|
||||
rpl_fdopendir (int fd)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstat (fd, &st))
|
||||
return NULL;
|
||||
if (!S_ISDIR (st.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
return fdopendir (fd);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FDOPENDIR */
|
135
lib/fstatat.c
Normal file
135
lib/fstatat.c
Normal file
@ -0,0 +1,135 @@
|
||||
/* Work around an fstatat bug on Solaris 9.
|
||||
|
||||
Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert and Jim Meyering. */
|
||||
|
||||
/* If the user's config.h happens to include <sys/stat.h>, let it include only
|
||||
the system's <sys/stat.h> here, so that orig_fstatat doesn't recurse to
|
||||
rpl_fstatat. */
|
||||
#define __need_system_sys_stat_h
|
||||
#include <config.h>
|
||||
|
||||
/* Get the original definition of fstatat. It might be defined as a macro. */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#undef __need_system_sys_stat_h
|
||||
|
||||
#if HAVE_FSTATAT
|
||||
static int
|
||||
orig_fstatat (int fd, char const *filename, struct stat *buf, int flags)
|
||||
{
|
||||
return fstatat (fd, filename, buf, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
|
||||
eliminates this include because of the preliminary #include <sys/stat.h>
|
||||
above. */
|
||||
#include "sys/stat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG
|
||||
|
||||
# ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
# define LSTAT_FOLLOWS_SLASHED_SYMLINK 0
|
||||
# endif
|
||||
|
||||
/* fstatat should always follow symbolic links that end in /, but on
|
||||
Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified.
|
||||
Likewise, trailing slash on a non-directory should be an error.
|
||||
These are the same problems that lstat.c and stat.c address, so
|
||||
solve it in a similar way.
|
||||
|
||||
AIX 7.1 fstatat (AT_FDCWD, ..., 0) always fails, which is a bug.
|
||||
Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero. */
|
||||
|
||||
int
|
||||
rpl_fstatat (int fd, char const *file, struct stat *st, int flag)
|
||||
{
|
||||
int result = orig_fstatat (fd, file, st, flag);
|
||||
size_t len;
|
||||
|
||||
if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0)
|
||||
return result;
|
||||
len = strlen (file);
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
{
|
||||
/* Fix lstat behavior. */
|
||||
if (file[len - 1] != '/' || S_ISDIR (st->st_mode))
|
||||
return 0;
|
||||
if (!S_ISLNK (st->st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
/* Fix stat behavior. */
|
||||
if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/')
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else /* ! (HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG) */
|
||||
|
||||
/* On mingw, the gnulib <sys/stat.h> defines 'stat' as a function-like
|
||||
macro; but using it in AT_FUNC_F2 causes compilation failure
|
||||
because the preprocessor sees a use of a macro that requires two
|
||||
arguments but is only given one. Hence, we need an inline
|
||||
forwarder to get past the preprocessor. */
|
||||
static int
|
||||
stat_func (char const *name, struct stat *st)
|
||||
{
|
||||
return stat (name, st);
|
||||
}
|
||||
|
||||
/* Likewise, if there is no native 'lstat', then the gnulib
|
||||
<sys/stat.h> defined it as stat, which also needs adjustment. */
|
||||
# if !HAVE_LSTAT
|
||||
# undef lstat
|
||||
# define lstat stat_func
|
||||
# endif
|
||||
|
||||
/* Replacement for Solaris' function by the same name.
|
||||
<http://www.google.com/search?q=fstatat+site:docs.sun.com>
|
||||
First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE").
|
||||
Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd.
|
||||
If either the save_cwd or the restore_cwd fails (relatively unlikely),
|
||||
then give a diagnostic and exit nonzero.
|
||||
Otherwise, this function works just like Solaris' fstatat. */
|
||||
|
||||
# define AT_FUNC_NAME fstatat
|
||||
# define AT_FUNC_F1 lstat
|
||||
# define AT_FUNC_F2 stat_func
|
||||
# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
|
||||
# define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag
|
||||
# define AT_FUNC_POST_FILE_ARGS , st
|
||||
# include "at-func.c"
|
||||
# undef AT_FUNC_NAME
|
||||
# undef AT_FUNC_F1
|
||||
# undef AT_FUNC_F2
|
||||
# undef AT_FUNC_USE_F1_COND
|
||||
# undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
# undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#endif /* !HAVE_FSTATAT */
|
@ -21,7 +21,7 @@
|
||||
# the same distribution terms as the rest of that program.
|
||||
#
|
||||
# Generated by gnulib-tool.
|
||||
# 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
|
||||
# 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
|
||||
|
||||
|
||||
MOSTLYCLEANFILES += core *.stackdump
|
||||
@ -64,6 +64,17 @@ EXTRA_DIST += allocator.h
|
||||
|
||||
## end gnulib module allocator
|
||||
|
||||
## begin gnulib module at-internal
|
||||
|
||||
if gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b
|
||||
|
||||
endif
|
||||
EXTRA_DIST += openat-priv.h openat-proc.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += openat-proc.c
|
||||
|
||||
## end gnulib module at-internal
|
||||
|
||||
## begin gnulib module c-ctype
|
||||
|
||||
libgnu_a_SOURCES += c-ctype.h c-ctype.c
|
||||
@ -124,6 +135,54 @@ EXTRA_DIST += sha512.h
|
||||
|
||||
## end gnulib module crypto/sha512
|
||||
|
||||
## begin gnulib module dirent
|
||||
|
||||
BUILT_SOURCES += dirent.h
|
||||
|
||||
# We need the following in order to create <dirent.h> when the system
|
||||
# doesn't have one that works with the given compiler.
|
||||
dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
|
||||
sed -e 's|@''GUARD_PREFIX''@|GL|g' \
|
||||
-e 's|@''HAVE_DIRENT_H''@|$(HAVE_DIRENT_H)|g' \
|
||||
-e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
|
||||
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
|
||||
-e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
|
||||
-e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \
|
||||
-e 's/@''GNULIB_OPENDIR''@/$(GNULIB_OPENDIR)/g' \
|
||||
-e 's/@''GNULIB_READDIR''@/$(GNULIB_READDIR)/g' \
|
||||
-e 's/@''GNULIB_REWINDDIR''@/$(GNULIB_REWINDDIR)/g' \
|
||||
-e 's/@''GNULIB_CLOSEDIR''@/$(GNULIB_CLOSEDIR)/g' \
|
||||
-e 's/@''GNULIB_DIRFD''@/$(GNULIB_DIRFD)/g' \
|
||||
-e 's/@''GNULIB_FDOPENDIR''@/$(GNULIB_FDOPENDIR)/g' \
|
||||
-e 's/@''GNULIB_SCANDIR''@/$(GNULIB_SCANDIR)/g' \
|
||||
-e 's/@''GNULIB_ALPHASORT''@/$(GNULIB_ALPHASORT)/g' \
|
||||
-e 's/@''HAVE_OPENDIR''@/$(HAVE_OPENDIR)/g' \
|
||||
-e 's/@''HAVE_READDIR''@/$(HAVE_READDIR)/g' \
|
||||
-e 's/@''HAVE_REWINDDIR''@/$(HAVE_REWINDDIR)/g' \
|
||||
-e 's/@''HAVE_CLOSEDIR''@/$(HAVE_CLOSEDIR)/g' \
|
||||
-e 's|@''HAVE_DECL_DIRFD''@|$(HAVE_DECL_DIRFD)|g' \
|
||||
-e 's|@''HAVE_DECL_FDOPENDIR''@|$(HAVE_DECL_FDOPENDIR)|g' \
|
||||
-e 's|@''HAVE_FDOPENDIR''@|$(HAVE_FDOPENDIR)|g' \
|
||||
-e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \
|
||||
-e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \
|
||||
-e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \
|
||||
-e 's|@''REPLACE_CLOSEDIR''@|$(REPLACE_CLOSEDIR)|g' \
|
||||
-e 's|@''REPLACE_DIRFD''@|$(REPLACE_DIRFD)|g' \
|
||||
-e 's|@''REPLACE_FDOPENDIR''@|$(REPLACE_FDOPENDIR)|g' \
|
||||
-e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
|
||||
-e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
|
||||
-e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
|
||||
< $(srcdir)/dirent.in.h; \
|
||||
} > $@-t && \
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += dirent.h dirent.h-t
|
||||
|
||||
EXTRA_DIST += dirent.in.h
|
||||
|
||||
## end gnulib module dirent
|
||||
|
||||
## begin gnulib module dosname
|
||||
|
||||
if gl_GNULIB_ENABLED_dosname
|
||||
@ -238,6 +297,15 @@ EXTRA_DIST += fcntl.in.h
|
||||
|
||||
## end gnulib module fcntl-h
|
||||
|
||||
## begin gnulib module fdopendir
|
||||
|
||||
|
||||
EXTRA_DIST += fdopendir.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += fdopendir.c
|
||||
|
||||
## end gnulib module fdopendir
|
||||
|
||||
## begin gnulib module filemode
|
||||
|
||||
libgnu_a_SOURCES += filemode.c
|
||||
@ -255,6 +323,15 @@ EXTRA_libgnu_a_SOURCES += fpending.c
|
||||
|
||||
## end gnulib module fpending
|
||||
|
||||
## begin gnulib module fstatat
|
||||
|
||||
|
||||
EXTRA_DIST += at-func.c fstatat.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += at-func.c fstatat.c
|
||||
|
||||
## end gnulib module fstatat
|
||||
|
||||
## begin gnulib module getgroups
|
||||
|
||||
if gl_GNULIB_ENABLED_getgroups
|
||||
@ -412,6 +489,15 @@ EXTRA_libgnu_a_SOURCES += mktime.c
|
||||
|
||||
## end gnulib module mktime
|
||||
|
||||
## begin gnulib module openat-h
|
||||
|
||||
if gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
|
||||
endif
|
||||
EXTRA_DIST += openat.h
|
||||
|
||||
## end gnulib module openat-h
|
||||
|
||||
## begin gnulib module pathmax
|
||||
|
||||
if gl_GNULIB_ENABLED_pathmax
|
||||
@ -457,6 +543,15 @@ EXTRA_libgnu_a_SOURCES += readlink.c
|
||||
|
||||
## end gnulib module readlink
|
||||
|
||||
## begin gnulib module readlinkat
|
||||
|
||||
|
||||
EXTRA_DIST += at-func.c readlinkat.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += at-func.c readlinkat.c
|
||||
|
||||
## end gnulib module readlinkat
|
||||
|
||||
## begin gnulib module root-uid
|
||||
|
||||
if gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c
|
||||
|
6
lib/openat-die.c
Normal file
6
lib/openat-die.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* Respond to a save- or restore-cwd failure.
|
||||
This should never happen with Emacs. */
|
||||
#include <config.h>
|
||||
#include "openat.h"
|
||||
void openat_save_fail (int errnum) { abort (); }
|
||||
void openat_restore_fail (int errnum) { abort (); }
|
64
lib/openat-priv.h
Normal file
64
lib/openat-priv.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* Internals for openat-like functions.
|
||||
|
||||
Copyright (C) 2005-2006, 2009-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#ifndef _GL_HEADER_OPENAT_PRIV
|
||||
#define _GL_HEADER_OPENAT_PRIV
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Maximum number of bytes that it is safe to allocate as a single
|
||||
array on the stack, and that is known as a compile-time constant.
|
||||
The assumption is that we'll touch the array very quickly, or a
|
||||
temporary very near the array, provoking an out-of-memory trap. On
|
||||
some operating systems, there is only one guard page for the stack,
|
||||
and a page size can be as small as 4096 bytes. Subtract 64 in the
|
||||
hope that this will let the compiler touch a nearby temporary and
|
||||
provoke a trap. */
|
||||
#define SAFER_ALLOCA_MAX (4096 - 64)
|
||||
|
||||
#define SAFER_ALLOCA(m) ((m) < SAFER_ALLOCA_MAX ? (m) : SAFER_ALLOCA_MAX)
|
||||
|
||||
#if defined PATH_MAX
|
||||
# define OPENAT_BUFFER_SIZE SAFER_ALLOCA (PATH_MAX)
|
||||
#elif defined _XOPEN_PATH_MAX
|
||||
# define OPENAT_BUFFER_SIZE SAFER_ALLOCA (_XOPEN_PATH_MAX)
|
||||
#else
|
||||
# define OPENAT_BUFFER_SIZE SAFER_ALLOCA (1024)
|
||||
#endif
|
||||
|
||||
char *openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file);
|
||||
|
||||
/* Trying to access a BUILD_PROC_NAME file will fail on systems without
|
||||
/proc support, and even on systems *with* ProcFS support. Return
|
||||
nonzero if the failure may be legitimate, e.g., because /proc is not
|
||||
readable, or the particular .../fd/N directory is not present. */
|
||||
#define EXPECTED_ERRNO(Errno) \
|
||||
((Errno) == ENOTDIR || (Errno) == ENOENT \
|
||||
|| (Errno) == EPERM || (Errno) == EACCES \
|
||||
|| (Errno) == ENOSYS /* Solaris 8 */ \
|
||||
|| (Errno) == EOPNOTSUPP /* FreeBSD */)
|
||||
|
||||
/* Wrapper function shared among linkat and renameat. */
|
||||
int at_func2 (int fd1, char const *file1,
|
||||
int fd2, char const *file2,
|
||||
int (*func) (char const *file1, char const *file2));
|
||||
|
||||
#endif /* _GL_HEADER_OPENAT_PRIV */
|
110
lib/openat-proc.c
Normal file
110
lib/openat-proc.c
Normal file
@ -0,0 +1,110 @@
|
||||
/* Create /proc/self/fd-related names for subfiles of open directories.
|
||||
|
||||
Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "intprops.h"
|
||||
|
||||
/* The results of open() in this file are not used with fchdir,
|
||||
and we do not leak fds to any single-threaded code that could use stdio,
|
||||
therefore save some unnecessary work in fchdir.c.
|
||||
FIXME - if the kernel ever adds support for multi-thread safety for
|
||||
avoiding standard fds, then we should use open_safer. */
|
||||
#undef open
|
||||
#undef close
|
||||
|
||||
#define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/%s"
|
||||
|
||||
#define PROC_SELF_FD_NAME_SIZE_BOUND(len) \
|
||||
(sizeof PROC_SELF_FD_FORMAT - sizeof "%d%s" \
|
||||
+ INT_STRLEN_BOUND (int) + (len) + 1)
|
||||
|
||||
|
||||
/* Set BUF to the expansion of PROC_SELF_FD_FORMAT, using FD and FILE
|
||||
respectively for %d and %s. If successful, return BUF if the
|
||||
result fits in BUF, dynamically allocated memory otherwise. But
|
||||
return NULL if /proc is not reliable, either because the operating
|
||||
system support is lacking or because memory is low. */
|
||||
char *
|
||||
openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file)
|
||||
{
|
||||
static int proc_status = 0;
|
||||
|
||||
/* Make sure the caller gets ENOENT when appropriate. */
|
||||
if (!*file)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (! proc_status)
|
||||
{
|
||||
/* Set PROC_STATUS to a positive value if /proc/self/fd is
|
||||
reliable, and a negative value otherwise. Solaris 10
|
||||
/proc/self/fd mishandles "..", and any file name might expand
|
||||
to ".." after symbolic link expansion, so avoid /proc/self/fd
|
||||
if it mishandles "..". Solaris 10 has openat, but this
|
||||
problem is exhibited on code that built on Solaris 8 and
|
||||
running on Solaris 10. */
|
||||
|
||||
int proc_self_fd = open ("/proc/self/fd",
|
||||
O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
|
||||
if (proc_self_fd < 0)
|
||||
proc_status = -1;
|
||||
else
|
||||
{
|
||||
/* Detect whether /proc/self/fd/%i/../fd exists, where %i is the
|
||||
number of a file descriptor open on /proc/self/fd. On Linux,
|
||||
that name resolves to /proc/self/fd, which was opened above.
|
||||
However, on Solaris, it may resolve to /proc/self/fd/fd, which
|
||||
cannot exist, since all names in /proc/self/fd are numeric. */
|
||||
char dotdot_buf[PROC_SELF_FD_NAME_SIZE_BOUND (sizeof "../fd" - 1)];
|
||||
sprintf (dotdot_buf, PROC_SELF_FD_FORMAT, proc_self_fd, "../fd");
|
||||
proc_status = access (dotdot_buf, F_OK) ? -1 : 1;
|
||||
close (proc_self_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_status < 0)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
size_t bufsize = PROC_SELF_FD_NAME_SIZE_BOUND (strlen (file));
|
||||
char *result = buf;
|
||||
if (OPENAT_BUFFER_SIZE < bufsize)
|
||||
{
|
||||
result = malloc (bufsize);
|
||||
if (! result)
|
||||
return NULL;
|
||||
}
|
||||
sprintf (result, PROC_SELF_FD_FORMAT, fd, file);
|
||||
return result;
|
||||
}
|
||||
}
|
120
lib/openat.h
Normal file
120
lib/openat.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* provide a replacement openat function
|
||||
Copyright (C) 2004-2006, 2008-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#ifndef _GL_HEADER_OPENAT
|
||||
#define _GL_HEADER_OPENAT
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
|
||||
#if !HAVE_OPENAT
|
||||
|
||||
int openat_permissive (int fd, char const *file, int flags, mode_t mode,
|
||||
int *cwd_errno);
|
||||
bool openat_needs_fchdir (void);
|
||||
|
||||
#else
|
||||
|
||||
# define openat_permissive(Fd, File, Flags, Mode, Cwd_errno) \
|
||||
openat (Fd, File, Flags, Mode)
|
||||
# define openat_needs_fchdir() false
|
||||
|
||||
#endif
|
||||
|
||||
_Noreturn void openat_restore_fail (int);
|
||||
_Noreturn void openat_save_fail (int);
|
||||
|
||||
/* Using these function names makes application code
|
||||
slightly more readable than it would be with
|
||||
fchownat (..., 0) or fchownat (..., AT_SYMLINK_NOFOLLOW). */
|
||||
|
||||
#if GNULIB_FCHOWNAT
|
||||
|
||||
# ifndef FCHOWNAT_INLINE
|
||||
# define FCHOWNAT_INLINE _GL_INLINE
|
||||
# endif
|
||||
|
||||
FCHOWNAT_INLINE int
|
||||
chownat (int fd, char const *file, uid_t owner, gid_t group)
|
||||
{
|
||||
return fchownat (fd, file, owner, group, 0);
|
||||
}
|
||||
|
||||
FCHOWNAT_INLINE int
|
||||
lchownat (int fd, char const *file, uid_t owner, gid_t group)
|
||||
{
|
||||
return fchownat (fd, file, owner, group, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if GNULIB_FCHMODAT
|
||||
|
||||
# ifndef FCHMODAT_INLINE
|
||||
# define FCHMODAT_INLINE _GL_INLINE
|
||||
# endif
|
||||
|
||||
FCHMODAT_INLINE int
|
||||
chmodat (int fd, char const *file, mode_t mode)
|
||||
{
|
||||
return fchmodat (fd, file, mode, 0);
|
||||
}
|
||||
|
||||
FCHMODAT_INLINE int
|
||||
lchmodat (int fd, char const *file, mode_t mode)
|
||||
{
|
||||
return fchmodat (fd, file, mode, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if GNULIB_STATAT
|
||||
|
||||
# ifndef STATAT_INLINE
|
||||
# define STATAT_INLINE _GL_INLINE
|
||||
# endif
|
||||
|
||||
STATAT_INLINE int
|
||||
statat (int fd, char const *name, struct stat *st)
|
||||
{
|
||||
return fstatat (fd, name, st, 0);
|
||||
}
|
||||
|
||||
STATAT_INLINE int
|
||||
lstatat (int fd, char const *name, struct stat *st)
|
||||
{
|
||||
return fstatat (fd, name, st, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* For now, there are no wrappers named laccessat or leuidaccessat,
|
||||
since gnulib doesn't support faccessat(,AT_SYMLINK_NOFOLLOW) and
|
||||
since access rights on symlinks are of limited utility. Likewise,
|
||||
wrappers are not provided for accessat or euidaccessat, so as to
|
||||
avoid dragging in -lgen on some platforms. */
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* _GL_HEADER_OPENAT */
|
47
lib/readlinkat.c
Normal file
47
lib/readlinkat.c
Normal file
@ -0,0 +1,47 @@
|
||||
/* Read a symlink relative to an open directory.
|
||||
Copyright (C) 2009-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Eric Blake */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/* Gnulib provides a readlink stub for mingw; use it for distinction
|
||||
between EINVAL and ENOENT, rather than always failing with ENOSYS. */
|
||||
|
||||
/* POSIX 2008 says that unlike readlink, readlinkat returns 0 for
|
||||
success instead of the buffer length. But this would render
|
||||
readlinkat worthless since readlink does not guarantee a
|
||||
NUL-terminated buffer. Assume this was a bug in POSIX. */
|
||||
|
||||
/* Read the contents of symlink FILE into buffer BUF of size LEN, in the
|
||||
directory open on descriptor FD. If possible, do it without changing
|
||||
the working directory. Otherwise, resort to using save_cwd/fchdir,
|
||||
then readlink/restore_cwd. If either the save_cwd or the restore_cwd
|
||||
fails, then give a diagnostic and exit nonzero. */
|
||||
|
||||
#define AT_FUNC_NAME readlinkat
|
||||
#define AT_FUNC_F1 readlink
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , char *buf, size_t len
|
||||
#define AT_FUNC_POST_FILE_ARGS , buf, len
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
#undef AT_FUNC_RESULT
|
3
lib/save-cwd.c
Normal file
3
lib/save-cwd.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define SAVE_CWD_INLINE _GL_EXTERN_INLINE
|
||||
#include "save-cwd.h"
|
46
lib/save-cwd.h
Normal file
46
lib/save-cwd.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Do not save and restore the current working directory.
|
||||
|
||||
Copyright 2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Gnulib needs to save and restore the current working directory to
|
||||
fully emulate functions like fstatat. But Emacs doesn't care what
|
||||
the current working directory is; it always uses absolute file
|
||||
names. This module replaces the Gnulib module by omitting the code
|
||||
that Emacs does not need. */
|
||||
|
||||
#ifndef SAVE_CWD_H
|
||||
#define SAVE_CWD_H 1
|
||||
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef SAVE_CWD_INLINE
|
||||
# define SAVE_CWD_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
struct saved_cwd { int desc; };
|
||||
|
||||
SAVE_CWD_INLINE int
|
||||
save_cwd (struct saved_cwd *cwd)
|
||||
{
|
||||
cwd->desc = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SAVE_CWD_INLINE int restore_cwd (struct saved_cwd const *cwd) { return 0; }
|
||||
SAVE_CWD_INLINE void free_cwd (struct saved_cwd *cwd) { }
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif
|
64
m4/dirent_h.m4
Normal file
64
m4/dirent_h.m4
Normal file
@ -0,0 +1,64 @@
|
||||
# dirent_h.m4 serial 16
|
||||
dnl Copyright (C) 2008-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl Written by Bruno Haible.
|
||||
|
||||
AC_DEFUN([gl_DIRENT_H],
|
||||
[
|
||||
dnl Use AC_REQUIRE here, so that the default behavior below is expanded
|
||||
dnl once only, before all statements that occur in other macros.
|
||||
AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
|
||||
|
||||
dnl <dirent.h> is always overridden, because of GNULIB_POSIXCHECK.
|
||||
gl_CHECK_NEXT_HEADERS([dirent.h])
|
||||
if test $ac_cv_header_dirent_h = yes; then
|
||||
HAVE_DIRENT_H=1
|
||||
else
|
||||
HAVE_DIRENT_H=0
|
||||
fi
|
||||
AC_SUBST([HAVE_DIRENT_H])
|
||||
|
||||
dnl Check for declarations of anything we want to poison if the
|
||||
dnl corresponding gnulib module is not in use.
|
||||
gl_WARN_ON_USE_PREPARE([[#include <dirent.h>
|
||||
]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_DIRENT_MODULE_INDICATOR],
|
||||
[
|
||||
dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
|
||||
AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
|
||||
gl_MODULE_INDICATOR_SET_VARIABLE([$1])
|
||||
dnl Define it also as a C macro, for the benefit of the unit tests.
|
||||
gl_MODULE_INDICATOR_FOR_TESTS([$1])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_DIRENT_H_DEFAULTS],
|
||||
[
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR
|
||||
GNULIB_OPENDIR=0; AC_SUBST([GNULIB_OPENDIR])
|
||||
GNULIB_READDIR=0; AC_SUBST([GNULIB_READDIR])
|
||||
GNULIB_REWINDDIR=0; AC_SUBST([GNULIB_REWINDDIR])
|
||||
GNULIB_CLOSEDIR=0; AC_SUBST([GNULIB_CLOSEDIR])
|
||||
GNULIB_DIRFD=0; AC_SUBST([GNULIB_DIRFD])
|
||||
GNULIB_FDOPENDIR=0; AC_SUBST([GNULIB_FDOPENDIR])
|
||||
GNULIB_SCANDIR=0; AC_SUBST([GNULIB_SCANDIR])
|
||||
GNULIB_ALPHASORT=0; AC_SUBST([GNULIB_ALPHASORT])
|
||||
dnl Assume proper GNU behavior unless another module says otherwise.
|
||||
HAVE_OPENDIR=1; AC_SUBST([HAVE_OPENDIR])
|
||||
HAVE_READDIR=1; AC_SUBST([HAVE_READDIR])
|
||||
HAVE_REWINDDIR=1; AC_SUBST([HAVE_REWINDDIR])
|
||||
HAVE_CLOSEDIR=1; AC_SUBST([HAVE_CLOSEDIR])
|
||||
HAVE_DECL_DIRFD=1; AC_SUBST([HAVE_DECL_DIRFD])
|
||||
HAVE_DECL_FDOPENDIR=1;AC_SUBST([HAVE_DECL_FDOPENDIR])
|
||||
HAVE_FDOPENDIR=1; AC_SUBST([HAVE_FDOPENDIR])
|
||||
HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR])
|
||||
HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT])
|
||||
REPLACE_OPENDIR=0; AC_SUBST([REPLACE_OPENDIR])
|
||||
REPLACE_CLOSEDIR=0; AC_SUBST([REPLACE_CLOSEDIR])
|
||||
REPLACE_DIRFD=0; AC_SUBST([REPLACE_DIRFD])
|
||||
REPLACE_FDOPENDIR=0; AC_SUBST([REPLACE_FDOPENDIR])
|
||||
])
|
61
m4/fdopendir.m4
Normal file
61
m4/fdopendir.m4
Normal file
@ -0,0 +1,61 @@
|
||||
# serial 10
|
||||
# See if we need to provide fdopendir.
|
||||
|
||||
dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Eric Blake.
|
||||
|
||||
AC_DEFUN([gl_FUNC_FDOPENDIR],
|
||||
[
|
||||
AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
dnl FreeBSD 7.3 has the function, but failed to declare it.
|
||||
AC_CHECK_DECLS([fdopendir], [], [HAVE_DECL_FDOPENDIR=0], [[
|
||||
#include <dirent.h>
|
||||
]])
|
||||
AC_CHECK_FUNCS_ONCE([fdopendir])
|
||||
if test $ac_cv_func_fdopendir = no; then
|
||||
HAVE_FDOPENDIR=0
|
||||
else
|
||||
AC_CACHE_CHECK([whether fdopendir works],
|
||||
[gl_cv_func_fdopendir_works],
|
||||
[AC_RUN_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#if !HAVE_DECL_FDOPENDIR
|
||||
extern
|
||||
# ifdef __cplusplus
|
||||
"C"
|
||||
# endif
|
||||
DIR *fdopendir (int);
|
||||
#endif
|
||||
]], [int result = 0;
|
||||
int fd = open ("conftest.c", O_RDONLY);
|
||||
if (fd < 0) result |= 1;
|
||||
if (fdopendir (fd)) result |= 2;
|
||||
if (close (fd)) result |= 4;
|
||||
return result;])],
|
||||
[gl_cv_func_fdopendir_works=yes],
|
||||
[gl_cv_func_fdopendir_works=no],
|
||||
[case "$host_os" in
|
||||
# Guess yes on glibc systems.
|
||||
*-gnu*) gl_cv_func_fdopendir_works="guessing yes" ;;
|
||||
# If we don't know, assume the worst.
|
||||
*) gl_cv_func_fdopendir_works="guessing no" ;;
|
||||
esac
|
||||
])])
|
||||
case "$gl_cv_func_fdopendir_works" in
|
||||
*yes) ;;
|
||||
*)
|
||||
REPLACE_FDOPENDIR=1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
])
|
60
m4/fstatat.m4
Normal file
60
m4/fstatat.m4
Normal file
@ -0,0 +1,60 @@
|
||||
# fstatat.m4 serial 3
|
||||
dnl Copyright (C) 2004-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Jim Meyering.
|
||||
|
||||
# If we have the fstatat function, and it has the bug (in AIX 7.1)
|
||||
# that it does not fill in st_size correctly, use the replacement function.
|
||||
AC_DEFUN([gl_FUNC_FSTATAT],
|
||||
[
|
||||
AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||
AC_CHECK_FUNCS_ONCE([fstatat])
|
||||
|
||||
if test $ac_cv_func_fstatat = no; then
|
||||
HAVE_FSTATAT=0
|
||||
else
|
||||
dnl Test for an AIX 7.1 bug; see
|
||||
dnl <http://lists.gnu.org/archive/html/bug-tar/2011-09/msg00015.html>.
|
||||
AC_CACHE_CHECK([whether fstatat (..., 0) works],
|
||||
[gl_cv_func_fstatat_zero_flag],
|
||||
[AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE(
|
||||
[[
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct stat a;
|
||||
return fstatat (AT_FDCWD, ".", &a, 0) != 0;
|
||||
}
|
||||
]])],
|
||||
[gl_cv_func_fstatat_zero_flag=yes],
|
||||
[gl_cv_func_fstatat_zero_flag=no],
|
||||
[case "$host_os" in
|
||||
aix*) gl_cv_func_fstatat_zero_flag="guessing no";;
|
||||
*) gl_cv_func_fstatat_zero_flag="guessing yes";;
|
||||
esac
|
||||
])
|
||||
])
|
||||
|
||||
case $gl_cv_func_fstatat_zero_flag+$gl_cv_func_lstat_dereferences_slashed_symlink in
|
||||
*yes+*yes) ;;
|
||||
*) REPLACE_FSTATAT=1
|
||||
case $gl_cv_func_fstatat_zero_flag in
|
||||
*yes)
|
||||
AC_DEFINE([HAVE_WORKING_FSTATAT_ZERO_FLAG], [1],
|
||||
[Define to 1 if fstatat (..., 0) works.
|
||||
For example, it does not work in AIX 7.1.])
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
])
|
@ -40,6 +40,7 @@ AC_DEFUN([gl_EARLY],
|
||||
AC_REQUIRE([gl_PROG_AR_RANLIB])
|
||||
# Code from module alloca-opt:
|
||||
# Code from module allocator:
|
||||
# Code from module at-internal:
|
||||
# Code from module c-ctype:
|
||||
# Code from module c-strcase:
|
||||
# Code from module careadlinkat:
|
||||
@ -49,6 +50,7 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module crypto/sha1:
|
||||
# Code from module crypto/sha256:
|
||||
# Code from module crypto/sha512:
|
||||
# Code from module dirent:
|
||||
# Code from module dosname:
|
||||
# Code from module dtoastr:
|
||||
# Code from module dtotimespec:
|
||||
@ -61,8 +63,10 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module extern-inline:
|
||||
# Code from module faccessat:
|
||||
# Code from module fcntl-h:
|
||||
# Code from module fdopendir:
|
||||
# Code from module filemode:
|
||||
# Code from module fpending:
|
||||
# Code from module fstatat:
|
||||
# Code from module getgroups:
|
||||
# Code from module getloadavg:
|
||||
# Code from module getopt-gnu:
|
||||
@ -82,11 +86,13 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module mktime:
|
||||
# Code from module multiarch:
|
||||
# Code from module nocrash:
|
||||
# Code from module openat-h:
|
||||
# Code from module pathmax:
|
||||
# Code from module pselect:
|
||||
# Code from module pthread_sigmask:
|
||||
# Code from module putenv:
|
||||
# Code from module readlink:
|
||||
# Code from module readlinkat:
|
||||
# Code from module root-uid:
|
||||
# Code from module sig2str:
|
||||
# Code from module signal-h:
|
||||
@ -159,6 +165,7 @@ AC_DEFUN([gl_INIT],
|
||||
gl_SHA1
|
||||
gl_SHA256
|
||||
gl_SHA512
|
||||
gl_DIRENT_H
|
||||
AC_REQUIRE([gl_C99_STRTOLD])
|
||||
gl_FUNC_DUP2
|
||||
if test $HAVE_DUP2 = 0 || test $REPLACE_DUP2 = 1; then
|
||||
@ -178,12 +185,23 @@ AC_DEFUN([gl_INIT],
|
||||
gl_MODULE_INDICATOR([faccessat])
|
||||
gl_UNISTD_MODULE_INDICATOR([faccessat])
|
||||
gl_FCNTL_H
|
||||
gl_FUNC_FDOPENDIR
|
||||
if test $HAVE_FDOPENDIR = 0 || test $REPLACE_FDOPENDIR = 1; then
|
||||
AC_LIBOBJ([fdopendir])
|
||||
fi
|
||||
gl_DIRENT_MODULE_INDICATOR([fdopendir])
|
||||
gl_MODULE_INDICATOR([fdopendir])
|
||||
gl_FILEMODE
|
||||
gl_FUNC_FPENDING
|
||||
if test $ac_cv_func___fpending = no; then
|
||||
AC_LIBOBJ([fpending])
|
||||
gl_PREREQ_FPENDING
|
||||
fi
|
||||
gl_FUNC_FSTATAT
|
||||
if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then
|
||||
AC_LIBOBJ([fstatat])
|
||||
fi
|
||||
gl_SYS_STAT_MODULE_INDICATOR([fstatat])
|
||||
gl_GETLOADAVG
|
||||
if test $HAVE_GETLOADAVG = 0; then
|
||||
AC_LIBOBJ([getloadavg])
|
||||
@ -253,6 +271,11 @@ AC_DEFUN([gl_INIT],
|
||||
gl_PREREQ_READLINK
|
||||
fi
|
||||
gl_UNISTD_MODULE_INDICATOR([readlink])
|
||||
gl_FUNC_READLINKAT
|
||||
if test $HAVE_READLINKAT = 0; then
|
||||
AC_LIBOBJ([readlinkat])
|
||||
fi
|
||||
gl_UNISTD_MODULE_INDICATOR([readlinkat])
|
||||
gl_FUNC_SIG2STR
|
||||
if test $ac_cv_func_sig2str = no; then
|
||||
AC_LIBOBJ([sig2str])
|
||||
@ -311,11 +334,13 @@ AC_DEFUN([gl_INIT],
|
||||
fi
|
||||
gl_STDLIB_MODULE_INDICATOR([unsetenv])
|
||||
gl_UTIMENS
|
||||
gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false
|
||||
gl_gnulib_enabled_dosname=false
|
||||
gl_gnulib_enabled_euidaccess=false
|
||||
gl_gnulib_enabled_getgroups=false
|
||||
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
|
||||
gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
|
||||
gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false
|
||||
gl_gnulib_enabled_pathmax=false
|
||||
gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
|
||||
gl_gnulib_enabled_stat=false
|
||||
@ -323,6 +348,13 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_strtoull=false
|
||||
gl_gnulib_enabled_verify=false
|
||||
gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b; then
|
||||
AC_LIBOBJ([openat-proc])
|
||||
gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_dosname ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_dosname; then
|
||||
@ -385,6 +417,12 @@ AC_DEFUN([gl_INIT],
|
||||
fi
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7; then
|
||||
gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_pathmax ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_pathmax; then
|
||||
@ -455,12 +493,30 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=true
|
||||
fi
|
||||
}
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
|
||||
fi
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_dosname
|
||||
fi
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_euidaccess
|
||||
fi
|
||||
if test $HAVE_FACCESSAT = 0; then
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
fi
|
||||
if test $HAVE_FDOPENDIR = 0; then
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
|
||||
fi
|
||||
if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
|
||||
fi
|
||||
if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then
|
||||
func_gl_gnulib_m4code_dosname
|
||||
fi
|
||||
if test $HAVE_FSTATAT = 0 || test $REPLACE_FSTATAT = 1; then
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
fi
|
||||
if test $REPLACE_GETOPT = 1; then
|
||||
func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36
|
||||
fi
|
||||
@ -473,6 +529,15 @@ AC_DEFUN([gl_INIT],
|
||||
if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
|
||||
func_gl_gnulib_m4code_stat
|
||||
fi
|
||||
if test $HAVE_READLINKAT = 0; then
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
|
||||
fi
|
||||
if test $HAVE_READLINKAT = 0; then
|
||||
func_gl_gnulib_m4code_dosname
|
||||
fi
|
||||
if test $HAVE_READLINKAT = 0; then
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
fi
|
||||
if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test $ac_cv_type_long_long_int = yes; then
|
||||
func_gl_gnulib_m4code_strtoll
|
||||
fi
|
||||
@ -486,11 +551,13 @@ AC_DEFUN([gl_INIT],
|
||||
func_gl_gnulib_m4code_verify
|
||||
fi
|
||||
m4_pattern_allow([^gl_GNULIB_ENABLED_])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
|
||||
@ -656,6 +723,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/careadlinkat.h
|
||||
lib/close-stream.c
|
||||
lib/close-stream.h
|
||||
lib/dirent.in.h
|
||||
lib/dosname.h
|
||||
lib/dtoastr.c
|
||||
lib/dtotimespec.c
|
||||
@ -665,10 +733,12 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/execinfo.in.h
|
||||
lib/faccessat.c
|
||||
lib/fcntl.in.h
|
||||
lib/fdopendir.c
|
||||
lib/filemode.c
|
||||
lib/filemode.h
|
||||
lib/fpending.c
|
||||
lib/fpending.h
|
||||
lib/fstatat.c
|
||||
lib/ftoastr.c
|
||||
lib/ftoastr.h
|
||||
lib/getgroups.c
|
||||
@ -689,11 +759,15 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/md5.h
|
||||
lib/mktime-internal.h
|
||||
lib/mktime.c
|
||||
lib/openat-priv.h
|
||||
lib/openat-proc.c
|
||||
lib/openat.h
|
||||
lib/pathmax.h
|
||||
lib/pselect.c
|
||||
lib/pthread_sigmask.c
|
||||
lib/putenv.c
|
||||
lib/readlink.c
|
||||
lib/readlinkat.c
|
||||
lib/root-uid.h
|
||||
lib/sha1.c
|
||||
lib/sha1.h
|
||||
@ -746,6 +820,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/c-strtod.m4
|
||||
m4/clock_time.m4
|
||||
m4/close-stream.m4
|
||||
m4/dirent_h.m4
|
||||
m4/dup2.m4
|
||||
m4/environ.m4
|
||||
m4/euidaccess.m4
|
||||
@ -755,8 +830,10 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/faccessat.m4
|
||||
m4/fcntl-o.m4
|
||||
m4/fcntl_h.m4
|
||||
m4/fdopendir.m4
|
||||
m4/filemode.m4
|
||||
m4/fpending.m4
|
||||
m4/fstatat.m4
|
||||
m4/getgroups.m4
|
||||
m4/getloadavg.m4
|
||||
m4/getopt.m4
|
||||
@ -780,6 +857,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/pthread_sigmask.m4
|
||||
m4/putenv.m4
|
||||
m4/readlink.m4
|
||||
m4/readlinkat.m4
|
||||
m4/setenv.m4
|
||||
m4/sha1.m4
|
||||
m4/sha256.m4
|
||||
|
19
m4/readlinkat.m4
Normal file
19
m4/readlinkat.m4
Normal file
@ -0,0 +1,19 @@
|
||||
# serial 3
|
||||
# See if we need to provide readlinkat replacement.
|
||||
|
||||
dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Eric Blake.
|
||||
|
||||
AC_DEFUN([gl_FUNC_READLINKAT],
|
||||
[
|
||||
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
AC_CHECK_FUNCS_ONCE([readlinkat])
|
||||
if test $ac_cv_func_readlinkat = no; then
|
||||
HAVE_READLINKAT=0
|
||||
fi
|
||||
])
|
@ -1,3 +1,9 @@
|
||||
2013-02-01 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).
|
||||
* inc/sys/stat.h (fstatat):
|
||||
* inc/unistd.h (readlinkat): New decls.
|
||||
|
||||
2013-01-28 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* inc/dirent.h (opendir): Update prototype.
|
||||
|
@ -110,6 +110,7 @@ _CRTIMP int __cdecl __MINGW_NOTHROW fstat (int, struct stat*);
|
||||
_CRTIMP int __cdecl __MINGW_NOTHROW chmod (const char*, int);
|
||||
_CRTIMP int __cdecl __MINGW_NOTHROW stat (const char*, struct stat*);
|
||||
_CRTIMP int __cdecl __MINGW_NOTHROW lstat (const char*, struct stat*);
|
||||
_CRTIMP int __cdecl __MINGW_NOTHROW fstatat (int, char const *,
|
||||
struct stat *, int);
|
||||
|
||||
#endif /* INC_SYS_STAT_H_ */
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
and whose prototypes are usually found in unistd.h on POSIX
|
||||
platforms. */
|
||||
extern ssize_t readlink (const char *, char *, size_t);
|
||||
extern ssize_t readlinkat (int, const char *, char *, size_t);
|
||||
extern int symlink (char const *, char const *);
|
||||
extern int setpgid (pid_t, pid_t);
|
||||
extern pid_t getpgrp (void);
|
||||
|
@ -1,3 +1,34 @@
|
||||
2013-02-01 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).
|
||||
* conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): Remove.
|
||||
* 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.
|
||||
* 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.
|
||||
* filelock.c (current_lock_owner): Use emacs_readlinkat
|
||||
rather than emacs_readlink.
|
||||
* lisp.h (emacs_readlinkat): New decl.
|
||||
(READLINK_BUFSIZE, emacs_readlink): Remove.
|
||||
* sysdep.c: Do not include <allocator.h>, <careadlinkat.h>.
|
||||
(emacs_norealloc_allocator, emacs_readlink): Remove.
|
||||
This stuff is moved to fileio.c.
|
||||
* w32.c (fstatat, readlinkat): New functions.
|
||||
(careadlinkat): Don't check that fd == AT_FDCWD.
|
||||
(careadlinkatcwd): Remove; no longer needed.
|
||||
|
||||
2013-01-31 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* fileio.c (choose_write_coding_system): Make it callable from Lisp.
|
||||
|
@ -182,10 +182,6 @@ extern void _DebPrint (const char *fmt, ...);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Tell gnulib to omit support for openat-related functions having a
|
||||
first argument other than AT_FDCWD. */
|
||||
#define GNULIB_SUPPORT_ONLY_AT_FDCWD
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
120
src/dired.c
120
src/dired.c
@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include <grp.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dirent.h>
|
||||
@ -54,6 +55,7 @@ static Lisp_Object Qfile_attributes;
|
||||
static Lisp_Object Qfile_attributes_lessp;
|
||||
|
||||
static ptrdiff_t scmp (const char *, const char *, ptrdiff_t);
|
||||
static Lisp_Object file_attributes (int, char const *, Lisp_Object);
|
||||
|
||||
/* Return the number of bytes in DP's name. */
|
||||
static ptrdiff_t
|
||||
@ -66,6 +68,44 @@ dirent_namelen (struct dirent *dp)
|
||||
#endif
|
||||
}
|
||||
|
||||
static DIR *
|
||||
open_directory (char const *name, int *fdp)
|
||||
{
|
||||
DIR *d;
|
||||
int fd, opendir_errno;
|
||||
|
||||
block_input ();
|
||||
|
||||
#ifdef DOS_NT
|
||||
/* Directories cannot be opened. The emulation assumes that any
|
||||
file descriptor other than AT_FDCWD corresponds to the most
|
||||
recently opened directory. This hack is good enough for Emacs. */
|
||||
fd = 0;
|
||||
d = opendir (name);
|
||||
opendir_errno = errno;
|
||||
#else
|
||||
fd = emacs_open (name, O_RDONLY | O_DIRECTORY, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
opendir_errno = errno;
|
||||
d = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = fdopendir (fd);
|
||||
opendir_errno = errno;
|
||||
if (! d)
|
||||
close (fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
unblock_input ();
|
||||
|
||||
*fdp = fd;
|
||||
errno = opendir_errno;
|
||||
return d;
|
||||
}
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
Lisp_Object
|
||||
directory_files_internal_w32_unwind (Lisp_Object arg)
|
||||
@ -96,6 +136,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
||||
Lisp_Object id_format)
|
||||
{
|
||||
DIR *d;
|
||||
int fd;
|
||||
ptrdiff_t directory_nbytes;
|
||||
Lisp_Object list, dirfilename, encoded_directory;
|
||||
struct re_pattern_buffer *bufp = NULL;
|
||||
@ -142,9 +183,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
||||
/* Now *bufp is the compiled form of MATCH; don't call anything
|
||||
which might compile a new regexp until we're done with the loop! */
|
||||
|
||||
block_input ();
|
||||
d = opendir (SSDATA (dirfilename));
|
||||
unblock_input ();
|
||||
d = open_directory (SSDATA (dirfilename), &fd);
|
||||
if (d == NULL)
|
||||
report_file_error ("Opening directory", Fcons (directory, Qnil));
|
||||
|
||||
@ -259,20 +298,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
||||
|
||||
if (attrs)
|
||||
{
|
||||
/* Construct an expanded filename for the directory entry.
|
||||
Use the decoded names for input to Ffile_attributes. */
|
||||
Lisp_Object decoded_fullname, fileattrs;
|
||||
struct gcpro gcpro1, gcpro2;
|
||||
|
||||
decoded_fullname = fileattrs = Qnil;
|
||||
GCPRO2 (decoded_fullname, fileattrs);
|
||||
|
||||
/* Both Fexpand_file_name and Ffile_attributes can GC. */
|
||||
decoded_fullname = Fexpand_file_name (name, directory);
|
||||
fileattrs = Ffile_attributes (decoded_fullname, id_format);
|
||||
|
||||
Lisp_Object fileattrs
|
||||
= file_attributes (fd, dp->d_name, id_format);
|
||||
list = Fcons (Fcons (finalname, fileattrs), list);
|
||||
UNGCPRO;
|
||||
}
|
||||
else
|
||||
list = Fcons (finalname, list);
|
||||
@ -413,8 +441,7 @@ These are all file names in directory DIRECTORY which begin with FILE. */)
|
||||
return file_name_completion (file, directory, 1, Qnil);
|
||||
}
|
||||
|
||||
static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
|
||||
struct stat *st_addr);
|
||||
static int file_name_completion_stat (int, struct dirent *, struct stat *);
|
||||
static Lisp_Object Qdefault_directory;
|
||||
|
||||
static Lisp_Object
|
||||
@ -422,6 +449,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
|
||||
Lisp_Object predicate)
|
||||
{
|
||||
DIR *d;
|
||||
int fd;
|
||||
ptrdiff_t bestmatchsize = 0;
|
||||
int matchcount = 0;
|
||||
/* 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,
|
||||
|
||||
encoded_dir = ENCODE_FILE (dirname);
|
||||
|
||||
block_input ();
|
||||
d = opendir (SSDATA (Fdirectory_file_name (encoded_dir)));
|
||||
unblock_input ();
|
||||
d = open_directory (SSDATA (Fdirectory_file_name (encoded_dir)), &fd);
|
||||
if (!d)
|
||||
report_file_error ("Opening directory", Fcons (dirname, Qnil));
|
||||
|
||||
@ -495,7 +521,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
|
||||
SCHARS (encoded_file)))
|
||||
continue;
|
||||
|
||||
if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
|
||||
if (file_name_completion_stat (fd, dp, &st) < 0)
|
||||
continue;
|
||||
|
||||
directoryp = S_ISDIR (st.st_mode) != 0;
|
||||
@ -772,14 +798,9 @@ scmp (const char *s1, const char *s2, ptrdiff_t len)
|
||||
}
|
||||
|
||||
static int
|
||||
file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
|
||||
struct stat *st_addr)
|
||||
file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr)
|
||||
{
|
||||
ptrdiff_t len = dirent_namelen (dp);
|
||||
ptrdiff_t pos = SCHARS (dirname);
|
||||
int value;
|
||||
USE_SAFE_ALLOCA;
|
||||
char *fullname = SAFE_ALLOCA (len + pos + 2);
|
||||
|
||||
#ifdef MSDOS
|
||||
/* 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,
|
||||
_djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
|
||||
#endif /* MSDOS */
|
||||
|
||||
memcpy (fullname, SDATA (dirname), pos);
|
||||
if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
|
||||
fullname[pos++] = DIRECTORY_SEP;
|
||||
|
||||
memcpy (fullname + pos, dp->d_name, len);
|
||||
fullname[pos + len] = 0;
|
||||
|
||||
/* We want to return success if a link points to a nonexistent file,
|
||||
but we want to return the status for what the link points to,
|
||||
in case it is a directory. */
|
||||
value = lstat (fullname, st_addr);
|
||||
value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW);
|
||||
if (value == 0 && S_ISLNK (st_addr->st_mode))
|
||||
stat (fullname, st_addr);
|
||||
fstatat (fd, dp->d_name, st_addr, 0);
|
||||
#ifdef MSDOS
|
||||
_djstat_flags = save_djstat_flags;
|
||||
#endif /* MSDOS */
|
||||
SAFE_FREE ();
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -886,18 +899,8 @@ On some FAT-based filesystems, only the date of last access is recorded,
|
||||
so last access time will always be midnight of that day. */)
|
||||
(Lisp_Object filename, Lisp_Object id_format)
|
||||
{
|
||||
Lisp_Object values[12];
|
||||
Lisp_Object encoded;
|
||||
struct stat s;
|
||||
int lstat_result;
|
||||
|
||||
/* An array to hold the mode string generated by filemodestring,
|
||||
including its terminating space and null byte. */
|
||||
char modes[sizeof "-rwxr-xr-x "];
|
||||
|
||||
Lisp_Object handler;
|
||||
struct gcpro gcpro1;
|
||||
char *uname = NULL, *gname = NULL;
|
||||
|
||||
filename = Fexpand_file_name (filename, Qnil);
|
||||
|
||||
@ -913,9 +916,22 @@ so last access time will always be midnight of that day. */)
|
||||
return call3 (handler, Qfile_attributes, filename, id_format);
|
||||
}
|
||||
|
||||
GCPRO1 (filename);
|
||||
encoded = ENCODE_FILE (filename);
|
||||
UNGCPRO;
|
||||
return file_attributes (AT_FDCWD, SSDATA (encoded), id_format);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
file_attributes (int fd, char const *name, Lisp_Object id_format)
|
||||
{
|
||||
Lisp_Object values[12];
|
||||
struct stat s;
|
||||
int lstat_result;
|
||||
|
||||
/* An array to hold the mode string generated by filemodestring,
|
||||
including its terminating space and null byte. */
|
||||
char modes[sizeof "-rwxr-xr-x "];
|
||||
|
||||
char *uname = NULL, *gname = NULL;
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
/* 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. */)
|
||||
w32_stat_get_owner_group = 1;
|
||||
#endif
|
||||
|
||||
lstat_result = lstat (SSDATA (encoded), &s);
|
||||
lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
w32_stat_get_owner_group = 0;
|
||||
@ -934,7 +950,7 @@ so last access time will always be midnight of that day. */)
|
||||
if (lstat_result < 0)
|
||||
return Qnil;
|
||||
|
||||
values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename)
|
||||
values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name)
|
||||
: S_ISDIR (s.st_mode) ? Qt : Qnil);
|
||||
values[1] = make_number (s.st_nlink);
|
||||
|
||||
|
40
src/fileio.c
40
src/fileio.c
@ -82,6 +82,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#endif
|
||||
|
||||
#include "systime.h"
|
||||
#include <allocator.h>
|
||||
#include <careadlinkat.h>
|
||||
#include <stat-time.h>
|
||||
|
||||
#ifdef HPUX
|
||||
@ -2759,6 +2761,29 @@ If there is no error, returns nil. */)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* Relative to directory FD, return the symbolic link value of FILENAME.
|
||||
On failure, return nil. */
|
||||
Lisp_Object
|
||||
emacs_readlinkat (int fd, char const *filename)
|
||||
{
|
||||
static struct allocator const emacs_norealloc_allocator =
|
||||
{ xmalloc, NULL, xfree, memory_full };
|
||||
Lisp_Object val;
|
||||
char readlink_buf[1024];
|
||||
char *buf = careadlinkat (fd, filename, readlink_buf, sizeof readlink_buf,
|
||||
&emacs_norealloc_allocator, readlinkat);
|
||||
if (!buf)
|
||||
return Qnil;
|
||||
|
||||
val = build_string (buf);
|
||||
if (buf[0] == '/' && strchr (buf, ':'))
|
||||
val = concat2 (build_string ("/:"), val);
|
||||
if (buf != readlink_buf)
|
||||
xfree (buf);
|
||||
val = DECODE_FILE (val);
|
||||
return val;
|
||||
}
|
||||
|
||||
DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
|
||||
doc: /* Return non-nil if file FILENAME is the name of a symbolic link.
|
||||
The value is the link target, as a string.
|
||||
@ -2769,9 +2794,6 @@ points to a nonexistent file. */)
|
||||
(Lisp_Object filename)
|
||||
{
|
||||
Lisp_Object handler;
|
||||
char *buf;
|
||||
Lisp_Object val;
|
||||
char readlink_buf[READLINK_BUFSIZE];
|
||||
|
||||
CHECK_STRING (filename);
|
||||
filename = Fexpand_file_name (filename, Qnil);
|
||||
@ -2784,17 +2806,7 @@ points to a nonexistent file. */)
|
||||
|
||||
filename = ENCODE_FILE (filename);
|
||||
|
||||
buf = emacs_readlink (SSDATA (filename), readlink_buf);
|
||||
if (! buf)
|
||||
return Qnil;
|
||||
|
||||
val = build_string (buf);
|
||||
if (buf[0] == '/' && strchr (buf, ':'))
|
||||
val = concat2 (build_string ("/:"), val);
|
||||
if (buf != readlink_buf)
|
||||
xfree (buf);
|
||||
val = DECODE_FILE (val);
|
||||
return val;
|
||||
return emacs_readlinkat (AT_FDCWD, SSDATA (filename));
|
||||
}
|
||||
|
||||
DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
|
||||
|
@ -390,12 +390,14 @@ current_lock_owner (lock_info_type *owner, char *lfname)
|
||||
lock_info_type local_owner;
|
||||
intmax_t n;
|
||||
char *at, *dot, *colon;
|
||||
char readlink_buf[READLINK_BUFSIZE];
|
||||
char *lfinfo = emacs_readlink (lfname, readlink_buf);
|
||||
Lisp_Object lfinfo_object = emacs_readlinkat (AT_FDCWD, lfname);
|
||||
char *lfinfo;
|
||||
struct gcpro gcpro1;
|
||||
|
||||
/* If nonexistent lock file, all is well; otherwise, got strange error. */
|
||||
if (!lfinfo)
|
||||
if (NILP (lfinfo_object))
|
||||
return errno == ENOENT ? 0 : -1;
|
||||
lfinfo = SSDATA (lfinfo_object);
|
||||
|
||||
/* Even if the caller doesn't want the owner info, we still have to
|
||||
read it to determine return value. */
|
||||
@ -407,12 +409,9 @@ current_lock_owner (lock_info_type *owner, char *lfname)
|
||||
at = strrchr (lfinfo, '@');
|
||||
dot = strrchr (lfinfo, '.');
|
||||
if (!at || !dot)
|
||||
{
|
||||
if (lfinfo != readlink_buf)
|
||||
xfree (lfinfo);
|
||||
return -1;
|
||||
}
|
||||
len = at - lfinfo;
|
||||
GCPRO1 (lfinfo_object);
|
||||
owner->user = xmalloc (len + 1);
|
||||
memcpy (owner->user, lfinfo, len);
|
||||
owner->user[len] = 0;
|
||||
@ -445,8 +444,7 @@ current_lock_owner (lock_info_type *owner, char *lfname)
|
||||
owner->host[len] = 0;
|
||||
|
||||
/* We're done looking at the link info. */
|
||||
if (lfinfo != readlink_buf)
|
||||
xfree (lfinfo);
|
||||
UNGCPRO;
|
||||
|
||||
/* On current host? */
|
||||
if (STRINGP (Fsystem_name ())
|
||||
|
@ -3294,6 +3294,7 @@ extern Lisp_Object close_file_unwind (Lisp_Object);
|
||||
extern Lisp_Object restore_point_unwind (Lisp_Object);
|
||||
extern _Noreturn void report_file_error (const char *, Lisp_Object);
|
||||
extern bool internal_delete_file (Lisp_Object);
|
||||
extern Lisp_Object emacs_readlinkat (int, const char *);
|
||||
extern bool file_directory_p (const char *);
|
||||
extern bool file_accessible_directory_p (const char *);
|
||||
extern void init_fileio (void);
|
||||
@ -3566,8 +3567,6 @@ extern int emacs_open (const char *, int, int);
|
||||
extern int emacs_close (int);
|
||||
extern ptrdiff_t emacs_read (int, char *, ptrdiff_t);
|
||||
extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t);
|
||||
enum { READLINK_BUFSIZE = 1024 };
|
||||
extern char *emacs_readlink (const char *, char [READLINK_BUFSIZE]);
|
||||
|
||||
extern void unlock_all_files (void);
|
||||
extern void lock_file (Lisp_Object);
|
||||
|
18
src/sysdep.c
18
src/sysdep.c
@ -30,9 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <allocator.h>
|
||||
#include <c-ctype.h>
|
||||
#include <careadlinkat.h>
|
||||
#include <ignore-value.h>
|
||||
#include <utimens.h>
|
||||
|
||||
@ -2247,22 +2245,6 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
|
||||
|
||||
return (bytes_written);
|
||||
}
|
||||
|
||||
static struct allocator const emacs_norealloc_allocator =
|
||||
{ xmalloc, NULL, xfree, memory_full };
|
||||
|
||||
/* Get the symbolic link value of FILENAME. Return a pointer to a
|
||||
NUL-terminated string. If readlink fails, return NULL and set
|
||||
errno. If the value fits in INITIAL_BUF, return INITIAL_BUF.
|
||||
Otherwise, allocate memory and return a pointer to that memory. If
|
||||
memory allocation fails, diagnose and fail without returning. If
|
||||
successful, store the length of the symbolic link into *LINKLEN. */
|
||||
char *
|
||||
emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
|
||||
{
|
||||
return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
|
||||
&emacs_norealloc_allocator, careadlinkatcwd);
|
||||
}
|
||||
|
||||
/* Return a struct timeval that is roughly equivalent to T.
|
||||
Use the least timeval not less than T.
|
||||
|
60
src/w32.c
60
src/w32.c
@ -4274,6 +4274,30 @@ lstat (const char * path, struct stat * buf)
|
||||
return stat_worker (path, buf, 0);
|
||||
}
|
||||
|
||||
int
|
||||
fstatat (int fd, char const *name, struct stat *st, int flags)
|
||||
{
|
||||
/* Rely on a hack: an open directory is modeled as file descriptor 0.
|
||||
This is good enough for the current usage in Emacs, but is fragile.
|
||||
|
||||
FIXME: Add proper support for fdopendir, fstatatat, readlinkat.
|
||||
Gnulib does this and can serve as a model. */
|
||||
char fullname[MAX_PATH];
|
||||
|
||||
if (fd != AT_FDCWD)
|
||||
{
|
||||
if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
|
||||
< 0)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
name = fullname;
|
||||
}
|
||||
|
||||
return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
|
||||
}
|
||||
|
||||
/* Provide fstat and utime as well as stat for consistent handling of
|
||||
file timestamps. */
|
||||
int
|
||||
@ -4816,6 +4840,28 @@ readlink (const char *name, char *buf, size_t buf_size)
|
||||
return retval;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
readlinkat (int fd, char const *name, char *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
/* Rely on a hack: an open directory is modeled as file descriptor 0,
|
||||
as in fstatat. FIXME: Add proper support for readlinkat. */
|
||||
char fullname[MAX_PATH];
|
||||
|
||||
if (fd != AT_FDCWD)
|
||||
{
|
||||
if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
|
||||
< 0)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
name = fullname;
|
||||
}
|
||||
|
||||
return readlink (name, buffer, buffer_size);
|
||||
}
|
||||
|
||||
/* If FILE is a symlink, return its target (stored in a static
|
||||
buffer); otherwise return FILE.
|
||||
|
||||
@ -5168,12 +5214,6 @@ careadlinkat (int fd, char const *filename,
|
||||
char linkname[MAX_PATH];
|
||||
ssize_t link_size;
|
||||
|
||||
if (fd != AT_FDCWD)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
|
||||
|
||||
if (link_size > 0)
|
||||
@ -5191,14 +5231,6 @@ careadlinkat (int fd, char const *filename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
careadlinkatcwd (int fd, char const *filename, char *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
(void) fd;
|
||||
return readlink (filename, buffer, buffer_size);
|
||||
}
|
||||
|
||||
|
||||
/* Support for browsing other processes and their attributes. See
|
||||
process.c for the Lisp bindings. */
|
||||
|
Loading…
Reference in New Issue
Block a user