autoupdate
[gnulib.git] / lib / openat.c
index fe539de..929d264 100644 (file)
@@ -17,7 +17,9 @@
 
 /* written by Jim Meyering */
 
-#include <config.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
 #include "openat.h"
 
@@ -27,8 +29,7 @@
 #include <errno.h>
 #include <fcntl.h>
 
-#include "error.h"
-#include "exitfail.h"
+#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
 #include "save-cwd.h"
 
 #include "gettext.h"
@@ -43,7 +44,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,12 +63,11 @@ 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 || IS_ABSOLUTE_FILE_NAME (file))
+    return open (file, flags, mode);
 
   if (save_cwd (&saved_cwd) != 0)
-    error (exit_failure, errno,
-          _("openat: unable to record current working directory"));
+    openat_save_fail (errno);
 
   if (fchdir (fd) != 0)
     {
@@ -77,12 +77,11 @@ 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)
-    error (exit_failure, errno,
-          _("openat: unable to restore working directory"));
+    openat_restore_fail (errno);
 
   free_cwd (&saved_cwd);
 
@@ -90,13 +89,20 @@ rpl_openat (int fd, char const *filename, int flags, ...)
   return new_fd;
 }
 
+#if !HAVE_FDOPENDIR
+
 /* 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.  */
+   Otherwise, this function works just like Solaris' fdopendir.
+
+   W A R N I N G:
+   Unlike the other fd-related functions here, this one
+   effectively consumes its FD parameter.  The caller should not
+   close or otherwise manipulate FD if this function returns successfully.  */
 DIR *
 fdopendir (int fd)
 {
@@ -104,12 +110,8 @@ fdopendir (int fd)
   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"));
+    openat_save_fail (errno);
 
   if (fchdir (fd) != 0)
     {
@@ -123,15 +125,18 @@ fdopendir (int fd)
   saved_errno = errno;
 
   if (restore_cwd (&saved_cwd) != 0)
-    error (exit_failure, errno,
-          _("fdopendir: unable to restore working directory"));
+    openat_restore_fail (errno);
 
   free_cwd (&saved_cwd);
+  if (dir)
+    close (fd);
 
   errno = saved_errno;
   return dir;
 }
 
+#endif
+
 /* 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.
@@ -140,7 +145,7 @@ fdopendir (int fd)
    then give a diagnostic and exit nonzero.
    Otherwise, this function works just like Solaris' fstatat.  */
 int
-fstatat (int fd, char const *filename, struct stat *st, int flag)
+fstatat (int fd, char const *file, struct stat *st, int flag)
 {
   struct saved_cwd saved_cwd;
   int saved_errno;
@@ -148,12 +153,11 @@ fstatat (int fd, char const *filename, struct stat *st, int flag)
 
   if (fd == AT_FDCWD)
     return (flag == AT_SYMLINK_NOFOLLOW
-           ? lstat (filename, st)
-           : stat (filename, st));
+           ? lstat (file, st)
+           : stat (file, st));
 
   if (save_cwd (&saved_cwd) != 0)
-    error (exit_failure, errno,
-          _("fstatat: unable to record current working directory"));
+    openat_save_fail (errno);
 
   if (fchdir (fd) != 0)
     {
@@ -164,13 +168,52 @@ fstatat (int fd, char const *filename, struct stat *st, int flag)
     }
 
   err = (flag == AT_SYMLINK_NOFOLLOW
-        ? lstat (filename, st)
-        : stat (filename, st));
+        ? lstat (file, st)
+        : stat (file, st));
+  saved_errno = errno;
+
+  if (restore_cwd (&saved_cwd) != 0)
+    openat_restore_fail (errno);
+
+  free_cwd (&saved_cwd);
+
+  errno = saved_errno;
+  return err;
+}
+
+/* Replacement for Solaris' function by the same name.
+   <http://www.google.com/search?q=unlinkat+site:docs.sun.com>
+   Simulate it by doing save_cwd/fchdir/(unlink|rmdir)/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' unlinkat.  */
+int
+unlinkat (int fd, char const *file, int flag)
+{
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  int err;
+
+  if (fd == AT_FDCWD)
+    return (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
+
+  if (save_cwd (&saved_cwd) != 0)
+    openat_save_fail (errno);
+
+  if (fchdir (fd) != 0)
+    {
+      saved_errno = errno;
+      free_cwd (&saved_cwd);
+      errno = saved_errno;
+      return -1;
+    }
+
+  err = (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
   saved_errno = errno;
 
   if (restore_cwd (&saved_cwd) != 0)
-    error (exit_failure, errno,
-          _("fstatat: unable to restore working directory"));
+    openat_restore_fail (errno);
 
   free_cwd (&saved_cwd);