Line data Source code
1 : #include "precizer.h"
2 :
3 : /**
4 : * @brief Validates path consistency between database records and provided config variables
5 : *
6 : * @details This function performs validation of paths by comparing paths stored
7 : * in the database against paths provided as config variables. The validation
8 : * process involves:
9 : *
10 : * 1. Checking if paths stored in database match paths passed as config variables
11 : * 2. Warning user about potential data loss if paths mismatch
12 : * 3. Handling forced path updates when --force flag is used
13 : *
14 : * The function supports several operational modes:
15 : * - Normal mode: Validates paths and prevents updates if mismatch detected
16 : * - Force mode: Allows path updates even when mismatches are detected
17 : * - Compare mode: Skips validation entirely
18 : *
19 : * Database operations:
20 : * - Queries existing paths from database
21 : * - Creates temporary tables for tracking mismatched paths
22 : * - Performs path prefix comparisons
23 : *
24 : * @note This function is crucial for preventing accidental data loss by ensuring
25 : * path consistency before performing database operations.
26 : *
27 : * @warning Using --force flag can lead to loss or replacement of file and
28 : * checksum information if used incorrectly.
29 : *
30 : * Error handling:
31 : * - Memory allocation failures
32 : * - SQLite preparation and execution errors
33 : * - Path mismatch detection
34 : *
35 : * @provide Return Status code indicating operation result:
36 : * - SUCCESS (0): Paths are valid or force flag is used
37 : * - FAILURE (1): Path mismatch detected without force flag
38 : * or database operation error occurred
39 : */
40 186 : Return db_validate_paths(void)
41 : {
42 : /// The status that will be passed to return() before exiting.
43 : /// By default, the function worked without errors.
44 186 : Return status = SUCCESS;
45 :
46 : // Don't do anything
47 186 : if(config->compare == true)
48 : {
49 32 : return(status);
50 : }
51 :
52 : /* Interrupt the function smoothly */
53 : /* Interrupt when Ctrl+C */
54 154 : if(global_interrupt_flag == true)
55 : {
56 0 : provide(status);
57 : }
58 :
59 154 : sqlite3_stmt *select_stmt = NULL;
60 154 : sqlite3_stmt *insert_stmt = NULL;
61 154 : int rc = 0;
62 :
63 154 : bool paths_are_equal = true;
64 :
65 154 : create(char,select_sql);
66 :
67 : // Create the SQL request
68 154 : if(config->paths[0] != NULL)
69 : {
70 154 : char const *sql_1 = "SELECT ID FROM paths WHERE prefix NOT IN (";
71 :
72 154 : status = concat_literal(select_sql,sql_1);
73 :
74 154 : if(SUCCESS != status)
75 : {
76 0 : del(select_sql);
77 0 : provide(status);
78 : }
79 :
80 308 : for(int i = 0; config->paths[i]; i++)
81 : {
82 154 : create(char,path);
83 :
84 154 : run(db_sql_wrap_string(path,config->paths[i]));
85 :
86 154 : run(concat_literal(select_sql,getcstring(path)));
87 :
88 154 : del(path);
89 :
90 154 : if(SUCCESS != status)
91 : {
92 0 : del(select_sql);
93 0 : provide(status);
94 : }
95 :
96 : // Not the last path in the array
97 154 : if(config->paths[i + 1] != 0)
98 : {
99 : /* Concatenate with the comma character "," */
100 0 : status = concat_literal(select_sql,",");
101 :
102 0 : if(SUCCESS != status)
103 : {
104 0 : del(select_sql);
105 0 : provide(status);
106 : }
107 : }
108 : }
109 :
110 : /* Close the string that contains SQL request */
111 :
112 : /* Concatenate with the ");" characters */
113 154 : status = concat_literal(select_sql,");");
114 :
115 154 : if(SUCCESS != status)
116 : {
117 0 : del(select_sql);
118 0 : provide(status);
119 : }
120 : }
121 :
122 154 : rc = sqlite3_prepare_v2(config->db,getstring(select_sql),-1,&select_stmt,NULL);
123 :
124 154 : if(SQLITE_OK != rc)
125 : {
126 0 : log_sqlite_error(config->db,rc,NULL,"Can't prepare select statement %s",getstring(select_sql));
127 0 : status = FAILURE;
128 : }
129 :
130 154 : if(SUCCESS == status)
131 : {
132 312 : while(SQLITE_ROW == (rc = sqlite3_step(select_stmt)))
133 : {
134 4 : sqlite3_int64 path_ID = -1;
135 :
136 4 : path_ID = sqlite3_column_int64(select_stmt,0);
137 :
138 4 : if(path_ID != -1)
139 : {
140 4 : paths_are_equal = false;
141 :
142 4 : const char *insert_sql = "INSERT INTO runtime_paths_id.the_path_id_does_not_exists (path_id) VALUES (?1);";
143 :
144 4 : rc = sqlite3_prepare_v2(config->db,insert_sql,-1,&insert_stmt,NULL);
145 :
146 4 : if(SQLITE_OK != rc)
147 : {
148 0 : log_sqlite_error(config->db,rc,NULL,"Can't prepare insert statement");
149 0 : status = FAILURE;
150 : }
151 :
152 4 : if(SUCCESS == status)
153 : {
154 4 : rc = sqlite3_bind_int64(insert_stmt,1,path_ID);
155 :
156 4 : if(SQLITE_OK != rc)
157 : {
158 0 : log_sqlite_error(config->db,rc,NULL,"Error binding value in insert");
159 0 : status = FAILURE;
160 : }
161 : }
162 :
163 4 : if(SUCCESS == status)
164 : {
165 : /* Execute SQL statement */
166 4 : if(sqlite3_step(insert_stmt) != SQLITE_DONE)
167 : {
168 0 : log_sqlite_error(config->db,rc,NULL,"Insert statement didn't return DONE");
169 0 : status = FAILURE;
170 : }
171 : }
172 :
173 4 : sqlite3_finalize(insert_stmt);
174 : }
175 : }
176 :
177 154 : if(SQLITE_DONE != rc)
178 : {
179 0 : log_sqlite_error(config->db,rc,NULL,"Select statement didn't finish with DONE");
180 0 : status = FAILURE;
181 : }
182 : }
183 :
184 154 : del(select_sql);
185 :
186 154 : sqlite3_finalize(select_stmt);
187 :
188 154 : if(SUCCESS == status)
189 : {
190 : /* If the primary database was just created */
191 154 : if(config->db_primary_file_exists == false && config->compare == false)
192 : {
193 78 : slog(TRACE,"The brand new database has just been created. No need to verify the paths stored in the database against those passed as command-line arguments\n");
194 78 : provide(status);
195 :
196 : } else {
197 :
198 76 : if(paths_are_equal == true)
199 : {
200 72 : slog(TRACE,"The paths written against the database and the paths passed as arguments are completely identical\n");
201 : } else {
202 4 : slog(EVERY,"The paths passed as arguments differ from those saved in the database. File paths and checksum information may be lost!\n");
203 :
204 4 : if(!(rational_logger_mode & SILENT))
205 : {
206 4 : slog(EVERY,"Paths saved in the database:\n");
207 :
208 : sqlite3_stmt *stmt;
209 4 : int rc_stmt = 0;
210 4 : char const *sql = "SELECT prefix FROM paths;";
211 :
212 4 : rc_stmt = sqlite3_prepare_v2(config->db,sql,-1,&stmt,NULL);
213 :
214 4 : if(SQLITE_OK != rc_stmt)
215 : {
216 0 : log_sqlite_error(config->db,rc_stmt,NULL,"Can't prepare select statement %s",sql);
217 0 : status = FAILURE;
218 : }
219 :
220 4 : if(SUCCESS == status)
221 : {
222 8 : while(SQLITE_ROW == (rc_stmt = sqlite3_step(stmt)))
223 : {
224 4 : const char *prefix = (const char *)sqlite3_column_text(stmt,0);
225 :
226 4 : slog(EVERY|UNDECOR,"%s\n",prefix);
227 : }
228 :
229 4 : if(SQLITE_DONE != rc_stmt)
230 : {
231 0 : log_sqlite_error(config->db,rc_stmt,NULL,"Select statement didn't finish with DONE");
232 0 : status = FAILURE;
233 : }
234 : }
235 :
236 4 : sqlite3_finalize(stmt);
237 : }
238 :
239 4 : if(config->force == true)
240 : {
241 2 : if(!(rational_logger_mode & SILENT))
242 : {
243 2 : slog(EVERY,"The " BOLD "--force" RESET " option has been used, so the following paths will be written to the %s:\n",config->db_file_name);
244 :
245 4 : for(int i = 0; config->paths[i]; i++)
246 : {
247 2 : slog(EVERY|UNDECOR,"%s\n",config->paths[i]);
248 : }
249 : }
250 : } else {
251 2 : slog(EVERY,"Use the " BOLD "--force" RESET " option only when the PATHS stored in the database need"
252 : " to be updated. Warning: If this option is used incorrectly, file and checksum information"
253 : " in the database may be lost or completely replaced with different values.\n");
254 2 : status = WARNING;
255 : }
256 : }
257 : }
258 : }
259 :
260 76 : provide(status);
261 : }
|