~ubuntu-branches/ubuntu/raring/findutils/raring

« back to all changes in this revision

Viewing changes to gnulib/lib/modechange.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2005-07-04 11:37:37 UTC
  • mto: (11.1.1 lenny) (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050704113737-oxfumqxsqgfz5gay
Tags: upstream-4.2.22
ImportĀ upstreamĀ versionĀ 4.2.22

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* modechange.c -- file mode manipulation
2
 
   Copyright (C) 1989, 1990, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
 
2
 
 
3
   Copyright (C) 1989, 1990, 1997, 1998, 1999, 2001, 2003, 2004, 2005
 
4
   Free Software Foundation, Inc.
3
5
 
4
6
   This program is free software; you can redistribute it and/or modify
5
7
   it under the terms of the GNU General Public License as published by
13
15
 
14
16
   You should have received a copy of the GNU General Public License
15
17
   along with this program; if not, write to the Free Software Foundation,
16
 
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
18
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
19
 
18
20
/* Written by David MacKenzie <djm@ai.mit.edu> */
19
21
 
20
 
/* The ASCII mode string is compiled into a linked list of `struct
 
22
/* The ASCII mode string is compiled into an array of `struct
21
23
   modechange', which can then be applied to each file to be changed.
22
24
   We do this instead of re-parsing the ASCII string for each file
23
25
   because the compiled form requires less computation to use; when
24
26
   changing the mode of many files, this probably results in a
25
 
   performance gain. */
 
27
   performance gain.  */
26
28
 
27
29
#if HAVE_CONFIG_H
28
30
# include <config.h>
30
32
 
31
33
#include "modechange.h"
32
34
#include <sys/stat.h>
33
 
#include "xstrtol.h"
34
 
 
35
 
#if STDC_HEADERS
36
 
# include <stdlib.h>
37
 
#else
38
 
char *malloc ();
39
 
#endif
40
 
 
41
 
#ifndef NULL
42
 
# define NULL 0
43
 
#endif
44
 
 
45
 
#if STAT_MACROS_BROKEN
46
 
# undef S_ISDIR
47
 
#endif
48
 
 
49
 
#if !defined(S_ISDIR) && defined(S_IFDIR)
50
 
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
51
 
#endif
 
35
#include "stat-macros.h"
 
36
#include "xalloc.h"
 
37
#include <stdlib.h>
52
38
 
53
39
/* The traditional octal values corresponding to each mode bit.  */
54
40
#define SUID 04000
65
51
#define XOTH 00001
66
52
#define ALLM 07777 /* all octal mode bits */
67
53
 
68
 
#ifndef S_ISUID
69
 
# define S_ISUID SUID
70
 
#endif
71
 
#ifndef S_ISGID
72
 
# define S_ISGID SGID
73
 
#endif
74
 
#ifndef S_ISVTX
75
 
# define S_ISVTX SVTX
76
 
#endif
77
 
#ifndef S_IRUSR
78
 
# define S_IRUSR RUSR
79
 
#endif
80
 
#ifndef S_IWUSR
81
 
# define S_IWUSR WUSR
82
 
#endif
83
 
#ifndef S_IXUSR
84
 
# define S_IXUSR XUSR
85
 
#endif
86
 
#ifndef S_IRGRP
87
 
# define S_IRGRP RGRP
88
 
#endif
89
 
#ifndef S_IWGRP
90
 
# define S_IWGRP WGRP
91
 
#endif
92
 
#ifndef S_IXGRP
93
 
# define S_IXGRP XGRP
94
 
#endif
95
 
#ifndef S_IROTH
96
 
# define S_IROTH ROTH
97
 
#endif
98
 
#ifndef S_IWOTH
99
 
# define S_IWOTH WOTH
100
 
#endif
101
 
#ifndef S_IXOTH
102
 
# define S_IXOTH XOTH
103
 
#endif
104
 
#ifndef S_IRWXU
105
 
# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
106
 
#endif
107
 
#ifndef S_IRWXG
108
 
# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
109
 
#endif
110
 
#ifndef S_IRWXO
111
 
# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
112
 
#endif
113
 
 
114
 
/* All the mode bits that can be affected by chmod.  */
115
 
#define CHMOD_MODE_BITS \
116
 
  (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
117
 
 
118
 
/* Return newly allocated memory to hold one element of type TYPE. */
119
 
#define talloc(type) ((type *) malloc (sizeof (type)))
120
 
 
121
 
/* Create a mode_change entry with the specified `=ddd'-style
122
 
   mode change operation, where NEW_MODE is `ddd'.  Return the
123
 
   new entry, or NULL upon failure.  */
 
54
/* Special operations flags.  */
 
55
enum
 
56
  {
 
57
    /* For the sentinel at the end of the mode changes array.  */
 
58
    MODE_DONE,
 
59
 
 
60
    /* The typical case.  */
 
61
    MODE_ORDINARY_CHANGE,
 
62
 
 
63
    /* In addition to the typical case, affect the execute bits if at
 
64
       least one execute bit is set already, or if the file is a
 
65
       directory.  */
 
66
    MODE_X_IF_ANY_X,
 
67
 
 
68
    /* Instead of the typical case, copy some existing permissions for
 
69
       u, g, or o onto the other two.  Which of u, g, or o is copied
 
70
       is determined by which bits are set in the `value' field.  */
 
71
    MODE_COPY_EXISTING
 
72
  };
 
73
 
 
74
/* Description of a mode change.  */
 
75
struct mode_change
 
76
{
 
77
  char op;                      /* One of "=+-".  */
 
78
  char flag;                    /* Special operations flag.  */
 
79
  mode_t affected;              /* Set for u, g, o, or a.  */
 
80
  mode_t value;                 /* Bits to add/remove.  */
 
81
};
 
82
 
 
83
/* Return a mode_change array with the specified `=ddd'-style
 
84
   mode change operation, where NEW_MODE is `ddd'.  */
124
85
 
125
86
static struct mode_change *
126
87
make_node_op_equals (mode_t new_mode)
127
88
{
128
 
  struct mode_change *p;
129
 
  p = talloc (struct mode_change);
130
 
  if (p == NULL)
131
 
    return p;
132
 
  p->next = NULL;
 
89
  struct mode_change *p = xmalloc (2 * sizeof *p);
133
90
  p->op = '=';
134
 
  p->flags = 0;
 
91
  p->flag = MODE_ORDINARY_CHANGE;
 
92
  p->affected = CHMOD_MODE_BITS;
135
93
  p->value = new_mode;
136
 
  p->affected = CHMOD_MODE_BITS;        /* Affect all permissions. */
 
94
  p[1].flag = MODE_DONE;
137
95
  return p;
138
96
}
139
97
 
140
 
/* Append entry E to the end of the link list with the specified
141
 
   HEAD and TAIL.  */
142
 
 
143
 
static void
144
 
mode_append_entry (struct mode_change **head,
145
 
                   struct mode_change **tail,
146
 
                   struct mode_change *e)
147
 
{
148
 
  if (*head == NULL)
149
 
    *head = *tail = e;
150
 
  else
151
 
    {
152
 
      (*tail)->next = e;
153
 
      *tail = e;
154
 
    }
155
 
}
156
 
 
157
 
/* Return a linked list of file mode change operations created from
 
98
/* Return a pointer to an array of file mode change operations created from
158
99
   MODE_STRING, an ASCII string that contains either an octal number
159
100
   specifying an absolute mode, or symbolic mode change operations with
160
101
   the form:
161
102
   [ugoa...][[+-=][rwxXstugo...]...][,...]
162
 
   MASKED_OPS is a bitmask indicating which symbolic mode operators (=+-)
163
 
   should not affect bits set in the umask when no users are given.
164
 
   Operators not selected in MASKED_OPS ignore the umask.
165
103
 
166
 
   Return MODE_INVALID if `mode_string' does not contain a valid
167
 
   representation of file mode change operations;
168
 
   return MODE_MEMORY_EXHAUSTED if there is insufficient memory. */
 
104
   Return NULL if `mode_string' does not contain a valid
 
105
   representation of file mode change operations.  */
169
106
 
170
107
struct mode_change *
171
 
mode_compile (const char *mode_string, unsigned int masked_ops)
 
108
mode_compile (char const *mode_string)
172
109
{
173
 
  struct mode_change *head;     /* First element of the linked list. */
174
 
  struct mode_change *tail;     /* An element of the linked list. */
175
 
  unsigned long octal_value;    /* The mode value, if octal.  */
176
 
  mode_t umask_value;           /* The umask value (surprise). */
177
 
 
178
 
  head = NULL;
179
 
#ifdef lint
180
 
  tail = NULL;
181
 
#endif
182
 
 
183
 
  if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK)
 
110
  /* The array of mode-change directives to be returned.  */
 
111
  struct mode_change *mc;
 
112
  size_t used = 0;
 
113
 
 
114
  if ('0' <= *mode_string && *mode_string < '8')
184
115
    {
185
 
      struct mode_change *p;
186
116
      mode_t mode;
187
 
      if (octal_value != (octal_value & ALLM))
188
 
        return MODE_INVALID;
 
117
      unsigned int octal_value = 0;
 
118
 
 
119
      do
 
120
        {
 
121
          octal_value = 8 * octal_value + *mode_string++ - '0';
 
122
          if (ALLM < octal_value)
 
123
            return NULL;
 
124
        }
 
125
      while ('0' <= *mode_string && *mode_string < '8');
189
126
 
190
127
      /* Help the compiler optimize the usual case where mode_t uses
191
128
         the traditional octal representation.  */
207
144
                          | (octal_value & WOTH ? S_IWOTH : 0)
208
145
                          | (octal_value & XOTH ? S_IXOTH : 0)));
209
146
 
210
 
      p = make_node_op_equals (mode);
211
 
      if (p == NULL)
212
 
        return MODE_MEMORY_EXHAUSTED;
213
 
      mode_append_entry (&head, &tail, p);
214
 
      return head;
 
147
      return make_node_op_equals (mode);
215
148
    }
216
149
 
217
 
  umask_value = umask (0);
218
 
  umask (umask_value);          /* Restore the old value. */
219
 
  --mode_string;
 
150
  /* Allocate enough space to hold the result.  */
 
151
  {
 
152
    size_t needed = 1;
 
153
    char const *p;
 
154
    for (p = mode_string; *p; p++)
 
155
      needed += (*p == '=' || *p == '+' || *p == '-');
 
156
    mc = xnmalloc (needed, sizeof *mc);
 
157
  }
220
158
 
221
 
  /* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
222
 
  do
 
159
  /* One loop iteration for each `[ugoa]*([-+=]([rwxXst]*|[ugo]))+'.  */
 
160
  for (;; mode_string++)
223
161
    {
224
 
      /* Which bits in the mode are operated on. */
225
 
      mode_t affected_bits = 0;
226
 
      /* `affected_bits' modified by umask. */
227
 
      mode_t affected_masked;
228
 
      /* Operators to actually use umask on. */
229
 
      unsigned ops_to_mask = 0;
230
 
 
231
 
      int who_specified_p;
232
 
 
233
 
      affected_bits = 0;
234
 
      ops_to_mask = 0;
235
 
      /* Turn on all the bits in `affected_bits' for each group given. */
236
 
      for (++mode_string;; ++mode_string)
 
162
      /* Which bits in the mode are operated on.  */
 
163
      mode_t affected = 0;
 
164
 
 
165
      /* Turn on all the bits in `affected' for each group given.  */
 
166
      for (;; mode_string++)
237
167
        switch (*mode_string)
238
168
          {
 
169
          default:
 
170
            goto invalid;
239
171
          case 'u':
240
 
            affected_bits |= S_ISUID | S_IRWXU;
 
172
            affected |= S_ISUID | S_IRWXU;
241
173
            break;
242
174
          case 'g':
243
 
            affected_bits |= S_ISGID | S_IRWXG;
 
175
            affected |= S_ISGID | S_IRWXG;
244
176
            break;
245
177
          case 'o':
246
 
            affected_bits |= S_ISVTX | S_IRWXO;
 
178
            affected |= S_ISVTX | S_IRWXO;
247
179
            break;
248
180
          case 'a':
249
 
            affected_bits |= CHMOD_MODE_BITS;
 
181
            affected |= CHMOD_MODE_BITS;
250
182
            break;
251
 
          default:
 
183
          case '=': case '+': case '-':
252
184
            goto no_more_affected;
253
185
          }
254
 
 
255
 
    no_more_affected:
256
 
      /* If none specified, affect all bits, except perhaps those
257
 
         set in the umask. */
258
 
      if (affected_bits)
259
 
        who_specified_p = 1;
260
 
      else
261
 
        {
262
 
          who_specified_p = 0;
263
 
          affected_bits = CHMOD_MODE_BITS;
264
 
          ops_to_mask = masked_ops;
265
 
        }
266
 
 
267
 
      while (*mode_string == '=' || *mode_string == '+' || *mode_string == '-')
268
 
        {
269
 
          struct mode_change *change = talloc (struct mode_change);
270
 
          if (change == NULL)
271
 
            {
272
 
              mode_free (head);
273
 
              return MODE_MEMORY_EXHAUSTED;
274
 
            }
275
 
 
276
 
          change->next = NULL;
277
 
          change->op = *mode_string;    /* One of "=+-". */
278
 
          affected_masked = affected_bits;
279
 
 
280
 
          /* Per the Single Unix Spec, if `who' is not specified and the
281
 
             `=' operator is used, then clear all the bits first.  */
282
 
          if (!who_specified_p &&
283
 
              ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS : 0))
284
 
            {
285
 
              struct mode_change *p = make_node_op_equals (0);
286
 
              if (p == NULL)
287
 
                return MODE_MEMORY_EXHAUSTED;
288
 
              mode_append_entry (&head, &tail, p);
289
 
            }
290
 
 
291
 
          if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
292
 
                             : *mode_string == '+' ? MODE_MASK_PLUS
293
 
                             : MODE_MASK_MINUS))
294
 
            affected_masked &= ~umask_value;
295
 
          change->affected = affected_masked;
296
 
          change->value = 0;
297
 
          change->flags = 0;
298
 
 
299
 
          /* Add the element to the tail of the list, so the operations
300
 
             are performed in the correct order. */
301
 
          mode_append_entry (&head, &tail, change);
302
 
 
303
 
          /* Set `value' according to the bits set in `affected_masked'. */
304
 
          for (++mode_string;; ++mode_string)
305
 
            switch (*mode_string)
306
 
              {
307
 
              case 'r':
308
 
                change->value |= ((S_IRUSR | S_IRGRP | S_IROTH)
309
 
                                  & affected_masked);
310
 
                break;
311
 
              case 'w':
312
 
                change->value |= ((S_IWUSR | S_IWGRP | S_IWOTH)
313
 
                                  & affected_masked);
314
 
                break;
315
 
              case 'X':
316
 
                change->flags |= MODE_X_IF_ANY_X;
317
 
                /* Fall through. */
318
 
              case 'x':
319
 
                change->value |= ((S_IXUSR | S_IXGRP | S_IXOTH)
320
 
                                  & affected_masked);
321
 
                break;
322
 
              case 's':
323
 
                /* Set the setuid/gid bits if `u' or `g' is selected. */
324
 
                change->value |= (S_ISUID | S_ISGID) & affected_masked;
325
 
                break;
326
 
              case 't':
327
 
                /* Set the "save text image" bit if `o' is selected. */
328
 
                change->value |= S_ISVTX & affected_masked;
329
 
                break;
330
 
              case 'u':
331
 
                /* Set the affected bits to the value of the `u' bits
332
 
                   on the same file.  */
333
 
                if (change->value)
334
 
                  goto invalid;
335
 
                change->value = S_IRWXU;
336
 
                change->flags |= MODE_COPY_EXISTING;
337
 
                break;
338
 
              case 'g':
339
 
                /* Set the affected bits to the value of the `g' bits
340
 
                   on the same file.  */
341
 
                if (change->value)
342
 
                  goto invalid;
343
 
                change->value = S_IRWXG;
344
 
                change->flags |= MODE_COPY_EXISTING;
345
 
                break;
346
 
              case 'o':
347
 
                /* Set the affected bits to the value of the `o' bits
348
 
                   on the same file.  */
349
 
                if (change->value)
350
 
                  goto invalid;
351
 
                change->value = S_IRWXO;
352
 
                change->flags |= MODE_COPY_EXISTING;
353
 
                break;
354
 
              default:
355
 
                goto no_more_values;
356
 
              }
357
 
        no_more_values:;
358
 
        }
