Annotation of embedaddon/rsync/chmod.c, revision 1.1
1.1 ! misho 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>