fdopendir: optimize on mingw
authorEric Blake <ebb9@byu.net>
Tue, 1 Sep 2009 16:05:44 +0000 (10:05 -0600)
committerEric Blake <ebb9@byu.net>
Thu, 3 Sep 2009 01:14:51 +0000 (19:14 -0600)
* lib/unistd.in.h (_gl_directory_name): New prototype.
* lib/fchdir.c (_gl_directory_name): Implement it.
(fchdir): Use it to simplify implementation.
* lib/fdopendir.c (fdopendir) [REPLACE_FCHDIR]: Use metadata from
fchdir, when available, to avoid calling [f]chdir().

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
lib/fchdir.c
lib/fdopendir.c
lib/unistd.in.h

index 0cd6e20963e20e92137237c8888ef0c36f0320c9..cf8b1155a1e15cca5418689695218286ea146059 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2009-09-02  Eric Blake  <ebb9@byu.net>
 
+       fdopendir: optimize on mingw
+       * lib/unistd.in.h (_gl_directory_name): New prototype.
+       * lib/fchdir.c (_gl_directory_name): Implement it.
+       (fchdir): Use it to simplify implementation.
+       * lib/fdopendir.c (fdopendir) [REPLACE_FCHDIR]: Use metadata from
+       fchdir, when available, to avoid calling [f]chdir().
+
        fdopendir: split into its own module
        * lib/openat.c (fdopendir): Move...
        * lib/fdopendir.c: ...into new file.
index 9b64e0294bcd823a4b5149d35d868cb4d9dfd69a..f35562911ac1b785d510578c0c48d71693ae650a 100644 (file)
@@ -154,6 +154,25 @@ _gl_register_dup (int oldfd, int newfd)
   return newfd;
 }
 
+/* If FD is currently visiting a directory, then return the name of
+   that directory.  Otherwise, return NULL and set errno.  */
+const char *
+_gl_directory_name (int fd)
+{
+  if (0 <= fd && fd < dirs_allocated && dirs[fd].name != NULL)
+    return dirs[fd].name;
+  /* At this point, fd is either invalid, or open but not a directory.
+     If dup2 fails, errno is correctly EBADF.  */
+  if (0 <= fd)
+    {
+      if (dup2 (fd, fd) == fd)
+        errno = ENOTDIR;
+    }
+  else
+    errno = EBADF;
+  return NULL;
+}
+
 /* Return stat information about FD in STATBUF.  Needed when
    rpl_open() used a dummy file to work around an open() that can't
    normally visit directories.  */
@@ -222,16 +241,6 @@ rpl_dup (int oldfd)
 int
 fchdir (int fd)
 {
-  if (fd >= 0 && fd < dirs_allocated && dirs[fd].name != NULL)
-    return chdir (dirs[fd].name);
-  /* At this point, fd is either invalid, or open but not a directory.
-     If dup2 fails, errno is correctly EBADF.  */
-  if (0 <= fd)
-    {
-      if (dup2 (fd, fd) == fd)
-        errno = ENOTDIR;
-    }
-  else
-    errno = EBADF;
-  return -1;
+  const char *name = _gl_directory_name (fd);
+  return name ? chdir (name) : -1;
 }
index 70951562f46deabee8ba40dfcf1fcde8e2fa47a4..3bc13acf4126a1aae1ee2704368d41be240e1f97 100644 (file)
@@ -30,7 +30,8 @@
 /* Replacement for Solaris' function by the same name.
    <http://www.google.com/search?q=fdopendir+site:docs.sun.com>
    First, try to simulate it via opendir ("/proc/self/fd/FD").  Failing
-   that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd.
+   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.
    Otherwise, this function works just like Solaris' fdopendir.
@@ -45,7 +46,6 @@
 DIR *
 fdopendir (int fd)
 {
-  struct saved_cwd saved_cwd;
   int saved_errno;
   DIR *dir;
 
@@ -66,6 +66,13 @@ fdopendir (int fd)
      save_cwd/restore_cwd.  */
   if (! dir && EXPECTED_ERRNO (saved_errno))
     {
+#if REPLACE_FCHDIR
+      const char *name = _gl_directory_name (fd);
+      if (name)
+        dir = opendir (name);
+      saved_errno = errno;
+#else /* !REPLACE_FCHDIR */
+      struct saved_cwd saved_cwd;
       if (save_cwd (&saved_cwd) != 0)
        openat_save_fail (errno);
 
@@ -84,6 +91,7 @@ fdopendir (int fd)
        }
 
       free_cwd (&saved_cwd);
+#endif /* !REPLACE_FCHDIR */
     }
 
   if (dir)
index 3a748a67284b656c98206e1bf87d6e3eaaed4bb4..fe645b79c6db7b48fd874acad5ce132d38f32442 100644 (file)
@@ -252,6 +252,7 @@ extern int dup (int);
 extern int _gl_register_fd (int fd, const char *filename);
 extern void _gl_unregister_fd (int fd);
 extern int _gl_register_dup (int oldfd, int newfd);
+extern const char *_gl_directory_name (int fd);
 
 # endif
 #elif defined GNULIB_POSIXCHECK