Merge minor changes from coreutils.
[gnulib.git] / lib / openat.c
index fa617b8..ec51b2d 100644 (file)
@@ -1,5 +1,5 @@
 /* provide a replacement openat function
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 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
@@ -13,7 +13,7 @@
 
    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* written by Jim Meyering */
 
@@ -43,7 +43,7 @@
    Otherwise, upon failure, set errno and return -1, as openat does.
    Upon successful completion, return a file descriptor.  */
 int
-rpl_openat (int fd, char const *filename, int flags, ...)
+rpl_openat (int fd, char const *file, int flags, ...)
 {
   struct saved_cwd saved_cwd;
   int saved_errno;
@@ -62,8 +62,8 @@ rpl_openat (int fd, char const *filename, int flags, ...)
       va_end (arg);
     }
 
-  if (fd == AT_FDCWD || *filename == '/')
-    return open (filename, flags, mode);
+  if (fd == AT_FDCWD || *file == '/')
+    return open (file, flags, mode);
 
   if (save_cwd (&saved_cwd) != 0)
     error (exit_failure, errno,
@@ -77,7 +77,7 @@ rpl_openat (int fd, char const *filename, int flags, ...)
       return -1;
     }
 
-  new_fd = open (filename, flags, mode);
+  new_fd = open (file, flags, mode);
   saved_errno = errno;
 
   if (restore_cwd (&saved_cwd) != 0)
@@ -89,3 +89,91 @@ rpl_openat (int fd, char const *filename, int flags, ...)
   errno = saved_errno;
   return new_fd;
 }
+
+/* Replacement for Solaris' function by the same name.
+   <http://www.google.com/search?q=fdopendir+site:docs.sun.com>
+   Simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd.
+   If either the save_cwd or the restore_cwd fails (relatively unlikely,
+   and usually indicative of a problem that deserves close attention),
+   then give a diagnostic and exit nonzero.
+   Otherwise, this function works just like Solaris' fdopendir.  */
+DIR *
+fdopendir (int fd)
+{
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  DIR *dir;
+
+  if (fd == AT_FDCWD)
+    return opendir (".");
+
+  if (save_cwd (&saved_cwd) != 0)
+    error (exit_failure, errno,
+          _("fdopendir: unable to record current working directory"));
+
+  if (fchdir (fd) != 0)
+    {
+      saved_errno = errno;
+      free_cwd (&saved_cwd);
+      errno = saved_errno;
+      return NULL;
+    }
+
+  dir = opendir (".");
+  saved_errno = errno;
+
+  if (restore_cwd (&saved_cwd) != 0)
+    error (exit_failure, errno,
+          _("fdopendir: unable to restore working directory"));
+
+  free_cwd (&saved_cwd);
+
+  errno = saved_errno;
+  return dir;
+}
+
+/* Replacement for Solaris' function by the same name.
+   <http://www.google.com/search?q=fstatat+site:docs.sun.com>
+   Simulate it by doing save_cwd/fchdir/(stat|lstat)/restore_cwd.
+   If either the save_cwd or the restore_cwd fails (relatively unlikely,
+   and usually indicative of a problem that deserves close attention),
+   then give a diagnostic and exit nonzero.
+   Otherwise, this function works just like Solaris' fstatat.  */
+int
+fstatat (int fd, char const *file, struct stat *st, int flag)
+{
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  int err;
+
+  if (fd == AT_FDCWD)
+    return (flag == AT_SYMLINK_NOFOLLOW
+           ? lstat (file, st)
+           : stat (file, st));
+
+  if (save_cwd (&saved_cwd) != 0)
+    error (exit_failure, errno,
+          _("fstatat: unable to record current working directory"));
+
+  if (fchdir (fd) != 0)
+    {
+      saved_errno = errno;
+      free_cwd (&saved_cwd);
+      errno = saved_errno;
+      return -1;
+    }
+
+  err = (flag == AT_SYMLINK_NOFOLLOW
+        ? lstat (file, st)
+        : stat (file, st));
+  saved_errno = errno;
+
+  if (restore_cwd (&saved_cwd) != 0)
+    error (exit_failure, errno,
+          _("fstatat: unable to restore working directory"));
+
+  free_cwd (&saved_cwd);
+
+  errno = saved_errno;
+  return err;
+}