LCOV - code coverage report
Current view: top level - src - ft_traverse.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 50.8 % 130 66
Test Date: 2025-10-15 21:43:52 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #include <apr_file_io.h>
       2              : #include <apr_strings.h>
       3              : #include <pcre.h>
       4              : 
       5              : #include "debug.h"
       6              : #include "ft_traverse.h"
       7              : #include "ft_types.h"
       8              : #include "ft_config.h"
       9              : 
      10              : #define MATCH_VECTOR_SIZE 210
      11              : 
      12          128 : static apr_status_t traverse_recursive(ft_conf_t *conf, const char *filename, apr_pool_t *gc_pool, struct stats const *stats,
      13              :                                        ft_ignore_context_t * parent_ctx)
      14              : {
      15              :     char errbuf[128];
      16              :     apr_finfo_t finfo;
      17              :     apr_dir_t *dir;
      18          128 :     apr_int32_t statmask =
      19              :         APR_FINFO_SIZE | APR_FINFO_MTIME | APR_FINFO_TYPE | APR_FINFO_USER | APR_FINFO_GROUP | APR_FINFO_UPROT |
      20              :         APR_FINFO_GPROT;
      21              :     apr_size_t fname_len;
      22              :     apr_uint32_t hash_value;
      23              :     apr_status_t status;
      24              : 
      25          128 :     if (!is_option_set(conf->mask, OPTION_FSYML)) {
      26          128 :         statmask |= APR_FINFO_LINK;
      27              :     }
      28              : 
      29          128 :     if (APR_SUCCESS != (status = apr_stat(&finfo, filename, statmask, gc_pool))) {
      30            0 :         if (is_option_set(conf->mask, OPTION_FSYML)) {
      31            0 :             statmask ^= APR_FINFO_LINK;
      32            0 :             if ((APR_SUCCESS == apr_stat(&finfo, filename, statmask, gc_pool)) && (finfo.filetype & APR_LNK)) {
      33            0 :                 if (is_option_set(conf->mask, OPTION_VERBO)) {
      34            0 :                     (void) fprintf(stderr, "Skipping : [%s] (broken link)\n", filename);
      35              :                 }
      36            0 :                 return APR_SUCCESS;
      37              :             }
      38              :         }
      39              : 
      40            0 :         DEBUG_ERR("error calling apr_stat on filename %s : %s", filename, apr_strerror(status, errbuf, 128));
      41            0 :         return status;
      42              :     }
      43              : 
      44          128 :     if (conf->respect_gitignore && parent_ctx) {
      45          128 :         ft_ignore_match_result_t match = ft_ignore_match(parent_ctx, filename, finfo.filetype == APR_DIR);
      46          128 :         if (match == FT_IGNORE_MATCH_IGNORED) {
      47            0 :             if (is_option_set(conf->mask, OPTION_VERBO)) {
      48            0 :                 (void) fprintf(stderr, "Ignoring (gitignore): [%s]\n", filename);
      49              :             }
      50            0 :             return APR_SUCCESS;
      51              :         }
      52              :     }
      53              : 
      54          128 :     if (0 != conf->userid) {
      55          128 :         if (finfo.user == conf->userid) {
      56          128 :             if (!(APR_UREAD & finfo.protection)) {
      57            0 :                 if (is_option_set(conf->mask, OPTION_VERBO)) {
      58            0 :                     (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
      59              :                 }
      60            0 :                 return APR_SUCCESS;
      61              :             }
      62              :         }
      63            0 :         else if (NULL != napr_hash_search(conf->gids, &finfo.group, sizeof(gid_t), &hash_value)) {
      64            0 :             if (!(APR_GREAD & finfo.protection)) {
      65            0 :                 if (is_option_set(conf->mask, OPTION_VERBO)) {
      66            0 :                     (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
      67              :                 }
      68            0 :                 return APR_SUCCESS;
      69              :             }
      70              :         }
      71            0 :         else if (!(APR_WREAD & finfo.protection)) {
      72            0 :             if (is_option_set(conf->mask, OPTION_VERBO)) {
      73            0 :                 (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
      74              :             }
      75            0 :             return APR_SUCCESS;
      76              :         }
      77              :     }
      78              : 
      79          128 :     if (APR_DIR == finfo.filetype) {
      80           16 :         if (0 != conf->userid) {
      81           16 :             if (finfo.user == conf->userid) {
      82           16 :                 if (!(APR_UEXECUTE & finfo.protection)) {
      83            0 :                     if (is_option_set(conf->mask, OPTION_VERBO)) {
      84            0 :                         (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
      85              :                     }
      86            0 :                     return APR_SUCCESS;
      87              :                 }
      88              :             }
      89            0 :             else if (NULL != napr_hash_search(conf->gids, &finfo.group, sizeof(gid_t), &hash_value)) {
      90            0 :                 if (!(APR_GEXECUTE & finfo.protection)) {
      91            0 :                     if (is_option_set(conf->mask, OPTION_VERBO)) {
      92            0 :                         (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
      93              :                     }
      94            0 :                     return APR_SUCCESS;
      95              :                 }
      96              :             }
      97            0 :             else if (!(APR_WEXECUTE & finfo.protection)) {
      98            0 :                 if (is_option_set(conf->mask, OPTION_VERBO)) {
      99            0 :                     (void) fprintf(stderr, "Skipping : [%s] (bad permission)\n", filename);
     100              :                 }
     101            0 :                 return APR_SUCCESS;
     102              :             }
     103              :         }
     104              : 
     105           16 :         if (APR_SUCCESS != (status = apr_dir_open(&dir, filename, gc_pool))) {
     106            0 :             DEBUG_ERR("error calling apr_dir_open(%s): %s", filename, apr_strerror(status, errbuf, 128));
     107            0 :             return status;
     108              :         }
     109           16 :         fname_len = strlen(filename);
     110              : 
     111           16 :         ft_ignore_context_t *current_ctx = parent_ctx;
     112           16 :         if (conf->respect_gitignore) {
     113           16 :             const char *gitignore_path = apr_pstrcat(gc_pool, filename, "/.gitignore", NULL);
     114              :             apr_finfo_t gitignore_finfo;
     115              : 
     116           16 :             if (APR_SUCCESS == apr_stat(&gitignore_finfo, gitignore_path, APR_FINFO_TYPE, gc_pool)
     117            0 :                 && gitignore_finfo.filetype == APR_REG) {
     118            0 :                 ft_ignore_context_t *local_ctx = ft_ignore_context_create(gc_pool, parent_ctx, filename);
     119            0 :                 if (APR_SUCCESS == ft_ignore_load_file(local_ctx, gitignore_path)) {
     120            0 :                     current_ctx = local_ctx;
     121            0 :                     if (is_option_set(conf->mask, OPTION_VERBO)) {
     122            0 :                         (void) fprintf(stderr, "Loaded .gitignore from: [%s]\n", filename);
     123              :                     }
     124              :                 }
     125              :             }
     126              :         }
     127          156 :         while ((APR_SUCCESS == (status = apr_dir_read(&finfo, APR_FINFO_NAME | APR_FINFO_TYPE, dir)))
     128          156 :                && (NULL != finfo.name)) {
     129              :             char *fullname;
     130              :             apr_size_t fullname_len;
     131              :             struct stats child;
     132              :             struct stats const *ancestor;
     133              : 
     134          140 :             if (NULL != napr_hash_search(conf->ig_files, finfo.name, strlen(finfo.name), NULL)) {
     135           35 :                 continue;
     136              :             }
     137              : 
     138          108 :             if ('.' == finfo.name[0] && !is_option_set(conf->mask, OPTION_SHOW_HIDDEN)) {
     139            2 :                 continue;
     140              :             }
     141              : 
     142          106 :             if (APR_DIR == finfo.filetype && !is_option_set(conf->mask, OPTION_RECSD)) {
     143            1 :                 continue;
     144              :             }
     145              : 
     146          105 :             fullname = apr_pstrcat(gc_pool, filename, ('/' == filename[fname_len - 1]) ? "" : "/", finfo.name, NULL);
     147          105 :             fullname_len = strlen(fullname);
     148              : 
     149          105 :             if ((NULL != conf->ig_regex) && (APR_DIR != finfo.filetype)) {
     150              :                 int match_code;
     151              :                 int ovector[MATCH_VECTOR_SIZE];
     152            0 :                 match_code = pcre_exec(conf->ig_regex, NULL, fullname, fullname_len, 0, 0, ovector, MATCH_VECTOR_SIZE);
     153            0 :                 if (match_code >= 0) {
     154            0 :                     continue;
     155              :                 }
     156              :             }
     157              : 
     158          105 :             if ((NULL != conf->wl_regex) && (APR_DIR != finfo.filetype)) {
     159              :                 int match_code;
     160              :                 int ovector[MATCH_VECTOR_SIZE];
     161            0 :                 match_code = pcre_exec(conf->wl_regex, NULL, fullname, fullname_len, 0, 0, ovector, MATCH_VECTOR_SIZE);
     162            0 :                 if (match_code < 0) {
     163            0 :                     continue;
     164              :                 }
     165              :             }
     166              : 
     167          105 :             if (stats) {
     168            2 :                 if (stats->stat.inode) {
     169            2 :                     for (ancestor = stats; (ancestor = ancestor->parent) != 0;) {
     170            0 :                         if (ancestor->stat.inode == stats->stat.inode && ancestor->stat.device == stats->stat.device) {
     171            0 :                             if (is_option_set(conf->mask, OPTION_VERBO)) {
     172            0 :                                 (void) fprintf(stderr, "Warning: %s: recursive directory loop\n", filename);
     173              :                             }
     174            0 :                             return APR_SUCCESS;
     175              :                         }
     176              :                     }
     177              :                 }
     178              :             }
     179          105 :             child.parent = stats;
     180          105 :             child.stat = finfo;
     181              : 
     182          105 :             status = traverse_recursive(conf, fullname, gc_pool, &child, current_ctx);
     183              : 
     184          105 :             if (APR_SUCCESS != status) {
     185            0 :                 DEBUG_ERR("error recursively calling traverse_recursive: %s", apr_strerror(status, errbuf, 128));
     186            0 :                 return status;
     187              :             }
     188              :         }
     189           16 :         if ((APR_SUCCESS != status) && (APR_ENOENT != status)) {
     190            0 :             DEBUG_ERR("error calling apr_dir_read: %s", apr_strerror(status, errbuf, 128));
     191            0 :             return status;
     192              :         }
     193              : 
     194           16 :         if (APR_SUCCESS != (status = apr_dir_close(dir))) {
     195            0 :             DEBUG_ERR("error calling apr_dir_close: %s", apr_strerror(status, errbuf, 128));
     196            0 :             return status;
     197              :         }
     198              :     }
     199          112 :     else if (APR_REG == finfo.filetype || ((APR_LNK == finfo.filetype) && (is_option_set(conf->mask, OPTION_FSYML)))) {
     200          112 :         if (finfo.size >= conf->minsize && (conf->maxsize == 0 || finfo.size <= conf->maxsize)) {
     201              :             ft_file_t *file;
     202              :             ft_fsize_t *fsize;
     203              : 
     204          110 :             file = apr_palloc(conf->pool, sizeof(struct ft_file_t));
     205          110 :             file->path = apr_pstrdup(conf->pool, filename);
     206          110 :             file->size = finfo.size;
     207          110 :             file->mtime = finfo.mtime;
     208              : 
     209          110 :             if ((conf->p_path) && (strlen(filename) >= conf->p_path_len)
     210            0 :                 && ((is_option_set(conf->mask, OPTION_ICASE) && !strncasecmp(filename, conf->p_path, conf->p_path_len))
     211            0 :                     || (!is_option_set(conf->mask, OPTION_ICASE) && !memcmp(filename, conf->p_path, conf->p_path_len)))) {
     212            0 :                 file->prioritized |= 0x1;
     213              :             }
     214              :             else {
     215          110 :                 file->prioritized &= 0x0;
     216              :             }
     217          110 :             file->cvec_ok &= 0x0;
     218          110 :             napr_heap_insert(conf->heap, file);
     219              : 
     220          110 :             if (NULL == (fsize = napr_hash_search(conf->sizes, &finfo.size, sizeof(apr_off_t), &hash_value))) {
     221           40 :                 fsize = apr_palloc(conf->pool, sizeof(struct ft_fsize_t));
     222           40 :                 fsize->val = finfo.size;
     223           40 :                 fsize->chksum_array = NULL;
     224           40 :                 fsize->nb_checksumed = 0;
     225           40 :                 fsize->nb_files = 0;
     226           40 :                 napr_hash_set(conf->sizes, fsize, hash_value);
     227              :             }
     228          110 :             fsize->nb_files++;
     229              :         }
     230              :     }
     231              : 
     232          128 :     return APR_SUCCESS;
     233              : }
     234              : 
     235           23 : apr_status_t ft_traverse_path(ft_conf_t *conf, const char *path)
     236              : {
     237              :     apr_pool_t *gc_pool;
     238              :     apr_status_t status;
     239              : 
     240           23 :     if (APR_SUCCESS != (status = apr_pool_create(&gc_pool, conf->pool))) {
     241              :         char errbuf[128];
     242            0 :         DEBUG_ERR("error calling apr_pool_create: %s", apr_strerror(status, errbuf, 128));
     243            0 :         return status;
     244              :     }
     245              : 
     246           23 :     status = traverse_recursive(conf, path, gc_pool, NULL, conf->global_ignores);
     247              : 
     248           23 :     apr_pool_destroy(gc_pool);
     249              : 
     250           23 :     return status;
     251              : }
        

Generated by: LCOV version 2.0-1