update from texinfo
[gnulib.git] / lib / modechange.c
index 71432fa..b4df338 100644 (file)
@@ -1,5 +1,7 @@
 /* modechange.c -- file mode manipulation
-   Copyright (C) 1989, 1990, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+   Copyright (C) 1989, 1990, 1997, 1998, 1999, 2001, 2003, 2004 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
 #include "modechange.h"
 #include <sys/stat.h>
 #include "xstrtol.h"
-
-#if STDC_HEADERS
-# include <stdlib.h>
-#else
-char *malloc ();
-#endif
-
-#ifndef NULL
-# define NULL 0
-#endif
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
 
 #if STAT_MACROS_BROKEN
 # undef S_ISDIR
@@ -50,50 +45,65 @@ char *malloc ();
 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 #endif
 
+/* The traditional octal values corresponding to each mode bit.  */
+#define SUID 04000
+#define SGID 02000
+#define SVTX 01000
+#define RUSR 00400
+#define WUSR 00200
+#define XUSR 00100
+#define RGRP 00040
+#define WGRP 00020
+#define XGRP 00010
+#define ROTH 00004
+#define WOTH 00002
+#define XOTH 00001
+#define ALLM 07777 /* all octal mode bits */
+
 #ifndef S_ISUID
-# define S_ISUID 04000
+# define S_ISUID SUID
 #endif
 #ifndef S_ISGID
-# define S_ISGID 04000
+# define S_ISGID SGID
 #endif
 #ifndef S_ISVTX
-# define S_ISVTX 01000
+# define S_ISVTX SVTX
 #endif
 #ifndef S_IRUSR
-# define S_IRUSR 0400
+# define S_IRUSR RUSR
 #endif
 #ifndef S_IWUSR
-# define S_IWUSR 0200
+# define S_IWUSR WUSR
 #endif
 #ifndef S_IXUSR
-# define S_IXUSR 0100
+# define S_IXUSR XUSR
 #endif
 #ifndef S_IRGRP
-# define S_IRGRP 0040
+# define S_IRGRP RGRP
 #endif
 #ifndef S_IWGRP
-# define S_IWGRP 0020
+# define S_IWGRP WGRP
 #endif
 #ifndef S_IXGRP
-# define S_IXGRP 0010
+# define S_IXGRP XGRP
 #endif
 #ifndef S_IROTH
-# define S_IROTH 0004
+# define S_IROTH ROTH
 #endif
 #ifndef S_IWOTH
-# define S_IWOTH 0002
+# define S_IWOTH WOTH
 #endif
 #ifndef S_IXOTH
-# define S_IXOTH 0001
+# define S_IXOTH XOTH
 #endif
 #ifndef S_IRWXU
-# define S_IRWXU 0700
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
 #endif
 #ifndef S_IRWXG
-# define S_IRWXG 0070
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
 #endif
 #ifndef S_IRWXO
-# define S_IRWXO 0007
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
 #endif
 
 /* All the mode bits that can be affected by chmod.  */
