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:44:34 +0800
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

A tiny patch, make chmod do not touch the inode if the new file
permission mode is same as it was before.

>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]