/* modechange.c -- file mode manipulation
Copyright (C) 1989, 1990 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Written by David MacKenzie <djm@ai.mit.edu> */
/* The ASCII mode string is compiled into a linked list of `struct
modechange', which can then be applied to each file to be changed.
We do this instead of re-parsing the ASCII string for each file
because the compiled form requires less computation to use; when
changing the mode of many files, this probably results in a
performance gain. */
#include <sys/types.h>
#include <sys/stat.h>
#include "modechange.h"
#include <stdlib.h>
/* Return file mode OLDMODE, adjusted as indicated by the list of change
operations CHANGES. If OLDMODE is a directory, the type `X'
change affects it even if no execute bits were set in OLDMODE.
The returned value has the S_IFMT bits cleared. */
unsigned short
mode_adjust (oldmode, changes)
unsigned oldmode;
const struct mode_change *changes;
{
unsigned short newmode; /* The adjusted mode and one operand. */
unsigned short value; /* The other operand. */
newmode = oldmode & 07777;
for (; changes; changes = changes->next)
{
if (changes->flags & MODE_COPY_EXISTING)
{
/* Isolate in `value' the bits in `newmode' to copy, given in
the mask `changes->value'. */
value = newmode & changes->value;
if (changes->value & 00700)
/* Copy `u' permissions onto `g' and `o'. */
value |= (value >> 3) | (value >> 6);
else if (changes->value & 00070)
/* Copy `g' permissions onto `u' and `o'. */
value |= (value << 3) | (value >> 3);
else
/* Copy `o' permissions onto `u' and `g'. */
value |= (value << 3) | (value << 6);
/* 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
to which the `changes->affected' mask is applied depends
on the old mode of each file. */
value &= changes->affected;
}
else
{
value = changes->value;
/* If `X', do not affect the execute bits if the file is not a
directory and no execute bits are already set. */
if ((changes->flags & MODE_X_IF_ANY_X)
&& !S_ISDIR (oldmode)
&& (newmode & 00111) == 0)
value &= ~00111; /* Clear the execute bits. */
}
switch (changes->op)
{
case '=':
/* Preserve the previous values in `newmode' of bits that are
not affected by this change operation. */
newmode = (newmode & ~changes->affected) | value;
break;
case '+':
newmode |= value;
break;
case '-':
newmode &= ~value;
break;
}
}
return newmode;
}
syntax highlighted by Code2HTML, v. 0.9.1