clsync
Loading...
Searching...
No Matches
rules.c
Go to the documentation of this file.
1/*
2 clsync - file tree sync utility based on inotify/kqueue
3
4 Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "common.h"
21
22#include <glib.h> // g_hash_table_*
23
24#include "rules.h"
25#include "error.h"
26
27int rule_complete ( rule_t *rule_p, char *expr, size_t *rules_count_p )
28{
29 debug ( 3, "<%s>.", expr );
30#ifdef VERYPARANOID
31
32 if ( rule_p->mask == RA_NONE ) {
33 error ( "Received a rule with rule_p->mask == 0x00. Exit." );
34 return EINVAL;
35 }
36
37#endif
38 char buf[BUFSIZ];
39 int ret = 0;
40
41 if ( rule_p->num >= MAXRULES ) {
42 error ( "Too many rules (%i >= %i).", rule_p->num, MAXRULES );
43 return ENOMEM;
44 }
45
46 if ( ( ret = regcomp ( &rule_p->expr, expr, REG_EXTENDED | REG_NOSUB ) ) ) {
47 regerror ( ret, &rule_p->expr, buf, BUFSIZ );
48 error ( "Invalid regexp pattern <%s>: %s (regex-errno: %i).", expr, buf, ret );
49 return ret;
50 }
51
52 ( *rules_count_p )++;
53 return ret;
54}
55
57{
58 int ret = 0;
59 char *rulfpath = ctx_p->rulfpath;
60 rule_t *rules = ctx_p->rules;
61 size_t *rules_count_p = &ctx_p->rules_count;
62 char *line_buf = NULL;
63 FILE *f = fopen ( rulfpath, "r" );
64
65 if ( f == NULL ) {
66 rules->mask = RA_NONE; // Terminator. End of rules' chain.
67 rules->perm = DEFAULT_RULES_PERM;
68 error ( "Cannot open \"%s\" for reading.", rulfpath );
69 return errno;
70 }
71
72 GHashTable *autowrules_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
73 int i = 0;
74 ssize_t linelen;
75 size_t size = 0;
76
77 while ( ( linelen = getline ( &line_buf, &size, f ) ) != -1 ) {
78 if ( linelen > 1 ) {
79 uint8_t sign = 0;
80 char *line = line_buf;
81 rule_t *rule;
82 rule = &rules[i];
83#ifdef VERYPARANOID
84 memset ( rule, 0, sizeof ( *rule ) );
85#endif
86 rule->num = i++;
87 line[--linelen] = 0;
88
89 // Parsing the first character of the line
90 switch ( *line ) {
91 case '+':
92 sign = RS_PERMIT;
93 break;
94
95 case '-':
96 sign = RS_REJECT;
97 break;
98
99 case '#': // Comment?
100 i--; // Canceling new rule
101 continue;
102
103 default:
104 error ( "Wrong rule action <%c>.", *line );
105 return EINVAL;
106 }
107
108 line++;
109 linelen--;
110 // Parsing the second character of the line
111 *line |= 0x20; // lower-casing
112 // Default rule->mask and rule->perm
113 // rule->mask - sets bitmask of operations that are affected by the rule
114 // rule->perm - sets bitmask of permit/reject for every operation. Effect have only bits specified by the rule->mask.
115 rule->mask = RA_ALL;
116
117 switch ( sign ) {
118 case RS_REJECT:
119 rule->perm = RA_NONE;
120 break;
121
122 case RS_PERMIT:
123 rule->perm = RA_ALL;
124 break;
125 }
126
127 switch ( *line ) {
128 case '*':
129 rule->objtype = 0; // "0" - means "of any type"
130 break;
131#ifdef DETAILED_FTYPE
132
133 case 's':
134 rule->objtype = S_IFSOCK;
135 break;
136
137 case 'l':
138 rule->objtype = S_IFLNK;
139 break;
140
141 case 'b':
142 rule->objtype = S_IFBLK;
143 break;
144
145 case 'c':
146 rule->objtype = S_IFCHR;
147 break;
148
149 case 'p':
150 rule->objtype = S_IFIFO;
151 break;
152#endif
153
154 case 'f':
155 rule->objtype = S_IFREG;
156 break;
157
158 case 'd':
159 rule->objtype = S_IFDIR;
160 break;
161
162 case 'W':
163 case 'w':
164 case 'm':
165 case 's':
166 if (
167 ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
168 ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
170 )
171 warning ( "Used \"w\" or/and \"m\" or/and \"s\" rule in rsync \"--monitor\" case."
172 " This may cause unexpected problems." );
173
174 rule->objtype = S_IFDIR;
175
176 switch ( *line ) {
177 case 'W':
179 break;
180
181 case 'w':
182 rule->mask = RA_WALK;
183 break;
184
185 case 'm':
187 break;
188
189 case 's':
190 rule->mask = RA_SYNC;
191 break;
192 }
193
194 break;
195
196 default:
197 warning ( "Cannot parse the rule <%s>", &line[-1] );
198 i--; // Canceling new rule
199 continue;
200 }
201
202 line++;
203 linelen--;
204 // Parsing the rest part of the line
205 debug ( 1, "Rule #%i <%c>[0x%02x 0x%02x] <%c>[0x%04x] pattern <%s> (length: %i).", rule->num, line[-2], rule->perm, rule->mask, line[-1], rule->objtype, line, linelen );
206
207 if ( ( ret = rule_complete ( rule, line, rules_count_p ) ) )
208 goto l_parse_rules_fromfile_end;
209
210 // Post-processing:
211 line--;
212 linelen++;
213#ifdef AUTORULESW
214
215 if ( *line != 'w' ) {
216 // processing --auto-add-rules-w
217 if ( ctx_p->flags[AUTORULESW] && ( sign == RS_PERMIT ) ) {
218 // Preparing to add appropriate w-rules
219 char skip = 0;
220 char *expr = alloca ( linelen + 2 );
221 memcpy ( expr, line, linelen + 1 );
222 size_t exprlen = linelen;
223
224 // Making expr to be starting with '^'
225 if ( line[1] == '^' ) {
226 expr++;
227 exprlen--;
228 } else
229 *expr = '^';
230
231 char *end;
232
233 if ( *line == 'd' || *line == '*' ) {
234 // "d" rule already doing what we need, so we can skip the last level
235 end = &expr[exprlen];
236
237 if ( end[-1] != '$' )
238 * ( end++ ) = '$';
239
240 *end = 0;
241// debug(3, "Don't adding w-rule for \"%s\" due to [*d]-rule for \"%s\"",
242// expr, &line[1]);
243 g_hash_table_insert ( autowrules_ht, strdup ( expr ), GINT_TO_POINTER ( 1 ) );
244 }
245
246 if ( !skip ) {
247 do {
248 // Decreasing directory level and make the '$' ending
249 end = strrchr ( expr, '/' );
250
251 if ( end != NULL ) {
252 if ( end[-1] != '$' )
253 * ( end++ ) = '$';
254
255 *end = 0;
256 exprlen = ( size_t ) ( end - expr );
257 } else {
258 expr[1] = '$';
259 expr[2] = 0;
260 exprlen = 2;
261 }
262
263 // Checking if it not already set
264 if ( !g_hash_table_lookup ( autowrules_ht, expr ) ) {
265 // Switching to next rule:
266 rule = &rules[i];
267 rule->num = i++;
268 // Adding the rule
269 rule->objtype = S_IFDIR;
270 rule->mask = RA_WALK;
271 rule->perm = RA_WALK;
272 debug ( 1, "Rule #%i <+> <w> pattern <%s> (length: %i) [auto].",
273 rule->num, expr, exprlen );
274
275 if ( ( ret = rule_complete ( rule, expr, rules_count_p ) ) )
276 goto l_parse_rules_fromfile_end;
277
278 g_hash_table_insert ( autowrules_ht, strdup ( expr ), GINT_TO_POINTER ( 1 ) );
279 }
280 } while ( end != NULL );
281 }
282 }
283 }
284
285#endif
286 }
287 }
288
289l_parse_rules_fromfile_end:
290
291 if ( size )
292 free ( line_buf );
293
294 fclose ( f );
295 debug ( 3, "Adding tail-rule #%u (effective #%u).", -1, i );
296 rules[i].mask = RA_NONE; // Terminator. End of rules' chain.
297 rules[i].perm = DEFAULT_RULES_PERM;
298 g_hash_table_destroy ( autowrules_ht );
299#ifdef _DEBUG_FORCE
300 debug ( 3, "Total (p == %p):", rules );
301 i = 0;
302
303 do {
304 debug ( 4, "\t%i\t%i\t%p/%p", i, rules[i].objtype, ( void * ) ( long ) rules[i].perm, ( void * ) ( long ) rules[i].mask );
305 i++;
306 } while ( rules[i].mask != RA_NONE );
307
308#endif
309 return ret;
310}
311
312/**
313 * @brief Checks file path by rules' expressions (parsed from file)
314 *
315 * @param[in] fpath Path to file of directory
316 * @param[in] st_mode st_mode received via *stat() functions
317 * @param[in] rules_p Pointer to start of rules array
318 * @param[in] ruleaction Operaton ID (see ruleaction_t)
319 * @param[in,out] rule_pp Pointer to pointer to rule, where the last search ended. Next search will be started from the specified rule. Can be "NULL" to disable this feature.
320 *
321 * @retval perm Permission bitmask
322 *
323 */
324// Checks file path by rules' expressions (parsed from file)
325// Return: RS_PERMIT or RS_REJECT for the "file path" and specified ruleaction
326
327ruleaction_t rules_search_getperm ( const char *fpath, mode_t st_mode, rule_t *rules_p, const ruleaction_t ruleaction, rule_t **rule_pp )
328{
329 debug ( 3, "rules_search_getperm(\"%s\", %p, %p, %p, %p)",
330 fpath, ( void * ) ( unsigned long ) st_mode, rules_p,
331 ( void * ) ( long ) ruleaction, ( void * ) ( long ) rule_pp
332 );
333 int i;
334 i = 0;
335 rule_t *rule_p = rules_p;
336 mode_t ftype = st_mode & S_IFMT;
337#ifdef _DEBUG_FORCE
338 debug ( 3, "Rules (p == %p):", rules_p );
339 i = 0;
340
341 do {
342 debug ( 3, "\t%i\t%i\t%p/%p", i, rules_p[i].objtype, ( void * ) ( long ) rules_p[i].perm, ( void * ) ( long ) rules_p[i].mask );
343 i++;
344 } while ( rules_p[i].mask != RA_NONE );
345
346#endif
347 i = 0;
348
349 if ( rule_pp != NULL )
350 if ( *rule_pp != NULL ) {
351 debug ( 3, "Previous position is set." );
352
353 if ( rule_p->mask == RA_NONE )
354 return rule_p->perm;
355
356 rule_p = ++ ( *rule_pp );
357 i = rule_p->num;
358 }
359
360 debug ( 3, "Starting from position %i", i );
361
362 while ( rule_p->mask != RA_NONE ) {
363 debug ( 3, "%i -> %p/%p: type compare: %p, %p -> %i",
364 i,
365 ( void * ) ( long ) rule_p->perm, ( void * ) ( long ) rule_p->mask,
366 ( void * ) ( unsigned long ) ftype, ( void * ) ( unsigned long ) rule_p->objtype,
367 ( unsigned char ) ! ( rule_p->objtype && ( rule_p->objtype != ftype ) )
368 );
369
370 if ( ! ( rule_p->mask & ruleaction ) ) { // Checking wrong operation type
371 debug ( 3, "action-mask mismatch. Skipping." );
372 rule_p++;
373 i++;// = &rules_p[++i];
374 continue;
375 }
376
377 if ( rule_p->objtype && ( rule_p->objtype != ftype ) ) {
378 debug ( 3, "objtype mismatch. Skipping." );
379 rule_p++;
380 i++;// = &rules_p[++i];
381 continue;
382 }
383
384 if ( !regexec ( &rule_p->expr, fpath, 0, NULL, 0 ) )
385 break;
386
387 debug ( 3, "doesn't match regex. Skipping." );
388 rule_p++;
389 i++;// = &rules_p[++i];
390 }
391
392 debug ( 2, "matched to rule #%u for \"%s\":\t%p/%p (queried: %p).", rule_p->mask == RA_NONE ? -1 : i, fpath,
393 ( void * ) ( long ) rule_p->perm, ( void * ) ( long ) rule_p->mask,
394 ( void * ) ( long ) ruleaction
395 );
396
397 if ( rule_pp != NULL )
398 *rule_pp = rule_p;
399
400 return rule_p->perm;
401}
402
403ruleaction_t rules_getperm ( const char *fpath, mode_t st_mode, rule_t *rules_p, ruleaction_t ruleactions )
404{
405 rule_t *rule_p = NULL;
406 ruleaction_t gotpermto = 0;
407 ruleaction_t resultperm = 0;
408 debug ( 3, "rules_getperm(\"%s\", %p, %p (#%u), %p)",
409 fpath, ( void * ) ( long ) st_mode, rules_p, rules_p->num, ( void * ) ( long ) ruleactions );
410
411 while ( ( gotpermto & ruleactions ) != ruleactions ) {
412 rules_search_getperm ( fpath, st_mode, rules_p, ruleactions, &rule_p );
413
414 if ( rule_p->mask == RA_NONE ) { // End of rules' list
415 resultperm |= rule_p->perm & ( gotpermto ^ RA_ALL );
416 break;
417 }
418
419 resultperm |= rule_p->perm & ( ( gotpermto ^ rule_p->mask ) &rule_p->mask ); // Adding perm bitmask of operations that was unknown before
420 gotpermto |= rule_p->mask; // Adding the mask
421 }
422
423 debug ( 3, "rules_getperm(\"%s\", %p, rules_p, %p): result perm is %p",
424 fpath, ( void * ) ( long ) st_mode, ( void * ) ( long ) ruleactions, ( void * ) ( long ) resultperm );
425 return resultperm;
426}
427
#define MAXRULES
#define BUFSIZ
#define DEFAULT_RULES_PERM
@ AUTORULESW
Definition ctx.h:75
@ MODE
Definition ctx.h:76
@ MODE_RSYNCSHELL
Definition ctx.h:165
@ MODE_RSYNCSO
Definition ctx.h:167
@ MODE_RSYNCDIRECT
Definition ctx.h:166
enum ruleaction_enum ruleaction_t
Definition ctx.h:196
@ RA_MONITOR
Definition ctx.h:191
@ RA_SYNC
Definition ctx.h:192
@ RA_NONE
Definition ctx.h:190
@ RA_ALL
Definition ctx.h:194
@ RA_WALK
Definition ctx.h:193
@ RS_PERMIT
Definition ctx.h:185
@ RS_REJECT
Definition ctx.h:184
#define error(...)
Definition error.h:36
#define debug(debug_level,...)
Definition error.h:50
#define warning(...)
Definition error.h:40
ctx_t * ctx_p
Definition mon_kqueue.c:85
int rule_complete(rule_t *rule_p, char *expr, size_t *rules_count_p)
Definition rules.c:27
ruleaction_t rules_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, ruleaction_t ruleactions)
Definition rules.c:403
ruleaction_t rules_search_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, const ruleaction_t ruleaction, rule_t **rule_pp)
Checks file path by rules' expressions (parsed from file)
Definition rules.c:327
int parse_rules_fromfile(ctx_t *ctx_p)
Definition rules.c:56
Definition ctx.h:315
int flags[(1<< 10)]
Definition ctx.h:338
size_t rules_count
Definition ctx.h:334
char * rulfpath
Definition ctx.h:385
rule_t rules[MAXRULES]
Definition ctx.h:333
Definition ctx.h:206
ruleaction_t perm
Definition ctx.h:210
mode_t objtype
Definition ctx.h:209
ruleaction_t mask
Definition ctx.h:211
regex_t expr
Definition ctx.h:208
int num
Definition ctx.h:207