Branch data Line data Source code
1 : : /**
2 : : *
3 : : * @file precizer.c
4 : : * @brief Main file
5 : : *
6 : : */
7 : : #include "precizer.h"
8 : :
9 : : /**
10 : : * Global definitions
11 : : *
12 : : */
13 : :
14 : : // Global variable controls signals to interrupt execution
15 : : // Atomic variable is very fast and will be called very often
16 : : _Atomic bool global_interrupt_flag = false;
17 : :
18 : : // The global structure Config where all runtime settings will be stored
19 : : Config _config;
20 : : Config *config = &_config;
21 : :
22 : : /**
23 : : * @mainpage
24 : : * @brief precizer is a CLI application designed to verify the integrity of files after synchronization.
25 : : * The program recursively traverses directories and creates a database
26 : : * of files and their checksums, followed by a quick comparison.
27 : : *
28 : : * @author Dennis Razumovsky
29 : : * @details precizer specializes in managing vast file systems.
30 : : * The program identifies synchronization errors by cross-referencing
31 : : * data and checksums from various sources. Alternatively, it can be
32 : : * used to crawl historical changes by comparing databases from the
33 : : * same sources over different times
34 : : */
35 : : /**
36 : : * @brief Program entry point for normal and TESTITALL builds
37 : : *
38 : : * @details Initializes runtime state, executes the main workflow, prints final
39 : : * diagnostics, and returns the shell exit status. In TESTITALL builds the same
40 : : * implementation is exposed as `test_main()`
41 : : *
42 : : * @param argc Number of CLI arguments
43 : : * @param argv CLI argument vector
44 : : * @return Process exit status for the completed run
45 : : */
46 : : #ifndef TESTITALL // Unit testing library
47 : 229 : int main(
48 : : int argc,
49 : : char **argv)
50 : : #else
51 : 226 : int test_main(
52 : : int argc,
53 : : char **argv)
54 : : #endif // TESTITALL
55 : : {
56 : : /* This function was reviewed line by line by a human and is not AI-generated
57 : : Any change to this function requires separate explicit approval */
58 : :
59 : : /* Status returned by this function through provide()
60 : : Default value assumes successful completion */
61 : 455 : Return status = SUCCESS;
62 : :
63 : : // Stack storage for traversal stats, zero-initialized.
64 : 455 : TraversalSummary _summary = {0};
65 : : // Use pointer form for consistency.
66 : 455 : TraversalSummary *summary = &_summary;
67 : :
68 : : // Initialize configuration with values
69 : 455 : init_config();
70 : :
71 : : // Fill Config structure
72 : : // parsing command line arguments
73 [ + - + + ]: 455 : run(parse_arguments(argc,argv));
74 : :
75 : : // Compile PCRE2 patterns from --ignore, --include, --lock-checksum once
76 : : // so that file traversal reuses compiled objects instead of recompiling per file
77 [ + + - + ]: 455 : run(compile_patterns());
78 : :
79 : : // Print program identity only when argument parsing is not in info mode
80 [ + + ]: 455 : if((status & INFO) == 0)
81 : : {
82 : 425 : about();
83 : : }
84 : :
85 : : // Verify that the provided paths exist and
86 : : // are directories
87 [ + + - + ]: 455 : run(paths_detect());
88 : :
89 : : // Initialize signals interception like Ctrl+C
90 [ + + - + ]: 455 : run(init_signals());
91 : :
92 : : // The current directory where app being executed
93 [ + + - + ]: 455 : run(determine_running_dir());
94 : :
95 : : // Generate DB file name if
96 : : // not passed as an argument
97 [ + + - + ]: 455 : run(db_determine_name());
98 : :
99 : : // Validate database file existence and set up existence flag
100 [ + + + + ]: 455 : run(db_primary_file_validate_existence());
101 : :
102 : : // Define the database operation mode
103 [ + + + + ]: 455 : run(db_determine_mode());
104 : :
105 : : // Primary database file integrity check
106 [ + + + + ]: 455 : run(db_primary_file_test());
107 : :
108 : : // Initialize SQLite database
109 [ + + + + ]: 455 : run(db_init());
110 : :
111 : : // Compare databases
112 [ + + + + ]: 455 : run(db_compare());
113 : :
114 : : // Check whether the database already exists or not yet
115 [ + + + + ]: 455 : run(db_contains_data());
116 : :
117 : : // Verify that the provided path arguments match
118 : : // the paths stored in the database
119 [ + + + + ]: 455 : run(db_validate_paths());
120 : :
121 : : // Save new prefixes that has been passed as
122 : : // arguments
123 [ + + - + ]: 455 : run(db_save_prefixes());
124 : :
125 : : // Just get a statistic
126 : 455 : summary->stats_only_pass = true;
127 [ + + - + ]: 455 : run(file_list(summary));
128 : :
129 : : // Get file list and their checksums
130 : 455 : summary->stats_only_pass = false;
131 [ + + + + ]: 455 : run(file_list(summary));
132 : :
133 : : // Update the database. Remove files that
134 : : // no longer exist.
135 [ + + - + ]: 455 : run(db_delete_missing_metadata());
136 : :
137 : : // Print remembered warning and error lines when delayed output is enabled
138 [ - + + + ]: 455 : call(show_remembered_messages());
139 : :
140 : : // Print final totals and runtime metrics after delayed warnings/errors.
141 : : // This runs only for successful execution flow.
142 [ + + ]: 455 : if((SUCCESS|WARNING) & status)
143 : : {
144 : 421 : show_statistics(summary);
145 : 421 : show_elapsed(summary);
146 : : }
147 : :
148 : : // Disable journaling, flush the journal to the main database,
149 : : // clear the cache, and close the database
150 [ - + + + ]: 455 : call(db_close(config->db,&config->db_primary_file_modified));
151 : :
152 : : // Optimizing the space occupied by a database file.
153 [ + + - + ]: 455 : run(db_primary_consider_vacuum());
154 : :
155 : : // Print out whether there have been changes to
156 : : // the file system and accordingly against the database
157 : : // since the last research
158 [ + + + + ]: 455 : run(status_of_changes());
159 : :
160 : : // Free allocated memory
161 : : // for arrays and variables
162 : 455 : free_config();
163 : :
164 : 455 : return(exit_status(status,argv));
165 : : }
|