LCOV - code coverage report
Current view: top level - src - file_list.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.2 % 256 218
Test Date: 2026-03-31 13:51:38 Functions: 100.0 % 2 2
Branches: 77.8 % 261 203

             Branch data     Line data    Source code
       1                 :             : #include "precizer.h"
       2                 :             : 
       3                 :             : /**
       4                 :             :  * @brief Compare two FTS entries by filename
       5                 :             :  * @param first Pointer to first FTSENT structure
       6                 :             :  * @param second Pointer to second FTSENT structure
       7                 :             :  * @return Integer less than, equal to, or greater than zero if first is found,
       8                 :             :  *         respectively, to be less than, to match, or be greater than second
       9                 :             :  */
      10                 :        6158 : static int compare_by_name(
      11                 :             :         const FTSENT **first,
      12                 :             :         const FTSENT **second)
      13                 :             : {
      14                 :        6158 :         return strcmp((*first)->fts_name,(*second)->fts_name);
      15                 :             : }
      16                 :             : 
      17                 :             : /**
      18                 :             :  * @brief Traverse configured paths and process files for one pass.
      19                 :             :  *
      20                 :             :  * Supports two modes controlled by summary->stats_only_pass:
      21                 :             :  * - true: collect counters and allocated size only;
      22                 :             :  * - false: hash files, update DB rows, and collect timing/hash metrics.
      23                 :             :  *
      24                 :             :  * @param summary Traversal state that is reset and populated by this call.
      25                 :             :  * @return SUCCESS, WARNING, or FAILURE.
      26                 :             :  */
      27                 :         758 : Return file_list(TraversalSummary *summary)
      28                 :             : {
      29                 :             :         /* Status returned by this function through provide()
      30                 :             :            Default value assumes successful completion */
      31                 :         758 :         Return status = SUCCESS;
      32                 :             : 
      33                 :             :         // Don't do anything
      34         [ +  + ]:         758 :         if(config->compare == true)
      35                 :             :         {
      36                 :         224 :                 provide(status);
      37                 :             :         }
      38                 :             : 
      39   [ +  +  +  + ]:         534 :         if(config->progress == false && summary->stats_only_pass == true)
      40                 :             :         {
      41                 :             :                 // Don't do anything
      42                 :         202 :                 provide(status);
      43                 :             :         }
      44                 :             : 
      45                 :             :         // Flags that reflect the presence of any changes
      46                 :             :         // since the last research
      47                 :             : 
      48                 :             :         // Print traversal/update banners only once
      49                 :         332 :         bool first_iteration = true;
      50                 :             : 
      51                 :             :         // Signals integrity issues for locked files
      52                 :         332 :         bool lock_checksum_violation_detected = false;
      53                 :             : 
      54                 :         332 :         FTS *file_systems = NULL;
      55                 :         332 :         FTSENT *p = NULL;
      56                 :             : 
      57                 :         332 :         int fts_options = FTS_PHYSICAL;
      58                 :             : 
      59         [ +  + ]:         332 :         if(config->start_device_only == true)
      60                 :             :         {
      61                 :           2 :                 fts_options |= FTS_XDEV;
      62                 :             :         }
      63                 :             : 
      64                 :             :         // Reset traversal counters and timing for this pass.
      65                 :         332 :         summary->count_dirs = 0;
      66                 :             : 
      67                 :             :         // Number of regular files seen in this pass.
      68                 :         332 :         summary->count_files = 0;
      69                 :             : 
      70                 :             :         // Number of symlinks seen in this pass.
      71                 :         332 :         summary->count_symlnks = 0;
      72                 :             : 
      73                 :             :         // Sum of allocated bytes for encountered files.
      74                 :         332 :         summary->total_allocated_bytes = 0;
      75                 :             : 
      76                 :             :         // Sum of bytes hashed by SHA512 during this pass.
      77                 :         332 :         summary->total_hashed_bytes = 0;
      78                 :             : 
      79                 :             :         // Track whether any output was produced
      80                 :         332 :         summary->at_least_one_file_was_shown = false;
      81                 :             : 
      82                 :             :         // Sum of per-file hashing elapsed time in nanoseconds.
      83                 :         332 :         summary->total_hashing_elapsed_ns = 0LL;
      84                 :             : 
      85         [ -  + ]:         332 :         if((file_systems = fts_open(config->paths,fts_options,compare_by_name)) == NULL)
      86                 :             :         {
      87                 :           0 :                 slog(ERROR,"fts_open() error\n");
      88                 :           0 :                 provide(FAILURE);
      89                 :             :         }
      90                 :             : 
      91                 :             :         /*
      92                 :             :          * Determine the absolute path prefix.
      93                 :             :          * We are only interested in relative paths in the database.
      94                 :             :          * To obtain a relative path, trim the prefix from the absolute path.
      95                 :             :          */
      96                 :         332 :         char *runtime_root = NULL;
      97                 :             : #if 0 // Old multiPATH solution
      98                 :             :         /**
      99                 :             :          * Index of the path prefix
     100                 :             :          * All full runtime paths are stored in the table "paths".
     101                 :             :          * A real path can be retrieved due to its index ID
     102                 :             :          */
     103                 :             :         sqlite3_int64 runtime_root_index = -1;
     104                 :             : #endif
     105                 :             : 
     106                 :             :         // Limit recursion to the depth determined in config->maxdepth
     107         [ +  + ]:         332 :         if(config->maxdepth > -1)
     108                 :             :         {
     109                 :           4 :                 slog(EVERY,"Recursion depth limited to: %d\n",config->maxdepth);
     110                 :             :         }
     111                 :             : 
     112   [ +  +  +  - ]:         332 :         if(summary->stats_only_pass == true && config->progress == true)
     113                 :             :         {
     114                 :          65 :                 slog(EVERY,"File system traversal initiated to calculate file count and storage usage\n");
     115                 :             :         }
     116                 :             : 
     117                 :         332 :         bool continue_the_loop = true;
     118                 :             : 
     119                 :             :         // Allocate space for a memory structure
     120                 :         332 :         create(unsigned char,file_buffer);
     121                 :             : 
     122         [ +  + ]:         332 :         if(summary->stats_only_pass == false)
     123                 :             :         {
     124                 :         267 :                 status = resize(file_buffer,file_buffer_memory());
     125                 :             : 
     126         [ -  + ]:         267 :                 if(SUCCESS != status)
     127                 :             :                 {
     128                 :           0 :                         provide(status);
     129                 :             :                 }
     130                 :             : #ifdef TESTITALL_TEST_HOOKS
     131                 :         267 :                 signal_wait_at_point(1U);
     132                 :             : #endif
     133                 :             :         }
     134                 :             : 
     135   [ +  +  +  - ]:       34614 :         while((p = fts_read(file_systems)) != NULL && continue_the_loop == true)
     136                 :             :         {
     137                 :             :                 /* Interrupt the loop smoothly */
     138                 :             :                 /* Interrupt when Ctrl+C */
     139         [ +  + ]:       34286 :                 if(global_interrupt_flag == true)
     140                 :             :                 {
     141                 :           4 :                         break;
     142                 :             :                 }
     143                 :             : 
     144                 :             :                 /* Get absolute path prefix from FTSENT structure and current runtime path */
     145         [ +  + ]:       34282 :                 if(p->fts_level == FTS_ROOTLEVEL)
     146                 :             :                 {
     147                 :         658 :                         size_t new_size = (size_t)(p->fts_pathlen + 1) * sizeof(char);
     148                 :             : 
     149                 :             :                         // All below run once per new path prefix
     150                 :         658 :                         char *tmp = (char *)realloc(runtime_root,new_size);
     151                 :             : 
     152         [ -  + ]:         658 :                         if(NULL == tmp)
     153                 :             :                         {
     154                 :           0 :                                 report("Memory allocation failed, requested size: %zu bytes",new_size);
     155                 :           0 :                                 status = FAILURE;
     156                 :           0 :                                 break;
     157                 :             :                         } else {
     158                 :         658 :                                 runtime_root = tmp;
     159                 :             :                         }
     160                 :             : 
     161                 :             :                         // Remember temporary string in long-lasting variable
     162                 :         658 :                         memcpy(runtime_root,p->fts_path,(size_t)p->fts_pathlen);
     163                 :             : 
     164         [ +  - ]:         658 :                         if(p->fts_pathlen > 0)
     165                 :             :                         {
     166                 :         658 :                                 runtime_root[p->fts_pathlen] = '\0';
     167                 :             :                         }
     168                 :             : 
     169                 :             :                         // Remove unnecessary trailing slash at the end of the directory path
     170                 :         658 :                         remove_trailing_slash(runtime_root);
     171                 :             : 
     172                 :             : #if 0 // Old multiPATH solution
     173                 :             :                         // If several paths were passed as arguments,
     174                 :             :                         // then the counting of the path prefix index
     175                 :             :                         // will start from zero
     176                 :             :                         if(SUCCESS != (status = db_get_runtime_root_index(config,
     177                 :             :                                 runtime_root,
     178                 :             :                                 &runtime_root_index)))
     179                 :             :                         {
     180                 :             :                                 continue_the_loop = false;
     181                 :             :                                 break;
     182                 :             :                         }
     183                 :             : #endif
     184                 :             :                 }
     185                 :             : 
     186   [ +  +  +  + ]:       34282 :                 if(config->maxdepth > -1 && p->fts_level > config->maxdepth + 1)
     187                 :             :                 {
     188         [ +  + ]:          42 :                         if(p->fts_info == FTS_D)
     189                 :             :                         {
     190                 :          14 :                                 (void)fts_set(file_systems,p,FTS_SKIP);
     191                 :             :                         }
     192                 :             : 
     193                 :          42 :                         continue;
     194                 :             :                 }
     195                 :             : 
     196   [ +  +  +  -  :       34240 :                 switch(p->fts_info)
                      + ]
     197                 :             :                 {
     198                 :       14886 :                         case FTS_D:
     199                 :             :                         {
     200                 :       14886 :                                 const char *relative_path = extract_relative_path(p->fts_path,runtime_root);
     201                 :             : 
     202                 :             :                                 // Captures files explicitly skipped or forced by regexp filters
     203                 :             :                                 // Ignored with --ignore= or admitted with --include=
     204                 :       14886 :                                 bool ignore = false;
     205                 :             : 
     206                 :             :                                 // Included with --include=
     207                 :       14886 :                                 bool include = false;
     208                 :             : 
     209                 :       14886 :                                 status = match_include_ignore(relative_path,&include,&ignore);
     210                 :             : 
     211         [ -  + ]:       14886 :                                 if(SUCCESS != status)
     212                 :             :                                 {
     213                 :           0 :                                         continue_the_loop = false;
     214                 :           0 :                                         break;
     215                 :             :                                 }
     216                 :             : 
     217         [ +  + ]:       14886 :                                 if(summary->stats_only_pass == false)
     218                 :             :                                 {
     219                 :       11754 :                                         directory_show(relative_path,
     220                 :             :                                                 &first_iteration,
     221                 :             :                                                 summary,
     222                 :             :                                                 ignore,
     223                 :             :                                                 include);
     224                 :             :                                 }
     225                 :             : 
     226         [ +  + ]:       14886 :                                 if(ignore == true)
     227                 :             :                                 {
     228                 :             :                                         /*
     229                 :             :                                          * Use FTS_SKIP for an ignored directory only when no --include patterns were provided
     230                 :             :                                          * If any --include is present, keep traversing even ignored directories
     231                 :             :                                          * At this point only the directory path itself was checked, not paths under it
     232                 :             :                                          * Otherwise FTS_SKIP would cut off child files that should be brought back by --include
     233                 :             :                                          */
     234         [ +  + ]:         208 :                                         if(config->include_specified == false)
     235                 :             :                                         {
     236                 :          22 :                                                 (void)fts_set(file_systems,p,FTS_SKIP);
     237                 :             :                                         }
     238                 :         208 :                                         break;
     239                 :             :                                 }
     240                 :             : 
     241         [ +  + ]:       14678 :                                 if(summary->stats_only_pass == false)
     242                 :             :                                 {
     243                 :             :                                         // Check access and skip subtrees that are not readable.
     244                 :       11638 :                                         status = verify_directory_access(file_systems,
     245                 :             :                                                 p,
     246                 :             :                                                 runtime_root,
     247                 :             :                                                 &first_iteration,
     248                 :             :                                                 summary);
     249                 :             :                                 }
     250                 :             : 
     251         [ -  + ]:       14678 :                                 if(SUCCESS != status)
     252                 :             :                                 {
     253                 :           0 :                                         continue_the_loop = false;
     254                 :           0 :                                         break;
     255                 :             :                                 }
     256                 :             : 
     257                 :       14678 :                                 summary->count_dirs++;
     258                 :       14678 :                                 break;
     259                 :             :                         }
     260                 :        4192 :                         case FTS_F:
     261                 :             :                         {
     262                 :        4192 :                                 summary->total_allocated_bytes += blocks_to_bytes(p->fts_statp->st_blocks);
     263                 :        4192 :                                 summary->count_files++;
     264                 :             : 
     265         [ +  + ]:        4192 :                                 if(summary->stats_only_pass == true)
     266                 :             :                                 {
     267                 :         844 :                                         continue;
     268                 :             :                                 }
     269                 :             : 
     270                 :             :                                 // Keep per-file processing state on the stack and attach
     271                 :             :                                 // the DB row that will be filled for this path
     272                 :        3348 :                                 File _file = {0};
     273                 :        3348 :                                 File *file = &_file;
     274                 :        3348 :                                 DBrow dbrow = {0};
     275                 :        3348 :                                 file->db = &dbrow;
     276                 :             : 
     277                 :        3348 :                                 const char *relative_path = extract_relative_path(p->fts_path,runtime_root);
     278                 :             : 
     279                 :             :                                 /* Get all file's metadata from the database */
     280                 :             : #if 0 // Old multiPATH solution
     281                 :             :                                 run(db_read_file_data_from(file,&runtime_root_index,relative_path));
     282                 :             : #else
     283   [ +  -  -  + ]:        3348 :                                 run(db_read_file_data_from(file,relative_path));
     284                 :             : #endif
     285                 :             : 
     286         [ -  + ]:        3348 :                                 if(SUCCESS != status)
     287                 :             :                                 {
     288                 :           0 :                                         continue_the_loop = false;
     289                 :        3348 :                                         break;
     290                 :             :                                 }
     291                 :             : 
     292                 :             :                                 // Tracks whether the current relative path existed in DB before current file processing
     293                 :        3348 :                                 const bool path_known = file->db->relative_path_was_in_db_before_processing == true;
     294                 :             : 
     295                 :        3348 :                                 LockChecksum lock_checksum_response = match_checksum_lock_pattern(relative_path);
     296                 :             : 
     297         [ -  + ]:        3348 :                                 if(FAIL_REGEXP_LOCK_CHECKSUM == lock_checksum_response)
     298                 :             :                                 {
     299                 :           0 :                                         slog(ERROR,"Fail lock-checksum REGEXP for a string: %s\n",relative_path);
     300                 :           0 :                                         status = FAILURE;
     301                 :           0 :                                         continue_the_loop = false;
     302                 :           0 :                                         break;
     303         [ +  + ]:        3348 :                                 } else if(LOCK_CHECKSUM == lock_checksum_response){
     304                 :             :                                         // Mark this file as checksum-locked
     305                 :         164 :                                         file->locked_checksum_file = true;
     306                 :             :                                 }
     307                 :             : 
     308                 :             :                                 // Store the final --include/--ignore decision in the per-file state
     309                 :        3348 :                                 status = match_include_ignore(relative_path,&file->include,&file->ignore);
     310                 :             : 
     311         [ -  + ]:        3348 :                                 if(SUCCESS != status)
     312                 :             :                                 {
     313                 :           0 :                                         continue_the_loop = false;
     314                 :           0 :                                         break;
     315                 :             :                                 }
     316                 :             : 
     317                 :             :                                 // Ensure checksum-locked files are tracked even if matched by ignore pattern
     318   [ +  +  -  +  :        3348 :                                 if(file->ignore == true && file->locked_checksum_file == true && path_known == false)
                   -  - ]
     319                 :             :                                 {
     320                 :           0 :                                         file->ignore = false;
     321                 :             :                                 }
     322                 :             : 
     323                 :             :                                 // Determine read access for non-ignored paths
     324         [ +  + ]:        3348 :                                 if(file->ignore == false)
     325                 :             :                                 {
     326                 :        3258 :                                         FileAccessStatus access_status = file_check_access(p->fts_path,(size_t)p->fts_pathlen,R_OK);
     327                 :             : 
     328         [ -  + ]:        3258 :                                         if(access_status == FILE_ACCESS_ERROR)
     329                 :             :                                         {
     330                 :           0 :                                                 status = FAILURE;
     331                 :           0 :                                                 continue_the_loop = false;
     332                 :           0 :                                                 break;
     333                 :             :                                         }
     334                 :             : 
     335                 :        3258 :                                         file->is_readable = (access_status == FILE_ACCESS_ALLOWED);
     336                 :             :                                 }
     337                 :             : 
     338                 :             :                                 // Copy the current metadata once for comparisons, hashing, logging,
     339                 :             :                                 // and database writes
     340   [ +  -  -  + ]:        3348 :                                 run(stat_copy(p->fts_statp,&file->stat));
     341                 :             : 
     342                 :             :                                 // Validate whether logical size, allocated blocks, and ctime/mtime
     343                 :             :                                 // changed since the previous scan.
     344                 :             :                                 // Default value is:
     345                 :        3348 :                                 file->db_record_vs_file_metadata_changes = NOT_EQUAL;
     346                 :             : 
     347         [ +  + ]:        3348 :                                 if(path_known == true)
     348                 :             :                                 {
     349                 :             :                                         // Validate whether logical size, allocated blocks, and ctime/mtime
     350                 :             :                                         // changed since the previous scan.
     351                 :        1304 :                                         file->db_record_vs_file_metadata_changes = file_compare_metadata_equivalence(&file->db->saved_stat,&file->stat);
     352                 :             :                                 }
     353                 :             : 
     354                 :        3348 :                                 bool file_metadata_identical = file->db_record_vs_file_metadata_changes == IDENTICAL;
     355                 :        3348 :                                 const bool has_saved_offset = file->db->saved_offset > 0;
     356                 :             :                                 // Indicates that the checksum-locked file has already been fully hashed and recorded
     357                 :        6696 :                                 bool lock_checksum_ready = file->locked_checksum_file == true
     358         [ +  + ]:         164 :                                         && path_known == true
     359   [ +  +  +  - ]:        3512 :                                         && has_saved_offset == false;
     360                 :             : 
     361                 :             :                                 // Used to skip files whose metadata and checksum are already up to date
     362                 :        3348 :                                 bool unchanged_and_complete = path_known == true
     363         [ +  + ]:        1304 :                                         && file_metadata_identical == true
     364   [ +  +  +  + ]:        4652 :                                         && has_saved_offset == false;
     365                 :             : 
     366   [ +  +  +  +  :        3348 :                                 if(unchanged_and_complete == true && !(config->rehash_locked == true && lock_checksum_ready == true))
                   +  + ]
     367                 :             :                                 {
     368                 :             :                                         // Relative path already in DB and doesn't require any change
     369                 :             :                                         break;
     370                 :             :                                 }
     371                 :             : 
     372                 :             :                                 // Derived flags to qualify the type of metadata change
     373                 :        2294 :                                 bool size_changed = (file->db_record_vs_file_metadata_changes & SIZE_CHANGED) != 0;
     374                 :             : 
     375                 :        2294 :                                 bool timestamps_changed = (file->db_record_vs_file_metadata_changes & (STATUS_CHANGED_TIME | MODIFICATION_TIME_CHANGED)) != 0;
     376                 :             : 
     377                 :        2294 :                                 bool timestamps_only_changed = path_known == true
     378         [ +  + ]:         250 :                                         && file_metadata_identical == false
     379         [ +  + ]:         224 :                                         && config->watch_timestamps == false
     380         [ +  + ]:         170 :                                         && size_changed == false
     381   [ +  +  +  - ]:        2544 :                                         && has_saved_offset == false;
     382                 :             : 
     383                 :             :                                 // Decision whether to rehash the file contents using
     384                 :             :                                 // the SHA512 algorithm. Defaults to rehash.
     385                 :        2294 :                                 file->rehash = true;
     386                 :             : 
     387         [ +  + ]:        2294 :                                 if(timestamps_only_changed == true)
     388                 :             :                                 {
     389                 :             :                                         // ctime/mtime changed only: update DB without rehash
     390                 :         126 :                                         file->rehash = false;
     391                 :             :                                 }
     392                 :             : 
     393   [ +  +  +  + ]:        2294 :                                 if(lock_checksum_ready == true && config->rehash_locked == true)
     394                 :             :                                 {
     395                 :          36 :                                         file->rehash = true;
     396                 :             :                                 }
     397                 :             : 
     398                 :             :                                 /* For a file which had been changed before creation
     399                 :             :                                    of its checksum has been already finished */
     400                 :             : 
     401                 :             :                                 // Can we resume hashing from a previous partial state?
     402                 :        2294 :                                 bool can_resume_partial_hash = has_saved_offset == true
     403   [ +  +  +  + ]:        2294 :                                         && file_metadata_identical == true;
     404                 :             : 
     405                 :             :                                 // Indicates that a previous partial hash is now invalid and must restart
     406                 :        2294 :                                 bool partial_hash_invalidated = has_saved_offset == true
     407   [ +  +  +  + ]:        2294 :                                         && file_metadata_identical == false;
     408                 :             : 
     409         [ +  + ]:        2294 :                                 if(can_resume_partial_hash == true)
     410                 :             :                                 {
     411                 :             :                                         // Continue hashing from the saved offset and SHA512 context
     412                 :             :                                         // Restore byte offset from where the previous pass stopped
     413                 :           2 :                                         file->checksum_offset = file->db->saved_offset;
     414                 :             :                                         // Restore SHA512 state to continue from that offset
     415                 :           2 :                                         memcpy(&file->mdContext,&file->db->saved_mdContext,sizeof(SHA512_Context));
     416                 :             : 
     417         [ +  + ]:        2292 :                                 } else if(partial_hash_invalidated == true){
     418                 :             :                                         /* The SHA512 hashing of the file had not been
     419                 :             :                                            finished previously and the file has been changed */
     420                 :             :                                         // Signal that hashing must restart from byte zero
     421                 :           2 :                                         file->rehashing_from_the_beginning = true;
     422                 :             :                                 }
     423                 :             : 
     424                 :             :                                 // Marks zero-length files to avoid unnecessary hashing
     425         [ +  + ]:        2294 :                                 if(file->stat.st_size == 0)
     426                 :             :                                 {
     427                 :           6 :                                         file->zero_size_file = true;
     428                 :           6 :                                         file->rehash = false;
     429                 :             :                                 }
     430                 :             : 
     431                 :             :                                 // Locked checksum files must not diverge once sealed
     432                 :        2294 :                                 file->lock_checksum_violation = lock_checksum_ready == true
     433   [ +  +  +  + ]:        2332 :                                         && (size_changed == true
     434         [ +  + ]:          38 :                                         || (config->watch_timestamps == true
     435         [ +  + ]:          20 :                                         && config->rehash_locked == false
     436         [ +  - ]:           2 :                                         && timestamps_changed == true));
     437                 :             : 
     438                 :             :                                 // Timestamps drift on a locked file may be ignored depending on config
     439                 :        2294 :                                 bool locked_timestamp_drift_only = lock_checksum_ready == true
     440         [ +  + ]:          48 :                                         && config->watch_timestamps == false
     441         [ +  + ]:          28 :                                         && config->rehash_locked == false
     442         [ +  - ]:          10 :                                         && timestamps_changed == true
     443   [ +  +  +  + ]:        2342 :                                         && size_changed == false;
     444                 :             : 
     445         [ +  + ]:        2294 :                                 if(locked_timestamp_drift_only == true)
     446                 :             :                                 {
     447                 :           2 :                                         break;
     448                 :             :                                 }
     449                 :             : 
     450                 :             :                                 // Hard hashing failure that should stop traversal for this pass
     451                 :        2292 :                                 bool hash_failed = false;
     452                 :             :                                 // Controls whether the final outcome for this file should be shown
     453                 :        2292 :                                 bool show_log = false;
     454                 :             : 
     455                 :        4584 :                                 bool should_process = file->is_readable == true
     456         [ +  - ]:        2220 :                                         && file->ignore == false
     457   [ +  +  +  + ]:        4512 :                                         && file->lock_checksum_violation == false;
     458                 :             : 
     459         [ +  + ]:        2292 :                                 if(should_process == true)
     460                 :             :                                 {
     461         [ +  + ]:        2208 :                                         if(file->rehash == true)
     462                 :             :                                         {
     463         [ +  - ]:        2086 :                                                 if(SUCCESS == status)
     464                 :             :                                                 {
     465                 :        2086 :                                                         status = sha512sum(p->fts_path,
     466                 :        2086 :                                                                 (size_t)p->fts_pathlen,
     467                 :             :                                                                 file_buffer,
     468                 :             :                                                                 summary,
     469                 :             :                                                                 file);
     470                 :             :                                                 }
     471                 :             : 
     472         [ +  - ]:        2086 :                                                 if(TRIUMPH & status)
     473                 :             :                                                 {
     474                 :             :                                                         /* If the sha512sum has been interrupted smoothly when Ctrl+C */
     475   [ +  +  +  - ]:        2086 :                                                         if(file->checksum_offset > 0 && global_interrupt_flag == true)
     476                 :             :                                                         {
     477                 :           2 :                                                                 file->hash_interrupted = true;
     478                 :             :                                                         }
     479                 :             : 
     480                 :             :                                                 } else {
     481                 :           0 :                                                         continue_the_loop = false;
     482                 :           0 :                                                         hash_failed = true;
     483                 :             :                                                 }
     484                 :             : 
     485                 :             :                                         } else {
     486                 :             :                                                 // No rehash: reuse the digest stored in the DB
     487                 :         122 :                                                 memcpy(file->sha512,file->db->sha512,sizeof(file->sha512));
     488                 :             :                                         }
     489                 :             : 
     490         [ +  - ]:        2208 :                                         if(hash_failed == false
     491         [ +  + ]:        2208 :                                                 && file->read_error == false
     492         [ +  + ]:        2207 :                                                 && config->rehash_locked == true
     493         [ +  - ]:          34 :                                                 && lock_checksum_ready == true
     494         [ +  - ]:          34 :                                                 && file->rehash == true
     495         [ +  - ]:          34 :                                                 && (TRIUMPH & status)
     496         [ +  - ]:          34 :                                                 && file->wrong_file_type == false
     497         [ +  - ]:          34 :                                                 && file->zero_size_file == false
     498         [ +  - ]:          34 :                                                 && file->checksum_offset == 0)
     499                 :             :                                         {
     500         [ +  + ]:          34 :                                                 if(memcmp(file->sha512,file->db->sha512,SHA512_DIGEST_LENGTH) != 0)
     501                 :             :                                                 {
     502                 :             :                                                         // Detects corruption when rehashing locked files
     503                 :           6 :                                                         file->locked_checksum_mismatch = true;
     504                 :             :                                                 }
     505                 :             :                                         }
     506                 :             :                                 }
     507                 :             : 
     508         [ +  + ]:        2292 :                                 if(file->is_readable != true
     509         [ +  - ]:        2220 :                                         || file->ignore == true
     510         [ +  + ]:        2220 :                                         || file->lock_checksum_violation == true
     511         [ +  - ]:        2208 :                                         || hash_failed == true
     512         [ +  + ]:        2208 :                                         || file->read_error == true
     513         [ +  + ]:        2207 :                                         || file->locked_checksum_mismatch == true)
     514                 :             :                                 {
     515                 :          91 :                                         show_log = true;
     516                 :             : 
     517                 :             :                                         /* When a checksum-locked file changed;
     518                 :             :                                            blocks rehash/DB update and flags corruption */
     519   [ +  +  +  +  :          91 :                                         if((file->lock_checksum_violation == true || file->locked_checksum_mismatch == true) && file->read_error == false)
                   +  - ]
     520                 :             :                                         {
     521                 :          18 :                                                 lock_checksum_violation_detected = true;
     522                 :          18 :                                                 config->show_remembered_messages_at_exit = true;
     523                 :             :                                         }
     524                 :             : 
     525         [ +  + ]:        2201 :                                 } else if(path_known == true){
     526                 :             :                                         /* Update in DB */
     527                 :         222 :                                         show_log = true;
     528                 :             : 
     529                 :         444 :                                         bool allow_locked_update = file->lock_checksum_violation == false
     530   [ +  -  +  + ]:         250 :                                                 && (file->locked_checksum_file == false
     531         [ -  + ]:          28 :                                                 || config->rehash_locked == true
     532         [ #  # ]:           0 :                                                 || has_saved_offset == true);
     533                 :             : 
     534                 :         222 :                                         bool should_update_db = path_known == true
     535         [ +  - ]:         222 :                                                 && allow_locked_update == true
     536   [ +  -  +  - ]:         666 :                                                 && (file->checksum_offset > file->db->saved_offset
     537   [ +  +  -  + ]:         222 :                                                 || (has_saved_offset == true && file->checksum_offset == 0)
     538         [ +  + ]:         218 :                                                 || file_metadata_identical == false);
     539                 :             : 
     540         [ +  + ]:         222 :                                         if(should_update_db == true)
     541                 :             :                                         {
     542                 :             :                                                 /* Update record in DB */
     543         [ +  - ]:         200 :                                                 if(TRIUMPH & status)
     544                 :             :                                                 {
     545                 :         200 :                                                         status = db_update_the_record_by_id(file);
     546                 :             : 
     547         [ -  + ]:         200 :                                                         if((TRIUMPH & status) == 0)
     548                 :             :                                                         {
     549                 :           0 :                                                                 continue_the_loop = false;
     550                 :           0 :                                                                 break;
     551                 :             :                                                         }
     552                 :             :                                                         // Record that the DB row was updated
     553                 :         200 :                                                         file->db_record_updated = true;
     554                 :             :                                                 }
     555                 :             :                                         }
     556                 :             :                                 } else {
     557                 :        1979 :                                         show_log = true;
     558                 :             : 
     559                 :             :                                         /* Insert into DB */
     560         [ +  - ]:        1979 :                                         if(TRIUMPH & status)
     561                 :             :                                         {
     562                 :             : #if 0 // Old multiPATH solution
     563                 :             :                                                 status = db_insert_the_record(&runtime_root_index,
     564                 :             :                                                         relative_path,
     565                 :             :                                                         file);
     566                 :             : #else
     567                 :        1979 :                                                 status = db_insert_the_record(relative_path,file);
     568                 :             : #endif
     569                 :             : 
     570         [ -  + ]:        1979 :                                                 if((TRIUMPH & status) == 0)
     571                 :             :                                                 {
     572                 :           0 :                                                         continue_the_loop = false;
     573                 :           0 :                                                         break;
     574                 :             :                                                 }
     575                 :             :                                                 // Record that a new DB row was inserted
     576                 :        1979 :                                                 file->new_db_record_inserted = true;
     577                 :             :                                         }
     578                 :             :                                 }
     579                 :             : 
     580         [ +  - ]:        2292 :                                 if(show_log == true)
     581                 :             :                                 {
     582                 :             :                                         // Print out of a file name and its changes
     583                 :        2292 :                                         show_file(relative_path,
     584                 :             :                                                 &first_iteration,
     585                 :             :                                                 summary,
     586                 :             :                                                 file);
     587                 :             :                                 }
     588                 :             : 
     589                 :        2292 :                                 break;
     590                 :             :                         }
     591                 :         278 :                         case FTS_SL:
     592                 :         278 :                                 summary->count_symlnks++;
     593                 :         278 :                                 break;
     594                 :           0 :                         case FTS_DNR:
     595                 :             :                         case FTS_ERR:
     596                 :             :                         case FTS_NS:
     597                 :             :                         {
     598         [ #  # ]:           0 :                                 if(summary->stats_only_pass == true)
     599                 :             :                                 {
     600                 :           0 :                                         break;
     601                 :             :                                 }
     602                 :             : 
     603                 :           0 :                                 const char *relative_path = extract_relative_path(p->fts_path,runtime_root);
     604                 :             : 
     605         [ #  # ]:           0 :                                 if(p->fts_info == FTS_DNR)
     606                 :             :                                 {
     607                 :           0 :                                         slog_show(EVERY|UNDECOR|REMEMBER,false,&first_iteration,summary,"inaccessible directory %s\n",relative_path);
     608                 :             : 
     609         [ #  # ]:           0 :                                 } else if(p->fts_info == FTS_NS){
     610                 :             : 
     611                 :           0 :                                         slog_show(EVERY|UNDECOR|REMEMBER,false,&first_iteration,summary,"cannot stat \"%s\" when reading %s\n",strerror(p->fts_errno),relative_path);
     612                 :             : 
     613                 :             :                                 } else {
     614                 :             : 
     615                 :           0 :                                         slog_show(EVERY|UNDECOR|REMEMBER,false,&first_iteration,summary,"fts error \"%s\" when reading %s\n",strerror(p->fts_errno),relative_path);
     616                 :             :                                 }
     617                 :             : 
     618                 :           0 :                                 break;
     619                 :             :                         }
     620                 :       14884 :                         default:
     621                 :       14884 :                                 break;
     622                 :             :                 }
     623                 :             :         }
     624                 :             : 
     625                 :         332 :         del(file_buffer);
     626                 :             : 
     627                 :         332 :         free(runtime_root);
     628                 :             : 
     629                 :         332 :         fts_close(file_systems);
     630                 :             : 
     631                 :             :         // Print completion banner only when traversal emitted visible path-level lines.
     632                 :             :         // Print preflight totals only for the stats-only pass from main().
     633         [ +  + ]:         332 :         if(SUCCESS == status)
     634                 :             :         {
     635         [ +  + ]:         330 :                 if(summary->at_least_one_file_was_shown == true)
     636                 :             :                 {
     637                 :             : 
     638                 :         183 :                         slog(EVERY,"File traversal complete\n");
     639                 :             :                 }
     640                 :             : 
     641         [ +  + ]:         330 :                 if(summary->stats_only_pass == true)
     642                 :             :                 {
     643                 :          65 :                         show_statistics(summary);
     644                 :             :                 }
     645                 :             :         }
     646                 :             : 
     647         [ +  + ]:         332 :         if(lock_checksum_violation_detected == true)
     648                 :             :         {
     649                 :          14 :                 slog(EVERY,BOLD "Warning! Data corruption detected for checksum-locked file!" RESET "\n");
     650                 :             : 
     651         [ +  - ]:          14 :                 if(SUCCESS == status)
     652                 :             :                 {
     653                 :          14 :                         status = WARNING;
     654                 :             :                 }
     655                 :             :         }
     656                 :             : 
     657                 :         332 :         provide(status);
     658                 :             : }
        

Generated by: LCOV version 2.0-1