Annotation of embedaddon/rsync/chmod.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Implement the core of the --chmod option.
3: *
4: * Copyright (C) 2002 Scott Howard
1.1.1.2 ! misho 5: * Copyright (C) 2005-2013 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
47: * pairs in a linked list. We return a pointer to new items on succcess
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>