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>