359
 
  } while (*mode_string == ',');
 
186
    no_more_affected:;
 
187
 
 
188
      do
 
189
        {
 
190
          char op = *mode_string++;
 
191
          mode_t value;
 
192
          char flag = MODE_COPY_EXISTING;
 
193
          struct mode_change *change;
 
194
 
 
195
          switch (*mode_string++)
 
196
            {
 
197
            case 'u':
 
198
              /* Set the affected bits to the value of the `u' bits
 
199
                 on the same file.  */
 
200
              value = S_IRWXU;
 
201
              break;
 
202
            case 'g':
 
203
              /* Set the affected bits to the value of the `g' bits
 
204
                 on the same file.  */
 
205
              value = S_IRWXG;
 
206
              break;
 
207
            case 'o':
 
208
              /* Set the affected bits to the value of the `o' bits
 
209
                 on the same file.  */
 
210
              value = S_IRWXO;
 
211
              break;
 
212
 
 
213
            default:
 
214
              value = 0;
 
215
              flag = MODE_ORDINARY_CHANGE;
 
216
 
 
217
              for (mode_string--;; mode_string++)
 
218
                switch (*mode_string)
 
219
                  {
 
220
                  case 'r':
 
221
                    value |= S_IRUSR | S_IRGRP | S_IROTH;
 
222
                    break;
 
223
                  case 'w':
 
224
                    value |= S_IWUSR | S_IWGRP | S_IWOTH;
 
225
                    break;
 
226
                  case 'x':
 
227
                    value |= S_IXUSR | S_IXGRP | S_IXOTH;
 
228
                    break;
 
229
                  case 'X':
 
230
                    flag = MODE_X_IF_ANY_X;
 
231
                    break;
 
232
                  case 's':
 
233
                    /* Set the setuid/gid bits if `u' or `g' is selected.  */
 
234
                    value |= S_ISUID | S_ISGID;
 
235
                    break;
 
236
                  case 't':
 
237
                    /* Set the "save text image" bit if `o' is selected.  */
 
238
                    value |= S_ISVTX;
 
239
                    break;
 
240
                  default:
 
241
                    goto no_more_values;
 
242
                  }
 
243
            no_more_values:;
 
244
            }
 
245
 
 
246
          change = &mc[used++];
 
247
          change->op = op;
 
248
          change->flag = flag;
 
249
          change->affected = affected;
 
250
          change->value = value;
 
251
        }
 
