File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / chmod.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /*
    2:  * Implement the core of the --chmod option.
    3:  *
    4:  * Copyright (C) 2002 Scott Howard
    5:  * Copyright (C) 2005-2009 Wayne Davison
    6:  *
    7:  * This program is free software; you can redistribute it and/or modify
    8:  * it under the terms of the GNU General Public License as published by
    9:  * the Free Software Foundation; either version 3 of the License, or
   10:  * (at your option) any later version.
   11:  *
   12:  * This program is distributed in the hope that it will be useful,
   13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:  * GNU General Public License for more details.
   16:  *
   17:  * You should have received a copy of the GNU General Public License along
   18:  * with this program; if not, visit the http://fsf.org website.
   19:  */
   20: 
   21: #include "rsync.h"
   22: 
   23: extern mode_t orig_umask;
   24: 
   25: #define FLAG_X_KEEP (1<<0)
   26: #define FLAG_DIRS_ONLY (1<<1)
   27: #define FLAG_FILES_ONLY (1<<2)
   28: 
   29: struct chmod_mode_struct {
   30: 	struct chmod_mode_struct *next;
   31: 	int ModeAND, ModeOR;
   32: 	char flags;
   33: };
   34: 
   35: #define CHMOD_ADD 1
   36: #define CHMOD_SUB 2
   37: #define CHMOD_EQ  3
   38: 
   39: #define STATE_ERROR 0
   40: #define STATE_1ST_HALF 1
   41: #define STATE_2ND_HALF 2
   42: 
   43: /* Parse a chmod-style argument, and break it down into one or more AND/OR
   44:  * pairs in a linked list.  We return a pointer to new items on succcess
   45:  * (appending the items to the specified list), or NULL on error. */
   46: struct chmod_mode_struct *parse_chmod(const char *modestr,
   47: 				      struct chmod_mode_struct **root_mode_ptr)
   48: {
   49: 	int state = STATE_1ST_HALF;
   50: 	int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
   51: 	struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
   52: 				 *prev_mode = NULL;
   53: 
   54: 	while (state != STATE_ERROR) {
   55: 		if (!*modestr || *modestr == ',') {
   56: 			int bits;
   57: 
   58: 			if (!op) {
   59: 				state = STATE_ERROR;
   60: 				break;
   61: 			}
   62: 			prev_mode = curr_mode;
   63: 			curr_mode = new_array(struct chmod_mode_struct, 1);
   64: 			if (prev_mode)
   65: 				prev_mode->next = curr_mode;
   66: 			else
   67: 				first_mode = curr_mode;
   68: 			curr_mode->next = NULL;
   69: 
   70: 			if (where)
   71: 				bits = where * what;
   72: 			else {
   73: 				where = 0111;
   74: 				bits = (where * what) & ~orig_umask;
   75: 			}
   76: 
   77: 			switch (op) {
   78: 			case CHMOD_ADD:
   79: 				curr_mode->ModeAND = CHMOD_BITS;
   80: 				curr_mode->ModeOR  = bits + topoct;
   81: 				break;
   82: 			case CHMOD_SUB:
   83: 				curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
   84: 				curr_mode->ModeOR  = 0;
   85: 				break;
   86: 			case CHMOD_EQ:
   87: 				curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
   88: 				curr_mode->ModeOR  = bits + topoct;
   89: 				break;
   90: 			}
   91: 
   92: 			curr_mode->flags = flags;
   93: 
   94: 			if (!*modestr)
   95: 				break;
   96: 			modestr++;
   97: 
   98: 			state = STATE_1ST_HALF;
   99: 			where = what = op = topoct = topbits = flags = 0;
  100: 		}
  101: 
  102: 		if (state != STATE_2ND_HALF) {
  103: 			switch (*modestr) {
  104: 			case 'D':
  105: 				if (flags & FLAG_FILES_ONLY)
  106: 					state = STATE_ERROR;
  107: 				flags |= FLAG_DIRS_ONLY;
  108: 				break;
  109: 			case 'F':
  110: 				if (flags & FLAG_DIRS_ONLY)
  111: 					state = STATE_ERROR;
  112: 				flags |= FLAG_FILES_ONLY;
  113: 				break;
  114: 			case 'u':
  115: 				where |= 0100;
  116: 				topbits |= 04000;
  117: 				break;
  118: 			case 'g':
  119: 				where |= 0010;
  120: 				topbits |= 02000;
  121: 				break;
  122: 			case 'o':
  123: 				where |= 0001;
  124: 				break;
  125: 			case 'a':
  126: 				where |= 0111;
  127: 				break;
  128: 			case '+':
  129: 				op = CHMOD_ADD;
  130: 				state = STATE_2ND_HALF;
  131: 				break;
  132: 			case '-':
  133: 				op = CHMOD_SUB;
  134: 				state = STATE_2ND_HALF;
  135: 				break;
  136: 			case '=':
  137: 				op = CHMOD_EQ;
  138: 				state = STATE_2ND_HALF;
  139: 				break;
  140: 			default:
  141: 				state = STATE_ERROR;
  142: 				break;
  143: 			}
  144: 		} else {
  145: 			switch (*modestr) {
  146: 			case 'r':
  147: 				what |= 4;
  148: 				break;
  149: 			case 'w':
  150: 				what |= 2;
  151: 				break;
  152: 			case 'X':
  153: 				flags |= FLAG_X_KEEP;
  154: 				/* FALL THROUGH */
  155: 			case 'x':
  156: 				what |= 1;
  157: 				break;
  158: 			case 's':
  159: 				if (topbits)
  160: 					topoct |= topbits;
  161: 				else
  162: 					topoct = 04000;
  163: 				break;
  164: 			case 't':
  165: 				topoct |= 01000;
  166: 				break;
  167: 			default:
  168: 				state = STATE_ERROR;
  169: 				break;
  170: 			}
  171: 		}
  172: 		modestr++;
  173: 	}
  174: 
  175: 	if (state == STATE_ERROR) {
  176: 		free_chmod_mode(first_mode);
  177: 		return NULL;
  178: 	}
  179: 
  180: 	if (!(curr_mode = *root_mode_ptr))
  181: 		*root_mode_ptr = first_mode;
  182: 	else {
  183: 		while (curr_mode->next)
  184: 			curr_mode = curr_mode->next;
  185: 		curr_mode->next = first_mode;
  186: 	}
  187: 
  188: 	return first_mode;
  189: }
  190: 
  191: 
  192: /* Takes an existing file permission and a list of AND/OR changes, and
  193:  * create a new permissions. */
  194: int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
  195: {
  196: 	int IsX = mode & 0111;
  197: 	int NonPerm = mode & ~CHMOD_BITS;
  198: 
  199: 	for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
  200: 		if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
  201: 			continue;
  202: 		if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
  203: 			continue;
  204: 		mode &= chmod_modes->ModeAND;
  205: 		if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
  206: 			mode |= chmod_modes->ModeOR & ~0111;
  207: 		else
  208: 			mode |= chmod_modes->ModeOR;
  209: 	}
  210: 
  211: 	return mode | NonPerm;
  212: }
  213: 
  214: /* Free the linked list created by parse_chmod. */
  215: int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
  216: {
  217: 	struct chmod_mode_struct *next;
  218: 
  219: 	while (chmod_modes) {
  220: 		next = chmod_modes->next;
  221: 		free(chmod_modes);
  222: 		chmod_modes = next;
  223: 	}
  224: 	return 0;
  225: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>