File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / chmod.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    1: /*
    2:  * Implement the core of the --chmod option.
    3:  *
    4:  * Copyright (C) 2002 Scott Howard
    5:  * Copyright (C) 2005-2020 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: #include "itypes.h"
   23: 
   24: extern mode_t orig_umask;
   25: 
   26: #define FLAG_X_KEEP (1<<0)
   27: #define FLAG_DIRS_ONLY (1<<1)
   28: #define FLAG_FILES_ONLY (1<<2)
   29: 
   30: struct chmod_mode_struct {
   31: 	struct chmod_mode_struct *next;
   32: 	int ModeAND, ModeOR;
   33: 	char flags;
   34: };
   35: 
   36: #define CHMOD_ADD 1
   37: #define CHMOD_SUB 2
   38: #define CHMOD_EQ  3
   39: #define CHMOD_SET 4
   40: 
   41: #define STATE_ERROR 0
   42: #define STATE_1ST_HALF 1
   43: #define STATE_2ND_HALF 2
   44: #define STATE_OCTAL_NUM 3
   45: 
   46: /* Parse a chmod-style argument, and break it down into one or more AND/OR
   47:  * pairs in a linked list.  We return a pointer to new items on success
   48:  * (appending the items to the specified list), or NULL on error. */
   49: struct chmod_mode_struct *parse_chmod(const char *modestr,
   50: 				      struct chmod_mode_struct **root_mode_ptr)
   51: {
   52: 	int state = STATE_1ST_HALF;
   53: 	int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
   54: 	struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
   55: 				 *prev_mode = NULL;
   56: 
   57: 	while (state != STATE_ERROR) {
   58: 		if (!*modestr || *modestr == ',') {
   59: 			int bits;
   60: 
   61: 			if (!op) {
   62: 				state = STATE_ERROR;
   63: 				break;
   64: 			}
   65: 			prev_mode = curr_mode;
   66: 			curr_mode = new_array(struct chmod_mode_struct, 1);
   67: 			if (prev_mode)
   68: 				prev_mode->next = curr_mode;
   69: 			else
   70: 				first_mode = curr_mode;
   71: 			curr_mode->next = NULL;
   72: 
   73: 			if (where)
   74: 				bits = where * what;
   75: 			else {
   76: 				where = 0111;
   77: 				bits = (where * what) & ~orig_umask;
   78: 			}
   79: 
   80: 			switch (op) {
   81: 			case CHMOD_ADD:
   82: 				curr_mode->ModeAND = CHMOD_BITS;
   83: 				curr_mode->ModeOR  = bits + topoct;
   84: 				break;
   85: 			case CHMOD_SUB:
   86: 				curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
   87: 				curr_mode->ModeOR  = 0;
   88: 				break;
   89: 			case CHMOD_EQ:
   90: 				curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
   91: 				curr_mode->ModeOR  = bits + topoct;
   92: 				break;
   93: 			case CHMOD_SET:
   94: 				curr_mode->ModeAND = 0;
   95: 				curr_mode->ModeOR  = bits;
   96: 				break;
   97: 			}
   98: 
   99: 			curr_mode->flags = flags;
  100: 
  101: 			if (!*modestr)
  102: 				break;
  103: 			modestr++;
  104: 
  105: 			state = STATE_1ST_HALF;
  106: 			where = what = op = topoct = topbits = flags = 0;
  107: 		}
  108: 
  109: 		switch (state) {
  110: 		case STATE_1ST_HALF:
  111: 			switch (*modestr) {
  112: 			case 'D':
  113: 				if (flags & FLAG_FILES_ONLY)
  114: 					state = STATE_ERROR;
  115: 				flags |= FLAG_DIRS_ONLY;
  116: 				break;
  117: 			case 'F':
  118: 				if (flags & FLAG_DIRS_ONLY)
  119: 					state = STATE_ERROR;
  120: 				flags |= FLAG_FILES_ONLY;
  121: 				break;
  122: 			case 'u':
  123: 				where |= 0100;
  124: 				topbits |= 04000;
  125: 				break;
  126: 			case 'g':
  127: 				where |= 0010;
  128: 				topbits |= 02000;
  129: 				break;
  130: 			case 'o':
  131: 				where |= 0001;
  132: 				break;
  133: 			case 'a':
  134: 				where |= 0111;
  135: 				break;
  136: 			case '+':
  137: 				op = CHMOD_ADD;
  138: 				state = STATE_2ND_HALF;
  139: 				break;
  140: 			case '-':
  141: 				op = CHMOD_SUB;
  142: 				state = STATE_2ND_HALF;
  143: 				break;
  144: 			case '=':
  145: 				op = CHMOD_EQ;
  146: 				state = STATE_2ND_HALF;
  147: 				break;
  148: 			default:
  149: 				if (isDigit(modestr) && *modestr < '8' && !where) {
  150: 					op = CHMOD_SET;
  151: 					state =  STATE_OCTAL_NUM;
  152: 					where = 1;
  153: 					what = *modestr - '0';
  154: 				} else
  155: 					state = STATE_ERROR;
  156: 				break;
  157: 			}
  158: 			break;
  159: 		case STATE_2ND_HALF:
  160: 			switch (*modestr) {
  161: 			case 'r':
  162: 				what |= 4;
  163: 				break;
  164: 			case 'w':
  165: 				what |= 2;
  166: 				break;
  167: 			case 'X':
  168: 				flags |= FLAG_X_KEEP;
  169: 				/* FALL THROUGH */
  170: 			case 'x':
  171: 				what |= 1;
  172: 				break;
  173: 			case 's':
  174: 				if (topbits)
  175: 					topoct |= topbits;
  176: 				else
  177: 					topoct = 04000;
  178: 				break;
  179: 			case 't':
  180: 				topoct |= 01000;
  181: 				break;
  182: 			default:
  183: 				state = STATE_ERROR;
  184: 				break;
  185: 			}
  186: 			break;
  187: 		case STATE_OCTAL_NUM:
  188: 			if (isDigit(modestr) && *modestr < '8') {
  189: 				what = what*8 + *modestr - '0';
  190: 				if (what > CHMOD_BITS)
  191: 					state = STATE_ERROR;
  192: 			} else
  193: 				state = STATE_ERROR;
  194: 			break;
  195: 		}
  196: 		modestr++;
  197: 	}
  198: 
  199: 	if (state == STATE_ERROR) {
  200: 		free_chmod_mode(first_mode);
  201: 		return NULL;
  202: 	}
  203: 
  204: 	if (!(curr_mode = *root_mode_ptr))
  205: 		*root_mode_ptr = first_mode;
  206: 	else {
  207: 		while (curr_mode->next)
  208: 			curr_mode = curr_mode->next;
  209: 		curr_mode->next = first_mode;
  210: 	}
  211: 
  212: 	return first_mode;
  213: }
  214: 
  215: 
  216: /* Takes an existing file permission and a list of AND/OR changes, and
  217:  * create a new permissions. */
  218: int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
  219: {
  220: 	int IsX = mode & 0111;
  221: 	int NonPerm = mode & ~CHMOD_BITS;
  222: 
  223: 	for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
  224: 		if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
  225: 			continue;
  226: 		if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
  227: 			continue;
  228: 		mode &= chmod_modes->ModeAND;
  229: 		if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
  230: 			mode |= chmod_modes->ModeOR & ~0111;
  231: 		else
  232: 			mode |= chmod_modes->ModeOR;
  233: 	}
  234: 
  235: 	return mode | NonPerm;
  236: }
  237: 
  238: /* Free the linked list created by parse_chmod. */
  239: int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
  240: {
  241: 	struct chmod_mode_struct *next;
  242: 
  243: 	while (chmod_modes) {
  244: 		next = chmod_modes->next;
  245: 		free(chmod_modes);
  246: 		chmod_modes = next;
  247: 	}
  248: 	return 0;
  249: }

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