252
      while (*mode_string == '=' || *mode_string == '+'
 
253
             || *mode_string == '-');
 
254
 
 
255
      if (*mode_string != ',')
 
256
        break;
 
257
    }
 
258
 
360
259
  if (*mode_string == 0)
361
 
    return head;
 
260
    {
 
261
      mc[used].flag = MODE_DONE;
 
262
      return mc;
 
263
    }
 
264
 
362
265
invalid:
363
 
  mode_free (head);
364
 
  return MODE_INVALID;
 
266
  free (mc);
 
267
  return NULL;
365
268
}
366
269
 
367
270
/* Return a file mode change operation that sets permissions to match those
368
 
   of REF_FILE.  Return MODE_BAD_REFERENCE if REF_FILE can't be accessed.  */
 
271
   of REF_FILE.  Return NULL (setting errno) if REF_FILE can't be accessed.  */
369
272
 
370
273
struct mode_change *
371
274
mode_create_from_ref (const char *ref_file)
372
275
{
373
 
  struct mode_change *change;   /* the only change element */
374
276
  struct stat ref_stats;
375
277
 
376
 
  if (stat (ref_file, &ref_stats))
377
 
    return MODE_BAD_REFERENCE;
378
 
 
379
 
  change = talloc (struct mode_change);
380
 
 
381
 
  if (change == NULL)
382
 
    return MODE_MEMORY_EXHAUSTED;
383
 
 
384
 
  change->op = '=';
385
 
  change->flags = 0;
386
 
  change->affected = CHMOD_MODE_BITS;
387
 
  change->value = ref_stats.st_mode;
388
 
  change->next = NULL;
389
 
 
390
 
  return change;
 
278
  if (stat (ref_file, &ref_stats) != 0)
 
279
    return NULL;
 
280
  return make_node_op_equals (ref_stats.st_mode);
391
281
}
392
282
 
