bug-coreutils
[Top][All Lists]
Advanced

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

Re: modify chmod


From: jeff.liu
Subject: Re: modify chmod
Date: Fri, 05 Feb 2010 22:15:23 +0800
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

>From c7bc43a05e4f021db8047ecd390b4fb75368f558 Mon Sep 17 00:00:00 2001
From: Jeff Liu <address@hidden>
Date: Fri, 5 Feb 2010 20:45:41 +0800
Subject: [PATCH 1/1] Modify chmod v1
 do not touch the inode if the new file permission bits is identical to it was 
before.

Signed-off-by: Jie Liu <address@hidden>
---
 gnulib      |    2 +-
 src/chmod.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/gnulib b/gnulib
index 2eb5a8a..4b93a25 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 2eb5a8a0ff8348149a9ca985e2ccbfb03bc8de53
+Subproject commit 4b93a2579fb567b9fbbeb24439770d814dac95cd
diff --git a/src/chmod.c b/src/chmod.c
index 3dab92e..30802d7 100644
--- a/src/chmod.c
+++ b/src/chmod.c
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <getopt.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include "system.h"
 #include "dev-ino.h"
@@ -32,6 +33,16 @@
 #include "root-dev-ino.h"
 #include "xfts.h"
 
+/* Some systems only have <sys/vfs.h>, other systems also
+ * have <sys/statfs.h>, where the former includes the latter.
+ * So it seems including the former is the best choice.  */
+#include "fs.h"
+#if HAVE_SYS_VFS_H
+#  include <sys/vfs.h>
+#else
+#  include <sys/statfs.h>
+#endif
+
 /* The official name of this program (e.g., no `g' prefix).  */
 #define PROGRAM_NAME "chmod"
 
@@ -83,6 +94,9 @@ static enum Verbosity verbosity = V_off;
    Otherwise NULL.  */
 static struct dev_ino *root_dev_ino;
 
+/* The effective user ID of the caller process.  */
+static uid_t euid;
+
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
@@ -170,6 +184,25 @@ describe_change (const char *file, mode_t mode,
           (unsigned long int) (mode & CHMOD_MODE_BITS), &perms[1]);
 }
 
+/* Return true if the file resides on NFS filesystem.
+ * limit this optimization to systems that provide statfs.  */
+
+static bool
+may_have_nfsacl(const char *file)
+{
+# if HAVE_SYS_VFS_H && HAVE_SYS_STATFS_H && HAVE_STRUCT_STATFS_F_TYPE
+  struct statfs buf;
+
+  /* If statfs fails, assume we can't use the optimization.  */
+  if (statfs (file, &buf) < 0)
+      return true;
+
+  return buf.f_type == S_MAGIC_NFS;
+#endif
+
+  return true;
+}
+
 /* Change the mode of FILE.
    Return true if successful.  This function is called
    once for every file system object that fts encounters.  */
@@ -257,18 +290,38 @@ process_file (FTS *fts, FTSENT *ent)
       old_mode = file_stats->st_mode;
       new_mode = mode_adjust (old_mode, S_ISDIR (old_mode) != 0, umask_value,
                               change, NULL);
-
-      if (! S_ISLNK (old_mode))
+
+     /* Do not touch the inode if the new file mode is the same as it was 
before;
+      * This is an optimization for some cases. However, the new behavior must 
be
+      * disabled for filesystems that support NFSv4 ACLs.
+      * The idea suggested by Paul Eggert refer to FreeBSD chmod(1).
+      * it uses pathconf(2)/lpathconf(2) to determine whether this is the case.
+      * but on linux, we lack of them. Instead, calling statfs(2) and compare 
the
+      * f_type we can still do optimization at least its not NFS.   */
+
+      if ((old_mode & CHMOD_MODE_BITS) == new_mode &&
+          !may_have_nfsacl (file_full_name))
         {
-          if (chmodat (fts->fts_cwd_fd, file, new_mode) == 0)
-            chmod_succeeded = true;
+          if (file_stats->st_uid != euid && euid != 0)
+            error (0, 0, _("changing permissions of %s: Operation not 
permitted"),
+                   quote (file_full_name));
           else
-            {
-              if (! force_silent)
-                error (0, errno, _("changing permissions of %s"),
-                       quote (file_full_name));
-              ok = false;
-            }
+            chmod_succeeded = true;
+        }
+      else
+        {
+          if (! S_ISLNK (old_mode))
+          {
+            if (chmodat (fts->fts_cwd_fd, file, new_mode) == 0)
+              chmod_succeeded = true;
+            else
+              {
+                if (! force_silent)
+                  error (0, errno, _("changing permissions of %s"),
+                         quote (file_full_name));
+                ok = false;
+              }
+         }
         }
     }
 
@@ -545,6 +598,8 @@ main (int argc, char **argv)
       root_dev_ino = NULL;
     }
 
+  euid = geteuid ();
+
   ok = process_files (argv + optind,
                       FTS_COMFOLLOW | FTS_PHYSICAL | FTS_DEFER_STAT);
 
-- 
1.5.4.3



reply via email to

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