"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/find.c" (30 Jan 2021, 18447 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.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 last 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