393
283
/* Return file mode OLDMODE, adjusted as indicated by the list of change
394
 
   operations CHANGES.  If OLDMODE is a directory, the type `X'
 
284
   operations CHANGES, which are interpreted assuming the umask is
 
285
   UMASK_VALUE.  If OLDMODE is a directory, the type `X'
395
286
   change affects it even if no execute bits were set in OLDMODE.
396
 
   The returned value has the S_IFMT bits cleared. */
 
287
   The returned value has the S_IFMT bits cleared.  */
397
288
 
398
289
mode_t
399
 
mode_adjust (mode_t oldmode, const struct mode_change *changes)
 
290
mode_adjust (mode_t oldmode, struct mode_change const *changes,
 
291
             mode_t umask_value)
400
292
{
401
 
  mode_t newmode;       /* The adjusted mode and one operand. */
402
 
  mode_t value;         /* The other operand. */
403
 
 
404
 
  newmode = oldmode & CHMOD_MODE_BITS;
405
 
 
406
 
  for (; changes; changes = changes->next)
 
293
  /* The adjusted mode.  */
 
294
  mode_t newmode = oldmode & CHMOD_MODE_BITS;
 
295
 
 
296
  for (; changes->flag != MODE_DONE; changes++)
407
297
    {
408
 
      if (changes->flags & MODE_COPY_EXISTING)
409
 
        {
410
 
          /* Isolate in `value' the bits in `newmode' to copy, given in
411
 
             the mask `changes->value'. */
412
 
          value = newmode & changes->value;
413
 
 
414
 
          if (changes->value & S_IRWXU)
415
 
            /* Copy `u' permissions onto `g' and `o'. */
416
 
            value |= (  (value & S_IRUSR ? S_IRGRP | S_IROTH : 0)
417
 
                      | (value & S_IWUSR ? S_IWGRP | S_IWOTH : 0)
418
 
                      | (value & S_IXUSR ? S_IXGRP | S_IXOTH : 0));
419
 
          else if (changes->value & S_IRWXG)
420
 
            /* Copy `g' permissions onto `u' and `o'. */
421
 
            value |= (  (value & S_IRGRP ? S_IRUSR | S_IROTH : 0)
422
 
                      | (value & S_IWGRP ? S_IWUSR | S_IWOTH : 0)
423
 
                      | (value & S_IXGRP ? S_IXUSR | S_IXOTH : 0));
424
 
          else
425
 
            /* Copy `o' permissions onto `u' and `g'. */
426
 
            value |= (  (value & S_IROTH ? S_IRUSR | S_IRGRP : 0)
427
 
                      | (value & S_IWOTH ? S_IWUSR | S_IWGRP : 0)
428
 
                      | (value & S_IXOTH ? S_IXUSR | S_IXGRP : 0));
429
 
 
430
 
          /* In order to change only `u', `g', or `o' permissions,
431
 
             or some combination thereof, clear unselected bits.
432
 
             This cannot be done in mode_compile because the value
433
 
             to which the `changes->affected' mask is applied depends
434
 
             on the old mode of each file. */
435
 
          value &= changes->affected;
436
 
        }
437
 
      else
438
 
        {
439
 
          value = changes->value;
440
 
          /* If `X', do not affect the execute bits if the file is not a
441
 
             directory and no execute bits are already set. */
442
 
          if ((changes->flags & MODE_X_IF_ANY_X)
443
 
              && !S_ISDIR (oldmode)
444
 
              && (newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
445
 
            /* Clear the execute bits. */
446
 
            value &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
447
 
        }
 
298
      mode_t affected = changes->affected;
 
299
      mode_t value = changes->value;
 
300
 
 
301
      switch (changes->flag)
 
302
        {
 
303
        case MODE_ORDINARY_CHANGE:
 
304
          break;
 
305
 
 
306
        case MODE_COPY_EXISTING:
 
307
          /* Isolate in `value' the bits in `newmode' to copy.  */
 
308
          value &= newmode;
 
309
 
 
310
          /* Copy the isolated bits to the other two parts.  */
 
311
          value |= ((value & (S_IRUSR | S_IRGRP | S_IROTH)
 
312
                     ? S_IRUSR | S_IRGRP | S_IROTH : 0)
 
313
                    | (value & (S_IWUSR | S_IWGRP | S_IWOTH)
 
314
                       ? S_IWUSR | S_IWGRP | S_IWOTH : 0)
 
315
                    | (value & (S_IXUSR | S_IXGRP | S_IXOTH)
 
316
                       ? S_IXUSR | S_IXGRP | S_IXOTH : 0));
 
317
          break;
 
318
 
 
319
        case MODE_X_IF_ANY_X:
 
320
          /* Affect the execute bits if execute bits are already set
 
321
             or if the file is a directory.  */
 
322
          if ((newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) || S_ISDIR (oldmode))
 
323
            value |= S_IXUSR | S_IXGRP | S_IXOTH;
 
324
          break;
 
325
        }
 
326
 
 
327
      /* If WHO was specified, limit the change to the affected bits.
 
328
         Otherwise, apply the umask.  */
 
329
      value &= (affected ? affected : ~umask_value);
448
330
 
449
331
      switch (changes->op)
450
332
        {
451
333
        case '=':
452
 
          /* Preserve the previous values in `newmode' of bits that are
453
 
             not affected by this change operation. */
454
 
          newmode = (newmode & ~changes->affected) | value;
455
 
          break;
 
334
          /* If WHO was specified, preserve the previous values of
 
335
             bits that are not affected by this change operation.
 
336
             Otherwise, clear all the bits.  */
 
337
          newmode = (affected ? newmode & ~affected : 0);
 
338
          /* Fall through.  */
456
339
        case '+':
457
340
          newmode |= value;
458
341
          break;
 
342
 
459
343
        case '-':
460
344
          newmode &= ~value;
461
345
          break;
462
346
        }
463
347
    }
 
348
 
464
349
  return newmode;
465
350
}
466
 
 
467
 
/* Free the memory used by the list of file mode change operations
468
 
   CHANGES. */
469
 
 
470
 
void
471
 
mode_free (register struct mode_change *changes)
472
 
{
473
 
  register struct mode_change *next;
474
 
 
475
 
  while (changes)
476
 
    {
477
 
      next = changes->next;
478
 
      free (changes);
479
 
      changes = next;
480
 
    }
481
 
}