Annotation of embedaddon/rsync/chmod.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:  * Implement the core of the --chmod option.
                      3:  *
                      4:  * Copyright (C) 2002 Scott Howard
1.1.1.4 ! misho       5:  * Copyright (C) 2005-2020 Wayne Davison
1.1       misho       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"
1.1.1.2   misho      22: #include "itypes.h"
1.1       misho      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
1.1.1.2   misho      39: #define CHMOD_SET 4
1.1       misho      40: 
                     41: #define STATE_ERROR 0
                     42: #define STATE_1ST_HALF 1
                     43: #define STATE_2ND_HALF 2
1.1.1.2   misho      44: #define STATE_OCTAL_NUM 3
1.1       misho      45: 
                     46: /* Parse a chmod-style argument, and break it down into one or more AND/OR
1.1.1.4 ! misho      47:  * pairs in a linked list.  We return a pointer to new items on success
1.1       misho      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;
1.1.1.2   misho      93:                        case CHMOD_SET:
                     94:                                curr_mode->ModeAND = 0;
                     95:                                curr_mode->ModeOR  = bits;
                     96:                                break;
1.1       misho      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: 
1.1.1.2   misho     109:                switch (state) {
                    110:                case STATE_1ST_HALF:
1.1       misho     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:
1.1.1.2   misho     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;
1.1       misho     156:                                break;
                    157:                        }
1.1.1.2   misho     158:                        break;
                    159:                case STATE_2ND_HALF:
1.1       misho     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:                        }
1.1.1.2   misho     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;
1.1       misho     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>