Branch data Line data Source code
1 : : #include "precizer.h"
2 : : #include <stdarg.h>
3 : :
4 : : /**
5 : : * @brief Retrieve a const pointer to a flag descriptor by index.
6 : : *
7 : : * Uses the mem helper to obtain a typed readonly view of the Flags array and
8 : : * performs bounds checking. Returns NULL if the descriptor is missing, type
9 : : * verification fails, or the index is out of range.
10 : : */
11 : 352 : static const Flags *lookup(
12 : : const memory *flags,
13 : : size_t index)
14 : : {
15 : 352 : const Flags *flags_data = cdata(Flags,flags);
16 : :
17 [ + - - + ]: 352 : if(flags_data == NULL || index >= flags->length)
18 : : {
19 : 0 : return(NULL);
20 : : }
21 : :
22 : 352 : return(&flags_data[index]);
23 : : }
24 : :
25 : : /**
26 : : * @brief Prints combinations of change flags for a file.
27 : : *
28 : : * This function evaluates a bitmask of change flags and prints the corresponding descriptions
29 : : * (e.g., "lsize", "asize", "ctime", "mtime") along with their metadata differences. The output uses
30 : : * the provided logger level, mirroring show_metadata behavior.
31 : : *
32 : : * Flag meanings:
33 : : * - lsize: logical file size (`st_size`)
34 : : * - asize: allocated size on disk (POSIX 512-byte blocks via blocks_to_bytes)
35 : : * - ctime: status change timestamp
36 : : * - mtime: content modification timestamp
37 : : *
38 : : */
39 : 226 : static void print_changes(
40 : : LOGMODES level,
41 : : Changed db_record_vs_file_metadata_changes,
42 : : const DBrow *dbrow,
43 : : const CmpctStat *stat)
44 : : {
45 : 226 : const char log_level = (char)(level | UNDECOR);
46 : :
47 [ + + + + ]: 226 : if(!((rational_logger_mode & VERBOSE) || config->watch_timestamps == true))
48 : : {
49 : 138 : return;
50 : : }
51 : :
52 : 88 : create(Flags,flags);
53 : :
54 : 88 : resize(flags,4);
55 : :
56 : 88 : Flags *flags_data = data(Flags,flags);
57 : :
58 [ - + ]: 88 : if(flags_data == NULL)
59 : : {
60 : 0 : del(flags);
61 : 0 : return;
62 : : }
63 : :
64 : 88 : flags_data[0] = (Flags){SIZE_CHANGED,"lsize"};
65 : 88 : flags_data[1] = (Flags){ALLOCATED_SIZE_CHANGED,"asize"};
66 : 88 : flags_data[2] = (Flags){STATUS_CHANGED_TIME,"ctime"};
67 : 88 : flags_data[3] = (Flags){MODIFICATION_TIME_CHANGED,"mtime"};
68 : :
69 : 88 : unsigned int flags_found = 0;
70 : :
71 : : /* Check each flag */
72 [ + + ]: 440 : for(size_t i = 0; i < flags->length; i++)
73 : : {
74 : 352 : const Flags *flag = lookup(flags,i);
75 : :
76 [ - + ]: 352 : if(flag == NULL)
77 : : {
78 : 0 : break;
79 : : }
80 : :
81 [ + + ]: 352 : if(db_record_vs_file_metadata_changes & flag->flag_value)
82 : : {
83 : : /* Add separator if not the first flag */
84 [ + + ]: 178 : if(flags_found > 0)
85 : : {
86 : 100 : slog(log_level," & ");
87 : : } else {
88 : 78 : slog(log_level,", changed: ");
89 : : }
90 : :
91 : 178 : slog(log_level,"%s",flag->flag_name);
92 : :
93 : 178 : show_metadata(level,flag->flag_value,&dbrow->saved_stat,stat);
94 : :
95 : 178 : flags_found++;
96 : : }
97 : : }
98 : :
99 : 88 : del(flags);
100 : : }
101 : :
102 : : /**
103 : : * @brief Show traversal banners once before the first visible log line of the main pass
104 : : *
105 : : */
106 : 1900 : static void show_banners(
107 : : bool *first_iteration,
108 : : const bool stats_only_pass)
109 : : {
110 [ - + ]: 1900 : if(first_iteration == NULL)
111 : : {
112 : 0 : return;
113 : : }
114 : :
115 : 1900 : bool show_traversal_started = false;
116 : 1900 : bool show_update_warning = false;
117 : 1900 : bool show_changes_will_be_reflected = false;
118 : 1900 : bool show_files_will_be_added = false;
119 : :
120 [ + + ]: 1900 : if(*first_iteration == true)
121 : : {
122 : 177 : *first_iteration = false;
123 : :
124 [ + - ]: 177 : if(stats_only_pass == false)
125 : : {
126 : 177 : show_traversal_started = true;
127 : :
128 [ + + ]: 177 : if(config->db_contains_data == true)
129 : : {
130 [ + - ]: 82 : if(config->update == true)
131 : : {
132 : 82 : show_update_warning = true;
133 : : }
134 : :
135 : 82 : show_changes_will_be_reflected = true;
136 : :
137 : : } else {
138 : :
139 : 95 : show_files_will_be_added = true;
140 : : }
141 : : }
142 : : }
143 : :
144 [ + + ]: 1900 : if(show_update_warning == true)
145 : : {
146 : 82 : slog(EVERY,"Update mode enabled for DB %s\n",confstr(db_file_name));
147 : : }
148 : :
149 [ + + ]: 1900 : if(show_traversal_started == true)
150 : : {
151 : 177 : slog(EVERY,"File traversal started\n");
152 : : }
153 : :
154 [ + + ]: 1900 : if(show_changes_will_be_reflected == true)
155 : : {
156 : 82 : slog(EVERY,BOLD "Changes reported during this scan against the DB %s:" RESET "\n",confstr(db_file_name));
157 : : }
158 : :
159 [ + + ]: 1900 : if(show_files_will_be_added == true)
160 : : {
161 : 95 : slog(EVERY,BOLD "Items reported during this traversal against the DB %s:" RESET "\n",confstr(db_file_name));
162 : : }
163 : : }
164 : :
165 : : /**
166 : : * @brief Log a line with banner/quiet handling and update output flags.
167 : : *
168 : : * Uses the call site metadata from the slog_show macro
169 : : * Banners are emitted only for the main traversal pass
170 : : *
171 : : */
172 : : __attribute__((format(printf,9,10)))
173 : 2236 : void slog_show_impl(
174 : : const char *filename,
175 : : const char *funcname,
176 : : int line,
177 : : const char level,
178 : : const bool respect_quiet,
179 : : bool *first_iteration,
180 : : bool *at_least_one_file_was_shown,
181 : : const bool stats_only_pass,
182 : : const char *fmt,
183 : : ...)
184 : : {
185 [ + + ]: 2236 : if(rational_logger_mode & SILENT)
186 : : {
187 : 336 : return;
188 : : }
189 : :
190 [ + + - + ]: 1900 : if(respect_quiet == true && config->quiet_ignored == true)
191 : : {
192 : 0 : return;
193 : : }
194 : :
195 : 1900 : show_banners(first_iteration,stats_only_pass);
196 : :
197 [ + - ]: 1900 : if(at_least_one_file_was_shown != NULL)
198 : : {
199 : 1900 : *at_least_one_file_was_shown = true;
200 : : }
201 : :
202 : 1900 : char *line_text = NULL;
203 : :
204 : : va_list args;
205 : 1900 : va_start(args,fmt);
206 : 1900 : int line_len = vasprintf(&line_text,fmt,args);
207 : 1900 : va_end(args);
208 : :
209 [ + - - + ]: 1900 : if(line_len < 0 || line_text == NULL)
210 : : {
211 : 0 : free(line_text);
212 : 0 : return;
213 : : }
214 : :
215 : 1900 : rational_logger(level,filename,(size_t)line,funcname,"%s",line_text);
216 : :
217 : 1900 : free(line_text);
218 : : }
219 : :
220 : : /**
221 : : * @brief Displays the relative path of a file with additional contextual information.
222 : : *
223 : : * This function prints the relative path of a file along with explanations of what actions
224 : : * will be taken regarding the file (e.g., ignore, updated, added, or rehashed). It also handles
225 : : * initial messages for traversal, updates, and warnings, emitted once before the first visible
226 : : * file or directory log, including read errors with errno.
227 : : *
228 : : */
229 : 1876 : void show_file(
230 : : const DBrow *dbrow,
231 : : const char *relative_path,
232 : : const CmpctStat *stat,
233 : : bool *first_iteration,
234 : : TraversalSummary *summary,
235 : : const Changed db_record_vs_file_metadata_changes,
236 : : const bool rehashing_from_the_beginning,
237 : : const bool ignore,
238 : : const bool include,
239 : : const bool locked_checksum_file,
240 : : const bool lock_checksum_violation,
241 : : const bool locked_checksum_mismatch,
242 : : const bool hash_interrupted,
243 : : const sqlite3_int64 checksum_offset,
244 : : const bool rehash,
245 : : const bool is_readable,
246 : : const bool zero_size_file,
247 : : const bool db_record_inserted,
248 : : const bool db_record_updated,
249 : : const bool read_error,
250 : : const int read_errno)
251 : : {
252 [ + + ]: 1876 : if(ignore == true)
253 : : {
254 [ + + ]: 68 : if(dbrow->relative_path_was_in_db_before_processing == false)
255 : : {
256 : 64 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"ignore & do not add %s\n",relative_path);
257 : : } else {
258 : 4 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"ignored & do not update %s\n",relative_path);
259 : : }
260 : :
261 [ + + ]: 1808 : } else if(read_error == true){
262 : :
263 : 1 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,"error \"%s\" when reading %s\n",strerror(read_errno),relative_path);
264 : :
265 [ + + ]: 1807 : } else if(is_readable == false){
266 : :
267 : 4 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,"inaccessible file %s\n",relative_path);
268 : :
269 [ + + ]: 1803 : } else if(dbrow->relative_path_was_in_db_before_processing == false){
270 : :
271 : : /* Add new */
272 : :
273 [ + - ]: 1569 : if(db_record_inserted == true)
274 : : {
275 [ + + ]: 1569 : if(include == true)
276 : : {
277 : 24 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"add included %s\n",relative_path);
278 : :
279 [ + + ]: 1545 : } else if(locked_checksum_file == true){
280 : :
281 : 62 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"lock checksum %s\n",relative_path);
282 : :
283 [ + + ]: 1483 : } else if(zero_size_file == true){
284 : :
285 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"add as empty %s\n",relative_path);
286 : :
287 : : } else {
288 : :
289 : 1481 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"new %s\n",relative_path);
290 : : }
291 : : }
292 : :
293 : : } else {
294 : :
295 : : /* Update existing */
296 : :
297 [ + + ]: 234 : if(locked_checksum_mismatch == true)
298 : : {
299 : :
300 : 6 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,RED "checksum locked & mismatch, data corrupted" RESET " %s\n",relative_path);
301 : :
302 [ + + ]: 228 : } else if(lock_checksum_violation == true){
303 : :
304 : 12 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,RED "checksum locked, data corruption detected" RESET);
305 : :
306 : 12 : print_changes(EVERY|REMEMBER,db_record_vs_file_metadata_changes,dbrow,stat);
307 : :
308 : 12 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary," %s\n",relative_path);
309 : :
310 [ + + + + ]: 216 : } else if(db_record_updated == true && include == true){
311 : :
312 : 6 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"update included");
313 : :
314 : 6 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
315 : :
316 : 6 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
317 : :
318 [ + + + + ]: 210 : } else if(db_record_updated == true && zero_size_file == true){
319 : :
320 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update as empty");
321 : :
322 : 2 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
323 : :
324 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
325 : :
326 [ + + ]: 208 : } else if(rehash == true){
327 : :
328 [ + + ]: 92 : if(rehashing_from_the_beginning == true)
329 : : {
330 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"rehash from the beginning");
331 : :
332 : 2 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
333 : :
334 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
335 : :
336 [ + + ]: 90 : } else if(dbrow->saved_offset > 0){
337 : :
338 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"continue to rehash from %s %s\n",bkbmbgbtbpbeb((const size_t)dbrow->saved_offset,FULL_VIEW),relative_path);
339 : :
340 [ + + ]: 88 : } else if(locked_checksum_file == true){
341 : :
342 : 22 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"locked rehash ok");
343 : :
344 : 22 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
345 : :
346 : 22 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
347 : :
348 [ + - ]: 66 : } else if(db_record_updated == true){
349 : :
350 : 66 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update & rehash");
351 : :
352 : 66 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
353 : :
354 : 66 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
355 : : }
356 : :
357 [ + - ]: 116 : } else if(db_record_updated == true){
358 : :
359 : 116 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update stat");
360 : :
361 : 116 : print_changes(EVERY,db_record_vs_file_metadata_changes,dbrow,stat);
362 : :
363 : 116 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
364 : : }
365 : : }
366 : :
367 [ + + ]: 1876 : if(hash_interrupted == true)
368 : : {
369 : 2 : slog_show(EVERY,false,first_iteration,summary,"SHA512 checksum for the file %s has been gracefully interrupted at byte: %s\n",relative_path,bkbmbgbtbpbeb((size_t)checksum_offset,FULL_VIEW));
370 : : }
371 : 1876 : }
|