@@ -157,8 +167,7 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
 {
   struct mode_change *head;    /* First element of the linked list. */
   struct mode_change *tail;    /* An element of the linked list. */
-  unsigned long mode_value;    /* The mode value, if octal.  */
-  char *string_end;            /* Pointer to end of parsed value.  */
+  unsigned long octal_value;   /* The mode value, if octal.  */
   mode_t umask_value;          /* The umask value (surprise). */
 
   head = NULL;
@@ -166,12 +175,34 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
   tail = NULL;
 #endif
 
-  if (xstrtoul (mode_string, &string_end, 8, &mode_value, "") == LONGINT_OK)
+  if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK)
     {
       struct mode_change *p;
-      if (mode_value > CHMOD_MODE_BITS)
+      mode_t mode;
+      if (octal_value != (octal_value & ALLM))
        return MODE_INVALID;
-      p = make_node_op_equals ((mode_t) mode_value);
+
+      /* Help the compiler optimize the usual case where mode_t uses
+        the traditional octal representation.  */
+      mode = ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX
+              && S_IRUSR == RUSR && S_IWUSR == WUSR && S_IXUSR == XUSR
+              && S_IRGRP == RGRP && S_IWGRP == WGRP && S_IXGRP == XGRP
+              && S_IROTH == ROTH && S_IWOTH == WOTH && S_IXOTH == XOTH)
+             ? octal_value
+             : (mode_t) ((octal_value & SUID ? S_ISUID : 0)
+                         | (octal_value & SGID ? S_ISGID : 0)
+                         | (octal_value & SVTX ? S_ISVTX : 0)
+                         | (octal_value & RUSR ? S_IRUSR : 0)
+                         | (octal_value & WUSR ? S_IWUSR : 0)
+                         | (octal_value & XUSR ? S_IXUSR : 0)
+                         | (octal_value & RGRP ? S_IRGRP : 0)
+                         | (octal_value & WGRP ? S_IWGRP : 0)
+                         | (octal_value & XGRP ? S_IXGRP : 0)
+                         | (octal_value & ROTH ? S_IROTH : 0)
+                         | (octal_value & WOTH ? S_IWOTH : 0)
+                         | (octal_value & XOTH ? S_IXOTH : 0)));
+
+      p = make_node_op_equals (mode);
       if (p == NULL)
        return MODE_MEMORY_EXHAUSTED;
       mode_append_entry (&head, &tail, p);
@@ -190,12 +221,10 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
       /* `affected_bits' modified by umask. */
       mode_t affected_masked;
       /* Operators to actually use umask on. */
-      unsigned ops_to_mask = 0;
+      unsigned int ops_to_mask = 0;
 
-      int who_specified_p;
+      bool who_specified_p;
 
-      affected_bits = 0;
-      ops_to_mask = 0;
       /* Turn on all the bits in `affected_bits' for each group given. */
       for (++mode_string;; ++mode_string)
        switch (*mode_string)
@@ -220,10 +249,10 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
       /* If none specified, affect all bits, except perhaps those
         set in the umask. */
       if (affected_bits)
-       who_specified_p = 1;
+       who_specified_p = true;
       else
        {
-         who_specified_p = 0;
+         who_specified_p = false;
          affected_bits = CHMOD_MODE_BITS;
          ops_to_mask = masked_ops;
        }
@@ -377,23 +406,23 @@ mode_adjust (mode_t oldmode, const struct mode_change *changes)
 
          if (changes->value & S_IRWXU)
            /* Copy `u' permissions onto `g' and `o'. */
-           value |= ((value & S_IRUSR ? S_IRGRP | S_IROTH : 0)
-                     | (value & S_IWUSR ? S_IWGRP | S_IROTH : 0)
+           value |= (  (value & S_IRUSR ? S_IRGRP | S_IROTH : 0)
+                     | (value & S_IWUSR ? S_IWGRP | S_IWOTH : 0)
                      | (value & S_IXUSR ? S_IXGRP | S_IXOTH : 0));
          else if (changes->value & S_IRWXG)
            /* Copy `g' permissions onto `u' and `o'. */
-           value |= ((value & S_IRGRP ? S_IRUSR | S_IROTH : 0)
-                     | (value & S_IWGRP ? S_IWUSR | S_IROTH : 0)
+           value |= (  (value & S_IRGRP ? S_IRUSR | S_IROTH : 0)
+                     | (value & S_IWGRP ? S_IWUSR | S_IWOTH : 0)
                      | (value & S_IXGRP ? S_IXUSR | S_IXOTH : 0));
          else
            /* Copy `o' permissions onto `u' and `g'. */
-           value |= ((value & S_IROTH ? S_IRUSR | S_IRGRP : 0)
-                     | (value & S_IWOTH ? S_IWUSR | S_IRGRP : 0)
+           value |= (  (value & S_IROTH ? S_IRUSR | S_IRGRP : 0)
+                     | (value & S_IWOTH ? S_IWUSR | S_IWGRP : 0)
                      | (value & S_IXOTH ? S_IXUSR | S_IXGRP : 0));
 
          /* In order to change only `u', `g', or `o' permissions,
             or some combination thereof, clear unselected bits.
-            This can not be done in mode_compile because the value
+            This cannot be done in mode_compile because the value
             to which the `changes->affected' mask is applied depends
             on the old mode of each file. */
          value &= changes->affected;