Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : /**
4 : : * @brief Open SQLite database from TMPDIR by relative filename
5 : : *
6 : : * @param[in] db_filename Database filename relative to TMPDIR
7 : : * @param[in] open_flags Flags passed to sqlite3_open_v2
8 : : * @param[out] db_out Opened database handle
9 : : *
10 : : * @return Return status code:
11 : : * - SUCCESS: Database opened successfully
12 : : * - FAILURE: Validation, path construction, or open failed
13 : : */
14 : 16 : static Return open_db_from_tmpdir(
15 : : const char *db_filename,
16 : : const int open_flags,
17 : : sqlite3 **db_out)
18 : : {
19 : : /* Status returned by this function through provide()
20 : : Default value assumes successful completion */
21 : 16 : Return status = SUCCESS;
22 : :
23 : 16 : create(char,db_path);
24 : :
25 [ + - - + ]: 16 : if(db_filename == NULL || db_out == NULL)
26 : : {
27 : 0 : status = FAILURE;
28 : : }
29 : :
30 [ + - ]: 16 : if(SUCCESS == status)
31 : : {
32 : 16 : status = construct_path(db_filename,db_path);
33 : : }
34 : :
35 [ + - ]: 16 : if(SUCCESS == status)
36 : : {
37 : 16 : *db_out = NULL;
38 : :
39 [ - + ]: 16 : if(SQLITE_OK != sqlite3_open_v2(getcstring(db_path),db_out,open_flags,NULL))
40 : : {
41 : 0 : status = FAILURE;
42 : :
43 [ # # ]: 0 : if(*db_out != NULL)
44 : : {
45 : 0 : (void)sqlite3_close(*db_out);
46 : 0 : *db_out = NULL;
47 : : }
48 : : }
49 : : }
50 : :
51 : 16 : del(db_path);
52 : :
53 : 16 : return(status);
54 : : }
55 : :
56 : : /**
57 : : * @brief Verify that DB relative_path set matches expected list exactly
58 : : *
59 : : * @param[in] db_filename DB file name relative to TMPDIR
60 : : * @param[in] expected_paths Sorted expected relative_path values
61 : : * @param[in] expected_count Number of expected paths
62 : : *
63 : : * @return Return status code:
64 : : * - SUCCESS: DB rows match expected paths exactly
65 : : * - FAILURE: Mismatch or DB access error
66 : : */
67 : 10 : Return db_paths_match(
68 : : const char *db_filename,
69 : : const char *const *expected_paths,
70 : : const int expected_count)
71 : : {
72 : : /* Status returned by this function through provide()
73 : : Default value assumes successful completion */
74 : 10 : Return status = SUCCESS;
75 : 10 : sqlite3 *db = NULL;
76 : 10 : sqlite3_stmt *stmt = NULL;
77 : 10 : const char *sql = "SELECT relative_path FROM files ORDER BY relative_path ASC;";
78 : 10 : create(char,db_path);
79 : :
80 [ + - + - : 10 : if(SUCCESS == status && (db_filename == NULL || expected_paths == NULL || expected_count < 0))
+ - - + ]
81 : : {
82 : 0 : status = FAILURE;
83 : : }
84 : :
85 [ + - ]: 10 : if(SUCCESS == status)
86 : : {
87 : 10 : status = construct_path(db_filename,db_path);
88 : : }
89 : :
90 [ + - - + ]: 10 : if(SUCCESS == status && SQLITE_OK != sqlite3_open_v2(getcstring(db_path),&db,SQLITE_OPEN_READONLY,NULL))
91 : : {
92 : 0 : status = FAILURE;
93 : : }
94 : :
95 [ + - - + ]: 10 : if(SUCCESS == status && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
96 : : {
97 : 0 : status = FAILURE;
98 : : }
99 : :
100 : 10 : int index = 0;
101 : :
102 [ + - ]: 10 : if(SUCCESS == status)
103 : : {
104 : 10 : int rc = sqlite3_step(stmt);
105 : :
106 [ + + ]: 68 : while(rc == SQLITE_ROW)
107 : : {
108 [ - + ]: 58 : if(index >= expected_count)
109 : : {
110 : 0 : status = FAILURE;
111 : 0 : break;
112 : : }
113 : :
114 : 58 : const unsigned char *db_path_text = sqlite3_column_text(stmt,0);
115 : :
116 [ + - - + ]: 58 : if(db_path_text == NULL || strcmp((const char *)db_path_text,expected_paths[index]) != 0)
117 : : {
118 : 0 : status = FAILURE;
119 : 0 : break;
120 : : }
121 : :
122 : 58 : index++;
123 : 58 : rc = sqlite3_step(stmt);
124 : : }
125 : :
126 [ + - - + ]: 10 : if(SUCCESS == status && rc != SQLITE_DONE)
127 : : {
128 : 0 : status = FAILURE;
129 : : }
130 : : }
131 : :
132 [ + - - + ]: 10 : if(SUCCESS == status && index != expected_count)
133 : : {
134 : 0 : status = FAILURE;
135 : : }
136 : :
137 [ + - ]: 10 : if(stmt != NULL)
138 : : {
139 : 10 : (void)sqlite3_finalize(stmt);
140 : : }
141 : :
142 [ + - ]: 10 : if(db != NULL)
143 : : {
144 : 10 : (void)sqlite3_close(db);
145 : : }
146 : :
147 : 10 : del(db_path);
148 : :
149 : 10 : return(status);
150 : : }
151 : :
152 : : /**
153 : : * @brief Read number of rows from files table
154 : : *
155 : : * @param[in] db_filename Database filename relative to TMPDIR
156 : : * @param[out] count_out Output row count
157 : : *
158 : : * @return Return status code:
159 : : * - SUCCESS: Count value was read
160 : : * - FAILURE: Validation, DB access, or query execution failed
161 : : */
162 : 2 : Return db_read_files_count(
163 : : const char *db_filename,
164 : : int *count_out)
165 : : {
166 : : /* Status returned by this function through provide()
167 : : Default value assumes successful completion */
168 : 2 : Return status = SUCCESS;
169 : 2 : sqlite3 *db = NULL;
170 : 2 : sqlite3_stmt *stmt = NULL;
171 : 2 : const char *sql = "SELECT COUNT(*) FROM files;";
172 : :
173 [ + - - + ]: 2 : if(db_filename == NULL || count_out == NULL)
174 : : {
175 : 0 : status = FAILURE;
176 : : }
177 : :
178 [ + - ]: 2 : if(SUCCESS == status)
179 : : {
180 : 2 : status = open_db_from_tmpdir(db_filename,SQLITE_OPEN_READONLY,&db);
181 : : }
182 : :
183 [ + - - + ]: 2 : if(SUCCESS == status && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
184 : : {
185 : 0 : status = FAILURE;
186 : : }
187 : :
188 [ + - ]: 2 : if(SUCCESS == status)
189 : : {
190 : 2 : int rc = sqlite3_step(stmt);
191 : :
192 [ + - ]: 2 : if(SQLITE_ROW == rc)
193 : : {
194 : 2 : *count_out = sqlite3_column_int(stmt,0);
195 : 2 : rc = sqlite3_step(stmt);
196 : :
197 [ - + ]: 2 : if(SQLITE_DONE != rc)
198 : : {
199 : 0 : status = FAILURE;
200 : : }
201 : : } else {
202 : 0 : status = FAILURE;
203 : : }
204 : : }
205 : :
206 [ + - ]: 2 : if(stmt != NULL)
207 : : {
208 : 2 : (void)sqlite3_finalize(stmt);
209 : : }
210 : :
211 [ + - ]: 2 : if(db != NULL)
212 : : {
213 : 2 : (void)sqlite3_close(db);
214 : : }
215 : :
216 : 2 : return(status);
217 : : }
218 : :
219 : : /**
220 : : * @brief Read db_version value from metadata table
221 : : *
222 : : * @param[in] db_filename Database filename relative to TMPDIR
223 : : * @param[out] db_version_out Output database version
224 : : *
225 : : * @return Return status code:
226 : : * - SUCCESS: Version value was read
227 : : * - FAILURE: Validation, DB access, or query execution failed
228 : : */
229 : 10 : Return read_db_version_from_metadata(
230 : : const char *db_filename,
231 : : int *db_version_out)
232 : : {
233 : : /* Status returned by this function through provide()
234 : : Default value assumes successful completion */
235 : 10 : Return status = SUCCESS;
236 : 10 : sqlite3 *db = NULL;
237 : 10 : sqlite3_stmt *stmt = NULL;
238 : 10 : const char *sql = "SELECT db_version FROM metadata LIMIT 1;";
239 : :
240 [ + - - + ]: 10 : if(db_filename == NULL || db_version_out == NULL)
241 : : {
242 : 0 : status = FAILURE;
243 : : }
244 : :
245 [ + - ]: 10 : if(SUCCESS == status)
246 : : {
247 : 10 : status = open_db_from_tmpdir(db_filename,SQLITE_OPEN_READONLY,&db);
248 : : }
249 : :
250 [ + - - + ]: 10 : if(SUCCESS == status && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
251 : : {
252 : 0 : status = FAILURE;
253 : : }
254 : :
255 [ + - ]: 10 : if(SUCCESS == status)
256 : : {
257 : 10 : int rc = sqlite3_step(stmt);
258 : :
259 [ + - ]: 10 : if(SQLITE_ROW == rc)
260 : : {
261 : 10 : *db_version_out = sqlite3_column_int(stmt,0);
262 : 10 : rc = sqlite3_step(stmt);
263 : :
264 [ - + ]: 10 : if(SQLITE_DONE != rc)
265 : : {
266 : 0 : status = FAILURE;
267 : : }
268 : : } else {
269 : 0 : status = FAILURE;
270 : : }
271 : : }
272 : :
273 [ + - ]: 10 : if(stmt != NULL)
274 : : {
275 : 10 : (void)sqlite3_finalize(stmt);
276 : : }
277 : :
278 [ + - ]: 10 : if(db != NULL)
279 : : {
280 : 10 : (void)sqlite3_close(db);
281 : : }
282 : :
283 : 10 : return(status);
284 : : }
285 : :
286 : : /**
287 : : * @brief Read final offset and SHA512 checksum for one file from files table
288 : : *
289 : : * @param[in] db_filename Database filename relative to TMPDIR
290 : : * @param[in] relative_path Relative path key in files table
291 : : * @param[out] offset_out Output offset value, 0 when SQL value is NULL
292 : : * @param[out] sha512_out Output SHA512 bytes with SHA512_DIGEST_LENGTH size
293 : : *
294 : : * @return Return status code:
295 : : * - SUCCESS: Row was found and outputs were filled
296 : : * - FAILURE: Validation, DB access, missing row, or SHA512 blob size mismatch
297 : : */
298 : 2 : Return read_final_sha512_from_db(
299 : : const char *db_filename,
300 : : const char *relative_path,
301 : : sqlite3_int64 *offset_out,
302 : : unsigned char *sha512_out)
303 : : {
304 : : /* Status returned by this function through provide()
305 : : Default value assumes successful completion */
306 : 2 : Return status = SUCCESS;
307 : 2 : sqlite3 *db = NULL;
308 : 2 : sqlite3_stmt *stmt = NULL;
309 : 2 : const char *sql = "SELECT offset, sha512 FROM files WHERE relative_path = ?1;";
310 : :
311 [ + - ]: 2 : if(db_filename == NULL
312 [ + - ]: 2 : || relative_path == NULL
313 [ + - ]: 2 : || offset_out == NULL
314 [ - + ]: 2 : || sha512_out == NULL)
315 : : {
316 : 0 : status = FAILURE;
317 : : }
318 : :
319 [ + - ]: 2 : if(SUCCESS == status)
320 : : {
321 : 2 : status = open_db_from_tmpdir(db_filename,SQLITE_OPEN_READONLY,&db);
322 : : }
323 : :
324 [ + - - + ]: 2 : if((SUCCESS == status) && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
325 : : {
326 : 0 : status = FAILURE;
327 : : }
328 : :
329 [ + - - + ]: 2 : if((SUCCESS == status) && SQLITE_OK != sqlite3_bind_text(stmt,1,relative_path,(int)strlen(relative_path),SQLITE_TRANSIENT))
330 : : {
331 : 0 : status = FAILURE;
332 : : }
333 : :
334 [ + - ]: 2 : if(SUCCESS == status)
335 : : {
336 : 2 : const int step_rc = sqlite3_step(stmt);
337 [ - + ]: 2 : if(step_rc != SQLITE_ROW)
338 : : {
339 : 0 : status = FAILURE;
340 : : }
341 : : }
342 : :
343 [ + - ]: 2 : if(SUCCESS == status)
344 : : {
345 [ + - ]: 2 : if(sqlite3_column_type(stmt,0) == SQLITE_NULL)
346 : : {
347 : 2 : *offset_out = 0;
348 : : } else {
349 : 0 : *offset_out = sqlite3_column_int64(stmt,0);
350 : : }
351 : :
352 : 2 : const void *sha512_blob = sqlite3_column_blob(stmt,1);
353 : 2 : const int sha512_bytes = sqlite3_column_bytes(stmt,1);
354 : :
355 [ + - - + ]: 2 : if(sha512_blob == NULL || sha512_bytes != SHA512_DIGEST_LENGTH)
356 : : {
357 : 0 : status = FAILURE;
358 : : } else {
359 : 2 : memcpy(sha512_out,sha512_blob,(size_t)SHA512_DIGEST_LENGTH);
360 : : }
361 : :
362 : 2 : const int done_rc = sqlite3_step(stmt);
363 [ + - - + ]: 2 : if((SUCCESS == status) && done_rc != SQLITE_DONE)
364 : : {
365 : 0 : status = FAILURE;
366 : : }
367 : : }
368 : :
369 [ + - ]: 2 : if(stmt != NULL)
370 : : {
371 : 2 : (void)sqlite3_finalize(stmt);
372 : : }
373 : :
374 [ + - ]: 2 : if(db != NULL)
375 : : {
376 : 2 : (void)sqlite3_close(db);
377 : : }
378 : :
379 : 2 : return(status);
380 : : }
381 : :
382 : : /**
383 : : * @brief Set files.sha512 to NULL for one row in the database
384 : : *
385 : : * @param[in] db_filename Database filename relative to TMPDIR
386 : : * @param[in] relative_path Relative path key in files table
387 : : *
388 : : * @return Return status code:
389 : : * - SUCCESS: SHA512 value was set to NULL for at least one row
390 : : * - FAILURE: Validation, DB access, bind, step, or change check failed
391 : : */
392 : 2 : Return db_set_sha512_to_null(
393 : : const char *db_filename,
394 : : const char *relative_path)
395 : : {
396 : : /* Status returned by this function through provide()
397 : : Default value assumes successful completion */
398 : 2 : Return status = SUCCESS;
399 : 2 : sqlite3 *db = NULL;
400 : 2 : sqlite3_stmt *stmt = NULL;
401 : 2 : const char *sql = "UPDATE files SET sha512 = NULL WHERE relative_path = ?1;";
402 : :
403 [ + - - + ]: 2 : if(db_filename == NULL || relative_path == NULL)
404 : : {
405 : 0 : status = FAILURE;
406 : : }
407 : :
408 [ + - ]: 2 : if(SUCCESS == status)
409 : : {
410 : 2 : status = open_db_from_tmpdir(db_filename,SQLITE_OPEN_READWRITE,&db);
411 : : }
412 : :
413 [ + - - + ]: 2 : if(SUCCESS == status && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
414 : : {
415 : 0 : status = FAILURE;
416 : : }
417 : :
418 [ + - - + ]: 2 : if(SUCCESS == status && SQLITE_OK != sqlite3_bind_text(stmt,1,relative_path,(int)strlen(relative_path),SQLITE_TRANSIENT))
419 : : {
420 : 0 : status = FAILURE;
421 : : }
422 : :
423 [ + - - + ]: 2 : if(SUCCESS == status && SQLITE_DONE != sqlite3_step(stmt))
424 : : {
425 : 0 : status = FAILURE;
426 : : }
427 : :
428 [ + - - + ]: 2 : if(SUCCESS == status && sqlite3_changes(db) < 1)
429 : : {
430 : 0 : status = FAILURE;
431 : : }
432 : :
433 [ + - ]: 2 : if(stmt != NULL)
434 : : {
435 : 2 : (void)sqlite3_finalize(stmt);
436 : : }
437 : :
438 [ + - ]: 2 : if(db != NULL)
439 : : {
440 : 2 : (void)sqlite3_close(db);
441 : : }
442 : :
443 : 2 : return(status);
444 : : }
445 : :
446 : : /**
447 : : * @brief Read intermediate offset and mdContext size for one file from DB
448 : : *
449 : : * @param[in] db_filename DB file name relative to TMPDIR
450 : : * @param[in] relative_path File path in DB relative_path column
451 : : * @param[out] offset_out Output offset value from files table
452 : : * @param[out] md_context_bytes_out Output byte size of mdContext column
453 : : *
454 : : * @return Return status code:
455 : : * - SUCCESS: Row was found and outputs were filled
456 : : * - FAILURE: Validation, DB access, or row parsing failed
457 : : */
458 : 4 : Return read_resume_state_from_db(
459 : : const char *db_filename,
460 : : const char *relative_path,
461 : : sqlite3_int64 *offset_out,
462 : : int *md_context_bytes_out)
463 : : {
464 : : /* Status returned by this function through provide()
465 : : Default value assumes successful completion */
466 : 4 : Return status = SUCCESS;
467 : 4 : sqlite3 *db = NULL;
468 : 4 : sqlite3_stmt *stmt = NULL;
469 : 4 : const char *sql = "SELECT offset, mdContext FROM files WHERE relative_path = ?1;";
470 : 4 : create(char,db_path);
471 : :
472 [ + - + - ]: 4 : if(SUCCESS == status && (db_filename == NULL
473 [ + - ]: 4 : || relative_path == NULL
474 [ + - ]: 4 : || offset_out == NULL
475 [ - + ]: 4 : || md_context_bytes_out == NULL))
476 : : {
477 : 0 : status = FAILURE;
478 : : }
479 : :
480 [ + - ]: 4 : if(SUCCESS == status)
481 : : {
482 : 4 : status = construct_path(db_filename,db_path);
483 : : }
484 : :
485 [ + - - + ]: 4 : if(SUCCESS == status && SQLITE_OK != sqlite3_open_v2(getcstring(db_path),&db,SQLITE_OPEN_READONLY,NULL))
486 : : {
487 : 0 : status = FAILURE;
488 : : }
489 : :
490 [ + - - + ]: 4 : if(SUCCESS == status && SQLITE_OK != sqlite3_prepare_v2(db,sql,-1,&stmt,NULL))
491 : : {
492 : 0 : status = FAILURE;
493 : : }
494 : :
495 [ + - - + ]: 4 : if(SUCCESS == status && SQLITE_OK != sqlite3_bind_text(stmt,1,relative_path,(int)strlen(relative_path),SQLITE_TRANSIENT))
496 : : {
497 : 0 : status = FAILURE;
498 : : }
499 : :
500 [ + - ]: 4 : if(SUCCESS == status)
501 : : {
502 : 4 : const int step_rc = sqlite3_step(stmt);
503 [ - + ]: 4 : if(step_rc != SQLITE_ROW)
504 : : {
505 : 0 : status = FAILURE;
506 : : }
507 : : }
508 : :
509 [ + - ]: 4 : if(SUCCESS == status)
510 : : {
511 [ - + ]: 4 : if(sqlite3_column_type(stmt,0) == SQLITE_NULL)
512 : : {
513 : 0 : *offset_out = 0;
514 : : } else {
515 : 4 : *offset_out = sqlite3_column_int64(stmt,0);
516 : : }
517 : :
518 : 4 : *md_context_bytes_out = sqlite3_column_bytes(stmt,1);
519 : :
520 : 4 : const int done_rc = sqlite3_step(stmt);
521 [ - + ]: 4 : if(done_rc != SQLITE_DONE)
522 : : {
523 : 0 : status = FAILURE;
524 : : }
525 : : }
526 : :
527 [ + - ]: 4 : if(stmt != NULL)
528 : : {
529 : 4 : (void)sqlite3_finalize(stmt);
530 : : }
531 : :
532 [ + - ]: 4 : if(db != NULL)
533 : : {
534 : 4 : (void)sqlite3_close(db);
535 : : }
536 : :
537 : 4 : del(db_path);
538 : :
539 : 4 : return(status);
540 : : }
|