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