summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2007-01-14 11:32:10 +0000
committerBruno Haible <bruno@clisp.org>2007-01-14 11:32:10 +0000
commit854ebf64dc7dae95a43a4e139e075156d2add805 (patch)
treeaec3ad9c300a815e631ca5862c47f6dce1e90e1e
parent3f244fc82c73922c3b8186c42f7a6922f4c064dc (diff)
downloadgnulib-854ebf64dc7dae95a43a4e139e075156d2add805.tar.gz
New module 'fchdir'.
-rw-r--r--ChangeLog33
-rwxr-xr-xMODULES.html.sh1
-rw-r--r--lib/backupfile.c5
-rw-r--r--lib/chown.c5
-rw-r--r--lib/clean-temp.c7
-rw-r--r--lib/copy-file.c6
-rw-r--r--lib/dirent_.h42
-rw-r--r--lib/dup-safer.c2
-rw-r--r--lib/execute.c5
-rw-r--r--lib/fchdir.c277
-rw-r--r--lib/fcntl_.h19
-rw-r--r--lib/fsusage.c5
-rw-r--r--lib/gc-gnulib.c5
-rw-r--r--lib/getcwd.c5
-rw-r--r--lib/glob.c5
-rw-r--r--lib/javacomp.c5
-rw-r--r--lib/mountlist.c10
-rw-r--r--lib/openat-proc.c5
-rw-r--r--lib/pagealign_alloc.c5
-rw-r--r--lib/pipe.c5
-rw-r--r--lib/progreloc.c5
-rw-r--r--lib/savedir.c5
-rw-r--r--lib/unistd_.h52
-rw-r--r--lib/utime.c5
-rw-r--r--m4/fchdir.m429
-rw-r--r--m4/unistd_h.m418
-rw-r--r--modules/fchdir41
-rw-r--r--modules/unistd12
28 files changed, 612 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 688ac05694..eff0b42f2c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2006-12-30 Bruno Haible <bruno@clisp.org>
+
+ * modules/fchdir: New file.
+ * modules/unistd (Files): Add lib/unistd_.h.
+ (Makefile.am): Generate unistd.h from unistd_.h.
+ * lib/fchdir.c: New file.
+ * lib/dirent_.h: New file.
+ * lib/unistd_.h: New file.
+ * lib/fcntl_.h (open) [FCHDIR_REPLACEMENT]: New replacement.
+ * m4/fchdir.m4: New file.
+ * m4/unistd_h.m4 (gl_PREREQ_UNISTD): New macro.
+ (gl_HEADER_UNISTD): Invoke it.
+ * lib/dup-safer.c (dup_safer) [FCHDIR_REPLACEMENT]: Use the dup
+ function.
+ * lib/backupfile.c (opendir, closedir): Undefine.
+ * lib/chown.c (open, close): Undefine.
+ * lib/clean-temp.c (open, close): Undefine.
+ * lib/copy-file.c (open, close): Undefine.
+ * lib/execute.c (open, close): Undefine.
+ * lib/fsusage.c (open, close): Undefine.
+ * lib/gc-gnulib.c (open, close): Undefine.
+ * lib/getcwd.c (opendir, closedir): Undefine.
+ * lib/glob.c (opendir, closedir): Undefine.
+ * lib/javacomp.c (open, close): Undefine.
+ * lib/mountlist.c (open, close, opendir, closedir): Undefine.
+ * lib/openat-proc.c (open, close): Undefine.
+ * lib/pagealign_alloc.c (open, close): Undefine.
+ * lib/pipe.c (open, close): Undefine.
+ * lib/progreloc.c (open, close): Undefine.
+ * lib/savedir.c (opendir, closedir): Undefine.
+ * lib/utime.c (open, close): Undefine.
+ * MODULES.html.sh (Support for systems lacking POSIX:2001): Add fchdir.
+
2007-01-10 Bruno Haible <bruno@clisp.org>
* lib/striconv.c (mem_cd_iconv): Align the temporary buffer.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 5836e34318..68a3152ba8 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1921,6 +1921,7 @@ func_all_modules ()
func_begin_table
func_module chown
func_module dup2
+ func_module fchdir
func_module ftruncate
func_module getaddrinfo
func_module getcwd
diff --git a/lib/backupfile.c b/lib/backupfile.c
index 5875d3a112..adfc0e5411 100644
--- a/lib/backupfile.c
+++ b/lib/backupfile.c
@@ -82,6 +82,11 @@
of `digit' even when the host does not conform to POSIX. */
#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef opendir
+#undef closedir
+
/* The extension added to file names to produce a simple (as opposed
to numbered) backup file name. */
char const *simple_backup_suffix = "~";
diff --git a/lib/chown.c b/lib/chown.c
index 1301aa6ad7..2da2c80ab4 100644
--- a/lib/chown.c
+++ b/lib/chown.c
@@ -33,6 +33,11 @@
#include <fcntl.h>
#include <errno.h>
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
/* Provide a more-closely POSIX-conforming version of chown on
systems with one or both of the following problems:
- chown doesn't treat an ID of -1 as meaning
diff --git a/lib/clean-temp.c b/lib/clean-temp.c
index aa82974a1e..7acc68857d 100644
--- a/lib/clean-temp.c
+++ b/lib/clean-temp.c
@@ -67,6 +67,13 @@
# define uintptr_t unsigned long
#endif
+#if !GNULIB_FCNTL_SAFER
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+# undef open
+# undef close
+#endif
+
/* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
ensure that while constructing or modifying the data structures, the field
diff --git a/lib/copy-file.c b/lib/copy-file.c
index 4314f4c6d1..5a5dcf72c6 100644
--- a/lib/copy-file.c
+++ b/lib/copy-file.c
@@ -46,6 +46,12 @@
#define _(str) gettext (str)
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
+
void
copy_file_preserving (const char *src_filename, const char *dest_filename)
{
diff --git a/lib/dirent_.h b/lib/dirent_.h
new file mode 100644
index 0000000000..cadc267f8a
--- /dev/null
+++ b/lib/dirent_.h
@@ -0,0 +1,42 @@
+/* Wrapper around <dirent.h>.
+ Copyright (C) 2006 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 2, 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, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GL_DIRENT_H
+#define _GL_DIRENT_H
+
+#include @ABSOLUTE_DIRENT_H@
+
+
+/* Declare overridden functions. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FCHDIR_REPLACEMENT
+# define opendir rpl_opendir
+extern DIR * opendir (const char *);
+# define closedir rpl_closedir
+extern int closedir (DIR *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _GL_DIRENT_H */
diff --git a/lib/dup-safer.c b/lib/dup-safer.c
index d0606eeb4c..7b12b615ca 100644
--- a/lib/dup-safer.c
+++ b/lib/dup-safer.c
@@ -35,7 +35,7 @@
int
dup_safer (int fd)
{
-#ifdef F_DUPFD
+#if defined F_DUPFD && !defined FCHDIR_REPLACEMENT
return fcntl (fd, F_DUPFD, STDERR_FILENO + 1);
#else
/* fd_safer calls us back, but eventually the recursion unwinds and
diff --git a/lib/execute.c b/lib/execute.c
index cb72343f80..ea9388034b 100644
--- a/lib/execute.c
+++ b/lib/execute.c
@@ -70,6 +70,11 @@ extern char **environ;
# define STDERR_FILENO 2
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
#ifdef EINTR
diff --git a/lib/fchdir.c b/lib/fchdir.c
new file mode 100644
index 0000000000..c05a9f3149
--- /dev/null
+++ b/lib/fchdir.c
@@ -0,0 +1,277 @@
+/* fchdir replacement.
+ Copyright (C) 2006 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 2, 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, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "canonicalize.h"
+#include "dirfd.h"
+#include "strdup.h"
+
+/* This replacement assumes that a directory is not renamed while opened
+ through a file descriptor. */
+
+/* Array of file descriptors opened. If it points to a directory, it stores
+ info about this directory; otherwise it stores an errno value of ENOTDIR. */
+typedef struct
+{
+ char *name; /* Absolute name of the directory, or NULL. */
+ int saved_errno; /* If name == NULL: The error code describing the failure
+ reason. */
+} dir_info_t;
+static dir_info_t *dirs;
+static size_t dirs_allocated;
+
+/* Try to ensure dirs has enough room for a slot at index fd. */
+static void
+ensure_dirs_slot (size_t fd)
+{
+ if (fd >= dirs_allocated)
+ {
+ size_t new_allocated;
+ dir_info_t *new_dirs;
+ size_t i;
+
+ new_allocated = 2 * dirs_allocated + 1;
+ if (new_allocated <= fd)
+ new_allocated = fd + 1;
+ new_dirs =
+ (dirs != NULL
+ ? (dir_info_t *) realloc (dirs, new_allocated * sizeof (dir_info_t))
+ : (dir_info_t *) malloc (new_allocated * sizeof (dir_info_t)));
+ if (new_dirs != NULL)
+ {
+ for (i = dirs_allocated; i < new_allocated; i++)
+ {
+ new_dirs[i].name = NULL;
+ new_dirs[i].saved_errno = ENOTDIR;
+ }
+ dirs = new_dirs;
+ dirs_allocated = new_allocated;
+ }
+ }
+}
+
+/* Override open() and close(), to keep track of the open file descriptors. */
+
+int
+close (int fd)
+#undef close
+{
+ int retval = close (fd);
+
+ if (retval >= 0 && fd >= 0 && fd < dirs_allocated)
+ {
+ if (dirs[fd].name != NULL)
+ free (dirs[fd].name);
+ dirs[fd].name = NULL;
+ dirs[fd].saved_errno = ENOTDIR;
+ }
+ return retval;
+}
+
+int
+open (const char *filename, int flags, ...)
+#undef open
+{
+ mode_t mode;
+ int fd;
+ struct stat statbuf;
+
+ mode = 0;
+ if (flags & O_CREAT)
+ {
+ va_list arg;
+ va_start (arg, flags);
+
+ /* If mode_t is narrower than int, use the promoted type (int),
+ not mode_t. Use sizeof to guess whether mode_t is narrower;
+ we don't know of any practical counterexamples. */
+ mode = (sizeof (mode_t) < sizeof (int)
+ ? va_arg (arg, int)
+ : va_arg (arg, mode_t));
+
+ va_end (arg);
+ }
+ fd = open (filename, flags, mode);
+ if (fd >= 0)
+ {
+ ensure_dirs_slot (fd);
+ if (fd < dirs_allocated
+ && fstat (fd, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
+ {
+ dirs[fd].name = canonicalize_file_name (filename);
+ if (dirs[fd].name == NULL)
+ dirs[fd].saved_errno = errno;
+ }
+ }
+ return fd;
+}
+
+/* Override opendir() and closedir(), to keep track of the open file
+ descriptors. Needed because there is a function dirfd(). */
+
+int
+closedir (DIR *dp)
+#undef closedir
+{
+ int fd = dirfd (dp);
+ int retval = closedir (dp);
+
+ if (retval >= 0 && fd >= 0 && fd < dirs_allocated)
+ {
+ if (dirs[fd].name != NULL)
+ free (dirs[fd].name);
+ dirs[fd].name = NULL;
+ dirs[fd].saved_errno = ENOTDIR;
+ }
+ return retval;
+}
+
+DIR *
+opendir (const char *filename)
+#undef opendir
+{
+ DIR *dp;
+
+ dp = opendir (filename);
+ if (dp != NULL)
+ {
+ int fd = dirfd (dp);
+ if (fd >= 0)
+ {
+ ensure_dirs_slot (fd);
+ if (fd < dirs_allocated)
+ {
+ dirs[fd].name = canonicalize_file_name (filename);
+ if (dirs[fd].name == NULL)
+ dirs[fd].saved_errno = errno;
+ }
+ }
+ }
+ return dp;
+}
+
+/* Override dup() and dup2(), to keep track of open file descriptors. */
+
+int
+dup (int oldfd)
+#undef dup
+{
+ int newfd = dup (oldfd);
+
+ if (oldfd >= 0 && newfd >= 0)
+ {
+ ensure_dirs_slot (newfd);
+ if (newfd < dirs_allocated)
+ {
+ if (oldfd < dirs_allocated)
+ {
+ if (dirs[oldfd].name != NULL)
+ {
+ dirs[newfd].name = strdup (dirs[oldfd].name);
+ if (dirs[newfd].name == NULL)
+ dirs[newfd].saved_errno = ENOMEM;
+ }
+ else
+ {
+ dirs[newfd].name = NULL;
+ dirs[newfd].saved_errno = dirs[oldfd].saved_errno;
+ }
+ }
+ else
+ {
+ dirs[newfd].name = NULL;
+ dirs[newfd].saved_errno = ENOMEM;
+ }
+ }
+ }
+ return newfd;
+}
+
+int
+dup2 (int oldfd, int newfd)
+#undef dup2
+{
+ int retval = dup2 (oldfd, newfd);
+
+ if (retval >= 0 && oldfd >= 0 && newfd >= 0 && newfd != oldfd)
+ {
+ ensure_dirs_slot (newfd);
+ if (newfd < dirs_allocated)
+ {
+ if (oldfd < dirs_allocated)
+ {
+ if (dirs[oldfd].name != NULL)
+ {
+ dirs[newfd].name = strdup (dirs[oldfd].name);
+ if (dirs[newfd].name == NULL)
+ dirs[newfd].saved_errno = ENOMEM;
+ }
+ else
+ {
+ dirs[newfd].name = NULL;
+ dirs[newfd].saved_errno = dirs[oldfd].saved_errno;
+ }
+ }
+ else
+ {
+ dirs[newfd].name = NULL;
+ dirs[newfd].saved_errno = ENOMEM;
+ }
+ }
+ }
+ return retval;
+}
+
+/* Implement fchdir() in terms of chdir(). */
+
+int
+fchdir (int fd)
+{
+ if (fd >= 0)
+ {
+ if (fd < dirs_allocated)
+ {
+ if (dirs[fd].name != NULL)
+ return chdir (dirs[fd].name);
+ else
+ {
+ errno = dirs[fd].saved_errno;
+ return -1;
+ }
+ }
+ else
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ else
+ {
+ errno = EBADF;
+ return -1;
+ }
+}
diff --git a/lib/fcntl_.h b/lib/fcntl_.h
index 5c2857caef..e16ad54afe 100644
--- a/lib/fcntl_.h
+++ b/lib/fcntl_.h
@@ -26,6 +26,25 @@
#include <unistd.h>
#include @ABSOLUTE_FCNTL_H@
+
+/* Declare overridden functions. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FCHDIR_REPLACEMENT
+# define open rpl_open
+extern int open (const char *, int, ...);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* Fix up the O_* macros. */
+
#if !defined O_DIRECT && defined O_DIRECTIO
/* Tru64 spells it `O_DIRECTIO'. */
# define O_DIRECT O_DIRECTIO
diff --git a/lib/fsusage.c b/lib/fsusage.c
index a305979bab..337bf5315d 100644
--- a/lib/fsusage.c
+++ b/lib/fsusage.c
@@ -56,6 +56,11 @@
# include "full-read.h"
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
/* Many space usage primitives use all 1 bits to denote a value that is
not applicable or unknown. Propagate this information by returning
a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
diff --git a/lib/gc-gnulib.c b/lib/gc-gnulib.c
index 5ce31c1500..f414f433ef 100644
--- a/lib/gc-gnulib.c
+++ b/lib/gc-gnulib.c
@@ -68,6 +68,11 @@
# include "rijndael-api-fst.h"
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
Gc_rc
gc_init (void)
{
diff --git a/lib/getcwd.c b/lib/getcwd.c
index 292bc19a33..f13da4dcc6 100644
--- a/lib/getcwd.c
+++ b/lib/getcwd.c
@@ -97,6 +97,11 @@
# define __opendir opendir
# define __readdir readdir
#endif
+
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ therefore save some unnecessary recursion in fchdir.c. */
+#undef opendir
+#undef closedir
/* Get the name of the current working directory, and put it in SIZE
bytes of BUF. Returns NULL if the directory couldn't be determined or
diff --git a/lib/glob.c b/lib/glob.c
index 6f8641aad8..edef095e6d 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -162,6 +162,11 @@ static const char *next_brace_sub (const char *begin, int flags) __THROW;
#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef opendir
+#undef closedir
+
static int glob_in_dir (const char *pattern, const char *directory,
int flags, int (*errfunc) (const char *, int),
glob_t *pglob);
diff --git a/lib/javacomp.c b/lib/javacomp.c
index ba0f437004..5d3d60be4f 100644
--- a/lib/javacomp.c
+++ b/lib/javacomp.c
@@ -53,6 +53,11 @@
#define _(str) gettext (str)
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
/* Survey of Java compilers.
diff --git a/lib/mountlist.c b/lib/mountlist.c
index d70a1a2081..bb01f91efb 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -143,6 +143,16 @@ char *strstr ();
# define SIZE_MAX ((size_t) -1)
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef opendir
+#undef closedir
+
#ifndef ME_DUMMY
# define ME_DUMMY(Fs_name, Fs_type) \
(strcmp (Fs_type, "autofs") == 0 \
diff --git a/lib/openat-proc.c b/lib/openat-proc.c
index 87293a46f7..ff2fff0033 100644
--- a/lib/openat-proc.c
+++ b/lib/openat-proc.c
@@ -34,6 +34,11 @@
#include "same-inode.h"
#include "xalloc.h"
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
#define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/%s"
#define PROC_SELF_FD_NAME_SIZE_BOUND(len) \
diff --git a/lib/pagealign_alloc.c b/lib/pagealign_alloc.c
index cbbe76346e..c06dd0da4f 100644
--- a/lib/pagealign_alloc.c
+++ b/lib/pagealign_alloc.c
@@ -52,6 +52,11 @@
# endif
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
#if HAVE_MMAP || ! HAVE_POSIX_MEMALIGN
diff --git a/lib/pipe.c b/lib/pipe.c
index 19feaf4e7b..521872be6d 100644
--- a/lib/pipe.c
+++ b/lib/pipe.c
@@ -69,6 +69,11 @@ extern char **environ;
# define STDERR_FILENO 2
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
#ifdef EINTR
diff --git a/lib/progreloc.c b/lib/progreloc.c
index e9fb647058..cb97959992 100644
--- a/lib/progreloc.c
+++ b/lib/progreloc.c
@@ -77,6 +77,11 @@
# define FILE_SYSTEM_PREFIX_LEN(P) 0
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
#undef set_program_name
diff --git a/lib/savedir.c b/lib/savedir.c
index 12084ee90b..d930fb4af2 100644
--- a/lib/savedir.c
+++ b/lib/savedir.c
@@ -43,6 +43,11 @@
# define NAME_SIZE_DEFAULT 512
#endif
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef opendir
+#undef closedir
+
/* Return a freshly allocated string containing the file names
in directory DIRP, separated by '\0' characters;
the end is marked by two '\0' characters in a row.
diff --git a/lib/unistd_.h b/lib/unistd_.h
new file mode 100644
index 0000000000..36fa673124
--- /dev/null
+++ b/lib/unistd_.h
@@ -0,0 +1,52 @@
+/* Substitute for and wrapper around <unistd.h>.
+ Copyright (C) 2006 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 2, 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, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GL_UNISTD_H
+#define _GL_UNISTD_H
+
+#if HAVE_UNISTD_H
+# include @ABSOLUTE_UNISTD_H@
+#endif
+
+
+/* Declare overridden functions. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FCHDIR_REPLACEMENT
+
+/* Change the process' current working directory to the directory on which
+ the given file descriptor is open. */
+extern int fchdir (int /*fd*/);
+
+# define close rpl_close
+extern int close (int);
+# define dup rpl_dup
+extern int dup (int);
+# define dup2 rpl_dup2
+extern int dup2 (int, int);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _GL_UNISTD_H */
diff --git a/lib/utime.c b/lib/utime.c
index 421a7cc58e..273a5fb31f 100644
--- a/lib/utime.c
+++ b/lib/utime.c
@@ -47,6 +47,11 @@ struct utimbuf
};
#endif
+/* The results of open() in this file are not used with fchdir,
+ therefore save some unnecessary work in fchdir.c. */
+#undef open
+#undef close
+
/* Emulate utime (file, NULL) for systems (like 4.3BSD) that do not
interpret it to set the access and modification times of FILE to
the current time. Return 0 if successful, -1 if not. */
diff --git a/m4/fchdir.m4 b/m4/fchdir.m4
new file mode 100644
index 0000000000..caebfcbe06
--- /dev/null
+++ b/m4/fchdir.m4
@@ -0,0 +1,29 @@
+# fchdir.m4 serial 1
+dnl Copyright (C) 2006 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.
+
+AC_DEFUN([gl_FUNC_FCHDIR],
+[
+ AC_CHECK_FUNCS_ONCE([fchdir])
+ if test $ac_cv_func_fchdir = no; then
+ AC_LIBOBJ([fchdir])
+ gl_PREREQ_FCHDIR
+ AC_DEFINE([FCHDIR_REPLACEMENT], 1,
+ [Define if gnulib's fchdir() replacement is used.])
+ gl_ABSOLUTE_HEADER([dirent.h])
+ ABSOLUTE_DIRENT_H=\"$gl_cv_absolute_dirent_h\"
+ DIRENT_H='dirent.h'
+ UNISTD_H2='unistd.h'
+ else
+ DIRENT_H=
+ UNISTD_H2=
+ fi
+ AC_SUBST([ABSOLUTE_DIRENT_H])
+ AC_SUBST([DIRENT_H])
+ AC_SUBST([UNISTD_H2])
+])
+
+# Prerequisites of lib/fchdir.c.
+AC_DEFUN([gl_PREREQ_FCHDIR], [:])
diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4
index 9c77f9bd0d..9d499dfe84 100644
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 2
+# unistd_h.m4 serial 3
dnl Copyright (C) 2006 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -8,11 +8,25 @@ dnl Written by Simon Josefsson
AC_DEFUN([gl_HEADER_UNISTD],
[
- dnl Prerequisites of lib/unistd.h.
AC_CHECK_HEADERS([unistd.h], [
UNISTD_H=''
], [
UNISTD_H='unistd.h'
])
AC_SUBST(UNISTD_H)
+ dnl This module decides to build unistd.h if it is missing.
+ dnl The fchdir module decides to build unistd.h if fchdir() is missing.
+ dnl Therefore check for the prerequisites of lib/unistd.h always.
+ gl_PREREQ_UNISTD
+])
+
+dnl Prerequisites of lib/unistd.h.
+AC_DEFUN([gl_PREREQ_UNISTD],
+[
+ AC_CHECK_HEADERS_ONCE([unistd.h])
+ if test $ac_cv_header_unistd_h = yes; then
+ gl_ABSOLUTE_HEADER([unistd.h])
+ ABSOLUTE_UNISTD_H=\"$gl_cv_absolute_unistd_h\"
+ fi
+ AC_SUBST([ABSOLUTE_UNISTD_H])
])
diff --git a/modules/fchdir b/modules/fchdir
new file mode 100644
index 0000000000..b8fa651088
--- /dev/null
+++ b/modules/fchdir
@@ -0,0 +1,41 @@
+Description:
+fchdir() function: change current directory, given an open file descriptor.
+
+Files:
+lib/fchdir.c
+lib/dirent_.h
+m4/fchdir.m4
+
+Depends-on:
+fcntl
+unistd
+canonicalize-lgpl
+dirfd
+strdup
+
+configure.ac:
+gl_FUNC_FCHDIR
+
+Makefile.am:
+BUILT_SOURCES += $(DIRENT_H) $(UNISTD_H2)
+
+# 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_.h
+ rm -f $@-t $@
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+ sed -e 's|@''ABSOLUTE_DIRENT_H''@|$(ABSOLUTE_DIRENT_H)|g' \
+ < $(srcdir)/dirent_.h; \
+ } > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += dirent.h dirent.h-t
+
+Include:
+#include <unistd.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
+
diff --git a/modules/unistd b/modules/unistd
index 177b95ce19..d04c80c2ac 100644
--- a/modules/unistd
+++ b/modules/unistd
@@ -3,6 +3,7 @@ A <unistd.h> for systems lacking it.
Files:
m4/unistd_h.m4
+lib/unistd_.h
Depends-on:
@@ -14,11 +15,14 @@ BUILT_SOURCES += $(UNISTD_H)
# We need the following in order to create an empty placeholder for
# <unistd.h> when the system doesn't have one.
-unistd.h:
+unistd.h: unistd_.h
+ rm -f $@-t $@
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
- echo '/* Empty placeholder for $@. */'; \
- } > $@
-MOSTLYCLEANFILES += unistd.h
+ sed -e 's|@''ABSOLUTE_UNISTD_H''@|$(ABSOLUTE_UNISTD_H)|g' \
+ < $(srcdir)/unistd_.h; \
+ } > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += unistd.h unistd.h-t
Include:
#include <unistd.h>