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 : 232 : static void print_changes(
40 : : LOGMODES level,
41 : : const File *file)
42 : : {
43 : 232 : const unsigned int log_level = (unsigned int)(level | UNDECOR);
44 : :
45 [ + + + + ]: 232 : if(!((rational_logger_mode & VERBOSE) || config->watch_timestamps == true))
46 : : {
47 : 144 : return;
48 : : }
49 : :
50 : 88 : create(Flags,flags);
51 : :
52 : 88 : resize(flags,4);
53 : :
54 : 88 : Flags *flags_data = data(Flags,flags);
55 : :
56 [ - + ]: 88 : if(flags_data == NULL)
57 : : {
58 : 0 : del(flags);
59 : 0 : return;
60 : : }
61 : :
62 : 88 : flags_data[0] = (Flags){SIZE_CHANGED,"lsize"};
63 : 88 : flags_data[1] = (Flags){ALLOCATED_SIZE_CHANGED,"asize"};
64 : 88 : flags_data[2] = (Flags){STATUS_CHANGED_TIME,"ctime"};
65 : 88 : flags_data[3] = (Flags){MODIFICATION_TIME_CHANGED,"mtime"};
66 : :
67 : 88 : unsigned int flags_found = 0;
68 : :
69 : : /* Check each flag */
70 [ + + ]: 440 : for(size_t i = 0; i < flags->length; i++)
71 : : {
72 : 352 : const Flags *flag = lookup(flags,i);
73 : :
74 [ - + ]: 352 : if(flag == NULL)
75 : : {
76 : 0 : break;
77 : : }
78 : :
79 [ + + ]: 352 : if(file->db_record_vs_file_metadata_changes & flag->flag_value)
80 : : {
81 : : /* Add separator if not the first flag */
82 [ + + ]: 178 : if(flags_found > 0)
83 : : {
84 : 100 : slog(log_level," & ");
85 : : } else {
86 : 78 : slog(log_level,", changed: ");
87 : : }
88 : :
89 : 178 : slog(log_level,"%s",flag->flag_name);
90 : :
91 : 178 : show_metadata(level,flag->flag_value,&file->db->saved_stat,&file->stat);
92 : :
93 : 178 : flags_found++;
94 : : }
95 : : }
96 : :
97 : 88 : del(flags);
98 : : }
99 : :
100 : : /**
101 : : * @brief Show traversal banners once before the first visible log line of the main pass
102 : : *
103 : : */
104 : 1984 : static void show_banners(
105 : : bool *first_iteration,
106 : : const bool stats_only_pass)
107 : : {
108 [ - + ]: 1984 : if(first_iteration == NULL)
109 : : {
110 : 0 : return;
111 : : }
112 : :
113 : 1984 : bool show_traversal_started = false;
114 : 1984 : bool show_update_warning = false;
115 : 1984 : bool show_changes_will_be_reflected = false;
116 : 1984 : bool show_files_will_be_added = false;
117 : :
118 [ + + ]: 1984 : if(*first_iteration == true)
119 : : {
120 : 185 : *first_iteration = false;
121 : :
122 [ + - ]: 185 : if(stats_only_pass == false)
123 : : {
124 : 185 : show_traversal_started = true;
125 : :
126 [ + + ]: 185 : if(config->db_contains_data == true)
127 : : {
128 [ + - ]: 84 : if(config->update == true)
129 : : {
130 : 84 : show_update_warning = true;
131 : : }
132 : :
133 : 84 : show_changes_will_be_reflected = true;
134 : :
135 : : } else {
136 : :
137 : 101 : show_files_will_be_added = true;
138 : : }
139 : : }
140 : : }
141 : :
142 [ + + ]: 1984 : if(show_update_warning == true)
143 : : {
144 : 84 : slog(EVERY,"Update mode enabled for DB %s\n",confstr(db_file_name));
145 : : }
146 : :
147 [ + + ]: 1984 : if(show_traversal_started == true)
148 : : {
149 : 185 : slog(EVERY,"File traversal started\n");
150 : : }
151 : :
152 [ + + ]: 1984 : if(show_changes_will_be_reflected == true)
153 : : {
154 : 84 : slog(EVERY,BOLD "Changes reported during this scan against the DB %s:" RESET "\n",confstr(db_file_name));
155 : : }
156 : :
157 [ + + ]: 1984 : if(show_files_will_be_added == true)
158 : : {
159 : 101 : slog(EVERY,BOLD "Items reported during this traversal against the DB %s:" RESET "\n",confstr(db_file_name));
160 : : }
161 : : }
162 : :
163 : : /**
164 : : * @brief Log a line with banner/quiet handling and update output flags.
165 : : *
166 : : * Uses the call site metadata from the slog_show macro
167 : : * Banners are emitted only for the main traversal pass
168 : : *
169 : : */
170 : : __attribute__((format(printf,9,10)))
171 : 2658 : void slog_show_impl(
172 : : const char *filename,
173 : : const char *funcname,
174 : : int line,
175 : : const unsigned int level,
176 : : const bool respect_quiet,
177 : : bool *first_iteration,
178 : : bool *at_least_one_file_was_shown,
179 : : const bool stats_only_pass,
180 : : const char *fmt,
181 : : ...)
182 : : {
183 [ + + ]: 2658 : if(rational_logger_mode & SILENT)
184 : : {
185 : 674 : return;
186 : : }
187 : :
188 [ + + - + ]: 1984 : if(respect_quiet == true && config->quiet_ignored == true)
189 : : {
190 : 0 : return;
191 : : }
192 : :
193 : 1984 : show_banners(first_iteration,stats_only_pass);
194 : :
195 [ + - ]: 1984 : if(at_least_one_file_was_shown != NULL)
196 : : {
197 : 1984 : *at_least_one_file_was_shown = true;
198 : : }
199 : :
200 : 1984 : char *line_text = NULL;
201 : :
202 : : va_list args;
203 : 1984 : va_start(args,fmt);
204 : 1984 : int line_len = vasprintf(&line_text,fmt,args);
205 : 1984 : va_end(args);
206 : :
207 [ + - - + ]: 1984 : if(line_len < 0 || line_text == NULL)
208 : : {
209 : 0 : free(line_text);
210 : 0 : return;
211 : : }
212 : :
213 : 1984 : rational_logger(level,filename,(size_t)line,funcname,"%s",line_text);
214 : :
215 : 1984 : free(line_text);
216 : : }
217 : :
218 : : /**
219 : : * @brief Displays the relative path of a file with additional contextual information.
220 : : *
221 : : * This function prints the relative path of a file along with explanations of what actions
222 : : * will be taken regarding the file (e.g., ignore, updated, added, or rehashed). It also handles
223 : : * initial messages for traversal, updates, and warnings, emitted once before the first visible
224 : : * file or directory log, including read errors with errno.
225 : : *
226 : : */
227 : 2292 : void show_file(
228 : : const char *relative_path,
229 : : bool *first_iteration,
230 : : TraversalSummary *summary,
231 : : const File *file)
232 : : {
233 [ + + ]: 2292 : if(file->ignore == true)
234 : : {
235 [ + + ]: 68 : if(file->db->relative_path_was_in_db_before_processing == false)
236 : : {
237 : 64 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"ignore & do not add %s\n",relative_path);
238 : : } else {
239 : 4 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"ignored & do not update %s\n",relative_path);
240 : : }
241 : :
242 [ + + ]: 2224 : } else if(file->read_error == true){
243 : :
244 : 1 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,"error \"%s\" when reading %s\n",strerror(file->read_errno),relative_path);
245 : :
246 [ + + ]: 2223 : } else if(file->is_readable == false){
247 : :
248 : 4 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,"inaccessible file %s\n",relative_path);
249 : :
250 [ + + ]: 2219 : } else if(file->db->relative_path_was_in_db_before_processing == false){
251 : :
252 : : /* Add new */
253 : :
254 [ + - ]: 1979 : if(file->new_db_record_inserted == true)
255 : : {
256 [ + + ]: 1979 : if(file->include == true)
257 : : {
258 : 24 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"add included %s\n",relative_path);
259 : :
260 [ + + ]: 1955 : } else if(file->locked_checksum_file == true){
261 : :
262 : 68 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"lock checksum %s\n",relative_path);
263 : :
264 [ + + ]: 1887 : } else if(file->zero_size_file == true){
265 : :
266 : 4 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"add as empty %s\n",relative_path);
267 : :
268 : : } else {
269 : :
270 : 1883 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"new %s\n",relative_path);
271 : : }
272 : : }
273 : :
274 : : } else {
275 : :
276 : : /* Update existing */
277 : :
278 [ + + ]: 240 : if(file->locked_checksum_mismatch == true)
279 : : {
280 : :
281 : 6 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,RED "checksum locked & mismatch, data corrupted" RESET " %s\n",relative_path);
282 : :
283 [ + + ]: 234 : } else if(file->lock_checksum_violation == true){
284 : :
285 : 12 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary,RED "checksum locked, data corruption detected" RESET);
286 : :
287 : 12 : print_changes(EVERY|REMEMBER,file);
288 : :
289 : 12 : slog_show(EVERY|UNDECOR|REMEMBER,false,first_iteration,summary," %s\n",relative_path);
290 : :
291 [ + + + + ]: 222 : } else if(file->db_record_updated == true && file->include == true){
292 : :
293 : 6 : slog_show(EVERY|UNDECOR,true,first_iteration,summary,"update included");
294 : :
295 : 6 : print_changes(EVERY,file);
296 : :
297 : 6 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
298 : :
299 [ + + + + ]: 216 : } else if(file->db_record_updated == true && file->zero_size_file == true){
300 : :
301 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update as empty");
302 : :
303 : 2 : print_changes(EVERY,file);
304 : :
305 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
306 : :
307 [ + + ]: 214 : } else if(file->rehash == true){
308 : :
309 [ + + ]: 98 : if(file->rehashing_from_the_beginning == true)
310 : : {
311 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"rehash from the beginning");
312 : :
313 : 2 : print_changes(EVERY,file);
314 : :
315 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
316 : :
317 [ + + ]: 96 : } else if(file->db->saved_offset > 0){
318 : :
319 : 2 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"continue to rehash from %s %s\n",bkbmbgbtbpbeb((const size_t)file->db->saved_offset,FULL_VIEW),relative_path);
320 : :
321 [ + + ]: 94 : } else if(file->locked_checksum_file == true){
322 : :
323 : 28 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"locked rehash ok");
324 : :
325 : 28 : print_changes(EVERY,file);
326 : :
327 : 28 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
328 : :
329 [ + - ]: 66 : } else if(file->db_record_updated == true){
330 : :
331 : 66 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update & rehash");
332 : :
333 : 66 : print_changes(EVERY,file);
334 : :
335 : 66 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
336 : : }
337 : :
338 [ + - ]: 116 : } else if(file->db_record_updated == true){
339 : :
340 : 116 : slog_show(EVERY|UNDECOR,false,first_iteration,summary,"update stat");
341 : :
342 : 116 : print_changes(EVERY,file);
343 : :
344 : 116 : slog_show(EVERY|UNDECOR,false,first_iteration,summary," %s\n",relative_path);
345 : : }
346 : : }
347 : :
348 [ + + ]: 2292 : if(file->hash_interrupted == true)
349 : : {
350 : 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)file->checksum_offset,FULL_VIEW));
351 : : }
352 : 2292 : }
|