bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

FYI: openat evolution: new functions: fchmodat, fchownat


From: Jim Meyering
Subject: FYI: openat evolution: new functions: fchmodat, fchownat
Date: Wed, 11 Jan 2006 16:30:23 +0100

I need fchmodat and fchownat for the upcoming fts.c changes,
so I've just checked in these changes:

2006-01-11  Jim Meyering  <address@hidden>

        * openat.c (fchownat): New function.
        * openat.h (fchmodat, fchownat): Declare.
        (chmodat, lchmodat): Define convenience functions.
        (chownat, lchownat): Likewise.
        * fchmodat.c (fchmodat): New file and function.

2006-01-11  Jim Meyering  <address@hidden>

        * openat.m4 (gl_FUNC_OPENAT): Require and compile fchmodat.c.
        Check for the lchmod function.

Index: m4/openat.m4
===================================================================
RCS file: /fetish/cu/m4/openat.m4,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -p -u -r1.8 -r1.9
--- m4/openat.m4        30 Nov 2005 13:05:03 -0000      1.8
+++ m4/openat.m4        11 Jan 2006 15:25:30 -0000      1.9
@@ -1,7 +1,7 @@
-#serial 7
-# See if we need to use our replacement for Solaris' openat function.
+#serial 8
+# See if we need to use our replacement for Solaris' openat et al functions.
 
-dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+dnl Copyright (C) 2004, 2005, 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.
@@ -12,12 +12,15 @@ AC_DEFUN([gl_FUNC_OPENAT],
 [
   AC_LIBSOURCES([openat.c, openat.h, openat-priv.h, openat-die.c])
   AC_LIBSOURCES([mkdirat.c])
+  AC_LIBSOURCES([fchmodat.c])
 
-  # No system provides a mkdirat function; compile it unconditionally.
+  # No system provides these functions; compile them unconditionally.
   AC_LIBOBJ([mkdirat])
+  AC_LIBOBJ([fchmodat])
 
   AC_LIBOBJ([openat-die])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_FUNCS_ONCE([lchmod])
   AC_CHECK_FUNCS_ONCE([fdopendir])
   AC_REPLACE_FUNCS(openat)
   case $ac_cv_func_openat in
Index: lib/openat.c
===================================================================
RCS file: /fetish/cu/lib/openat.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -p -u -r1.23 -r1.24
--- lib/openat.c        22 Dec 2005 14:34:20 -0000      1.23
+++ lib/openat.c        11 Jan 2006 13:32:03 -0000      1.24
@@ -1,5 +1,5 @@
 /* provide a replacement openat function
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 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
@@ -23,16 +23,16 @@
 
 #include "openat.h"
 
+#include <stdarg.h>
+#include <stddef.h>
+#include <errno.h>
+
 #include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
 #include "fcntl--.h"
 #include "openat-priv.h"
 #include "save-cwd.h"
 #include "unistd--.h"
 
-#include <stdarg.h>
-#include <stddef.h>
-#include <errno.h>
-
 /* Replacement for Solaris' openat function.
    <http://www.google.com/search?q=openat+site:docs.sun.com>
    Simulate it by doing save_cwd/fchdir/open/restore_cwd.
@@ -286,3 +286,57 @@ unlinkat (int fd, char const *file, int 
   errno = saved_errno;
   return err;
 }
+
+/* Replacement for Solaris' function by the same name.
+   Invoke chown or lchown on file, FILE, using OWNER and GROUP, in the
+   directory open on descriptor FD.  If FLAG is AT_SYMLINK_NOFOLLOW, then
+   use lchown, otherwise, use chown.  If possible, do it without changing
+   the working directory.  Otherwise, resort to using save_cwd/fchdir,
+   then mkdir/restore_cwd.  If either the save_cwd or the restore_cwd
+   fails, then give a diagnostic and exit nonzero.  */
+int
+fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
+{
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  int err;
+
+  if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
+    return (flag == AT_SYMLINK_NOFOLLOW
+           ? lchown (file, owner, group)
+           : chown (file, owner, group));
+
+  {
+    char *proc_file;
+    BUILD_PROC_NAME (proc_file, fd, file);
+    err = (flag == AT_SYMLINK_NOFOLLOW
+          ? lchown (proc_file, owner, group)
+          : chown (proc_file, owner, group));
+    /* If the syscall succeeds, or if it fails with an unexpected
+       errno value, then return right away.  Otherwise, fall through
+       and resort to using save_cwd/restore_cwd.  */
+    if (0 <= err || ! EXPECTED_ERRNO (errno))
+      return err;
+  }
+
+  if (save_cwd (&saved_cwd) != 0)
+    openat_save_fail (errno);
+
+  err = fchdir (fd);
+  saved_errno = errno;
+
+  if (! err)
+    {
+      err = (flag == AT_SYMLINK_NOFOLLOW
+            ? lchown (file, owner, group)
+            : chown (file, owner, group));
+      saved_errno = errno;
+
+      if (restore_cwd (&saved_cwd) != 0)
+       openat_restore_fail (errno);
+    }
+
+  free_cwd (&saved_cwd);
+  errno = saved_errno;
+  return err;
+}
Index: lib/openat.h
===================================================================
RCS file: /fetish/cu/lib/openat.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -p -u -r1.15 -r1.16
--- lib/openat.h        17 Dec 2005 06:55:01 -0000      1.15
+++ lib/openat.h        11 Jan 2006 13:32:47 -0000      1.16
@@ -1,5 +1,5 @@
 /* provide a replacement openat function
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 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
@@ -72,3 +72,32 @@ int unlinkat (int fd, char const *file, 
 int mkdirat (int fd, char const *file, mode_t mode);
 void openat_restore_fail (int) ATTRIBUTE_NORETURN;
 void openat_save_fail (int) ATTRIBUTE_NORETURN;
+int fchmodat (int fd, char const *file, mode_t mode, int flag);
+int fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag);
+
+/* Using these function names makes application code
+   slightly more readable than it would be with
+   fchownat (..., 0) or fchownat (..., AT_SYMLINK_NOFOLLOW).  */
+static inline int
+chownat (int fd, char const *file, uid_t owner, gid_t group)
+{
+  return fchownat (fd, file, owner, group, 0);
+}
+
+static inline int
+lchownat (int fd, char const *file, uid_t owner, gid_t group)
+{
+  return fchownat (fd, file, owner, group, AT_SYMLINK_NOFOLLOW);
+}
+
+static inline int
+chmodat (int fd, char const *file, mode_t mode)
+{
+  return fchmodat (fd, file, mode, 0);
+}
+
+static inline int
+lchmodat (int fd, char const *file, mode_t mode)
+{
+  return fchmodat (fd, file, mode, AT_SYMLINK_NOFOLLOW);
+}
Index: lib/fchmodat.c
===================================================================
RCS file: lib/fchmodat.c
diff -N lib/fchmodat.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/fchmodat.c      11 Jan 2006 13:30:31 -0000      1.1
@@ -0,0 +1,104 @@
+/* Change the protections of file relative to an open directory.
+   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.  */
+
+/* written by Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "openat.h"
+
+#include <errno.h>
+
+#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "save-cwd.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#include "openat-priv.h"
+
+/* Some systems don't have ENOSYS.  */
+#ifndef ENOSYS
+# ifdef ENOTSUP
+#  define ENOSYS ENOTSUP
+# else
+/* Some systems don't have ENOTSUP either.  */
+#  define ENOSYS EINVAL
+# endif
+#endif
+
+#ifndef HAVE_LCHMOD
+# undef lchmod
+# define lchmod(f,m) (errno = ENOSYS, -1)
+#endif
+
+/* Solaris 10 has no function like this.
+   Invoke chmod or lchmod on file, FILE, using mode MODE, in the directory
+   open on descriptor FD.  If possible, do it without changing the
+   working directory.  Otherwise, resort to using save_cwd/fchdir,
+   then mkdir/restore_cwd.  If either the save_cwd or the restore_cwd
+   fails, then give a diagnostic and exit nonzero.
+   Note that an attempt to use a FLAG value of AT_SYMLINK_NOFOLLOW
+   on a system without lchmod support causes this function to fail.  */
+int
+fchmodat (int fd, char const *file, mode_t mode, int flag)
+{
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  int err;
+
+  if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
+    return (flag == AT_SYMLINK_NOFOLLOW
+           ? lchmod (file, mode)
+           : chmod (file, mode));
+
+  {
+    char *proc_file;
+    BUILD_PROC_NAME (proc_file, fd, file);
+    err = (flag == AT_SYMLINK_NOFOLLOW
+          ? lchmod (proc_file, mode)
+          : chmod (proc_file, mode));
+    /* If the syscall succeeds, or if it fails with an unexpected
+       errno value, then return right away.  Otherwise, fall through
+       and resort to using save_cwd/restore_cwd.  */
+    if (0 <= err || ! EXPECTED_ERRNO (errno))
+      return err;
+  }
+
+  if (save_cwd (&saved_cwd) != 0)
+    openat_save_fail (errno);
+
+  err = fchdir (fd);
+  saved_errno = errno;
+
+  if (! err)
+    {
+      err = (flag == AT_SYMLINK_NOFOLLOW
+            ? lchmod (file, mode)
+            : chmod (file, mode));
+      saved_errno = errno;
+
+      if (restore_cwd (&saved_cwd) != 0)
+       openat_restore_fail (errno);
+    }
+
+  free_cwd (&saved_cwd);
+  errno = saved_errno;
+  return err;
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]