"Fossies" - the Fresh Open Source Software Archive 
Member "libisofs-1.5.4/libisofs/find.c" (8 Jul 2020, 18447 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "find.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /*
2 * Copyright (c) 2008 Vreixo Formoso
3 *
4 * This file is part of the libisofs project; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License version 2
6 * or later as published by the Free Software Foundation.
7 * See COPYING file for details.
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "../config.h"
12 #endif
13
14 #include "libisofs.h"
15 #include "node.h"
16
17 #include <fnmatch.h>
18 #include <string.h>
19
20 struct iso_find_condition
21 {
22 /*
23 * Check whether the given node matches this condition.
24 *
25 * @param cond
26 * The condition to check
27 * @param node
28 * The node that should be checked
29 * @return
30 * 1 if the node matches the condition, 0 if not
31 */
32 int (*matches)(IsoFindCondition *cond, IsoNode *node);
33
34 /**
35 * Free condition specific data
36 */
37 void (*free)(IsoFindCondition*);
38
39 /** condition specific data */
40 void *data;
41 };
42
43 struct find_iter_data
44 {
45 IsoDir *dir; /**< original dir of the iterator */
46 IsoDirIter *iter;
47 IsoDirIter *itersec; /**< iterator to deal with child dirs */
48 IsoFindCondition *cond;
49 int err; /**< error? */
50 IsoNode *current; /**< node to be returned next */
51 IsoNode *prev; /**< last returned node, needed for removal */
52 int free_cond; /**< whether to free cond on iter_free */
53 };
54
55 static
56 int get_next(struct find_iter_data *iter, IsoNode **n)
57 {
58 int ret;
59
60 if (iter->itersec != NULL) {
61 ret = iso_dir_iter_next(iter->itersec, n);
62 if (ret <= 0) {
63 /* secondary item no more needed */
64 iso_dir_iter_free(iter->itersec);
65 iter->itersec = NULL;
66 }
67 if (ret != 0) {
68 /* success or error */
69 return ret;
70 }
71 }
72
73 /*
74 * we reach here if:
75 * - no secondary item is present
76 * - secondary item has no more items
77 */
78
79 while ((ret = iso_dir_iter_next(iter->iter, n)) == 1) {
80 if (iter->cond->matches(iter->cond, *n)) {
81 return ISO_SUCCESS;
82 } else if (ISO_NODE_IS_DIR(*n)) {
83 /* recurse on child dir */
84 struct find_iter_data *data;
85 ret = iso_dir_find_children((IsoDir*)*n, iter->cond,
86 &iter->itersec);
87 if (ret < 0) {
88 return ret;
89 }
90 data = iter->itersec->data;
91 data->free_cond = 0; /* we don't need sec iter to free cond */
92 return get_next(iter, n);
93 }
94 }
95 return ret;
96 }
97
98 static
99 void update_next(IsoDirIter *iter)
100 {
101 int ret;
102 IsoNode *n;
103 struct find_iter_data *data = iter->data;
104
105 if (data->prev) {
106 iso_node_unref(data->prev);
107 }
108 data->prev = data->current;
109
110 if (data->itersec == NULL && data->current != NULL
111 && ISO_NODE_IS_DIR(data->current)) {
112
113 /* we need to recurse on child dir */
114 struct find_iter_data *data2;
115 ret = iso_dir_find_children((IsoDir*)data->current, data->cond,
116 &data->itersec);
117 if (ret < 0) {
118 data->current = NULL;
119 data->err = ret;
120 return;
121 }
122 data2 = data->itersec->data;
123 data2->free_cond = 0; /* we don't need sec iter to free cond */
124 }
125
126 ret = get_next(data, &n);
127 iso_node_unref((IsoNode*)iter->dir);
128 if (ret == 1) {
129 data->current = n;
130 iso_node_ref(n);
131 data->err = 0;
132 iter->dir = n->parent;
133 } else {
134 data->current = NULL;
135 data->err = ret;
136 iter->dir = data->dir;
137 }
138 iso_node_ref((IsoNode*)iter->dir);
139 }
140
141 static
142 int find_iter_next(IsoDirIter *iter, IsoNode **node)
143 {
144 struct find_iter_data *data;
145
146 if (iter == NULL || node == NULL) {
147 return ISO_NULL_POINTER;
148 }
149 data = iter->data;
150
151 if (data->err < 0) {
152 return data->err;
153 }
154 *node = data->current;
155 update_next(iter);
156 return (*node == NULL) ? 0 : ISO_SUCCESS;
157 }
158
159 static
160 int find_iter_has_next(IsoDirIter *iter)
161 {
162 struct find_iter_data *data = iter->data;
163
164 return (data->current != NULL);
165 }
166
167 static
168 void find_iter_free(IsoDirIter *iter)
169 {
170 struct find_iter_data *data = iter->data;
171 if (data->free_cond) {
172 data->cond->free(data->cond);
173 free(data->cond);
174 }
175
176 iso_node_unref((IsoNode*)data->dir);
177
178 /* free refs to nodes */
179 if (data->prev) {
180 iso_node_unref(data->prev);
181 }
182 if (data->current) {
183 iso_node_unref(data->current);
184 }
185
186 /* free underlying iter */
187 iso_dir_iter_free(data->iter);
188 free(iter->data);
189 }
190
191 static
192 int find_iter_take(IsoDirIter *iter)
193 {
194 struct find_iter_data *data = iter->data;
195
196 if (data->prev == NULL) {
197 return ISO_ERROR; /* next not called or end of dir */
198 }
199 return iso_node_take(data->prev);
200 }
201
202 static
203 int find_iter_remove(IsoDirIter *iter)
204 {
205 struct find_iter_data *data = iter->data;
206
207 if (data->prev == NULL) {
208 return ISO_ERROR; /* next not called or end of dir */
209 }
210 return iso_node_remove(data->prev);
211 }
212
213 void find_notify_child_taken(IsoDirIter *iter, IsoNode *node)
214 {
215 struct find_iter_data *data = iter->data;
216
217 if (data->prev == node) {
218 /* free our ref */
219 iso_node_unref(node);
220 data->prev = NULL;
221 } else if (data->current == node) {
222 iso_node_unref(node);
223 data->current = NULL;
224 update_next(iter);
225 }
226 }
227
228 static
229 struct iso_dir_iter_iface find_iter_class = {
230 find_iter_next,
231 find_iter_has_next,
232 find_iter_free,
233 find_iter_take,
234 find_iter_remove,
235 find_notify_child_taken
236 };
237
238 int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
239 IsoDirIter **iter)
240 {
241 int ret;
242 IsoDirIter *children;
243 IsoDirIter *it;
244 struct find_iter_data *data;
245
246 if (dir == NULL || cond == NULL || iter == NULL) {
247 return ISO_NULL_POINTER;
248 }
249 it = malloc(sizeof(IsoDirIter));
250 if (it == NULL) {
251 return ISO_OUT_OF_MEM;
252 }
253 data = malloc(sizeof(struct find_iter_data));
254 if (data == NULL) {
255 free(it);
256 return ISO_OUT_OF_MEM;
257 }
258 ret = iso_dir_get_children(dir, &children);
259 if (ret < 0) {
260 free(it);
261 free(data);
262 return ret;
263 }
264
265 it->class = &find_iter_class;
266 it->dir = (IsoDir*)dir;
267 data->iter = children;
268 data->itersec = NULL;
269 data->cond = cond;
270 data->free_cond = 1;
271 data->err = 0;
272 data->prev = data->current = NULL;
273 it->data = data;
274
275 if (iso_dir_iter_register(it) < 0) {
276 free(it);
277 return ISO_OUT_OF_MEM;
278 }
279
280 iso_node_ref((IsoNode*)dir);
281
282 /* take another ref to the original dir */
283 data->dir = (IsoDir*)dir;
284 iso_node_ref((IsoNode*)dir);
285
286 update_next(it);
287
288 *iter = it;
289 return ISO_SUCCESS;
290 }
291
292 /*************** find by name wildcard condition *****************/
293
294 static
295 int cond_name_matches(IsoFindCondition *cond, IsoNode *node)
296 {
297 char *pattern = (char*) cond->data;
298 int ret = fnmatch(pattern, node->name, 0);
299 return ret == 0 ? 1 : 0;
300 }
301
302 static
303 void cond_name_free(IsoFindCondition *cond)
304 {
305 free(cond->data);
306 }
307
308 /**
309 * Create a new condition that checks if the node name matches the given
310 * wildcard.
311 *
312 * @param wildcard
313 * @result
314 * The created IsoFindCondition, NULL on error.
315 *
316 * @since 0.6.4
317 */
318 IsoFindCondition *iso_new_find_conditions_name(const char *wildcard)
319 {
320 IsoFindCondition *cond;
321 if (wildcard == NULL) {
322 return NULL;
323 }
324 cond = malloc(sizeof(IsoFindCondition));
325 if (cond == NULL) {
326 return NULL;
327 }
328 cond->data = strdup(wildcard);
329 cond->free = cond_name_free;
330 cond->matches = cond_name_matches;
331 return cond;
332 }
333
334 /*************** find by mode condition *****************/
335
336 static
337 int cond_mode_matches(IsoFindCondition *cond, IsoNode *node)
338 {
339 mode_t *mask = (mode_t*) cond->data;
340 return node->mode & *mask ? 1 : 0;
341 }
342
343 static
344 void cond_mode_free(IsoFindCondition *cond)
345 {
346 free(cond->data);
347 }
348
349 /**
350 * Create a new condition that checks the node mode against a mode mask. It
351 * can be used to check both file type and permissions.
352 *
353 * For example:
354 *
355 * iso_new_find_conditions_mode(S_IFREG) : search for regular files
356 * iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
357 * devices where owner has write permissions.
358 *
359 * @param mask
360 * Mode mask to AND against node mode.
361 * @result
362 * The created IsoFindCondition, NULL on error.
363 *
364 * @since 0.6.4
365 */
366 IsoFindCondition *iso_new_find_conditions_mode(mode_t mask)
367 {
368 IsoFindCondition *cond;
369 mode_t *data;
370 cond = malloc(sizeof(IsoFindCondition));
371 if (cond == NULL) {
372 return NULL;
373 }
374 data = malloc(sizeof(mode_t));
375 if (data == NULL) {
376 free(cond);
377 return NULL;
378 }
379 *data = mask;
380 cond->data = data;
381 cond->free = cond_mode_free;
382 cond->matches = cond_mode_matches;
383 return cond;
384 }
385
386 /*************** find by gid condition *****************/
387
388 static
389 int cond_gid_matches(IsoFindCondition *cond, IsoNode *node)
390 {
391 gid_t *gid = (gid_t*) cond->data;
392 return node->gid == *gid ? 1 : 0;
393 }
394
395 static
396 void cond_gid_free(IsoFindCondition *cond)
397 {
398 free(cond->data);
399 }
400
401 /**
402 * Create a new condition that checks the node gid.
403 *
404 * @param gid
405 * Desired Group Id.
406 * @result
407 * The created IsoFindCondition, NULL on error.
408 *
409 * @since 0.6.4
410 */
411 IsoFindCondition *iso_new_find_conditions_gid(gid_t gid)
412 {
413 IsoFindCondition *cond;
414 gid_t *data;
415 cond = malloc(sizeof(IsoFindCondition));
416 if (cond == NULL) {
417 return NULL;
418 }
419 data = malloc(sizeof(gid_t));
420 if (data == NULL) {
421 free(cond);
422 return NULL;
423 }
424 *data = gid;
425 cond->data = data;
426 cond->free = cond_gid_free;
427 cond->matches = cond_gid_matches;
428 return cond;
429 }
430
431 /*************** find by uid condition *****************/
432
433 static
434 int cond_uid_matches(IsoFindCondition *cond, IsoNode *node)
435 {
436 uid_t *uid = (uid_t*) cond->data;
437 return node->uid == *uid ? 1 : 0;
438 }
439
440 static
441 void cond_uid_free(IsoFindCondition *cond)
442 {
443 free(cond->data);
444 }
445
446 /**
447 * Create a new condition that checks the node uid.
448 *
449 * @param uid
450 * Desired User Id.
451 * @result
452 * The created IsoFindCondition, NULL on error.
453 *
454 * @since 0.6.4
455 */
456 IsoFindCondition *iso_new_find_conditions_uid(uid_t uid)
457 {
458 IsoFindCondition *cond;
459 uid_t *data;
460 cond = malloc(sizeof(IsoFindCondition));
461 if (cond == NULL) {
462 return NULL;
463 }
464 data = malloc(sizeof(uid_t));
465 if (data == NULL) {
466 free(cond);
467 return NULL;
468 }
469 *data = uid;
470 cond->data = data;
471 cond->free = cond_uid_free;
472 cond->matches = cond_uid_matches;
473 return cond;
474 }
475
476 /*************** find by timestamps condition *****************/
477
478 struct cond_times
479 {
480 time_t time;
481 int what_time; /* 0 atime, 1 mtime, 2 ctime */
482 enum iso_find_comparisons comparison;
483 };
484
485 static
486 int cond_time_matches(IsoFindCondition *cond, IsoNode *node)
487 {
488 time_t node_time;
489 struct cond_times *data = cond->data;
490
491 switch (data->what_time) {
492 case 0: node_time = node->atime; break;
493 case 1: node_time = node->mtime; break;
494 default: node_time = node->ctime; break;
495 }
496
497 switch (data->comparison) {
498 case ISO_FIND_COND_GREATER:
499 return node_time > data->time ? 1 : 0;
500 case ISO_FIND_COND_GREATER_OR_EQUAL:
501 return node_time >= data->time ? 1 : 0;
502 case ISO_FIND_COND_EQUAL:
503 return node_time == data->time ? 1 : 0;
504 case ISO_FIND_COND_LESS:
505 return node_time < data->time ? 1 : 0;
506 case ISO_FIND_COND_LESS_OR_EQUAL:
507 return node_time <= data->time ? 1 : 0;
508 }
509 /* should never happen */
510 return 0;
511 }
512
513 static
514 void cond_time_free(IsoFindCondition *cond)
515 {
516 free(cond->data);
517 }
518
519 /**
520 * Create a new condition that checks the time of last access.
521 *
522 * @param time
523 * Time to compare against IsoNode atime.
524 * @param comparison
525 * Comparison to be done between IsoNode atime and submitted time.
526 * Note that ISO_FIND_COND_GREATER, for example, is true if the node
527 * time is greater than the submitted time.
528 * @result
529 * The created IsoFindCondition, NULL on error.
530 *
531 * @since 0.6.4
532 */
533 IsoFindCondition *iso_new_find_conditions_atime(time_t time,
534 enum iso_find_comparisons comparison)
535 {
536 IsoFindCondition *cond;
537 struct cond_times *data;
538 cond = malloc(sizeof(IsoFindCondition));
539 if (cond == NULL) {
540 return NULL;
541 }
542 data = malloc(sizeof(struct cond_times));
543 if (data == NULL) {
544 free(cond);
545 return NULL;
546 }
547 data->time = time;
548 data->comparison = comparison;
549 data->what_time = 0; /* atime */
550 cond->data = data;
551 cond->free = cond_time_free;
552 cond->matches = cond_time_matches;
553 return cond;
554 }
555
556 /**
557 * Create a new condition that checks the time of last modification.
558 *
559 * @param time
560 * Time to compare against IsoNode mtime.
561 * @param comparison
562 * Comparison to be done between IsoNode mtime and submitted time.
563 * Note that ISO_FIND_COND_GREATER, for example, is true if the node
564 * time is greater than the submitted time.
565 * @result
566 * The created IsoFindCondition, NULL on error.
567 *
568 * @since 0.6.4
569 */
570 IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
571 enum iso_find_comparisons comparison)
572 {
573 IsoFindCondition *cond;
574 struct cond_times *data;
575 cond = malloc(sizeof(IsoFindCondition));
576 if (cond == NULL) {
577 return NULL;
578 }
579 data = malloc(sizeof(struct cond_times));
580 if (data == NULL) {
581 free(cond);
582 return NULL;
583 }
584 data->time = time;
585 data->comparison = comparison;
586 data->what_time = 1; /* mtime */
587 cond->data = data;
588 cond->free = cond_time_free;
589 cond->matches = cond_time_matches;
590 return cond;
591 }
592
593 /**
594 * Create a new condition that checks the time of last status change.
595 *
596 * @param time
597 * Time to compare against IsoNode ctime.
598 * @param comparison
599 * Comparison to be done between IsoNode ctime and submitted time.
600 * Note that ISO_FIND_COND_GREATER, for example, is true if the node
601 * time is greater than the submitted time.
602 * @result
603 * The created IsoFindCondition, NULL on error.
604 *
605 * @since 0.6.4
606 */
607 IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
608 enum iso_find_comparisons comparison)
609 {
610 IsoFindCondition *cond;
611 struct cond_times *data;
612 cond = malloc(sizeof(IsoFindCondition));
613 if (cond == NULL) {
614 return NULL;
615 }
616 data = malloc(sizeof(struct cond_times));
617 if (data == NULL) {
618 free(cond);
619 return NULL;
620 }
621 data->time = time;
622 data->comparison = comparison;
623 data->what_time = 2; /* ctime */
624 cond->data = data;
625 cond->free = cond_time_free;
626 cond->matches = cond_time_matches;
627 return cond;
628 }
629
630 /*************** logical operations on conditions *****************/
631
632 struct logical_binary_conditions {
633 IsoFindCondition *a;
634 IsoFindCondition *b;
635 };
636
637 static
638 void cond_logical_binary_free(IsoFindCondition *cond)
639 {
640 struct logical_binary_conditions *data;
641 data = cond->data;
642 data->a->free(data->a);
643 free(data->a);
644 data->b->free(data->b);
645 free(data->b);
646 free(cond->data);
647 }
648
649 static
650 int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node)
651 {
652 struct logical_binary_conditions *data = cond->data;
653 return data->a->matches(data->a, node) && data->b->matches(data->b, node);
654 }
655
656 /**
657 * Create a new condition that check if the two given conditions are
658 * valid.
659 *
660 * @param a
661 * @param b
662 * IsoFindCondition to compare
663 * @result
664 * The created IsoFindCondition, NULL on error.
665 *
666 * @since 0.6.4
667 */
668 IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
669 IsoFindCondition *b)
670 {
671 IsoFindCondition *cond;
672 struct logical_binary_conditions *data;
673 cond = malloc(sizeof(IsoFindCondition));
674 if (cond == NULL) {
675 return NULL;
676 }
677 data = malloc(sizeof(struct logical_binary_conditions));
678 if (data == NULL) {
679 free(cond);
680 return NULL;
681 }
682 data->a = a;
683 data->b = b;
684 cond->data = data;
685 cond->free = cond_logical_binary_free;
686 cond->matches = cond_logical_and_matches;
687 return cond;
688 }
689
690 static
691 int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node)
692 {
693 struct logical_binary_conditions *data = cond->data;
694 return data->a->matches(data->a, node) || data->b->matches(data->b, node);
695 }
696
697 /**
698 * Create a new condition that check if at least one the two given conditions
699 * is valid.
700 *
701 * @param a
702 * @param b
703 * IsoFindCondition to compare
704 * @result
705 * The created IsoFindCondition, NULL on error.
706 *
707 * @since 0.6.4
708 */
709 IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
710 IsoFindCondition *b)
711 {
712 IsoFindCondition *cond;
713 struct logical_binary_conditions *data;
714 cond = malloc(sizeof(IsoFindCondition));
715 if (cond == NULL) {
716 return NULL;
717 }
718 data = malloc(sizeof(struct logical_binary_conditions));
719 if (data == NULL) {
720 free(cond);
721 return NULL;
722 }
723 data->a = a;
724 data->b = b;
725 cond->data = data;
726 cond->free = cond_logical_binary_free;
727 cond->matches = cond_logical_or_matches;
728 return cond;
729 }
730
731 static
732 void cond_not_free(IsoFindCondition *cond)
733 {
734 IsoFindCondition *negate = cond->data;
735 negate->free(negate);
736 free(negate);
737 }
738
739 static
740 int cond_not_matches(IsoFindCondition *cond, IsoNode *node)
741 {
742 IsoFindCondition *negate = cond->data;
743 return !(negate->matches(negate, node));
744 }
745
746 /**
747 * Create a new condition that check if the given conditions is false.
748 *
749 * @param negate
750 * @result
751 * The created IsoFindCondition, NULL on error.
752 *
753 * @since 0.6.4
754 */
755 IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate)
756 {
757 IsoFindCondition *cond;
758 cond = malloc(sizeof(IsoFindCondition));
759 if (cond == NULL) {
760 return NULL;
761 }
762 cond->data = negate;
763 cond->free = cond_not_free;
764 cond->matches = cond_not_matches;
765 return cond;
766 }
767