1 /*
2 *
3 * The Sleuth Kit
4 *
5 * Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
6 * Copyright (c) 2010-2012 Basis Technology Corporation. All Rights
7 * reserved.
8 *
9 * This software is distributed under the Common Public License 1.0
10 */
11
12 /**
13 * \file TskImgDBSqlite.cpp
14 * A SQLite based implementation of the framework data access layer.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <cassert>
20 #include <iostream>
21 #include <sstream>
22 #include <iomanip>
23 #include <map>
24 #include <assert.h>
25
26 #include "Poco/UnicodeConverter.h"
27 #include "Poco/Thread.h"
28
29 #include "TskImgDBSqlite.h"
30 #include "TskServices.h"
31 #include "tsk/framework/utilities/TskException.h"
32 #include "TskDBBlackboard.h"
33
34 #include "Poco/UnicodeConverter.h"
35 #include "Poco/NumberParser.h"
36 #include "Poco/Path.h"
37
38 #define IMGDB_CHUNK_SIZE 1024*1024*1 // what size chunks should the database use when growing and shrinking
39 #define IMGDB_MAX_RETRY_COUNT 50 // how many times will we retry a SQL statement
40 #define IMGDB_RETRY_WAIT 100 // how long (in milliseconds) are we willing to wait between retries
41
42 /**
43 * Set the database location. Must call
44 * initialize() before the object can be used.
45 * @param a_outpath Directory to store the database in. This
46 * directory must already exist.
47 */
TskImgDBSqlite(const char * a_outpath)48 TskImgDBSqlite::TskImgDBSqlite(const char * a_outpath)
49 {
50 strncpy(m_outPath, a_outpath, 256);
51 // ensure that the path ends with a '/'
52 if (m_outPath[strlen(m_outPath)-1] != '/') {
53 int len1 = strlen(m_outPath);
54 m_outPath[len1] = '/';
55 m_outPath[len1+1] = '\0';
56 }
57 strncpy(m_dbFilePath, m_outPath, 256);
58 strncat(m_dbFilePath, "image.db", 256);
59 m_db = NULL;
60 }
61
~TskImgDBSqlite()62 TskImgDBSqlite::~TskImgDBSqlite()
63 {
64 (void) close();
65 }
66
close()67 int TskImgDBSqlite::close()
68 {
69 if (m_db) {
70 if (sqlite3_close(m_db) == SQLITE_OK)
71 m_db = NULL;
72 else
73 return 1;
74 }
75 return 0;
76 }
77
dropTables()78 int TskImgDBSqlite::dropTables()
79 {
80 if (!m_db)
81 return 1;
82
83 char * errmsg;
84 // Drop all the tables. No error checking just Teutonic Destruction...
85 sqlite3_exec(m_db, "DROP TABLE db_info",NULL, NULL, &errmsg);
86 sqlite3_exec(m_db, "DROP TABLE image_info",NULL, NULL, &errmsg);
87 sqlite3_exec(m_db, "DROP TABLE image_names",NULL, NULL, &errmsg);
88 sqlite3_exec(m_db, "DROP TABLE vol_info",NULL, NULL, &errmsg);
89 sqlite3_exec(m_db, "DROP TABLE fs_info",NULL, NULL, &errmsg);
90 sqlite3_exec(m_db, "DROP TABLE fs_files",NULL, NULL, &errmsg);
91 sqlite3_exec(m_db, "DROP TABLE fs_blocks",NULL, NULL, &errmsg);
92 sqlite3_exec(m_db, "DROP TABLE files",NULL, NULL, &errmsg);
93 sqlite3_exec(m_db, "DROP TABLE derived_files",NULL, NULL, &errmsg);
94 sqlite3_exec(m_db, "DROP TABLE carved_files",NULL, NULL, &errmsg);
95 sqlite3_exec(m_db, "DROP TABLE carved_sectors",NULL, NULL, &errmsg);
96 sqlite3_exec(m_db, "DROP TABLE alloc_unalloc_map", NULL, NULL, &errmsg);
97 sqlite3_exec(m_db, "DROP TABLE blackboard_artifacts", NULL, NULL, &errmsg);
98 sqlite3_exec(m_db, "DROP TABLE blackboard_attributes", NULL, NULL, &errmsg);
99 sqlite3_exec(m_db, "DROP TABLE blackboard_artifact_types", NULL, NULL, &errmsg);
100 sqlite3_exec(m_db, "DROP TABLE blackboard_attribute_types", NULL, NULL, &errmsg);
101 sqlite3_exec(m_db, "DROP TABLE file_hashes", NULL, NULL, &errmsg);
102 sqlite3_exec(m_db, "DROP TABLE modules", NULL, NULL, &errmsg);
103 sqlite3_exec(m_db, "DROP TABLE module_status", NULL, NULL, &errmsg);
104 sqlite3_exec(m_db, "DROP TABLE unalloc_img_status", NULL, NULL, &errmsg);
105 sqlite3_exec(m_db, "DROP TABLE unused_sectors", NULL, NULL, &errmsg);
106 sqlite3_exec(m_db, "DROP INDEX attrs_artifact_id", NULL, NULL, &errmsg);
107 sqlite3_exec(m_db, "DROP INDEX attrs_attribute_type", NULL, NULL, &errmsg);
108 sqlite3_exec(m_db, "DROP INDEX attrs_obj_id", NULL, NULL, &errmsg);
109
110 return 0;
111 }
112
initialize()113 int TskImgDBSqlite::initialize()
114 {
115 std::wstringstream infoMessage;
116 char * errmsg;
117
118 // Open the database.
119 if (open() != 0)
120 {
121 // Error message will have been logged by open()
122 return 1;
123 }
124
125 // Clean up the whole database.
126 dropTables();
127
128 std::string stmt;
129
130 sqlite3_stmt *statement;
131
132 // set page size -- 4k is much faster on Windows than the default
133 executeStatement("PRAGMA page_size = 4096;", statement, "TskImgDBSqlite::initialize");
134 sqlite3_finalize(statement);
135
136 // we don't have a mechanism to recover from a crash anyway
137 executeStatement("PRAGMA synchronous = 0;", statement, "TskImgDBSqlite::initialize");
138 sqlite3_finalize(statement);
139
140 // ----- DB_INFO
141 stmt = "CREATE TABLE db_info (name TEXT PRIMARY KEY, version TEXT)";
142 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
143 infoMessage << L"TskImgDBSqlite::initialize - Error creating db_info table: " << errmsg;
144 LOGERROR(infoMessage.str());
145
146 sqlite3_free(errmsg);
147 return 1;
148 }
149
150 // ----- IMAGE_INFO
151 stmt = "CREATE TABLE image_info (type INTEGER, ssize INTEGER)";
152 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
153 infoMessage << L"TskImgDBSqlite::initialize - Error creating image_info table: " << errmsg;
154 LOGERROR(infoMessage.str());
155
156 sqlite3_free(errmsg);
157 return 1;
158 }
159
160 // ----- IMAGE_NAMES
161 stmt = "CREATE TABLE image_names (seq INTEGER PRIMARY KEY, name TEXT)";
162 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
163 infoMessage << L"TskImgDBSqlite::initialize - Error creating image_names table: " << errmsg;
164 LOGERROR(infoMessage.str());
165
166 sqlite3_free(errmsg);
167 return 1;
168 }
169
170 // ----- VOL_INFO
171 stmt = "CREATE TABLE vol_info (vol_id INTEGER PRIMARY KEY, sect_start INTEGER NOT NULL, "
172 "sect_len INTEGER NOT NULL, description TEXT, flags INTEGER)";
173 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
174 infoMessage << L"TskImgDBSqlite::initialize - Error creating vol_info table: " << errmsg;
175 LOGERROR(infoMessage.str());
176
177 sqlite3_free(errmsg);
178 return 1;
179 }
180
181 // ----- FS_INFO
182 stmt = "CREATE TABLE fs_info (fs_id INTEGER PRIMARY KEY, img_byte_offset INTEGER, "
183 "vol_id INTEGER NOT NULL, fs_type INTEGER, block_size INTEGER, "
184 "block_count INTEGER, root_inum INTEGER, first_inum INTEGER, last_inum INTEGER)";
185 if (sqlite3_exec(m_db, stmt.c_str() , NULL, NULL, &errmsg) != SQLITE_OK) {
186 infoMessage << L"TskImgDBSqlite::initialize - Error creating fs_info table: " << errmsg;
187 LOGERROR(infoMessage.str());
188
189 sqlite3_free(errmsg);
190 return 1;
191 }
192
193 // ----- FILES
194 stmt = "CREATE TABLE files (file_id INTEGER PRIMARY KEY, type_id INTEGER, "
195 "name TEXT, par_file_id INTEGER, dir_type INTEGER, meta_type INTEGER, "
196 "dir_flags INTEGER, meta_flags INTEGER, size INTEGER, ctime INTEGER, "
197 "crtime INTEGER, atime INTEGER, mtime INTEGER, mode INTEGER, uid INTEGER, "
198 "gid INTEGER, status INTEGER, full_path TEXT)";
199 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
200 infoMessage << L"TskImgDBSqlite::initialize - Error creating files table: " << errmsg;
201 LOGERROR(infoMessage.str());
202
203 sqlite3_free(errmsg);
204 return 1;
205 }
206
207 // ----- FS_FILES
208 stmt = "CREATE TABLE fs_files (file_id INTEGER PRIMARY KEY, fs_id INTEGER, "
209 "fs_file_id INTEGER, attr_type INTEGER, attr_id INTEGER)";
210 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
211 {
212 infoMessage << L"TskImgDBSqlite::initialize - Error creating fs_files table: " << errmsg;
213 LOGERROR(infoMessage.str());
214
215 sqlite3_free(errmsg);
216 return 1;
217 }
218
219 // ----- FS_BLOCKS
220 stmt = "CREATE TABLE fs_blocks (fs_id INTEGER NOT NULL, file_id INTEGER NOT NULL, seq INTEGER, "
221 "blk_start INTEGER NOT NULL, blk_len INTEGER NOT NULL)";
222 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
223 {
224 infoMessage << L"TskImgDBSqlite::initialize - Error creating fs_blocks table: " << errmsg;
225 LOGERROR(infoMessage.str());
226
227 sqlite3_free(errmsg);
228 return 1;
229 }
230
231 // ----- CARVED_FILES
232 stmt = "CREATE TABLE carved_files (file_id INTEGER PRIMARY KEY, vol_id INTEGER)";
233 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
234 {
235 infoMessage << L"TskImgDBSqlite::initialize - Error creating carved_files table: " << errmsg;
236 LOGERROR(infoMessage.str());
237
238 sqlite3_free(errmsg);
239 return 1;
240 }
241
242 // ----- SECTOR_LIST
243 stmt = "CREATE TABLE carved_sectors ("
244 "file_id INTEGER, seq INTEGER, sect_start INTEGER, sect_len INTEGER)";
245 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
246 {
247 infoMessage << L"TskImgDBSqlite::initialize - Error creating carved_sectors table: " << errmsg;
248 LOGERROR(infoMessage.str());
249
250 sqlite3_free(errmsg);
251 return 1;
252 }
253
254 // ----- DERIVED_FILES
255 stmt = "CREATE TABLE derived_files (file_id INTEGER PRIMARY KEY, derivation_details TEXT)";
256 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
257 {
258 infoMessage << L"TskImgDBSqlite::initialize - Error creating derived_files table: " << errmsg;
259 LOGERROR(infoMessage.str());
260
261 sqlite3_free(errmsg);
262 return 1;
263 }
264
265 // ----- ALLOC_UNALLOC_MAP
266 stmt = "CREATE TABLE alloc_unalloc_map (vol_id INTEGER, unalloc_img_id INTEGER, "
267 "unalloc_img_sect_start INTEGER, sect_len INTEGER, orig_img_sect_start INTEGER)";
268 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
269 {
270 infoMessage << L"TskImgDBSqlite::initialize - Error creating alloc_unalloc_map table: " << errmsg;
271 LOGERROR(infoMessage.str());
272
273 sqlite3_free(errmsg);
274 return 1;
275 }
276
277 // ----- FILE_HASHES
278 stmt = "CREATE TABLE file_hashes (file_id INTEGER PRIMARY KEY, md5 TEXT, sha1 TEXT, sha2_256 TEXT, sha2_512 TEXT, known INTEGER)";
279 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
280 infoMessage << L"TskImgDBSqlite::initialize - Error creating file_hashes table: " << errmsg;
281 LOGERROR(infoMessage.str());
282
283 sqlite3_free(errmsg);
284 return 1;
285 }
286
287 // ----- MODULES
288 stmt = "CREATE TABLE modules (module_id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, description TEXT)";
289 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
290 infoMessage << L"TskImgDBSqlite::initialize - Error creating module table: " << errmsg;
291 LOGERROR(infoMessage.str());
292
293 sqlite3_free(errmsg);
294 return 1;
295 }
296
297 // ----- MODULE_STATUS
298 stmt = "CREATE TABLE module_status (file_id INTEGER, module_id INTEGER, status INTEGER, PRIMARY KEY (file_id, module_id))";
299 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
300 infoMessage << L"TskImgDBSqlite::initialize - Error creating module_status table: " << errmsg;
301 LOGERROR(infoMessage.str());
302
303 sqlite3_free(errmsg);
304 return 1;
305 }
306
307 // ----- UNALLOC_IMG_STATUS
308 stmt = "CREATE TABLE unalloc_img_status (unalloc_img_id INTEGER PRIMARY KEY, status INTEGER)";
309 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
310 infoMessage << L"TskImgDBSqlite::initialize - Error creating unalloc_img_status table: " << errmsg;
311 LOGERROR(infoMessage.str());
312
313 sqlite3_free(errmsg);
314 return 1;
315 }
316
317 // ----- UNUSED_SECTORS
318 stmt = "CREATE TABLE unused_sectors (file_id INTEGER PRIMARY KEY, sect_start INTEGER, sect_len INTEGER, vol_id INTEGER)";
319 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
320 infoMessage << L"TskImgDBSqlite::initialize - Error creating unused_sectors table: " << errmsg;
321 LOGERROR(infoMessage.str());
322
323 sqlite3_free(errmsg);
324 return 1;
325 }
326
327 // ----- BLACKBOARD_ARTIFACTS
328 stmt = "CREATE TABLE blackboard_artifacts (artifact_id INTEGER PRIMARY KEY, obj_id INTEGER NOT NULL, artifact_type_id INTEGER)";
329 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
330 infoMessage << L"TskImgDBSqlite::initialize - Error creating blackboard_artifacts table: " << errmsg;
331 LOGERROR(infoMessage.str());
332
333 sqlite3_free(errmsg);
334 return 1;
335 }
336
337 // ----- BLACKBOARD_ATTRIBUTES
338 stmt = "CREATE TABLE blackboard_attributes (artifact_id INTEGER NOT NULL, source TEXT, context TEXT, attribute_type_id INTEGER NOT NULL, value_type INTEGER NOT NULL, "
339 "value_byte BLOB, value_text TEXT, value_int32 INTEGER, value_int64 INTEGER, value_double NUMERIC(20, 10), obj_id INTEGER NOT NULL)";
340 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
341 infoMessage << L"TskImgDBSqlite::initialize - Error creating blackboard_attributes table: " << errmsg;
342 LOGERROR(infoMessage.str());
343
344 sqlite3_free(errmsg);
345 return 1;
346 }
347
348 // ----- BLACKBOARD_ARTIFACT_TYPES
349 stmt = "CREATE TABLE blackboard_artifact_types (artifact_type_id INTEGER PRIMARY KEY, type_name TEXT, display_name TEXT)";
350 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
351 infoMessage << L"TskImgDBSqlite::initialize - Error creating blackboard_artifact_types table: " << errmsg;
352 LOGERROR(infoMessage.str());
353
354 sqlite3_free(errmsg);
355 return 1;
356 }
357
358 // ----- BLACKBOARD_ATTRIBUTE_TYPES
359 stmt = "CREATE TABLE blackboard_attribute_types (attribute_type_id INTEGER PRIMARY KEY, type_name TEXT, display_name TEXT)";
360 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
361 infoMessage << L"TskImgDBSqlite::initialize - Error creating blackboard_attribute_types table: " << errmsg;
362 LOGERROR(infoMessage.str());
363
364 sqlite3_free(errmsg);
365 return 1;
366 }
367
368 // ----- CREATE INDEXES
369 stmt = "CREATE INDEX attrs_artifact_id ON blackboard_attributes(artifact_id)";
370 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
371 infoMessage << L"TskImgDBSqlite::initialize - Error creating attrs_artifact_id index: " << errmsg;
372 LOGERROR(infoMessage.str());
373
374 sqlite3_free(errmsg);
375 return 1;
376 }
377
378 stmt = "CREATE INDEX attrs_attribute_type ON blackboard_attributes(attribute_type_id)";
379 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
380 infoMessage << L"TskImgDBSqlite::initialize - Error creating attrs_attribute_type index: " << errmsg;
381 LOGERROR(infoMessage.str());
382
383 sqlite3_free(errmsg);
384 return 1;
385 }
386
387 stmt = "CREATE INDEX attrs_obj_id ON blackboard_attributes(obj_id)";
388 if (sqlite3_exec(m_db, stmt.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
389 infoMessage << L"TskImgDBSqlite::initialize - Error creating attrs_obj_id index: " << errmsg;
390 LOGERROR(infoMessage.str());
391
392 sqlite3_free(errmsg);
393 return 1;
394 }
395
396 map<int, TskArtifactNames> artTypes = TskImgDB::getAllArtifactTypes();
397 for (map<int, TskArtifactNames>::iterator it = artTypes.begin(); it != artTypes.end(); it++) {
398 addArtifactType(it->first, it->second.typeName, it->second.displayName);
399 }
400 map<int, TskAttributeNames> attrTypes = TskImgDB::getAllAttributeTypes();
401 for (map<int, TskAttributeNames>::iterator it = attrTypes.begin(); it != attrTypes.end(); it++) {
402 addAttributeType(it->first, it->second.typeName, it->second.displayName);
403 }
404
405 addToolInfo("DBSchema", IMGDB_SCHEMA_VERSION);
406 LOGINFO(L"ImgDB Created.");
407
408 return 0;
409 }
410
411 /*
412 * If the database file exists this method will open it otherwise
413 * it will create a new database.
414 * This method also configures the chunk size and the busy handler
415 * for the newly opened database.
416 */
open()417 int TskImgDBSqlite::open()
418 {
419 std::wstringstream infoMessage;
420
421 #if 0
422 if (sqlite3_open16(m_dbFilePath, &m_db))
423 #else
424 if (sqlite3_open(m_dbFilePath, &m_db))
425 #endif
426 {
427 infoMessage << L"TskImgDBSqlite::open - Can't create new database: " << sqlite3_errmsg(m_db);
428 LOGERROR(infoMessage.str());
429
430 sqlite3_close(m_db);
431 return 1;
432 }
433
434 // The chunk size setting defines by how much the database will grow
435 // or shrink. The primary motivation behind this setting is to reduce
436 // database file fragmentation and potential performance improvements.
437 // We, however, are using this setting as a workaround for database
438 // corruption issues we have been experiencing when the database is
439 // updated by multiple concurrent processes.
440 // Database corruption was occurring when SQLite determined that the
441 // number of database pages in the database was greater than a value
442 // that it had previously cached.
443 // This workaround is a crude mechanism to get around that situation.
444 int chunkSize = IMGDB_CHUNK_SIZE;
445
446 if (sqlite3_file_control(m_db, NULL, SQLITE_FCNTL_CHUNK_SIZE, &chunkSize) != SQLITE_OK)
447 {
448 infoMessage << L"TskImgDBSqlite::open - Failed to set chunk size: " << sqlite3_errmsg(m_db);
449 LOGERROR(infoMessage.str());
450
451 sqlite3_close(m_db);
452 return 1;
453 }
454
455 // Register a busy handler that will retry statements in situations
456 // where the database is locked by another process.
457 if (sqlite3_busy_handler(m_db, TskImgDBSqlite::busyHandler, m_db) != SQLITE_OK)
458 {
459 infoMessage << L"TskImgDBSqlite::open - Failed to set busy handler: " << sqlite3_errmsg(m_db);
460 LOGERROR(infoMessage.str());
461
462 sqlite3_close(m_db);
463 return 1;
464 }
465
466 LOGINFO(L"ImgDB Opened.");
467
468 return 0;
469 }
470
addToolInfo(const char * name,const char * version)471 int TskImgDBSqlite::addToolInfo(const char* name, const char* version)
472 {
473 char *errmsg;
474 char stmt[1024];
475
476 if (!m_db)
477 return 1;
478
479 sqlite3_snprintf(1024, stmt,
480 "INSERT INTO db_info (name, version) VALUES ('%q', '%q');",
481 name, version);
482 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
483 {
484 std::wstringstream infoMessage;
485 infoMessage << L"TskImgDBSqlite::addToolInfo - Error adding data to db_info table: " << errmsg;
486 LOGERROR(infoMessage.str());
487
488 sqlite3_free(errmsg);
489 return 1;
490 }
491
492 return 0;
493 }
494
addImageInfo(int type,int size)495 int TskImgDBSqlite::addImageInfo(int type, int size)
496 {
497 char *errmsg;
498 std::stringstream stmt;
499
500 if (!m_db)
501 return 1;
502
503 stmt << "INSERT INTO image_info (type, ssize) VALUES ("<< type << ", " << size << ");";
504 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK)
505 {
506 std::wstringstream infoMessage;
507 infoMessage << L"TskImgDBSqlite::addImageInfo - Error adding data to image_info table: " << errmsg;
508 LOGERROR(infoMessage.str());
509
510 sqlite3_free(errmsg);
511 return 1;
512 }
513
514 return 0;
515 }
516
addImageName(char const * imgPath)517 int TskImgDBSqlite::addImageName(char const *imgPath)
518 {
519 char *errmsg;
520 char stmt[1024];
521
522 if (!m_db)
523 return 1;
524
525 sqlite3_snprintf(1024, stmt,
526 "INSERT INTO image_names (seq, name) VALUES (NULL, '%q')",
527 imgPath);
528 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
529 {
530 std::wstringstream infoMessage;
531 infoMessage << L"TskImgDBSqlite::addImageName - Error adding data to image_names table: " << errmsg;
532 LOGERROR(infoMessage.str());
533
534 sqlite3_free(errmsg);
535 return 1;
536 }
537 return 0;
538 }
539
540 /*
541 * Adds the sector addresses of the volumes into the db.
542 */
addVolumeInfo(const TSK_VS_PART_INFO * vs_part)543 int TskImgDBSqlite::addVolumeInfo(const TSK_VS_PART_INFO * vs_part)
544 {
545 char stmt[1024];
546 char * errmsg;
547
548 if (!m_db)
549 return 1;
550
551 sqlite3_snprintf(1024, stmt,
552 "INSERT INTO vol_info (vol_id, sect_start, sect_len, description, flags) VALUES (%d,%"
553 PRIuOFF ",%" PRIuOFF ",'%q',%d)", (int)vs_part->addr,
554 vs_part->start, vs_part->len, vs_part->desc, vs_part->flags);
555
556 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK) {
557 std::wstringstream infoMessage;
558 infoMessage << L"TskImgDBSqlite::addVolumeInfo - Error adding data to vol_info table: " << errmsg;
559 LOGERROR(infoMessage.str());
560
561 sqlite3_free(errmsg);
562 return 1;
563 }
564
565 return 0;
566 }
567
addFsInfo(int volId,int fsId,const TSK_FS_INFO * fs_info)568 int TskImgDBSqlite::addFsInfo(int volId, int fsId, const TSK_FS_INFO * fs_info)
569 {
570 std::stringstream stmt;
571 char * errmsg;
572
573 if (!m_db)
574 return 1;
575
576 stmt <<
577 "INSERT INTO fs_info (fs_id, img_byte_offset, vol_id, fs_type, block_size, "
578 "block_count, root_inum, first_inum, last_inum) VALUES (" <<
579 fsId << ", " << fs_info->offset << ", " << volId << ", " <<
580 (int)fs_info->ftype << ", " << fs_info->block_size << ", " << fs_info->block_count << ", " <<
581 fs_info->root_inum << ", " << fs_info->first_inum << ", " << fs_info->last_inum << ")";
582
583 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
584 std::wstringstream infoMessage;
585 infoMessage << L"TskImgDBSqlite::addFsInfo - Error adding data to fs_info table: " << errmsg;
586 LOGERROR(infoMessage.str());
587
588 sqlite3_free(errmsg);
589 return 1;
590 }
591
592 return 0;
593 }
594
595
596 /**
597 * Given a file system and fs_file_id, return the file_id.
598 */
getFileId(int a_fsId,uint64_t a_fsFileId) const599 uint64_t TskImgDBSqlite::getFileId(int a_fsId, uint64_t a_fsFileId) const
600 {
601 if (!m_db)
602 return 0;
603
604 sqlite3_stmt * statement;
605 std::stringstream stmt;
606 uint64_t fileId = 0;
607 stmt << "SELECT file_id FROM fs_files WHERE fs_id=" << a_fsId << " and fs_file_id=" << a_fsFileId << ";";
608
609 /********** FIND the unallocated volumes *************/
610 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
611 int result = sqlite3_step(statement);
612 if (result == SQLITE_ROW) {
613 fileId = (uint64_t)sqlite3_column_int64(statement, 0);
614 }
615 sqlite3_finalize(statement);
616 }
617 else {
618 std::wstringstream infoMessage;
619 infoMessage << L"TskImgDBSqlite::getFileId - Error querying fs_files table: " << sqlite3_errmsg(m_db);
620 LOGERROR(infoMessage.str());
621
622 return 0;
623 }
624 return fileId;
625 }
626
627
getFileRecord(const uint64_t fileId,TskFileRecord & fileRecord) const628 int TskImgDBSqlite::getFileRecord(const uint64_t fileId, TskFileRecord& fileRecord) const
629 {
630 if (!m_db)
631 return -1;
632
633 int ret = 0;
634
635 sqlite3_stmt * statement;
636 std::stringstream stmt;
637
638 stmt << "SELECT f.file_id, f.type_id, f.name, f.par_file_id, f.dir_type, f.meta_type, f.dir_flags, "
639 << "f.meta_flags, f.size, f.ctime, f.crtime, f.atime, f.mtime, f.mode, f.uid, f.gid, f.status, f.full_path, "
640 << "fh.md5, fh.sha1, fh.sha2_256, fh.sha2_512 "
641 << "FROM files f LEFT OUTER JOIN file_hashes fh ON f.file_id = fh.file_id WHERE f.file_id=" << fileId;
642
643 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK)
644 {
645 int result = sqlite3_step(statement);
646
647 if (result == SQLITE_ROW)
648 {
649 fileRecord.fileId = sqlite3_column_int64(statement, 0);
650 fileRecord.typeId = (TskImgDB::FILE_TYPES)sqlite3_column_int(statement, 1);
651 fileRecord.name = (char *)sqlite3_column_text(statement, 2);
652 fileRecord.parentFileId = sqlite3_column_int64(statement, 3);
653 fileRecord.dirType = (TSK_FS_NAME_TYPE_ENUM) sqlite3_column_int(statement, 4);
654 fileRecord.metaType = (TSK_FS_META_TYPE_ENUM) sqlite3_column_int(statement, 5);
655 fileRecord.dirFlags = (TSK_FS_NAME_FLAG_ENUM) sqlite3_column_int(statement, 6);
656 fileRecord.metaFlags = (TSK_FS_META_FLAG_ENUM) sqlite3_column_int(statement, 7);
657 fileRecord.size = sqlite3_column_int64(statement, 8);
658 fileRecord.ctime = sqlite3_column_int(statement, 9);
659 fileRecord.crtime = sqlite3_column_int(statement, 10);
660 fileRecord.atime = sqlite3_column_int(statement, 11);
661 fileRecord.mtime = sqlite3_column_int(statement, 12);
662 fileRecord.mode = (TSK_FS_META_MODE_ENUM)sqlite3_column_int(statement, 13);
663 fileRecord.uid = sqlite3_column_int(statement, 14);
664 fileRecord.gid = sqlite3_column_int(statement, 15);
665 fileRecord.status = (TskImgDB::FILE_STATUS) sqlite3_column_int(statement, 16);
666 fileRecord.fullPath = (char *)sqlite3_column_text(statement, 17);
667
668 if (sqlite3_column_type(statement, 18) == SQLITE_TEXT)
669 fileRecord.md5 = (char *)sqlite3_column_text(statement, 18);
670 if (sqlite3_column_type(statement, 19) == SQLITE_TEXT)
671 fileRecord.sha1 = (char *)sqlite3_column_text(statement, 19);
672 if (sqlite3_column_type(statement, 20) == SQLITE_TEXT)
673 fileRecord.sha2_256 = (char *)sqlite3_column_text(statement, 20);
674 if (sqlite3_column_type(statement, 21) == SQLITE_TEXT)
675 fileRecord.sha2_512 = (char *)sqlite3_column_text(statement, 21);
676 }
677 else
678 {
679 std::wstringstream msg;
680 msg << L"TskImgDBSqlite::getFileRecord - Error querying files table for file id: " << fileId;
681 LOGERROR(msg.str());
682
683 ret = -1;
684 }
685 sqlite3_finalize(statement);
686 }
687 else
688 {
689 std::wstringstream msg;
690 msg << L"TskImgDBSqlite::getFileRecord - Error querying files table for file id: " << fileId;
691 LOGERROR(msg.str());
692
693 ret = -1;
694 }
695
696 return ret;
697 }
698
addFsFileInfo(int fileSystemID,const TSK_FS_FILE * fileSystemFile,const char * fileName,int fileSystemAttrType,int fileSystemAttrID,uint64_t & fileID,const char * filePath)699 int TskImgDBSqlite::addFsFileInfo(int fileSystemID, const TSK_FS_FILE *fileSystemFile, const char *fileName, int fileSystemAttrType, int fileSystemAttrID, uint64_t &fileID, const char *filePath)
700 {
701 const std::string msgPrefix = "TskImgDBSqlite::addFsFileInfo : ";
702 fileID = 0;
703
704 if (!m_db)
705 {
706 return -1;
707 }
708
709 // Construct the full path of the file within the image.
710 std::string fullpath(filePath);
711 fullpath.append(fileName);
712
713 // Replace all single quotes in the file name with double single quotes to comply with SQLLite syntax.
714 std::string fileNameAsString(fileName);
715 size_t found = fileNameAsString.find("'");
716 if (found != std::string::npos) //Replace it and replace all its subsequent occurrences.
717 {
718 fileNameAsString.replace(found,1,"''");
719
720 while ((found=fileNameAsString.find("'", found+2)) != std::string::npos)// found+2 because we want to move past the newly inserted single quote.
721 {
722 fileNameAsString.replace(found,1,"''");
723 }
724 }
725
726 // Now remove all the control characters from the file name.
727 for (int codePoint=1; codePoint < 32; codePoint++)
728 {
729 char codePointAsHex[10];
730 codePointAsHex[0] = codePoint;
731 codePointAsHex[1] = '\0';
732 std::string stringToRemove(codePointAsHex);
733
734 found = fileNameAsString.find(stringToRemove);
735 if (found != std::string::npos) //Replace it and replace all its subsequent occurrences.
736 {
737 fileNameAsString.replace(found,1,"");
738
739 while ((found=fileNameAsString.find(stringToRemove,found+1)) != std::string::npos)// found+1 because the control characters are just 1 character.
740 {
741 fileNameAsString.replace(found,1,"");
742 }
743 }
744 }
745
746 fileName = fileNameAsString.c_str();
747
748 // Get the file size.
749 TSK_OFF_T size = 0;
750 const TSK_FS_ATTR *fileSystemAttribute = tsk_fs_file_attr_get_id(const_cast<TSK_FS_FILE*>(fileSystemFile), fileSystemAttrID);
751 if (fileSystemAttribute)
752 {
753 size = fileSystemAttribute->size;
754 }
755
756 // Get the file metadata, if it's available.
757 int mtime = 0;
758 int crtime = 0;
759 int ctime = 0;
760 int atime = 0;
761 int meta_type = 0;
762 int meta_flags = 0;
763 int meta_mode = 0;
764 int gid = 0;
765 int uid = 0;
766 if (fileSystemFile->meta)
767 {
768 mtime = static_cast<int>(fileSystemFile->meta->mtime);
769 atime = static_cast<int>(fileSystemFile->meta->atime);
770 ctime = static_cast<int>(fileSystemFile->meta->ctime);
771 crtime = static_cast<int>(fileSystemFile->meta->crtime);
772 meta_type = fileSystemFile->meta->type;
773 meta_flags = fileSystemFile->meta->flags;
774 meta_mode = fileSystemFile->meta->mode;
775 gid = fileSystemFile->meta->gid;
776 uid = fileSystemFile->meta->uid;
777 }
778
779 // Insert into the files table.
780 char stmt[4096];
781 sqlite3_snprintf(4096, stmt,
782 "INSERT INTO files (file_id, type_id, status, name, par_file_id, dir_type, meta_type, "
783 "dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, full_path) VALUES (NULL, %d, %d,"
784 "'%q',%llu,%d,%d,%d,%d,%" PRIuOFF",%d,%d,%d,%d,%d,%d,%d,'%q')",
785 IMGDB_FILES_TYPE_FS, IMGDB_FILES_STATUS_READY_FOR_ANALYSIS, fileName,
786 findParObjId(fileSystemFile, fileSystemID),
787 fileSystemFile->name->type, meta_type,
788 fileSystemFile->name->flags, meta_flags, size, crtime, ctime, atime,
789 mtime, meta_mode, gid, uid, fullpath.c_str());
790 char *errmsg;
791 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
792 {
793 std::ostringstream msg;
794 msg << msgPrefix << "Error adding data to files table: " << errmsg;
795 LOGERROR(msg.str());
796
797 sqlite3_free(errmsg);
798 return -1;
799 }
800
801 // Get the file_id from the last insert.
802 fileID = sqlite3_last_insert_rowid(m_db);
803
804 // Insert into the fs_files table.
805 sqlite3_snprintf(4096, stmt,
806 "INSERT INTO fs_files (file_id, fs_id, fs_file_id, attr_type, attr_id) VALUES (%llu,%d,%"
807 PRIuINUM ",%d,%d)", fileID, fileSystemID, fileSystemFile->name->meta_addr, fileSystemAttrType, fileSystemAttrID);
808
809 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
810 {
811 std::ostringstream msg;
812 msg << msgPrefix << "Error adding data to fs_files table: " << errmsg;
813 LOGERROR(msg.str());
814
815 sqlite3_free(errmsg);
816 return -1;
817 }
818
819 //if dir, update parent id cache
820 if (meta_type == TSK_FS_META_TYPE_DIR) {
821 storeParObjId(fileSystemID, fileSystemFile, fileID);
822 }
823
824 return 0;
825 }
826
827 /**
828 * Add block info to the database. This table stores the run information for each file so that we
829 * can map which blocks are used by what files.
830 * @param a_fsId Id that the file is located in
831 * @param a_fileId ID of the file
832 * @param a_sequence The sequence number of this run in the file (0 for the first run, 1 for the second run, etc.)
833 * @param a_blk_addr Block address (the address that the file system uses -- NOT the physical sector addr)
834 * @param a_len The number of blocks in the run
835 * @returns 1 on error
836 */
addFsBlockInfo(int a_fsId,uint64_t a_fileId,int a_sequence,uint64_t a_blk_addr,uint64_t a_len)837 int TskImgDBSqlite::addFsBlockInfo(int a_fsId, uint64_t a_fileId, int a_sequence, uint64_t a_blk_addr, uint64_t a_len)
838 {
839 std::stringstream stmt;
840 char * errmsg;
841
842 if (!m_db)
843 return 1;
844
845 stmt <<
846 "INSERT INTO fs_blocks (fs_id, file_id, seq, blk_start, blk_len) VALUES (" <<
847 a_fsId << "," << a_fileId << "," << a_sequence << "," << a_blk_addr << "," << a_len << ")";
848
849 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
850 std::wstringstream infoMessage;
851 infoMessage << L"TskImgDBSqlite::addFsBlockInfo - Error adding data to fs_blocks table: " << errmsg;
852 LOGERROR(infoMessage.str());
853
854 sqlite3_free(errmsg);
855 return 1;
856 }
857
858 return 0;
859 }
860
addAllocUnallocMapInfo(int a_volID,int unallocImgID,uint64_t unallocImgStart,uint64_t length,uint64_t origImgStart)861 int TskImgDBSqlite::addAllocUnallocMapInfo(int a_volID, int unallocImgID,
862 uint64_t unallocImgStart, uint64_t length, uint64_t origImgStart)
863 {
864 std::stringstream stmt;
865 char * errmsg;
866
867 if (!m_db)
868 return 1;
869
870 stmt <<
871 "INSERT INTO alloc_unalloc_map (vol_id, unalloc_img_id, unalloc_img_sect_start, "
872 "sect_len, orig_img_sect_start) VALUES (" <<
873 a_volID << "," << unallocImgID << "," <<
874 unallocImgStart << "," << length << "," << origImgStart << ")";
875
876 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
877 std::wstringstream infoMessage;
878 infoMessage << L"TskImgDBSqlite::addAllocUnallocMapInfo - Error adding data to alloc_unalloc_map table: " << errmsg;
879 LOGERROR(infoMessage.str());
880
881 sqlite3_free(errmsg);
882 return 1;
883 }
884
885 return 0;
886 }
887
888 /**
889 * Get information on all of the free sectors in an image.
890 *
891 * @return Info on unallocated runs (or NULL on error). Caller must free this when done.
892 */
getFreeSectors() const893 SectorRuns * TskImgDBSqlite::getFreeSectors() const
894 {
895 std::stringstream infoMessage;
896 std::stringstream msg;
897
898 if (!m_db)
899 return NULL;
900
901 SectorRuns * sr = new SectorRuns();
902
903 LOGINFO("TskImgDBSqlite::getFreeSectors - Identifying Unallocated Sectors");
904
905 sqlite3_stmt * statement;
906
907 /********** FIND the unallocated volumes *************/
908 if (sqlite3_prepare_v2(m_db,
909 "SELECT vol_id, sect_start, sect_len, flags FROM vol_info;",
910 -1, &statement, 0) == SQLITE_OK) {
911 while(true) {
912 int result = sqlite3_step(statement);
913 if (result == SQLITE_ROW) {
914 int flags = sqlite3_column_int(statement, 3);
915
916 int vol_id = sqlite3_column_int(statement,0);
917 int64_t start = sqlite3_column_int64(statement,1);
918 int64_t len = sqlite3_column_int64(statement,2);
919
920 // add the unallocated volumes
921 if (flags & TSK_VS_PART_FLAG_UNALLOC) {
922 sr->addRun(start, len, vol_id);
923 }
924 // add the allocated volumes that don't have a known file system
925 else {
926 std::stringstream stmt;
927 sqlite3_stmt *statement2;
928 stmt << "SELECT fs_id FROM fs_info WHERE vol_id = " << vol_id << ";";
929 if (sqlite3_prepare_v2(m_db, stmt.str().c_str() , -1, &statement2, 0) == SQLITE_OK) {
930 if (sqlite3_step(statement2) != SQLITE_ROW) {
931 sr->addRun(start, len, vol_id);
932 }
933 sqlite3_finalize(statement2);
934 }
935 }
936 }
937 else {
938 break;
939 }
940 }
941 sqlite3_finalize(statement);
942 }
943 else {
944 infoMessage << "TskImgDBSqlite::getFreeSectors - Error querying vol_info table: " << sqlite3_errmsg(m_db);
945 LOGERROR(infoMessage.str());
946
947 return NULL;
948 }
949
950 /*************** Find the unallocated blocks in each file system *************/
951 // @@@ Need to make more dynamic
952 int blk_size[32];
953 memset(blk_size, 0, sizeof(blk_size));
954 uint64_t blk_count[32];
955 memset(blk_count, 0, sizeof(blk_count));
956 int vol_id[32];
957 uint64_t img_offset[32];
958
959 // get basic info on each file system
960 if (sqlite3_prepare_v2(m_db, "SELECT fs_id, vol_id, img_byte_offset, block_size, block_count FROM fs_info;", -1, &statement, 0) == SQLITE_OK) {
961 LOGINFO("TskImgDBSqlite::getFreeSectors - START LOOP: Find the unallocated blocks in each file system.");
962 while(true)
963 {
964 int result = sqlite3_step(statement);
965 if (result == SQLITE_ROW)
966 {
967 int fs_id = sqlite3_column_int(statement, 0);
968 if (fs_id > 32)
969 {
970 infoMessage.str("");
971 infoMessage << "TskImgDBSqlite::getFreeSectors - fs_id in fs_info is bigger than 32: " << fs_id;
972 LOGERROR(infoMessage.str());
973 break;
974 }
975 vol_id[fs_id] = sqlite3_column_int(statement, 1);
976 img_offset[fs_id] = sqlite3_column_int64(statement, 2) / 512;
977 blk_size[fs_id] = sqlite3_column_int(statement, 3) / 512;
978 blk_count[fs_id] = sqlite3_column_int64(statement, 4);
979 // Debug Info
980 msg.str("");
981 msg << "TskImgDBSqlite::getFreeSectors - fs_id=" << fs_id << " vol_id=" << vol_id[fs_id] << " img_offset=" << img_offset[fs_id] << " blk_size=" << blk_size[fs_id] <<
982 " blk_count=" << blk_count[fs_id];
983 LOGINFO(msg.str().c_str());
984 }
985 else
986 {
987 break;
988 }
989 }
990 sqlite3_finalize(statement);
991 LOGINFO("TskImgDBSqlite::getFreeSectors - DONE: Find the unallocated blocks in each file system.");
992 }
993 else
994 {
995 infoMessage.str("");
996 infoMessage << "TskImgDBSqlite::getFreeSectors - Error querying fs_info table: " << sqlite3_errmsg(m_db);
997 LOGERROR(infoMessage.str());
998
999 return NULL;
1000 }
1001
1002 // see what blocks have been used and add them to a list
1003 TSK_LIST *seen[32];
1004 memset(seen, 0, 32*sizeof(TSK_LIST *));
1005
1006 if (sqlite3_prepare_v2(m_db, "SELECT fs_id, file_id, blk_start, blk_len FROM fs_blocks;", -1, &statement, 0) == SQLITE_OK) {
1007 LOGINFO("TskImgDBSqlite::getFreeSectors - START LOOP: see what blocks have been used and add them to a list.");
1008 while(true) {
1009 int result = sqlite3_step(statement);
1010 if (result == SQLITE_ROW) {
1011 int fs_id = sqlite3_column_int(statement, 0);
1012 if (fs_id > 32) {
1013 infoMessage.str("");
1014 infoMessage << "TskImgDBSqlite::getFreeSectors - fs_id in fs_info is bigger than 32: " << fs_id;
1015 LOGERROR(infoMessage.str());
1016 continue;
1017 }
1018 uint64_t file_id = (uint64_t)sqlite3_column_int64(statement, 1);
1019 int64_t addr = sqlite3_column_int64(statement, 2);
1020 int64_t len = sqlite3_column_int64(statement, 3);
1021
1022 // We only want to consider the runs for files that we allocated.
1023 std::stringstream stmt;
1024 stmt << "SELECT meta_flags from files WHERE file_id=" << file_id;
1025
1026 sqlite3_stmt * statement2;
1027 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement2, 0) != SQLITE_OK) {
1028 infoMessage.str("");
1029 infoMessage << "TskImgDBSqlite::getFreeSectors - error finding flags for file " << file_id;
1030 LOGERROR(infoMessage.str());
1031 continue;
1032 }
1033 sqlite3_step(statement2);
1034 int flags = sqlite3_column_int(statement2, 0);
1035 sqlite3_finalize(statement2);
1036
1037 if (flags & TSK_FS_META_FLAG_UNALLOC)
1038 continue;
1039
1040 // @@@ We can probably find a more efficient storage method than this...
1041 int error = 0;
1042 for (int64_t i = 0; i < len; i++) {
1043 if (tsk_list_add(&seen[fs_id], addr+i)) {
1044 infoMessage.str("");
1045 infoMessage << "TskImgDBSqlite::getFreeSectors - Error adding seen block address to list";
1046 LOGERROR(infoMessage.str());
1047
1048 error = 1;
1049 break;
1050 }
1051 }
1052 if (error)
1053 break;
1054 }
1055 else {
1056 break;
1057 }
1058 }
1059 sqlite3_finalize(statement);
1060 LOGINFO("TskImgDBSqlite::getFreeSectors - DONE: see what blocks have been used and add them to a list.");
1061 }
1062 else {
1063 infoMessage.str("");
1064 infoMessage << "TskImgDBSqlite::getFreeSectors - Error querying fs_block table: " << sqlite3_errmsg(m_db);
1065 LOGERROR(infoMessage.str());
1066
1067 return NULL;
1068 }
1069
1070 // cycle through each file system to find the unused blocks
1071 LOGINFO("TskImgDBSqlite::getFreeSectors - START LOOP: cycle through each file system to find the unused blocks.");
1072 for (int f = 0; f < 32; f++) {
1073 if (blk_count[f] == 0)
1074 continue;
1075
1076 uint64_t st = 0;
1077 int len = 0;
1078 // we previously adjusted blk_size and img_offset to be in sectors
1079
1080 msg.str("");
1081 msg << "blk_count[" << f << "]=" << blk_count[f];
1082 LOGINFO(msg.str().c_str());
1083
1084 for (uint64_t a = 0; a < blk_count[f]; a++) {
1085 // see if this addr was used in a file
1086 if (tsk_list_find(seen[f], a) == 0) {
1087 // we already have a run being defined
1088 if (len) {
1089 // same run, so add on to it
1090 if (st + len == a) {
1091 len++;
1092 }
1093 // different run, make a new one
1094 else {
1095 sr->addRun(img_offset[f]+st*blk_size[f], len*blk_size[f], vol_id[f]);
1096 st = a;
1097 len = 1;
1098 }
1099 }
1100 // start a new run
1101 else {
1102 st = a;
1103 len = 1;
1104 }
1105 }
1106 }
1107 // add the final run
1108 if (len) {
1109 sr->addRun(img_offset[f]+st*blk_size[f], len*blk_size[f], vol_id[f]);
1110 }
1111 tsk_list_free(seen[f]);
1112 seen[f] = NULL;
1113 }
1114 LOGINFO("TskImgDBSqlite::getFreeSectors - DONE: cycle through each file system to find the unused blocks.");
1115
1116 return sr;
1117 }
1118
getImageBaseName() const1119 std::string TskImgDBSqlite::getImageBaseName() const
1120 {
1121 // There may be multiple file paths if the image is a split image. Oreder by sequence number to extract the file name from the first path.
1122 sqlite3_stmt *statement;
1123 executeStatement("SELECT name FROM image_names ORDER BY seq;", statement, "TskImgDBSqlite::getImageBaseName");
1124
1125 int result = sqlite3_step(statement);
1126 if (result == SQLITE_ROW)
1127 {
1128 Poco::Path imagePath(reinterpret_cast<const char*>(sqlite3_column_text(statement, 0))); // Reinterpret from const unsigned char*
1129 return imagePath.getFileName();
1130 }
1131 else
1132 {
1133 return "";
1134 }
1135 }
1136
getImageNamesW() const1137 std::vector<std::wstring> TskImgDBSqlite::getImageNamesW() const
1138 {
1139 std::vector<std::wstring> imgList;
1140
1141 if (!m_db)
1142 return imgList;
1143
1144 sqlite3_stmt *statement;
1145
1146 if (sqlite3_prepare_v2(m_db, "SELECT name FROM image_names ORDER BY seq;",
1147 -1, &statement, 0) == SQLITE_OK)
1148 {
1149 while(true)
1150 {
1151 int result = sqlite3_step(statement);
1152 if (result == SQLITE_ROW) {
1153 imgList.push_back((wchar_t *)sqlite3_column_text16(statement, 0));
1154 }
1155 else {
1156 break;
1157 }
1158 }
1159
1160 sqlite3_finalize(statement);
1161 }
1162
1163 return imgList;
1164 }
1165
1166
getImageNames() const1167 std::vector<std::string> TskImgDBSqlite::getImageNames() const
1168 {
1169 std::vector<std::string> imgList;
1170
1171 if (!m_db)
1172 return imgList;
1173
1174 sqlite3_stmt *statement;
1175
1176 if (sqlite3_prepare_v2(m_db, "SELECT name FROM image_names ORDER BY seq;",
1177 -1, &statement, 0) == SQLITE_OK)
1178 {
1179 while(true)
1180 {
1181 int result = sqlite3_step(statement);
1182 if (result == SQLITE_ROW) {
1183 imgList.push_back((char *)sqlite3_column_text(statement, 0));
1184 }
1185 else {
1186 break;
1187 }
1188 }
1189
1190 sqlite3_finalize(statement);
1191 }
1192
1193 return imgList;
1194 }
1195
1196
1197
1198
1199 /**
1200 * @param a_fileId File id to get information about
1201 * @param a_fsOffset Byte offset of start of file system that the file is located in
1202 * @param a_fsFileId File system-specific id of the file
1203 * @param a_attrType Type of attribute for this file
1204 * @param a_attrId The ID of the attribute for this file
1205 * @returns -1 on error
1206 */
getFileUniqueIdentifiers(uint64_t a_fileId,uint64_t & a_fsOffset,uint64_t & a_fsFileId,int & a_attrType,int & a_attrId) const1207 int TskImgDBSqlite::getFileUniqueIdentifiers(uint64_t a_fileId, uint64_t &a_fsOffset, uint64_t &a_fsFileId, int &a_attrType, int &a_attrId) const
1208 {
1209 if (!m_db)
1210 return -1;
1211
1212 sqlite3_stmt * statement;
1213 std::stringstream stmt;
1214
1215 stmt <<
1216 "SELECT fs_file_id, attr_type, attr_id, fs_info.img_byte_offset "
1217 "FROM fs_files, fs_info WHERE file_id=" << a_fileId << " AND fs_info.fs_id = fs_files.fs_id;";
1218 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
1219 int result = sqlite3_step(statement);
1220 if (result == SQLITE_ROW) {
1221 a_fsFileId = sqlite3_column_int64(statement, 0);
1222 a_attrType = sqlite3_column_int(statement, 1);
1223 a_attrId = sqlite3_column_int(statement, 2);
1224 a_fsOffset = sqlite3_column_int64(statement, 3);
1225 }
1226 else {
1227 return -1;
1228 }
1229 sqlite3_finalize(statement);
1230 }
1231 else {
1232 std::wstringstream infoMessage;
1233 infoMessage << L"TskImgDBSqlite::getFileUniqueIdentifiers - Error querying fs_files table : " << sqlite3_errmsg(m_db);
1234 LOGERROR(infoMessage.str());
1235 return -1;
1236 }
1237
1238 return 0;
1239 }
1240
1241 /**
1242 * Get number of volumes in image.
1243 * @return Number of volumes in image or -1 on error
1244 */
getNumVolumes() const1245 int TskImgDBSqlite::getNumVolumes() const
1246 {
1247 if (!m_db)
1248 return 0;
1249
1250 int count = 0;
1251 sqlite3_stmt * statement;
1252
1253 /********** Get the number of volumes *************/
1254 if (sqlite3_prepare_v2(m_db, "SELECT count(*) from vol_info;", -1, &statement, 0) == SQLITE_OK)
1255 {
1256 int result = sqlite3_step(statement);
1257 if (result == SQLITE_ROW)
1258 {
1259 count = (int)sqlite3_column_int(statement, 0);
1260 }
1261 sqlite3_finalize(statement);
1262 }
1263 else
1264 {
1265 std::wstringstream msg;
1266 msg << L"TskImgDBSqlite::getNumVolumes - Error querying vol_info table: " << sqlite3_errmsg(m_db);
1267 LOGERROR(msg.str());
1268
1269 return -1;
1270 }
1271
1272 return count;
1273 }
1274 /**
1275 * Get number of files in image.
1276 * @return Number of files in image or -1 on error
1277 */
getNumFiles() const1278 int TskImgDBSqlite::getNumFiles() const
1279 {
1280 if (!m_db)
1281 return 0;
1282
1283 std::string condition("");
1284 return getFileCount(condition);
1285 }
1286
1287 /**
1288 * @returns the session_id or -1 on error.
1289 */
getSessionID() const1290 int TskImgDBSqlite::getSessionID() const
1291 {
1292 if (!m_db)
1293 return 0;
1294
1295 sqlite3_stmt * statement;
1296 std::string stmt("SELECT version from db_info WHERE name=\"SID\";");
1297 int sessionId = -1;
1298
1299 /********** FIND the unallocated volumes *************/
1300 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK) {
1301 int result = sqlite3_step(statement);
1302 if (result == SQLITE_ROW) {
1303 sessionId = (int)sqlite3_column_int(statement, 0);
1304 }
1305 sqlite3_finalize(statement);
1306 }
1307 else {
1308 std::wstringstream infoMessage;
1309 infoMessage << L"TskImgDBSqlite::getSessionID - Error querying db_info table for Session ID: " << sqlite3_errmsg(m_db);
1310 LOGERROR(infoMessage.str());
1311
1312 return -1;
1313 }
1314 return sessionId;
1315 }
1316
begin()1317 int TskImgDBSqlite::begin()
1318 {
1319 char *errmsg;
1320 if (!m_db)
1321 return 1;
1322
1323 if (sqlite3_exec(m_db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
1324 std::wstringstream infoMessage;
1325 infoMessage << L"TskImgDBSqlite::begin - BEGIN Error: " << errmsg;
1326 LOGERROR(infoMessage.str());
1327
1328 sqlite3_free(errmsg);
1329 return 1;
1330 }
1331 return 0;
1332 }
1333
commit()1334 int TskImgDBSqlite::commit()
1335 {
1336 char *errmsg;
1337 if (!m_db)
1338 return 1;
1339
1340 if (sqlite3_exec(m_db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
1341 std::wstringstream infoMessage;
1342 infoMessage << L"TskImgDBSqlite::commit - COMMIT Error: " << errmsg;
1343 LOGERROR(infoMessage.str());
1344
1345 sqlite3_free(errmsg);
1346 return 1;
1347 }
1348 return 0;
1349 }
1350
getUnallocRun(int a_unalloc_img_id,int a_file_offset) const1351 UnallocRun * TskImgDBSqlite::getUnallocRun(int a_unalloc_img_id, int a_file_offset) const
1352 {
1353 std::stringstream stmt;
1354 char * errmsg;
1355 if (!m_db)
1356 return NULL;
1357
1358 stmt << "SELECT vol_id, unalloc_img_sect_start, sect_len, orig_img_sect_start FROM "
1359 "alloc_unalloc_map WHERE unalloc_img_id = " << a_unalloc_img_id <<
1360 " AND unalloc_img_sect_start <= " << a_file_offset << " ORDER BY unalloc_img_sect_start DESC";
1361
1362 char **result;
1363 int nrow, ncol;
1364 if (sqlite3_get_table(m_db, stmt.str().c_str(), &result, &nrow, &ncol, &errmsg) != SQLITE_OK)
1365 {
1366 std::wstringstream infoMessage;
1367 infoMessage << L"TskImgDBSqlite::getUnallocRun - Error fetching data from alloc_unalloc_map table: " << errmsg;
1368 LOGERROR(infoMessage.str());
1369
1370 sqlite3_free(errmsg);
1371
1372 return new UnallocRun(-1, -1, -1, -1, -1);
1373 }
1374 else
1375 {
1376 int vol_id;
1377 int unalloc_img_sect_start;
1378 int sect_len;
1379 int orig_img_sect_start;
1380 // skip the headers
1381 // @@@ DO SOME ERROR CHECKING HERE to make sure that results has data...
1382 sscanf(result[4], "%d", &vol_id);
1383 sscanf(result[5], "%d", &unalloc_img_sect_start);
1384 sscanf(result[6], "%d", §_len);
1385 sscanf(result[7], "%d", &orig_img_sect_start);
1386 sqlite3_free_table(result);
1387 return new UnallocRun(vol_id, a_unalloc_img_id, unalloc_img_sect_start, sect_len, orig_img_sect_start);
1388 }
1389 }
1390
1391 /**
1392 * Adds information about a carved file into the database. This includes the sector layout
1393 * information.
1394 *
1395 * @param vol_id Volume in which the carved file was found in
1396 * @param name Name of the file
1397 * @param size Number of bytes in file
1398 * @param runStarts Array with starting sector (relative to start of image) for each run in file.
1399 * @param runLengths Array with number of sectors in each run
1400 * @param numRuns Number of entries in previous arrays
1401 * @param fileId Carved file Id (output)
1402 * @returns 0 on success or -1 on error.
1403 */
addCarvedFileInfo(int vol_id,const char * name,uint64_t size,uint64_t * runStarts,uint64_t * runLengths,int numRuns,uint64_t & fileId)1404 int TskImgDBSqlite::addCarvedFileInfo(int vol_id, const char *name, uint64_t size,
1405 uint64_t *runStarts, uint64_t *runLengths, int numRuns, uint64_t & fileId)
1406 {
1407 char stmt[1024];
1408 char * errmsg;
1409 std::wstringstream infoMessage;
1410
1411 if (!m_db)
1412 return -1;
1413
1414 // insert into files table
1415 sqlite3_snprintf(1024, stmt,
1416 "INSERT INTO files (file_id, type_id, name, par_file_id, dir_type, meta_type,"
1417 "dir_flags, meta_flags, size, ctime, crtime, atime, mtime, mode, uid, gid, status, full_path) "
1418 "VALUES (NULL, %d, '%q', NULL, %d, %d, %d, %d, %llu, 0, 0, 0, 0, NULL, NULL, NULL, %d, '%q')",
1419 IMGDB_FILES_TYPE_CARVED, name, (int)TSK_FS_NAME_TYPE_REG, (int)TSK_FS_META_TYPE_REG,
1420 (int)TSK_FS_NAME_FLAG_UNALLOC, (int)TSK_FS_META_FLAG_UNALLOC, size, IMGDB_FILES_STATUS_CREATED, name);
1421 // MAY-118 NOTE: addCarvedFileInfo insert entry into files table, but actual file on disk has not been created yet.
1422 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK) {
1423 infoMessage << L"TskImgDBSqlite::addCarvedFileInfo - Error adding data to file table for carved file: " << errmsg << L" " << stmt;
1424
1425 LOGERROR(infoMessage.str());
1426
1427 sqlite3_free(errmsg);
1428 return -1;
1429 }
1430
1431 // get the assigned file_id
1432 fileId = (uint64_t)sqlite3_last_insert_rowid(m_db);
1433
1434 // insert into the carved_files_table
1435 sqlite3_snprintf(1024, stmt, "INSERT INTO carved_files (file_id, vol_id)"
1436 "VALUES (%llu, %d)", fileId, vol_id);
1437 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK) {
1438 infoMessage << L"TskImgDBSqlite::addCarvedFileInfo - Error adding data to carved_files table: " << errmsg;
1439
1440 LOGERROR(infoMessage.str());
1441 sqlite3_free(errmsg);
1442 return -1;
1443 }
1444
1445 // insert into carved_sectors table
1446 for (int i = 0; i < numRuns; i++)
1447 {
1448 sqlite3_snprintf(1023, stmt,
1449 "INSERT INTO carved_sectors (file_id, seq, sect_start, sect_len) "
1450 "VALUES (%llu, %d, %llu, %llu)",
1451 fileId, i, runStarts[i], runLengths[i]);
1452 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK) {
1453 infoMessage << L"TskImgDBSqlite::addCarvedFileInfo - Error adding data to carved_sectors table: " << errmsg;
1454
1455 LOGERROR(infoMessage.str());
1456
1457 sqlite3_free(errmsg);
1458 return -1;
1459 }
1460 }
1461
1462 return 0;
1463 }
1464
1465 /**
1466 * Adds information about derived files to the database. Derived files typically come
1467 * from archives and may be compressed.
1468 *
1469 * @param name The name of the file.
1470 * @param parentId The id of the file from which this file is derived.
1471 * @param isDirectory True if entry is for a directory verus a file
1472 * @param size The size of the file.
1473 * @param details This is a string that may contain extra details related
1474 * to the particular type of mechanism that was used to derive this file,
1475 * e.g. files derived from zip archives may have extra information about the
1476 * compressed size of the file.
1477 * @param ctime Time file system file entry was changed.
1478 * @param crtime Time the file was created.
1479 * @param atime Last access time.
1480 * @param mtime Last modified time.
1481 * @param fileId Reference to location where file_id for file can be assigned
1482 * @param path Path of file
1483 *
1484 * @returns 0 on success or -1 on error.
1485 */
addDerivedFileInfo(const std::string & name,const uint64_t parentId,const bool isDirectory,const uint64_t size,const std::string & details,const int ctime,const int crtime,const int atime,const int mtime,uint64_t & fileId,std::string path)1486 int TskImgDBSqlite::addDerivedFileInfo(const std::string& name, const uint64_t parentId,
1487 const bool isDirectory, const uint64_t size,
1488 const std::string& details,
1489 const int ctime, const int crtime, const int atime, const int mtime,
1490 uint64_t &fileId, std::string path)
1491 {
1492 if (!m_db)
1493 return -1;
1494
1495 char stmt[1024];
1496 char * errmsg;
1497
1498 TSK_FS_NAME_TYPE_ENUM dirType = isDirectory ? TSK_FS_NAME_TYPE_DIR : TSK_FS_NAME_TYPE_REG;
1499 TSK_FS_META_TYPE_ENUM metaType = isDirectory ? TSK_FS_META_TYPE_DIR : TSK_FS_META_TYPE_REG;
1500
1501 // insert into files table
1502 sqlite3_snprintf(1024, stmt,
1503 "INSERT INTO files (file_id, type_id, name, par_file_id, dir_type, meta_type, size, ctime, crtime, atime, mtime, status, full_path) "
1504 "VALUES (NULL, %d, '%q', %llu, %d, %d, %llu, %d, %d, %d, %d, %d, '%q')",
1505 IMGDB_FILES_TYPE_DERIVED, name.c_str(), parentId, dirType, metaType, size, ctime, crtime, atime, mtime, IMGDB_FILES_STATUS_CREATED, path.c_str());
1506
1507 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
1508 {
1509 std::wstringstream msg;
1510 msg << L"TskImgDBSqlite::addDerivedFileInfo - Error adding data to file table for derived file: "
1511 << errmsg << L" " << stmt;
1512
1513 LOGERROR(msg.str());
1514
1515 sqlite3_free(errmsg);
1516 return -1;
1517 }
1518
1519 // get the assigned file_id
1520 fileId = sqlite3_last_insert_rowid(m_db);
1521
1522 // insert into the derived_files table
1523 sqlite3_snprintf(1024, stmt, "INSERT INTO derived_files (file_id, derivation_details) "
1524 "VALUES (%llu, '%q')", fileId, details.c_str());
1525 if (sqlite3_exec(m_db, stmt, NULL, NULL, &errmsg) != SQLITE_OK)
1526 {
1527 std::wstringstream msg;
1528 msg << L"TskImgDBSqlite::addDerivedFileInfo - Error adding data to derived_files table : "
1529 << errmsg;
1530
1531 LOGERROR(msg.str());
1532 sqlite3_free(errmsg);
1533 return -1;
1534 }
1535
1536 return 0;
1537 }
1538
1539 /**
1540 * Fills outBuffer with file IDs that match the name fileName.
1541 * Returns the number of file IDs written into outBuffer or -1 on error.
1542 */
getFileIds(char * a_fileName,uint64_t * a_outBuffer,int a_buffSize) const1543 int TskImgDBSqlite::getFileIds(char *a_fileName, uint64_t *a_outBuffer, int a_buffSize) const
1544 {
1545
1546 if (!m_db)
1547 return -1;
1548
1549 int outIdx = 0;
1550
1551 sqlite3_stmt * statement;
1552 std::stringstream stmt;
1553 stmt << "SELECT file_id FROM files WHERE name LIKE '" << a_fileName << "';";
1554 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
1555 while(sqlite3_step(statement) == SQLITE_ROW) {
1556 a_outBuffer[outIdx++] = (uint64_t)sqlite3_column_int64(statement, 0);
1557 }
1558 sqlite3_finalize(statement);
1559 }
1560 else {
1561 std::wstringstream infoMessage;
1562 infoMessage << L"TskImgDBSqlite::getFileIds - Error querying files table : " << sqlite3_errmsg(m_db);
1563 LOGERROR(infoMessage.str());
1564 return -1;
1565 }
1566
1567 return outIdx;
1568 }
1569
1570 /*
1571 * Return the minimum file id with status = READY_FOR_ANALYSIS in minFileId.
1572 * Return 0 on success, -1 if failed.
1573 */
getMinFileIdReadyForAnalysis(uint64_t & minFileId) const1574 int TskImgDBSqlite::getMinFileIdReadyForAnalysis(uint64_t & minFileId) const
1575 {
1576 if (!m_db)
1577 return -1;
1578
1579 minFileId = 0;
1580
1581 sqlite3_stmt * statement;
1582 std::stringstream stmt;
1583 stmt << "SELECT min(file_id) FROM files WHERE status = " <<
1584 TskImgDB::IMGDB_FILES_STATUS_READY_FOR_ANALYSIS << ";";
1585 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
1586 int result = sqlite3_step(statement);
1587 if (result == SQLITE_ROW) {
1588 minFileId = (uint64_t)sqlite3_column_int64(statement, 0);
1589 }
1590 sqlite3_finalize(statement);
1591 }
1592 else {
1593 std::wstringstream infoMessage;
1594 infoMessage << L"TskImgDBSqlite::getMinFileIdReadyForAnalysis - Error querying files table : " << sqlite3_errmsg(m_db);
1595 LOGERROR(infoMessage.str());
1596 return -1;
1597 }
1598 return 0;
1599 }
1600
1601 /**
1602 * Given the last file ID ready for analysis, find the largest file ID ready of analysis (in maxFileId)
1603 * Returns 0 on success or -1 on error.
1604 */
getMaxFileIdReadyForAnalysis(uint64_t a_lastFileId,uint64_t & maxFileId) const1605 int TskImgDBSqlite::getMaxFileIdReadyForAnalysis(uint64_t a_lastFileId, uint64_t & maxFileId) const
1606 {
1607 if (!m_db)
1608 return -1;
1609
1610 maxFileId = 0;
1611
1612 sqlite3_stmt * statement;
1613 std::stringstream stmt;
1614 stmt << "SELECT max(file_id) FROM files WHERE status = " <<
1615 TskImgDB::IMGDB_FILES_STATUS_READY_FOR_ANALYSIS <<
1616 " AND file_id >= " << a_lastFileId << ";";
1617 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
1618 int result = sqlite3_step(statement);
1619 if (result == SQLITE_ROW) {
1620 maxFileId = (uint64_t)sqlite3_column_int64(statement, 0);
1621 }
1622 sqlite3_finalize(statement);
1623 }
1624 else {
1625 std::wstringstream infoMessage;
1626 infoMessage << L"TskImgDBSqlite::getMaxFileIdReadyForAnalysis - Error querying files table : " << sqlite3_errmsg(m_db);
1627 LOGERROR(infoMessage.str());
1628 return -1;
1629 }
1630 return 0;
1631 }
1632
getFileSectors(uint64_t a_fileId) const1633 SectorRuns * TskImgDBSqlite::getFileSectors(uint64_t a_fileId) const
1634 {
1635 if (!m_db)
1636 return NULL;
1637
1638 SectorRuns * sr = new SectorRuns();
1639
1640 sqlite3_stmt * statement;
1641 std::stringstream stmt;
1642 int srCount = 0;
1643 stmt <<
1644 "SELECT fs_blocks.blk_start, fs_blocks.blk_len, "
1645 "fs_info.block_size, fs_info.img_byte_offset, fs_info.vol_id "
1646 "FROM files "
1647 "JOIN fs_files ON files.file_id = fs_files.file_id "
1648 "JOIN fs_blocks ON files.file_id = fs_blocks.file_id "
1649 "JOIN fs_info ON fs_blocks.fs_id = fs_info.fs_id "
1650 "WHERE files.file_id = " << a_fileId << " "
1651 "ORDER BY fs_blocks.seq;";
1652 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
1653 while(sqlite3_step(statement) == SQLITE_ROW) {
1654 uint64_t blkStart = (uint64_t)sqlite3_column_int64(statement, 0);
1655 uint64_t blkLength = (uint64_t)sqlite3_column_int64(statement, 1);
1656 int blkSize = sqlite3_column_int(statement, 2);
1657 uint64_t imgByteOffset = (uint64_t)sqlite3_column_int64(statement, 3);
1658 int volId = sqlite3_column_int(statement, 4);
1659
1660 uint64_t start = (imgByteOffset + blkStart * blkSize) / 512;
1661 uint64_t len = (blkLength * blkSize) / 512;
1662
1663 sr->addRun(start, len, volId);
1664 srCount++;
1665 }
1666
1667 sqlite3_finalize(statement);
1668 }
1669 else {
1670 std::wstringstream infoMessage;
1671 infoMessage <<
1672 L"TskImgDBSqlite::getFileSectors - "
1673 L"Error finding block data for file_id=" << a_fileId << ": " << sqlite3_errmsg(m_db);
1674 LOGERROR(infoMessage.str());
1675 return NULL;
1676 }
1677
1678 if (srCount < 1) {
1679 delete sr;
1680 sr = NULL;
1681 }
1682 return sr;
1683 }
1684
1685 /**
1686 * This callback mechanism is registered with SQLite and is
1687 * called whenever an operation would result in SQLITE_BUSY.
1688 * Each time this method is called we will back off IMGDB_RETRY_WAIT
1689 * x count milliseconds. A non zero return value tells SQLite to
1690 * retry the statement and a zero return value tells SQLite to
1691 * stop retrying, in which case it will return SQLITE_BUSY or
1692 * SQLITE_IOERR_BLOCKED to the caller.
1693 *
1694 * @param pDB - a pointer to the sqlite3 structure
1695 * @param count - the number of times this handler has been
1696 * called for this blocking event.
1697 */
busyHandler(void * pDB,int count)1698 int TskImgDBSqlite::busyHandler(void * pDB, int count)
1699 {
1700 if (count < IMGDB_MAX_RETRY_COUNT)
1701 {
1702 Poco::Thread::sleep(IMGDB_RETRY_WAIT * count);
1703 return 1;
1704 }
1705
1706 return 0;
1707 }
1708
1709
1710
updateFileStatus(uint64_t a_file_id,FILE_STATUS a_status)1711 int TskImgDBSqlite::updateFileStatus(uint64_t a_file_id, FILE_STATUS a_status)
1712 {
1713 if (!m_db)
1714 return 1;
1715
1716 std::stringstream stmt;
1717 char * errmsg;
1718
1719 stmt << "UPDATE files SET status = " << a_status << " WHERE file_id = " << a_file_id << ";";
1720 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
1721 std::wstringstream infoMessage;
1722 infoMessage << L"TskImgDBSqlite::updateFileStatus - Error UPDATE file status: " << sqlite3_errmsg(m_db);
1723 LOGERROR(infoMessage.str());
1724 return 1;
1725 }
1726
1727 return 0;
1728 }
1729
1730
updateKnownStatus(uint64_t a_file_id,KNOWN_STATUS a_status)1731 int TskImgDBSqlite::updateKnownStatus(uint64_t a_file_id, KNOWN_STATUS a_status)
1732 {
1733 if (!m_db)
1734 return 1;
1735
1736 std::stringstream stmt;
1737 char * errmsg;
1738
1739 stmt << "UPDATE file_hashes SET known = " << a_status << " WHERE file_id = " << a_file_id << ";";
1740 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
1741 std::wstringstream infoMessage;
1742 infoMessage << L"TskImgDBSqlite::updateFileStatus - Error UPDATE file status: " << sqlite3_errmsg(m_db);
1743 LOGERROR(infoMessage.str());
1744 return 1;
1745 }
1746
1747 return 0;
1748 }
1749
dbExist() const1750 bool TskImgDBSqlite::dbExist() const
1751 {
1752 if (m_db)
1753 return true;
1754 else
1755 return false;
1756 }
1757
getCarvedFileInfo(const std::string & stmt,std::map<uint64_t,std::string> & results) const1758 void TskImgDBSqlite::getCarvedFileInfo(const std::string& stmt, std::map<uint64_t, std::string>& results) const
1759 {
1760 sqlite3_stmt * statement;
1761 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
1762 {
1763 while (sqlite3_step(statement) == SQLITE_ROW)
1764 {
1765 uint64_t fileId = (uint64_t)sqlite3_column_int64(statement, 0);
1766 std::string fileName = (char*)sqlite3_column_text(statement, 1);
1767 std::string cfileName = (char*)sqlite3_column_text(statement, 2);
1768
1769 // Grab the extension and append it to the cfile name
1770 std::string::size_type pos = fileName.rfind('.');
1771 if (pos != std::string::npos)
1772 cfileName.append(fileName.substr(pos));
1773
1774 results[fileId] = cfileName;
1775 }
1776 sqlite3_finalize(statement);
1777 } else
1778 {
1779 std::wstringstream msg;
1780 msg << L"TskImgDBSqlite::getCarvedFileInfo - Error retrieving carved file details: "
1781 << sqlite3_errmsg(m_db);
1782 LOGERROR(msg.str());
1783 }
1784 }
1785
getUniqueCarvedFiles(HASH_TYPE hashType) const1786 std::map<uint64_t, std::string> TskImgDBSqlite::getUniqueCarvedFiles(HASH_TYPE hashType) const
1787 {
1788 if (!m_db)
1789 throw TskException("No database.");
1790
1791 std::map<uint64_t, std::string> results;
1792
1793 string hash;
1794 switch (hashType) {
1795 case TskImgDB::MD5:
1796 hash = "md5";
1797 break;
1798 case TskImgDB::SHA1:
1799 hash = "sha1";
1800 break;
1801 case TskImgDB::SHA2_256:
1802 hash = "sha2_256";
1803 break;
1804 case TskImgDB::SHA2_512:
1805 hash = "sha2_512";
1806 break;
1807 default:
1808 std::wstringstream msg;
1809 msg << L"TskImgDBSqlite::getUniqueCarvedFiles - Unsupported hashType : " << hashType;
1810 LOGERROR(msg.str());
1811 return results;
1812 }
1813
1814 stringstream stmt;
1815
1816 // If hashes have not been calculated return all carved files
1817 stmt << "SELECT count(*) FROM file_hashes;";
1818
1819 sqlite3_stmt * statement;
1820 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK)
1821 {
1822 if (sqlite3_step(statement) == SQLITE_ROW)
1823 {
1824 uint64_t counter = (uint64_t)sqlite3_column_int64(statement, 0);
1825 if (counter == 0)
1826 {
1827 sqlite3_finalize(statement);
1828 stmt.str("");
1829 stmt << "select c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' "
1830 << "|| c.file_id from files f, carved_files c, carved_sectors cs "
1831 << "where c.file_id = cs.file_id and cs.seq = 0 and f.file_id = c.file_id order by c.file_id";
1832 getCarvedFileInfo(stmt.str(), results);
1833 return results;
1834 }
1835 }
1836 sqlite3_finalize(statement);
1837 } else
1838 {
1839 std::wstringstream infoMessage;
1840 infoMessage << L"TskImgDBSqlite::getUniqueCarvedFiles - Error getting file_hashes count: " << sqlite3_errmsg(m_db);
1841 LOGERROR(infoMessage.str());
1842 }
1843
1844 stmt.str("");
1845
1846 // Get the set of files for which the hash has been calculated.
1847 stmt << "select c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' "
1848 << "|| c.file_id from files f, carved_files c, carved_sectors cs "
1849 << "where c.file_id = cs.file_id and cs.seq = 0 and f.file_id = c.file_id and c.file_id in "
1850 << "(select min(file_id) from file_hashes where " << hash << " != '' group by " << hash << ") order by c.file_id";
1851
1852 getCarvedFileInfo(stmt.str(), results);
1853
1854 // Next get the set of files for which the hash has *not* been calculated.
1855 stmt.str("");
1856
1857 stmt << "select c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' "
1858 << "|| c.file_id from files f, carved_files c, carved_sectors cs "
1859 << "where c.file_id = cs.file_id and cs.seq = 0 and f.file_id = c.file_id and c.file_id in "
1860 << "(select file_id from file_hashes where " << hash << " = '') order by c.file_id";
1861
1862 getCarvedFileInfo(stmt.str(), results);
1863
1864 // Finally, add file info for all of the carved files for which there are no hashes of any sort.
1865 // All of these files must be included because without hashes there is no way to determine uniqueness.
1866 stmt.clear();
1867 stmt.str("");
1868 stmt << "SELECT c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || c.file_id "
1869 << "FROM files f, carved_files c, carved_sectors cs "
1870 << "WHERE c.file_id = cs.file_id AND cs.seq = 0 AND f.file_id = c.file_id AND c.file_id NOT IN "
1871 << "(SELECT fh.file_id FROM file_hashes fh) ORDER BY c.file_id";
1872 getCarvedFileInfo(stmt.str(), results);
1873
1874 return results;
1875 }
1876
getCarvedFileInfo(const std::string & query,bool getHash,std::vector<TskCarvedFileInfo> & carvedFileInfos) const1877 void TskImgDBSqlite::getCarvedFileInfo(const std::string &query, bool getHash, std::vector<TskCarvedFileInfo> &carvedFileInfos) const
1878 {
1879 sqlite3_stmt *statement;
1880 executeStatement(query, statement, "TskImgDBSqlite::getCarvedFileInfo");
1881
1882 TskCarvedFileInfo info;
1883 while (sqlite3_step(statement) == SQLITE_ROW)
1884 {
1885 info.fileID = static_cast<uint64_t>(sqlite3_column_int64(statement, 0));
1886 std::string fileName = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1)); // Reinterpret from unsigned Char*
1887 info.cFileName = reinterpret_cast<const char*>(sqlite3_column_text(statement, 2)); // Reinterpret from unsigned Char*
1888 if (getHash)
1889 {
1890 info.hash = reinterpret_cast<const char*>(sqlite3_column_text(statement, 3));
1891 }
1892
1893 // Append the extension from the original file name to the constructed "cfile" name.
1894 std::string::size_type pos = fileName.rfind('.');
1895 if (pos != std::string::npos)
1896 {
1897 info.cFileName.append(fileName.substr(pos));
1898 }
1899
1900 carvedFileInfos.push_back(info);
1901 }
1902
1903 sqlite3_finalize(statement);
1904 }
1905
getUniqueCarvedFilesInfo(HASH_TYPE hashType) const1906 std::vector<TskCarvedFileInfo> TskImgDBSqlite::getUniqueCarvedFilesInfo(HASH_TYPE hashType) const
1907 {
1908 const std::string msgPrefix = "TskImgDBSqlite::getUniqueCarvedFilesInfo : ";
1909
1910 if (!m_db)
1911 {
1912 std::ostringstream msg;
1913 msg << msgPrefix << "no database connection";
1914 throw TskException(msg.str());
1915 }
1916
1917 // Map the requested hash type to a file_hashes table column name.
1918 string hash;
1919 switch (hashType)
1920 {
1921 case TskImgDB::MD5:
1922 hash = "md5";
1923 break;
1924 case TskImgDB::SHA1:
1925 hash = "sha1";
1926 break;
1927 case TskImgDB::SHA2_256:
1928 hash = "sha2_256";
1929 break;
1930 case TskImgDB::SHA2_512:
1931 hash = "sha2_512";
1932 break;
1933 default:
1934 std::ostringstream msg;
1935 msg << msgPrefix << "unsupported hash type :" << hashType;
1936 throw TskException(msg.str());
1937 }
1938
1939 std::vector<TskCarvedFileInfo> carvedFileInfos;
1940
1941 // Do a quick check to see if any hashes have been calculated.
1942 std::ostringstream query;
1943 query << "SELECT COUNT(*) FROM file_hashes;";
1944 sqlite3_stmt *countStmt;
1945 executeStatement(query.str(), countStmt, "TskImgDBSqlite::getUniqueCarvedFiles");
1946 if (sqlite3_step(countStmt) == SQLITE_ROW && static_cast<uint64_t>(sqlite3_column_int64(countStmt, 0)) != 0)
1947 {
1948 // At least one type of hash has been calculated (presumably for all files, but this is not guaranteed).
1949 // First, add file info for the set of unique files among the carved files for which the specified type of hash is available.
1950 query.clear();
1951 query.str("");
1952 query << "SELECT c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || c.file_id, fh." << hash << " "
1953 << "FROM files f, carved_files c, carved_sectors cs, file_hashes fh "
1954 << "WHERE c.file_id = cs.file_id AND cs.seq = 0 AND f.file_id = c.file_id AND c.file_id = fh.file_id AND c.file_id IN "
1955 << "(SELECT MIN(file_id) FROM file_hashes WHERE " << hash << " != '' GROUP BY " << hash << ") ORDER BY c.file_id";
1956 getCarvedFileInfo(query.str(), true, carvedFileInfos);
1957
1958 // Next, add file info for all of the carved files for which the specified hash is not available.
1959 // All of these files must be included because without the specified hash there is no acceptable way to determine uniqueness.
1960 query.clear();
1961 query.str("");
1962 query << "SELECT c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || c.file_id "
1963 << "FROM files f, carved_files c, carved_sectors cs "
1964 << "WHERE c.file_id = cs.file_id AND cs.seq = 0 AND f.file_id = c.file_id AND c.file_id IN "
1965 << "(SELECT file_id FROM file_hashes WHERE " << hash << " = '') ORDER BY c.file_id";
1966 getCarvedFileInfo(query.str(), false, carvedFileInfos);
1967
1968 // Finally, add file info for all of the carved files for which there are no hashes of any sort.
1969 // All of these files must be included because without hashes there is no way to determine uniqueness.
1970 query.clear();
1971 query.str("");
1972 query << "SELECT c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || c.file_id "
1973 << "FROM files f, carved_files c, carved_sectors cs "
1974 << "WHERE c.file_id = cs.file_id AND cs.seq = 0 AND f.file_id = c.file_id AND c.file_id NOT IN "
1975 << "(SELECT fh.file_id FROM file_hashes fh) ORDER BY c.file_id";
1976 getCarvedFileInfo(query.str(), false, carvedFileInfos);
1977 }
1978 else
1979 {
1980 // No hashes have been calculated.
1981 // Return carved file info all of the carved files because without hashes there is no way to determine uniqueness.
1982 query.clear();
1983 query.str("");
1984 query << "SELECT c.file_id, f.name, 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || c.file_id "
1985 << "FROM files f, carved_files c, carved_sectors cs "
1986 << "WHERE c.file_id = cs.file_id AND cs.seq = 0 AND f.file_id = c.file_id ORDER BY c.file_id";
1987 getCarvedFileInfo(query.str(), false, carvedFileInfos);
1988
1989 std::ostringstream msg;
1990 msg << msgPrefix << "no hashes available, returning all carved files";
1991 LOGWARN(msg.str());
1992 }
1993 sqlite3_finalize(countStmt);
1994
1995 return carvedFileInfos;
1996 }
1997
getCarvedFileIds() const1998 std::vector<uint64_t> TskImgDBSqlite::getCarvedFileIds() const
1999 {
2000 return getFileIdsWorker("carved_files");
2001 }
2002
getUniqueFileIds(HASH_TYPE hashType) const2003 std::vector<uint64_t> TskImgDBSqlite::getUniqueFileIds(HASH_TYPE hashType) const
2004 {
2005 if (!m_db)
2006 throw TskException("No database.");
2007
2008 std::vector<uint64_t> results;
2009
2010 string hash;
2011 switch (hashType) {
2012 case TskImgDB::MD5:
2013 hash = "md5";
2014 break;
2015 case TskImgDB::SHA1:
2016 hash = "sha1";
2017 break;
2018 case TskImgDB::SHA2_256:
2019 hash = "sha2_256";
2020 break;
2021 case TskImgDB::SHA2_512:
2022 hash = "sha2_512";
2023 break;
2024 default:
2025 std::wstringstream errorMsg;
2026 errorMsg << L"TskImgDBSqlite::getUniqueFileIds - Unsupported hashType : " << hashType ;
2027 LOGERROR(errorMsg.str());
2028 return results;
2029 }
2030
2031 stringstream stmt;
2032
2033 stmt << "SELECT min(file_id) FROM file_hashes WHERE " << hash << " != '' group by " << hash ;
2034
2035 sqlite3_stmt * statement;
2036 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2037 while (sqlite3_step(statement) == SQLITE_ROW) {
2038 uint64_t fileId = (uint64_t)sqlite3_column_int64(statement, 0);
2039 results.push_back(fileId);
2040 }
2041 sqlite3_finalize(statement);
2042 } else {
2043 std::wstringstream infoMessage;
2044 infoMessage << L"TskImgDBSqlite::getUniqueFileIds - Error querying file_hashes table: " << sqlite3_errmsg(m_db);
2045 LOGERROR(infoMessage.str());
2046 }
2047 return results;
2048 }
2049
getFileIds() const2050 std::vector<uint64_t> TskImgDBSqlite::getFileIds() const
2051 {
2052 return getFileIdsWorker("files");
2053 }
2054
getFileIdsWorker(std::string tableName,const std::string condition) const2055 std::vector<uint64_t> TskImgDBSqlite::getFileIdsWorker(std::string tableName, const std::string condition) const
2056 {
2057 if (!m_db)
2058 throw TskException("No database.");
2059
2060 std::vector<uint64_t> results;
2061
2062 stringstream stmt;
2063
2064 stmt << "SELECT file_id FROM " << tableName;
2065 if (condition.compare("") != 0)
2066 stmt << " WHERE " << condition;
2067 stmt << " ORDER BY file_id";
2068
2069 sqlite3_stmt * statement;
2070 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2071 while (sqlite3_step(statement) == SQLITE_ROW) {
2072 uint64_t fileId = (uint64_t)sqlite3_column_int64(statement, 0);
2073 results.push_back(fileId);
2074 }
2075 sqlite3_finalize(statement);
2076 } else {
2077 std::wstringstream infoMessage;
2078 infoMessage << L"TskImgDBSqlite::getFileIdsWorker - Error getting file ids from table " <<
2079 tableName.c_str() << ", " << sqlite3_errmsg(m_db);
2080 LOGERROR(infoMessage.str());
2081 }
2082 return results;
2083 }
2084
2085 /**
2086 * Get the list of file ids that match the given criteria.
2087 * The given string will be appended to "select files.file_id from files".
2088 * See \ref img_db_schema_v1_5_page for tables and columns to include in
2089 * the selection criteria.
2090 *
2091 * @param condition Must be a valid SQL string defining the selection criteria.
2092 * @returns The collection of file ids matching the selection criteria. Throws
2093 * TskException if database not initialized.
2094 */
getFileIds(const std::string & condition) const2095 std::vector<uint64_t> TskImgDBSqlite::getFileIds(const std::string& condition) const
2096 {
2097 if (!m_db)
2098 throw TskException("Database not initialized.");
2099
2100 std::vector<uint64_t> results;
2101
2102 std::string stmt("SELECT files.file_id FROM files");
2103
2104 constructStmt(stmt, condition);
2105
2106 sqlite3_stmt * statement;
2107 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
2108 {
2109 while (sqlite3_step(statement) == SQLITE_ROW)
2110 {
2111 uint64_t fileId = (uint64_t)sqlite3_column_int64(statement, 0);
2112 results.push_back(fileId);
2113 }
2114 sqlite3_finalize(statement);
2115 } else
2116 {
2117 std::wstringstream msg;
2118 msg << L"TskImgDBSqlite::getFilesIds - Error getting file ids: " << sqlite3_errmsg(m_db);
2119 LOGERROR(msg.str());
2120 }
2121 return results;
2122 }
2123 /*
2124 * Get the list of file records that match the given criteria.
2125 * The given string will be appended to "select ... from files".
2126 *
2127 * @param condition Must be a valid SQL string defining the selection criteria.
2128 * @returns The collection of file records matching the selection criteria. Throws
2129 * TskException if database not initialized.
2130 */
getFileRecords(const std::string & condition) const2131 const std::vector<TskFileRecord> TskImgDBSqlite::getFileRecords(const std::string& condition) const
2132 {
2133 if (!m_db)
2134 throw TskException("Database not initialized.");
2135
2136 std::vector<TskFileRecord> results;
2137
2138 std::stringstream stmtstrm;
2139
2140 stmtstrm << "SELECT f.file_id, f.type_id, f.name, f.par_file_id, f.dir_type, f.meta_type, f.dir_flags, "
2141 << "f.meta_flags, f.size, f.ctime, f.crtime, f.atime, f.mtime, f.mode, f.uid, f.gid, f.status, f.full_path, "
2142 << "fh.md5, fh.sha1, fh.sha2_256, fh.sha2_512 "
2143 << "FROM files f LEFT OUTER JOIN file_hashes fh ON f.file_id = fh.file_id ";
2144
2145 std::string stmt = stmtstrm.str();
2146 constructStmt(stmt, condition);
2147
2148 sqlite3_stmt * statement;
2149 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
2150 {
2151 while(sqlite3_step(statement) == SQLITE_ROW) {
2152 TskFileRecord fileRecord;
2153 fileRecord.fileId = sqlite3_column_int64(statement, 0);
2154 fileRecord.typeId = (TskImgDB::FILE_TYPES) sqlite3_column_int(statement, 1);
2155 fileRecord.name = (char *)sqlite3_column_text(statement, 2);
2156 fileRecord.parentFileId = sqlite3_column_int64(statement, 3);
2157 fileRecord.dirType = (TSK_FS_NAME_TYPE_ENUM) sqlite3_column_int(statement, 4);
2158 fileRecord.metaType = (TSK_FS_META_TYPE_ENUM) sqlite3_column_int(statement, 5);
2159 fileRecord.dirFlags = (TSK_FS_NAME_FLAG_ENUM) sqlite3_column_int(statement, 6);
2160 fileRecord.metaFlags = (TSK_FS_META_FLAG_ENUM) sqlite3_column_int(statement, 7);
2161 fileRecord.size = sqlite3_column_int64(statement, 8);
2162 fileRecord.ctime = sqlite3_column_int(statement, 9);
2163 fileRecord.crtime = sqlite3_column_int(statement, 10);
2164 fileRecord.atime = sqlite3_column_int(statement, 11);
2165 fileRecord.mtime = sqlite3_column_int(statement, 12);
2166 fileRecord.mode = (TSK_FS_META_MODE_ENUM) sqlite3_column_int(statement, 13);
2167 fileRecord.uid = sqlite3_column_int(statement, 14);
2168 fileRecord.gid = sqlite3_column_int(statement, 15);
2169 fileRecord.status = (TskImgDB::FILE_STATUS) sqlite3_column_int(statement, 16);
2170 fileRecord.fullPath = (char *)sqlite3_column_text(statement, 17);
2171
2172 if (sqlite3_column_type(statement, 18) == SQLITE_TEXT)
2173 fileRecord.md5 = (char *)sqlite3_column_text(statement, 18);
2174 if (sqlite3_column_type(statement, 19) == SQLITE_TEXT)
2175 fileRecord.sha1 = (char *)sqlite3_column_text(statement, 19);
2176 if (sqlite3_column_type(statement, 20) == SQLITE_TEXT)
2177 fileRecord.sha2_256 = (char *)sqlite3_column_text(statement, 20);
2178 if (sqlite3_column_type(statement, 21) == SQLITE_TEXT)
2179 fileRecord.sha2_512 = (char *)sqlite3_column_text(statement, 21);
2180 results.push_back(fileRecord);
2181 }
2182 }
2183 else
2184 {
2185 std::wstringstream msg;
2186 msg << L"TskImgDBSqlite::getFilesRecords - Error getting file reocrds: " << sqlite3_errmsg(m_db);
2187 LOGERROR(msg.str());
2188 }
2189 return results;
2190 }
2191
2192
2193 /**
2194 * Get the number of files that match the given criteria.
2195 * The given string will be appended to "select files.file_id from files".
2196 *
2197 * @param condition Must be a valid SQL string defining the selection criteria.
2198 * @returns The number of files matching the selection criteria.
2199 */
getFileCount(const std::string & condition) const2200 int TskImgDBSqlite::getFileCount(const std::string& condition) const
2201 {
2202 if (!m_db)
2203 throw TskException("Database not initialized.");
2204
2205 int result = 0;
2206
2207 std::string stmt("SELECT COUNT(files.file_id) FROM files");
2208
2209 constructStmt(stmt, condition);
2210
2211 sqlite3_stmt * statement;
2212 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
2213 {
2214 while (sqlite3_step(statement) == SQLITE_ROW)
2215 {
2216 result = (uint64_t)sqlite3_column_int(statement, 0);
2217 }
2218 sqlite3_finalize(statement);
2219 } else
2220 {
2221 std::wstringstream msg;
2222 msg << L"TskImgDBSqlite::getFileCount - Error getting file count: " << sqlite3_errmsg(m_db);
2223 LOGERROR(msg.str());
2224 }
2225 return result;
2226 }
2227
tsk_strnicmp(const char * s1,const char * s2,size_t N)2228 int tsk_strnicmp(const char *s1, const char *s2, size_t N)
2229 {
2230 if (N == 0)
2231 return 0;
2232 int diff = 0;
2233 if (s1 && s2) {
2234 while (N-- > 0 && (diff = (toupper(*s1) - toupper(*s2))) == 0 && *s1 && *s2) {
2235 s1++;
2236 s2++;
2237 }
2238 }
2239 else if (s1)
2240 return +1;
2241 else if (s2)
2242 return -1;
2243 return diff;
2244 }
2245
2246 /* Append condition to stmt to make a single SQL query.
2247 */
constructStmt(std::string & stmt,std::string condition) const2248 void TskImgDBSqlite::constructStmt(std::string& stmt, std::string condition) const
2249 {
2250 if (!condition.empty())
2251 {
2252 // Remove leading whitespace from condition
2253 condition.erase(0, condition.find_first_not_of(' '));
2254
2255 std::string whereClause("WHERE");
2256 std::string joinClause("JOIN");
2257 std::string leftClause("LEFT");
2258 std::string orderClause("ORDER");
2259
2260 /* If the condition doesn't start with one of the below statements
2261 * (WHERE, JOIN, etc.), then
2262 * it is presumably extending the FROM clause with
2263 * one or more table names. In this case we need to add the comma to
2264 * the statement. */
2265 if (tsk_strnicmp(condition.c_str(), whereClause.c_str(), whereClause.length()) != 0 &&
2266 tsk_strnicmp(condition.c_str(), joinClause.c_str(), joinClause.length()) != 0 &&
2267 tsk_strnicmp(condition.c_str(), leftClause.c_str(), leftClause.length()) != 0 &&
2268 tsk_strnicmp(condition.c_str(), orderClause.c_str(), orderClause.length()) != 0 &&
2269 condition[0] != ',')
2270 {
2271 stmt.append(",");
2272 }
2273 }
2274
2275 stmt.append(" ");
2276 stmt.append(condition);
2277 }
2278
2279 // Set file hash for hashType for a_file_id
2280 // Return 1 on failure, 0 on success.
setHash(const uint64_t a_file_id,const TskImgDB::HASH_TYPE hashType,const std::string & hash) const2281 int TskImgDBSqlite::setHash(const uint64_t a_file_id, const TskImgDB::HASH_TYPE hashType, const std::string& hash) const
2282 {
2283 if (!m_db)
2284 throw TskException("No database.");
2285
2286 string hashTypeStr;
2287 switch (hashType) {
2288 case TskImgDB::MD5:
2289 hashTypeStr = "md5";
2290 break;
2291 case TskImgDB::SHA1:
2292 hashTypeStr = "sha1";
2293 break;
2294 case TskImgDB::SHA2_256:
2295 hashTypeStr = "sha2_256";
2296 break;
2297 case TskImgDB::SHA2_512:
2298 hashTypeStr = "sha2_512";
2299 break;
2300 default:
2301 std::wstringstream errorMsg;
2302 errorMsg << L"TskImgDBSqlite::setHash - Unsupported hashType : " << hashType ;
2303 LOGERROR(errorMsg.str());
2304 return 1;
2305 }
2306
2307 stringstream stmt;
2308 std::string md5, sha1, sha2_256, sha2_512;
2309 int known = IMGDB_FILES_UNKNOWN;
2310 std::stringstream stream;
2311
2312 stmt << "SELECT md5, sha1, sha2_256, sha2_512, known from file_hashes WHERE file_id = " << a_file_id;
2313
2314 sqlite3_stmt * statement;
2315 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2316 int result = sqlite3_step(statement);
2317 if (result == SQLITE_ROW) {
2318 md5 = (char *)sqlite3_column_text(statement, 0);
2319 sha1 = (char *)sqlite3_column_text(statement, 1);
2320 sha2_256 = (char *)sqlite3_column_text(statement, 2);
2321 sha2_512 = (char *)sqlite3_column_text(statement, 3);
2322 known = (int)sqlite3_column_int(statement, 4);
2323 }
2324 sqlite3_finalize(statement);
2325 } else {
2326 ; // OK if not exists
2327 }
2328
2329 // insert new record
2330 stmt.str("");
2331 stmt << "INSERT OR REPLACE INTO file_hashes (file_id, md5, sha1, sha2_256, sha2_512, known) VALUES (" << a_file_id;
2332 switch (hashType) {
2333 case TskImgDB::MD5:
2334 stmt << ", '" << hash << "'";
2335 stmt << ", '" << sha1 << "'";
2336 stmt << ", '" << sha2_256 << "'";
2337 stmt << ", '" << sha2_512 << "'";
2338 stream << known;
2339 stmt << ", " << stream.str();
2340 break;
2341 case TskImgDB::SHA1:
2342 stmt << ", '" << md5 << "'";
2343 stmt << ", '" << hash << "'";
2344 stmt << ", '" << sha2_256 << "'";
2345 stmt << ", '" << sha2_512 << "'";
2346 stream << known;
2347 stmt << ", " << stream.str();
2348 break;
2349 case TskImgDB::SHA2_256:
2350 stmt << ", '" << md5 << "'";
2351 stmt << ", '" << sha1 << "'";
2352 stmt << ", '" << hash << "'";
2353 stmt << ", '" << sha2_512 << "'";
2354 stream << known;
2355 stmt << ", " << stream.str();
2356 break;
2357 case TskImgDB::SHA2_512:
2358 stmt << ", '" << md5 << "'";
2359 stmt << ", '" << sha1 << "'";
2360 stmt << ", '" << sha2_256 << "'";
2361 stmt << ", '" << hash << "'";
2362 stream << known;
2363 stmt << ", " << stream.str();
2364 break;
2365 }
2366 stmt << ")";
2367
2368 char *errmsg;
2369 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) != SQLITE_OK) {
2370 std::wstringstream infoMessage;
2371 infoMessage << L"TskImgDBSqlite::setHash - Error adding hash to file_hashes table: " << errmsg;
2372 LOGERROR(infoMessage.str());
2373 sqlite3_free(errmsg);
2374 return 1;
2375 }
2376
2377 return 0;
2378 }
2379
getCfileName(const uint64_t a_file_id) const2380 std::string TskImgDBSqlite::getCfileName(const uint64_t a_file_id) const
2381 {
2382 if (!m_db)
2383 throw TskException("No database.");
2384
2385 std::string cfileName;
2386 stringstream stmt;
2387
2388 stmt << "select 'cfile_' || c.vol_id || '_' || cs.sect_start || '_' || f.file_id"
2389 " from files f, carved_files c, carved_sectors cs where f.file_id = c.file_id and c.file_id = cs.file_id and cs.seq = 0"
2390 " and f.file_id = " << a_file_id;
2391
2392 sqlite3_stmt * statement;
2393 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2394 int result = sqlite3_step(statement);
2395 if (result == SQLITE_ROW) {
2396 cfileName = (char *)sqlite3_column_text(statement, 0);
2397 }
2398 sqlite3_finalize(statement);
2399 } else {
2400 std::wstringstream infoMessage;
2401 infoMessage << L"TskImgDBSqlite::getCfileName - Error querying tables: %S" << sqlite3_errmsg(m_db);
2402 LOGERROR(infoMessage.str());
2403 }
2404
2405 stmt.str("");
2406 stmt << "select f.name "
2407 " from files f, carved_files c, carved_sectors cs where f.file_id = c.file_id and c.file_id = cs.file_id and cs.seq = 0"
2408 " and f.file_id = " << a_file_id;
2409
2410 std::string name;
2411 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2412 int result = sqlite3_step(statement);
2413 if (result == SQLITE_ROW) {
2414 name = (char *)sqlite3_column_text(statement, 0);
2415 }
2416 sqlite3_finalize(statement);
2417 size_t pos = name.rfind('.');
2418 if (pos != string::npos)
2419 cfileName += name.substr(pos);
2420 } else {
2421 std::wstringstream infoMessage;
2422 infoMessage << L"TskImgDBSqlite::getCfileName - Error querying tables: " << sqlite3_errmsg(m_db);
2423 LOGERROR(infoMessage.str());
2424 }
2425
2426 return cfileName;
2427 }
2428
2429 /**
2430 * Return the ImageInfo
2431 * @param type Image Type (output)
2432 * @param sectorSize Image sector size (output)
2433 * @returns 0 on success or -1 on error.
2434 */
getImageInfo(int & type,int & sectorSize) const2435 int TskImgDBSqlite::getImageInfo(int & type, int & sectorSize) const
2436 {
2437 int rc = -1;
2438 if (!m_db)
2439 return rc;
2440
2441 stringstream stmt;
2442
2443 stmt << "SELECT type, ssize FROM image_info";
2444
2445 sqlite3_stmt * statement;
2446 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2447 int result = sqlite3_step(statement);
2448 if (result == SQLITE_ROW) {
2449 type = (int)sqlite3_column_int64(statement, 0);
2450 sectorSize = (int)sqlite3_column_int64(statement, 1);
2451 rc = 0;
2452 }
2453 sqlite3_finalize(statement);
2454 } else {
2455 std::wstringstream infoMessage;
2456 infoMessage << L"TskImgDBSqlite::getImageInfo - Error querying image_info table: " << sqlite3_errmsg(m_db);
2457 LOGERROR(infoMessage.str());
2458 return -1;
2459 }
2460 return rc;
2461 }
2462
2463 /**
2464 * Return a list of TskVolumeInfoRecord
2465 * @param volumeInfoList A list of TskVolumeInfoRecord (output)
2466 * @returns 0 on success or -1 on error.
2467 */
getVolumeInfo(std::list<TskVolumeInfoRecord> & volumeInfoList) const2468 int TskImgDBSqlite::getVolumeInfo(std::list<TskVolumeInfoRecord> & volumeInfoList) const
2469 {
2470 std::list<TskVolumeInfoRecord> list;
2471
2472 if (!m_db)
2473 return -1;
2474
2475 stringstream stmt;
2476 stmt << "SELECT vol_id, sect_start, sect_len, description, flags FROM vol_info";
2477
2478 sqlite3_stmt * statement;
2479 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2480 while (sqlite3_step(statement) == SQLITE_ROW) {
2481 TskVolumeInfoRecord vol_info;
2482 vol_info.vol_id = sqlite3_column_int(statement,0);
2483 vol_info.sect_start = sqlite3_column_int64(statement,1);
2484 vol_info.sect_len = sqlite3_column_int64(statement,2);
2485 vol_info.description.assign((char *)sqlite3_column_text(statement, 3));
2486 vol_info.flags = (TSK_VS_PART_FLAG_ENUM)sqlite3_column_int(statement, 4);
2487 volumeInfoList.push_back(vol_info);
2488 }
2489 sqlite3_finalize(statement);
2490 } else {
2491 std::wstringstream infoMessage;
2492 infoMessage << L"TskImgDBSqlite::getVolumeInfo - Error getting from vol_info table: " << sqlite3_errmsg(m_db);
2493 LOGERROR(infoMessage.str());
2494 return -1;
2495 }
2496 return 0;
2497 }
2498
2499 /**
2500 * Return a list of TskFsInfoRecord
2501 * @param fsInfoList A list of TskFsInfoRecord (output)
2502 * @returns 0 on success or -1 on error.
2503 */
getFsInfo(std::list<TskFsInfoRecord> & fsInfoList) const2504 int TskImgDBSqlite::getFsInfo(std::list<TskFsInfoRecord> & fsInfoList) const
2505 {
2506 std::list<TskFsInfoRecord> list;
2507
2508 if (!m_db)
2509 return -1;
2510
2511 stringstream stmt;
2512 stmt << "SELECT fs_id, img_byte_offset, vol_id, fs_type, block_size, block_count, root_inum, first_inum, last_inum FROM fs_info";
2513
2514 sqlite3_stmt * statement;
2515 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2516 while (sqlite3_step(statement) == SQLITE_ROW) {
2517 TskFsInfoRecord fs_info;
2518 fs_info.fs_id = sqlite3_column_int(statement,0);
2519 fs_info.img_byte_offset = sqlite3_column_int64(statement,1);
2520 fs_info.vol_id = sqlite3_column_int(statement,2);
2521 fs_info.fs_type = (TSK_FS_TYPE_ENUM)sqlite3_column_int(statement,3);
2522 fs_info.block_size = sqlite3_column_int(statement,4);
2523 fs_info.block_count = sqlite3_column_int64(statement,5);
2524 fs_info.root_inum = sqlite3_column_int64(statement,6);
2525 fs_info.first_inum = sqlite3_column_int64(statement,7);
2526 fs_info.last_inum = sqlite3_column_int64(statement,8);
2527 fsInfoList.push_back(fs_info);
2528 }
2529 sqlite3_finalize(statement);
2530 } else {
2531 std::wstringstream infoMessage;
2532 infoMessage << L"TskImgDBSqlite::getFsInfo - Error getting from fs_info table: " << sqlite3_errmsg(m_db);
2533 LOGERROR(infoMessage.str());
2534 return -1;
2535 }
2536 return 0;
2537 }
2538
2539 typedef std::map<std::string, int> FileTypeMap_t;
2540
getFileType(const char * name)2541 static std::string getFileType(const char *name)
2542 {
2543 std::string filename = name;
2544 size_t pos = filename.rfind('.');
2545 if (pos != std::string::npos) {
2546 std::string suffix = filename.substr(pos);
2547 std::string result;
2548 for (size_t i=0; i < suffix.size(); i++) {
2549 result += (char)tolower(suffix[i]);
2550 }
2551 return result;
2552 }
2553 else
2554 return std::string("");
2555 }
2556
2557 /**
2558 * Return a list of TskFileTypeRecord for all files.
2559 * @param fileTypeInfoList A list of TskFileTypeRecord (output)
2560 * @returns 0 on success or -1 on error.
2561 */
getFileInfoSummary(std::list<TskFileTypeRecord> & fileTypeInfoList) const2562 int TskImgDBSqlite::getFileInfoSummary(std::list<TskFileTypeRecord> &fileTypeInfoList) const
2563 {
2564 std::stringstream stmt;
2565 stmt << "SELECT name FROM files WHERE dir_type = " << TSK_FS_NAME_TYPE_REG;
2566
2567 return getFileTypeRecords(stmt.str(), fileTypeInfoList);
2568 }
2569
2570 /**
2571 * Return a list of TskFileTypeRecord for fileType
2572 * @param fileType FILE_TYPE to report
2573 * @param fileTypeInfoList A list of TskFileTypeRecord (output)
2574 * @returns 0 on success or -1 on error.
2575 */
getFileInfoSummary(FILE_TYPES fileType,std::list<TskFileTypeRecord> & fileTypeInfoList) const2576 int TskImgDBSqlite::getFileInfoSummary(FILE_TYPES fileType, std::list<TskFileTypeRecord> & fileTypeInfoList) const
2577 {
2578 stringstream stmt;
2579 stmt << "SELECT name FROM files WHERE type_id = " << fileType << " AND dir_type = " << TSK_FS_NAME_TYPE_REG;
2580
2581 return getFileTypeRecords(stmt.str(), fileTypeInfoList);
2582 }
2583
2584 /**
2585 * Return a list of TskFileTypeRecords matching the given SQL statement.
2586 * @param stmt The SQL statement used to match file records.
2587 * @param fileTypeInfoList A list of TskFileTypeRecord (output)
2588 * @returns 0 on success of -1 on error.
2589 */
getFileTypeRecords(const std::string & stmt,std::list<TskFileTypeRecord> & fileTypeInfoList) const2590 int TskImgDBSqlite::getFileTypeRecords(const std::string& stmt, std::list<TskFileTypeRecord>& fileTypeInfoList) const
2591 {
2592 if (!m_db)
2593 return -1;
2594
2595 std::list<TskFileTypeRecord> list;
2596
2597 sqlite3_stmt * statement;
2598 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK) {
2599 FileTypeMap_t fileTypeMap;
2600 while (sqlite3_step(statement) == SQLITE_ROW) {
2601 char *name = (char *)sqlite3_column_text(statement, 0);
2602 std::string type = getFileType(name);
2603 FileTypeMap_t::iterator iter = fileTypeMap.find(type);
2604 if (iter != fileTypeMap.end()) {
2605 // increment file counter
2606 int count = iter->second;
2607 fileTypeMap[type] = ++count;
2608 } else {
2609 // add a new file type
2610 fileTypeMap.insert(pair<std::string, int>(type, 1));
2611 }
2612 }
2613 for (FileTypeMap_t::const_iterator iter=fileTypeMap.begin(); iter != fileTypeMap.end(); iter++) {
2614 TskFileTypeRecord info;
2615 info.suffix.assign((*iter).first.c_str());
2616 info.count = (*iter).second;
2617 info.description.assign("File Type Description");
2618 fileTypeInfoList.push_back(info);
2619 }
2620 sqlite3_finalize(statement);
2621 } else {
2622 std::wstringstream infoMessage;
2623 infoMessage << L"TskImgDBSqlite::getFileTypeRecords - Error querying files table: " << sqlite3_errmsg(m_db);
2624 LOGERROR(infoMessage.str());
2625 return -1;
2626 }
2627 return 0;
2628 }
2629
2630 /**
2631 * Insert the Module record, if module name does not already exist in modules table.
2632 * Returns Module Id associated with the Module record.
2633 * @param name Module name
2634 * @param description Module description
2635 * @param moduleId Module Id (output)
2636 * @returns 0 on success, -1 on error.
2637 */
addModule(const std::string & name,const std::string & description,int & moduleId)2638 int TskImgDBSqlite::addModule(const std::string& name, const std::string& description, int & moduleId)
2639 {
2640 if (!m_db)
2641 return -1;
2642
2643 if (name.empty())
2644 {
2645 LOGWARN(L"TskImgDBSqlite::addModule - Given an empty module name.");
2646 return -1;
2647 }
2648
2649 moduleId = 0;
2650
2651 sqlite3_stmt * statement;
2652 char stmt[1024];
2653 sqlite3_snprintf(1024, stmt, "SELECT module_id FROM modules WHERE name = '%q';",
2654 name.c_str());
2655
2656 if (sqlite3_prepare_v2(m_db, stmt, -1, &statement, 0) == SQLITE_OK)
2657 {
2658 int result = sqlite3_step(statement);
2659 if (result == SQLITE_ROW)
2660 {
2661 // Already exists, return module_id
2662 moduleId = sqlite3_column_int(statement, 0);
2663 }
2664 else
2665 {
2666 // Create a new module record.
2667 char insertStmt[1024];
2668 char * errmsg;
2669 sqlite3_snprintf(1024, insertStmt,
2670 "INSERT INTO modules (module_id, name, description) VALUES (NULL, '%q', '%q');",
2671 name.c_str(), description.c_str());
2672 if (sqlite3_exec(m_db, insertStmt, NULL, NULL, &errmsg) == SQLITE_OK)
2673 {
2674 moduleId = (int)sqlite3_last_insert_rowid(m_db);
2675 }
2676 else
2677 {
2678 std::wstringstream msg;
2679 msg << L"TskImgDBSqlite::addModule - Error adding record to modules table: " << errmsg;
2680 LOGERROR(msg.str());
2681 sqlite3_free(errmsg);
2682 }
2683 }
2684 sqlite3_finalize(statement);
2685 }
2686 else
2687 {
2688 std::wstringstream msg;
2689 msg << L"TskImgDBSqlite::addModule - Failed to prepare statement: " << stmt;
2690 LOGERROR(msg.str());
2691 }
2692
2693 if (moduleId == 0)
2694 return -1;
2695
2696 return 0;
2697 }
2698
2699 /**
2700 * Insert the module status record.
2701 * @param file_id file_id
2702 * @param module_id module_id
2703 * @param status Status of module
2704 * @returns 0 on success, -1 on error.
2705 */
setModuleStatus(uint64_t file_id,int module_id,int status)2706 int TskImgDBSqlite::setModuleStatus(uint64_t file_id, int module_id, int status)
2707 {
2708 int rc = -1;
2709
2710 if (!m_db)
2711 return rc;
2712
2713 char * errmsg;
2714 std::stringstream stmt;
2715 stmt << "INSERT INTO module_status (file_id, module_id, status) VALUES (" <<
2716 file_id << ", " << module_id << ", " << status << ")";
2717
2718 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) == SQLITE_OK) {
2719 rc = 0;
2720 } else {
2721 std::wstringstream infoMessage;
2722 infoMessage << L"TskImgDBSqlite::setModuleStatus - Error adding data to module_status table: " << errmsg;
2723 LOGERROR(infoMessage.str());
2724 sqlite3_free(errmsg);
2725 }
2726 return rc;
2727 }
2728
2729 /**
2730 * Get a list of TskModuleStatus.
2731 * @param moduleInfoList A list of TskModuleStatus (output)
2732 * @returns 0 on success, -1 on error.
2733 */
getModuleInfo(std::vector<TskModuleInfo> & moduleInfoList) const2734 int TskImgDBSqlite::getModuleInfo(std::vector<TskModuleInfo> & moduleInfoList) const
2735 {
2736 int rc = -1;
2737
2738 if (!m_db)
2739 return rc;
2740
2741 stringstream stmt;
2742 stmt << "SELECT module_id, name, description FROM modules ORDER BY module_id";
2743
2744 sqlite3_stmt * statement;
2745 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2746 TskModuleInfo moduleInfo;
2747 while (sqlite3_step(statement) == SQLITE_ROW) {
2748 moduleInfo.module_id = (int)sqlite3_column_int64(statement, 0);
2749 moduleInfo.module_name = (char *)sqlite3_column_text(statement, 1);
2750 moduleInfo.module_description = (char *)sqlite3_column_text(statement, 2);
2751 moduleInfoList.push_back(moduleInfo);
2752 }
2753 sqlite3_finalize(statement);
2754 rc = 0;
2755 } else {
2756 std::wstringstream infoMessage;
2757 infoMessage << L"TskImgDBSqlite::getModuleInfo - Error querying modules table: " << sqlite3_errmsg(m_db);
2758 LOGERROR(infoMessage.str());
2759 }
2760 return rc;
2761 }
2762
2763 /**
2764 * Get a list of TskModuleStatus.
2765 * @param moduleStatusList A list of TskModuleStatus (output)
2766 * @returns 0 on success, -1 on error.
2767 */
getModuleErrors(std::vector<TskModuleStatus> & moduleStatusList) const2768 int TskImgDBSqlite::getModuleErrors(std::vector<TskModuleStatus> & moduleStatusList) const
2769 {
2770 int rc = -1;
2771
2772 if (!m_db)
2773 return rc;
2774
2775 stringstream stmt;
2776 stmt << "SELECT f.file_id, m.name, ms.status FROM module_status ms, files f, modules m"
2777 << " WHERE ms.status != 0 AND ms.file_id = f.file_id AND m.module_id = ms.module_id"
2778 << " ORDER BY f.file_id";
2779
2780 sqlite3_stmt * statement;
2781 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2782 TskModuleStatus moduleStatus;
2783 while (sqlite3_step(statement) == SQLITE_ROW) {
2784 moduleStatus.file_id = (uint64_t)sqlite3_column_int64(statement, 0);
2785 moduleStatus.module_name = (char *)sqlite3_column_text(statement, 1);
2786 moduleStatus.status = (int)sqlite3_column_int(statement, 2);
2787 moduleStatusList.push_back(moduleStatus);
2788 }
2789 sqlite3_finalize(statement);
2790 rc = 0;
2791 } else {
2792 std::wstringstream infoMessage;
2793 infoMessage << L"TskImgDBSqlite::getModuleErrors - Error querying module_status table: " << sqlite3_errmsg(m_db);
2794 LOGERROR(infoMessage.str());
2795 }
2796 // Find report module errors. These have file_id = 0.
2797 stmt.str("");
2798 stmt << "SELECT 0, m.name, ms.status FROM module_status ms, modules m"
2799 << " WHERE ms.status != 0 AND ms.file_id = 0 AND m.module_id = ms.module_id";
2800
2801 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2802 TskModuleStatus moduleStatus;
2803 while (sqlite3_step(statement) == SQLITE_ROW) {
2804 moduleStatus.file_id = (uint64_t)sqlite3_column_int64(statement, 0);
2805 moduleStatus.module_name = (char *)sqlite3_column_text(statement, 1);
2806 moduleStatus.status = (int)sqlite3_column_int(statement, 2);
2807 moduleStatusList.push_back(moduleStatus);
2808 }
2809 sqlite3_finalize(statement);
2810 rc = 0;
2811 } else {
2812 std::wstringstream infoMessage;
2813 infoMessage << L"TskImgDBSqlite::getModuleErrors - Error querying module_status table: " << sqlite3_errmsg(m_db);
2814 LOGERROR(infoMessage.str());
2815 }
2816 return rc;
2817 }
2818
2819 /*
2820 * Return a file name associated with a file_id, prefer Cfilename, otherwise name in the files table.
2821 * @param file_id file id
2822 * @returns file name as std::string
2823 */
getFileName(uint64_t file_id) const2824 std::string TskImgDBSqlite::getFileName(uint64_t file_id) const
2825 {
2826 std::string name;
2827
2828 if (!m_db)
2829 return name;
2830
2831 name = getCfileName(file_id);
2832 if (name == "") {
2833 TskFileRecord fileRecord;
2834 if (getFileRecord(file_id, fileRecord) == 0)
2835 name = fileRecord.name;
2836 }
2837 return name;
2838 }
2839
2840
getKnownStatus(const uint64_t fileId) const2841 TskImgDB::KNOWN_STATUS TskImgDBSqlite::getKnownStatus(const uint64_t fileId) const
2842 {
2843 int retval = -1;
2844
2845 if (!m_db)
2846 return (KNOWN_STATUS)retval;
2847
2848 stringstream stmt;
2849 stmt << "SELECT known FROM file_hashes WHERE file_id = " << fileId;
2850
2851 sqlite3_stmt * statement;
2852 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2853 if(sqlite3_step(statement) == SQLITE_ROW) {
2854 retval = (int)sqlite3_column_int(statement, 0);
2855 }
2856 sqlite3_finalize(statement);
2857 } else {
2858 std::wstringstream infoMessage;
2859 infoMessage << L"TskImgDBSqlite::getKnownStatus - Error getting known status " << sqlite3_errmsg(m_db);
2860 LOGERROR(infoMessage.str());
2861 }
2862
2863 return (KNOWN_STATUS)retval;
2864 }
2865
2866
2867 /**
2868 * Add a new row to the unalloc_img_status table, returning the unalloc_img_id.
2869 * @param unallocImgId unalloc_img_id (output)
2870 * @returns -1 on error, 0 on success.
2871 */
addUnallocImg(int & unallocImgId)2872 int TskImgDBSqlite::addUnallocImg(int & unallocImgId)
2873 {
2874 int rc = -1;
2875
2876 if (!m_db)
2877 return rc;
2878
2879 std::stringstream stmt;
2880 stmt << "INSERT INTO unalloc_img_status (unalloc_img_id, status) VALUES (NULL, " << TskImgDB::IMGDB_UNALLOC_IMG_STATUS_CREATED << ")";
2881 char * errmsg;
2882 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) == SQLITE_OK) {
2883 unallocImgId = (int)sqlite3_last_insert_rowid(m_db);
2884 rc = 0;
2885 } else {
2886 std::wstringstream infoMessage;
2887 infoMessage << L"TskImgDBSqlite::addUnallocImg - Error adding unalloc_img_status table: " << errmsg;
2888 LOGERROR(infoMessage.str());
2889 sqlite3_free(errmsg);
2890 }
2891 return rc;
2892 }
2893
2894 /**
2895 * Set the status in the unalloc_img_status table given the unalloc_img_id.
2896 * @param unallocImgId unalloc_img_id
2897 * @param status status of unalloc_img_id
2898 * @returns -1 on error, 0 on success.
2899 */
setUnallocImgStatus(int unallocImgId,TskImgDB::UNALLOC_IMG_STATUS status)2900 int TskImgDBSqlite::setUnallocImgStatus(int unallocImgId, TskImgDB::UNALLOC_IMG_STATUS status)
2901 {
2902 int rc = -1;
2903
2904 if (!m_db)
2905 return rc;
2906
2907 std::stringstream stmt;
2908 stmt << "UPDATE unalloc_img_status SET status = " << status << " WHERE unalloc_img_id = " << unallocImgId;
2909 char * errmsg;
2910 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, &errmsg) == SQLITE_OK) {
2911 rc = 0;
2912 } else {
2913 std::wstringstream infoMessage;
2914 infoMessage << L"TskImgDBSqlite::addUnallocImg - Error adding unalloc_img_status table: " << errmsg;
2915 LOGERROR(infoMessage.str());
2916 sqlite3_free(errmsg);
2917 }
2918 return rc;
2919 }
2920
2921 /**
2922 * Get the status of the unalloc_img_status table given the unalloc_img_id.
2923 * Can throws TskException.
2924 * @param unallocImgId unalloc_img_id
2925 * @returns TskImgDB::UNALLOC_IMG_STATUS
2926 */
getUnallocImgStatus(int unallocImgId) const2927 TskImgDB::UNALLOC_IMG_STATUS TskImgDBSqlite::getUnallocImgStatus(int unallocImgId) const
2928 {
2929 if (!m_db)
2930 throw TskException("Database not initialized.");
2931
2932 int status = 0;
2933 stringstream stmt;
2934 stmt << "SELECT status FROM unalloc_img_status WHERE unalloc_img_id = " << unallocImgId;
2935
2936 sqlite3_stmt * statement;
2937 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2938 if (sqlite3_step(statement) == SQLITE_ROW) {
2939 status = (int)sqlite3_column_int(statement, 0);
2940 }
2941 sqlite3_finalize(statement);
2942 } else {
2943 std::wstringstream infoMessage;
2944 infoMessage << L"TskImgDBSqlite::getUnallocImgStatus - Error getting unalloc_img_status: " << sqlite3_errmsg(m_db);
2945 LOGERROR(infoMessage.str());
2946 }
2947 return (TskImgDB::UNALLOC_IMG_STATUS)status;
2948 }
2949
2950 /**
2951 * Get all the unalloc_img_status table.
2952 * @param unallocImgStatusList A vector of TskUnallocImgStatusRecord (output)
2953 * @returns -1 on error, 0 on success.
2954 */
getAllUnallocImgStatus(std::vector<TskUnallocImgStatusRecord> & unallocImgStatusList) const2955 int TskImgDBSqlite::getAllUnallocImgStatus(std::vector<TskUnallocImgStatusRecord> & unallocImgStatusList) const
2956 {
2957 int rc = -1;
2958 unallocImgStatusList.clear();
2959
2960 if (!m_db)
2961 return rc;
2962
2963 stringstream stmt;
2964 stmt << "SELECT unalloc_img_id, status FROM unalloc_img_status";
2965
2966 sqlite3_stmt * statement;
2967 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
2968 while (sqlite3_step(statement) == SQLITE_ROW) {
2969 TskUnallocImgStatusRecord record;
2970 record.unallocImgId = (int)sqlite3_column_int(statement, 0);
2971 record.status = (TskImgDB::UNALLOC_IMG_STATUS)sqlite3_column_int(statement, 1);
2972 unallocImgStatusList.push_back(record);
2973 }
2974 rc = 0;
2975 sqlite3_finalize(statement);
2976 } else {
2977 std::wstringstream infoMessage;
2978 infoMessage << L"TskImgDBSqlite::getAllUnallocImgStatus - Error getting unalloc_img_status: " << sqlite3_errmsg(m_db);
2979 LOGERROR(infoMessage.str());
2980 }
2981 return rc;
2982 }
2983
2984 /**
2985 * Find and add all the unused sectors (unallocated and uncarved bytes) in the given unallocImgId
2986 * @param unallocImgId The unalloc image id.
2987 * @param unusedSectorsList A vector of TskUnusedSectorsRecord
2988 * @returns -1 on error, 0 on success.
2989 */
addUnusedSectors(int unallocImgId,std::vector<TskUnusedSectorsRecord> & unusedSectorsList)2990 int TskImgDBSqlite::addUnusedSectors(int unallocImgId, std::vector<TskUnusedSectorsRecord> & unusedSectorsList)
2991 {
2992 assert(unallocImgId > 0);
2993 int rc = -1;
2994 if (!m_db)
2995 return rc;
2996
2997 std::stringstream stmt;
2998 stmt << "SELECT vol_id, unalloc_img_sect_start, sect_len, orig_img_sect_start FROM alloc_unalloc_map "
2999 "WHERE unalloc_img_id = " << unallocImgId << " ORDER BY orig_img_sect_start ASC";
3000
3001 sqlite3_stmt * statement;
3002 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3003 vector<TskAllocUnallocMapRecord> allocUnallocMapList;
3004
3005 while (sqlite3_step(statement) == SQLITE_ROW) {
3006 TskAllocUnallocMapRecord record;
3007 record.vol_id = (int)sqlite3_column_int(statement, 0);
3008 record.unalloc_img_id = unallocImgId;
3009 record.unalloc_img_sect_start = (uint64_t)sqlite3_column_int64(statement, 1);
3010 record.sect_len = (uint64_t)sqlite3_column_int64(statement, 2);
3011 record.orig_img_sect_start = (uint64_t)sqlite3_column_int64(statement, 3);
3012 allocUnallocMapList.push_back(record);
3013 }
3014 sqlite3_finalize(statement);
3015
3016 for (std::vector<TskAllocUnallocMapRecord>::const_iterator it = allocUnallocMapList.begin();
3017 it != allocUnallocMapList.end(); it++)
3018 {
3019 // Sector position tracks our position through the unallocated map record.
3020 uint64_t sectPos = it->orig_img_sect_start;
3021
3022 uint64_t endSect = it->orig_img_sect_start + it->sect_len;
3023
3024 // Retrieve all carved_sector records in range for this section of unallocated space.
3025 stmt.str("");
3026 stmt << "SELECT cs.sect_start, cs.sect_len FROM carved_files cf, carved_sectors cs"
3027 << " WHERE cf.file_id = cs.file_id AND cs.sect_start >= " << it->orig_img_sect_start
3028 << " AND cs.sect_start < " << endSect << " ORDER BY cs.sect_start ASC";
3029
3030 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3031 while (sqlite3_step(statement) == SQLITE_ROW) {
3032 uint64_t cfileSectStart = (uint64_t)sqlite3_column_int64(statement, 0);
3033 uint64_t cfileSectLen = (uint64_t)sqlite3_column_int64(statement, 1);
3034 if (cfileSectStart > sectPos)
3035 {
3036 // We have a block of unused sectors between this position in the unallocated map
3037 // and the start of the carved file.
3038 addUnusedSector(sectPos, cfileSectStart, it->vol_id, unusedSectorsList);
3039 }
3040
3041 sectPos = cfileSectStart + cfileSectLen;
3042 }
3043
3044 // Handle case where there is slack at the end of the unalloc range
3045 if (sectPos < endSect)
3046 addUnusedSector(sectPos, endSect, it->vol_id, unusedSectorsList);
3047
3048 sqlite3_finalize(statement);
3049 } else {
3050 std::wstringstream infoMessage;
3051 infoMessage << L"TskImgDBSqlite::addUnusedSectors - Error querying carved_files, carved_sectors table: " << sqlite3_errmsg(m_db);
3052 LOGERROR(infoMessage.str());
3053 }
3054 }
3055 } else {
3056 std::wstringstream infoMessage;
3057 infoMessage << L"TskImgDBSqlite::addUnusedSectors - Error querying alloc_unalloc_map table: " << sqlite3_errmsg(m_db);
3058 LOGERROR(infoMessage.str());
3059 }
3060 return 0;
3061 }
3062
3063 /**
3064 * Add one unused sector to the database, add it to the files and unused_sectors tables.
3065 * @param sectStart Unused sector start.
3066 * @param sectEnd Unused sector end.
3067 * @param volId Volume Id of the unused sector.
3068 * @param unusedSectorsList A vector of TskUnusedSectorsRecord (output)
3069 * @returns -1 on error, 0 on success.
3070 */
addUnusedSector(uint64_t sectStart,uint64_t sectEnd,int volId,std::vector<TskUnusedSectorsRecord> & unusedSectorsList)3071 int TskImgDBSqlite::addUnusedSector(uint64_t sectStart, uint64_t sectEnd, int volId, std::vector<TskUnusedSectorsRecord> & unusedSectorsList)
3072 {
3073 assert(sectEnd > sectStart);
3074 int rc = -1;
3075 if (!m_db)
3076 return rc;
3077
3078 std::stringstream stmt;
3079
3080 std::string maxUnused = GetSystemProperty("MAX_UNUSED_FILE_SIZE_BYTES");
3081 const uint64_t maxUnusedFileSizeBytes = maxUnused.empty() ? (50 * 1024 * 1024) : Poco::NumberParser::parse64(maxUnused);
3082
3083 uint64_t maxUnusedSectorSize = maxUnusedFileSizeBytes / 512;
3084 uint64_t sectorIndex = 0;
3085 uint64_t sectorCount = (sectEnd - sectStart) / maxUnusedSectorSize;
3086
3087 while (sectorIndex <= sectorCount) {
3088 uint64_t thisSectStart = sectStart + (sectorIndex * maxUnusedSectorSize);
3089 uint64_t thisSectEnd = thisSectStart + (std::min)(maxUnusedSectorSize, sectEnd - thisSectStart);
3090
3091 stmt.str("");
3092 stmt << "INSERT INTO files (file_id, type_id, name, par_file_id, dir_type, meta_type,"
3093 "dir_flags, meta_flags, size, ctime, crtime, atime, mtime, mode, uid, gid, status, full_path) "
3094 "VALUES (NULL, " << IMGDB_FILES_TYPE_UNUSED << ", " << "'ufile'"
3095 << ", NULL, " << TSK_FS_NAME_TYPE_REG << ", " << TSK_FS_META_TYPE_REG << ", "
3096 << TSK_FS_NAME_FLAG_UNALLOC << ", " << TSK_FS_META_FLAG_UNALLOC << ", "
3097 << (thisSectEnd - thisSectStart) * 512 << ", NULL, NULL, NULL, NULL, NULL, NULL, NULL, " << IMGDB_FILES_STATUS_READY_FOR_ANALYSIS << "," << "'ufile'" << ")";
3098
3099 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, NULL) == SQLITE_OK) {
3100
3101 TskUnusedSectorsRecord record;
3102
3103 // get the file_id from the last insert
3104 record.fileId = sqlite3_last_insert_rowid(m_db);
3105 record.sectStart = thisSectStart;
3106 record.sectLen = thisSectEnd - thisSectStart;
3107
3108 std::stringstream name;
3109 name << "ufile_" << thisSectStart << "_" << thisSectEnd << "_" << record.fileId;
3110 stmt.str("");
3111 char *item;
3112 item = sqlite3_mprintf("%Q", name.str().c_str());
3113 stmt << "UPDATE files SET name = " << item << ", full_path = "
3114 << item << " WHERE file_id = " << record.fileId;
3115 sqlite3_free(item);
3116
3117 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, NULL) != SQLITE_OK) {
3118 std::wstringstream infoMessage;
3119 infoMessage << L"TskImgDBSqlite::addUnusedSector - Error update into files table: " << sqlite3_errmsg(m_db);
3120 LOGERROR(infoMessage.str());
3121 rc = -1;
3122 break;
3123 }
3124
3125 stmt.str("");
3126 stmt << "INSERT INTO unused_sectors (file_id, sect_start, sect_len, vol_id) VALUES ("
3127 << record.fileId << ", " << record.sectStart << ", " << record.sectLen << ", " << volId << ")";
3128
3129 if (sqlite3_exec(m_db, stmt.str().c_str(), NULL, NULL, NULL) != SQLITE_OK) {
3130 std::wstringstream infoMessage;
3131 infoMessage << L"TskImgDBSqlite::addUnusedSector - Error insert into unused_sectors table: " << sqlite3_errmsg(m_db);
3132 LOGERROR(infoMessage.str());
3133 rc = -1;
3134 break;
3135 }
3136
3137 unusedSectorsList.push_back(record);
3138 rc = 0;
3139
3140 } else {
3141 std::wstringstream infoMessage;
3142 infoMessage << L"TskImgDBSqlite::addUnusedSector - Error insert into files table: " << sqlite3_errmsg(m_db);
3143 LOGERROR(infoMessage.str());
3144 rc = -1;
3145 break;
3146 }
3147 sectorIndex++;
3148 } // while
3149 return rc;
3150 }
3151
3152 /**
3153 * Get unused sector record given a file id.
3154 * @param fileId File id of the unused sector.
3155 * @param unusedSectorsRecord TskUnusedSectorsRecord (output)
3156 * @returns -1 on error, 0 on success.
3157 */
getUnusedSector(uint64_t fileId,TskUnusedSectorsRecord & unusedSectorsRecord) const3158 int TskImgDBSqlite::getUnusedSector(uint64_t fileId, TskUnusedSectorsRecord & unusedSectorsRecord) const
3159 {
3160 int rc = -1;
3161 if (!m_db)
3162 return rc;
3163
3164 std::stringstream stmt;
3165 stmt << "SELECT sect_start, sect_len FROM unused_sectors WHERE file_id = " << fileId;
3166
3167 sqlite3_stmt * statement;
3168 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3169 if (sqlite3_step(statement) == SQLITE_ROW) {
3170 unusedSectorsRecord.fileId = fileId;
3171 unusedSectorsRecord.sectStart = (uint64_t)sqlite3_column_int64(statement, 0);
3172 unusedSectorsRecord.sectLen = (uint64_t)sqlite3_column_int64(statement, 1);
3173 rc = 0;
3174 } else {
3175 std::wstringstream msg;
3176 msg << L"TskDBSqlite::getUnusedSector - Error querying unused_sectors table for file_id "
3177 << fileId ;
3178 LOGERROR(msg.str());
3179 }
3180 } else {
3181 std::wstringstream msg;
3182 msg << L"TskDBSqlite::getUnusedSector - Error querying unused_sectors table: "
3183 << sqlite3_errmsg(m_db) ;
3184 LOGERROR(msg.str());
3185 }
3186 return rc;
3187 }
3188
3189 ///BLACKBOARD FUNCTIONS
3190 /**
3191 * Add the given blackboard attribute to the database
3192 * @param attr input attribute. should be fully populated
3193 */
addBlackboardAttribute(TskBlackboardAttribute attr)3194 void TskImgDBSqlite::addBlackboardAttribute(TskBlackboardAttribute attr)
3195 {
3196 if (!m_db)
3197 throw TskException("No database.");
3198
3199 std::stringstream str;
3200 char *item;
3201 sqlite3_stmt * statement;
3202
3203 str << "INSERT INTO blackboard_attributes (artifact_id, source, context, attribute_type_id, value_type, "
3204 "value_byte, value_text, value_int32, value_int64, value_double, obj_id) VALUES (";
3205 str << attr.getArtifactID() << ", ";
3206 item = sqlite3_mprintf("%Q", attr.getModuleName().c_str()); str << item << ", ";
3207 sqlite3_free(item);
3208 item = sqlite3_mprintf("%Q", attr.getContext().c_str()); str << item << ", ";
3209 sqlite3_free(item);
3210 str << attr.getAttributeTypeID() << ", ";
3211 str << attr.getValueType() << ", ";
3212 switch (attr.getValueType()) {
3213 case TSK_BYTE:
3214 str << " ?, '', 0, 0, 0.0";
3215 break;
3216 case TSK_STRING:
3217 item = sqlite3_mprintf("%Q", attr.getValueString().c_str());
3218 str << " '', " << item << ", 0, 0, 0.0";
3219 sqlite3_free(item);
3220 break;
3221 case TSK_INTEGER:
3222 str << " '', '', " << attr.getValueInt() << ", 0, 0.0";
3223 break;
3224 case TSK_LONG:
3225 str << " '', '', 0, " << attr.getValueLong() << ", 0.0";
3226 break;
3227 case TSK_DOUBLE:
3228 str << " '', '', 0, 0, " << setprecision(20) << attr.getValueDouble();
3229 break;
3230 };
3231 str << ", " << attr.getObjectID();
3232 str << ")";
3233
3234 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3235 int result = SQLITE_OK;
3236 unsigned char *pBuf = 0;
3237 if (attr.getValueType() == TSK_BYTE) {
3238 // Bind the byte vector
3239 int a_size = attr.getValueBytes().size();
3240 pBuf = new unsigned char[a_size];
3241 for (int i = 0; i < a_size; i++) {
3242 pBuf[i] = attr.getValueBytes()[i];
3243 }
3244 result = sqlite3_bind_blob(statement, 1, pBuf, a_size, SQLITE_STATIC);
3245 }
3246 if (result == SQLITE_OK) {
3247 result = sqlite3_step(statement);
3248 if (!(result == SQLITE_ROW || result == SQLITE_DONE)) {
3249 sqlite3_finalize(statement);
3250 if (pBuf) delete [] pBuf;
3251 throw TskException("TskImgDBSqlite::addBlackboardAttribute - Insert failed");
3252 }
3253 } else {
3254 std::wstringstream infoMessage;
3255 infoMessage << L"TskImgDBSqlite::addBlackboardAttribute - Error in sqlite3_bind_blob: " << sqlite3_errmsg(m_db);
3256 LOGERROR(infoMessage.str());
3257 throw TskException("TskImgDBSqlite::addBlackboardAttribute - Insert failed");
3258 }
3259 sqlite3_finalize(statement);
3260 if (pBuf) delete [] pBuf;
3261 } else {
3262 std::wstringstream infoMessage;
3263 infoMessage << L"TskImgDBSqlite::addBlackboardAttribute - Error adding data to blackboard table: " << sqlite3_errmsg(m_db);
3264 LOGERROR(infoMessage.str());
3265 throw TskException("TskImgDBSqlite::addBlackboardAttribute - Insert failed");
3266 }
3267 }
3268
3269 /**
3270 * Get the display name for the given artifact type id
3271 * @param artifactTypeID artifact type id
3272 * @returns display name
3273 */
getArtifactTypeDisplayName(int artifactTypeID)3274 string TskImgDBSqlite::getArtifactTypeDisplayName(int artifactTypeID){
3275 if (!m_db)
3276 throw TskException("No database.");
3277
3278 std::stringstream str;
3279 sqlite3_stmt * statement;
3280 std::string displayName = "";
3281
3282 str << "SELECT display_name FROM blackboard_artifact_types WHERE artifact_type_id = " << artifactTypeID;
3283
3284 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3285 int result = sqlite3_step(statement);
3286 if (result == SQLITE_ROW) {
3287 displayName = (char *)sqlite3_column_text(statement, 0);
3288 }
3289 else{
3290 std::wstringstream infoMessage;
3291 infoMessage << L"TskImgDBSqlite::getArtifactTypeDisplayName: " << sqlite3_errmsg(m_db);
3292 LOGERROR(infoMessage.str());
3293 throw TskException("TskImgDBSqlite::getArtifactTypeDisplayName - No artifact type with that ID");
3294 }
3295 sqlite3_finalize(statement);
3296 return displayName;
3297 }
3298 else{
3299 std::wstringstream infoMessage;
3300 infoMessage << L"TskImgDBSqlite::getArtifactTypeDisplayName: " << sqlite3_errmsg(m_db);
3301 LOGERROR(infoMessage.str());
3302 throw TskException("TskImgDBSqlite::getArtifactTypeDisplayName - Select failed");
3303 }
3304 }
3305
3306 /**
3307 * Get the artifact type id for the given artifact type string
3308 * @param artifactTypeString display name
3309 * @returns artifact type id
3310 */
getArtifactTypeID(string artifactTypeString)3311 int TskImgDBSqlite::getArtifactTypeID(string artifactTypeString){
3312 if (!m_db)
3313 throw TskException("No database.");
3314
3315 std::stringstream str;
3316 sqlite3_stmt * statement;
3317 int typeID;
3318
3319 str << "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = " << artifactTypeString;
3320
3321 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3322 int result = sqlite3_step(statement);
3323 if (result == SQLITE_ROW) {
3324 typeID = (int) sqlite3_column_int(statement, 0);
3325 }
3326 else{
3327 std::wstringstream infoMessage;
3328 infoMessage << L"TskImgDBSqlite::getArtifactTypeID: " << sqlite3_errmsg(m_db);
3329 LOGERROR(infoMessage.str());
3330 throw TskException("TskImgDBSqlite::getArtifactTypeID - No artifact type with that name");
3331 }
3332 sqlite3_finalize(statement);
3333 return typeID;
3334 }
3335 else{
3336 std::wstringstream infoMessage;
3337 infoMessage << L"TskImgDBSqlite::getArtifactTypeID: " << sqlite3_errmsg(m_db);
3338 LOGERROR(infoMessage.str());
3339 throw TskException("TskImgDBSqlite::getArtifactTypeID - Select failed");
3340 }
3341 }
3342
3343 /**
3344 * Get the artifact type name for the given artifact type id
3345 * @param artifactTypeID id
3346 * @returns artifact type name
3347 */
getArtifactTypeName(int artifactTypeID)3348 string TskImgDBSqlite::getArtifactTypeName(int artifactTypeID){
3349 if (!m_db)
3350 throw TskException("No database.");
3351
3352 std::stringstream str;
3353 sqlite3_stmt * statement;
3354 std::string typeName = "";
3355
3356 str << "SELECT type_name FROM blackboard_artifact_types WHERE artifact_type_id = " << artifactTypeID;
3357
3358 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3359 int result = sqlite3_step(statement);
3360 if (result == SQLITE_ROW) {
3361 typeName = (char *)sqlite3_column_text(statement, 0);
3362 }
3363 else{
3364 std::wstringstream infoMessage;
3365 infoMessage << L"TskImgDBSqlite::getArtifactTypeName: " << sqlite3_errmsg(m_db);
3366 LOGERROR(infoMessage.str());
3367 throw TskException("TskImgDBSqlite::getArtifactTypeName - No artifact type with that ID");
3368 }
3369 sqlite3_finalize(statement);
3370 return typeName;
3371 }
3372 else{
3373 std::wstringstream infoMessage;
3374 infoMessage << L"TskImgDBSqlite::getArtifactTypeName: " << sqlite3_errmsg(m_db);
3375 LOGERROR(infoMessage.str());
3376 throw TskException("TskImgDBSqlite::getArtifactTypeName - Select failed");
3377 }
3378 }
3379
3380 /**
3381 * Get the display name for the given attribute type id
3382 * @param attributeTypeID attribute type id
3383 * @returns display name
3384 */
getAttributeTypeDisplayName(int attributeTypeID)3385 string TskImgDBSqlite::getAttributeTypeDisplayName(int attributeTypeID){
3386 if (!m_db)
3387 throw TskException("No database.");
3388
3389 std::stringstream str;
3390 sqlite3_stmt * statement;
3391 std::string displayName = "";
3392
3393 str << "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " << attributeTypeID;
3394
3395 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3396 int result = sqlite3_step(statement);
3397 if (result == SQLITE_ROW) {
3398 displayName = (char *)sqlite3_column_text(statement, 0);
3399 }
3400 else{
3401 std::wstringstream infoMessage;
3402 infoMessage << L"TskImgDBSqlite::getAttributeTypeDisplayName: " << sqlite3_errmsg(m_db);
3403 LOGERROR(infoMessage.str());
3404 throw TskException("TskImgDBSqlite::getAttributeTypeDisplayName - No attribute type with that ID");
3405 }
3406 sqlite3_finalize(statement);
3407 return displayName;
3408 }
3409 else{
3410 std::wstringstream infoMessage;
3411 infoMessage << L"TskImgDBSqlite::getAttributeTypeDisplayName: " << sqlite3_errmsg(m_db);
3412 LOGERROR(infoMessage.str());
3413 throw TskException("TskImgDBSqlite::getAttributeTypeDisplayName - Select failed");
3414 }
3415 }
3416
3417 /**
3418 * Get the attribute type id for the given artifact type string
3419 * @param attributeTypeString display name
3420 * @returns attribute type id
3421 */
getAttributeTypeID(string attributeTypeString)3422 int TskImgDBSqlite::getAttributeTypeID(string attributeTypeString){
3423 if (!m_db)
3424 throw TskException("No database.");
3425
3426 std::stringstream str;
3427 sqlite3_stmt * statement;
3428 int typeID;
3429
3430 str << "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = " << attributeTypeString;
3431
3432 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3433 int result = sqlite3_step(statement);
3434 if (result == SQLITE_ROW) {
3435 typeID = (int) sqlite3_column_int(statement, 0);
3436 }
3437 else{
3438 std::wstringstream infoMessage;
3439 infoMessage << L"TskImgDBSqlite::getAttributeTypeID: " << sqlite3_errmsg(m_db);
3440 LOGERROR(infoMessage.str());
3441 throw TskException("TskImgDBSqlite::getAttributeTypeID - No artifact type with that name");
3442 }
3443 sqlite3_finalize(statement);
3444 return typeID;
3445 }
3446 else{
3447 std::wstringstream infoMessage;
3448 infoMessage << L"TskImgDBSqlite::getAttributeTypeID: " << sqlite3_errmsg(m_db);
3449 LOGERROR(infoMessage.str());
3450 throw TskException("TskImgDBSqlite::getAttributeTypeID - Select failed");
3451 }
3452 }
3453
3454 /**
3455 * Get the attribute type name for the given artifact type id
3456 * @param attributeTypeID id
3457 * @returns attribute type name
3458 */
getAttributeTypeName(int attributeTypeID)3459 string TskImgDBSqlite::getAttributeTypeName(int attributeTypeID){
3460 if (!m_db)
3461 throw TskException("No database.");
3462
3463 std::stringstream str;
3464 sqlite3_stmt * statement;
3465 std::string typeName = "";
3466
3467 str << "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " << attributeTypeID;
3468
3469 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK){
3470 int result = sqlite3_step(statement);
3471 if (result == SQLITE_ROW) {
3472 typeName = (char *)sqlite3_column_text(statement, 0);
3473 }
3474 else{
3475 std::wstringstream infoMessage;
3476 infoMessage << L"TskImgDBSqlite::getAttributeTypeName: " << sqlite3_errmsg(m_db);
3477 LOGERROR(infoMessage.str());
3478 throw TskException("TskImgDBSqlite::getAttributeTypeName - No attribute type with that ID");
3479 }
3480 sqlite3_finalize(statement);
3481 return typeName;
3482 }
3483 else{
3484 std::wstringstream infoMessage;
3485 infoMessage << L"TskImgDBSqlite::getAttributeTypeName: " << sqlite3_errmsg(m_db);
3486 LOGERROR(infoMessage.str());
3487 throw TskException("TskImgDBSqlite::getAttributeTypeName - Select failed");
3488 }
3489 }
3490
3491 /**
3492 * Get all artifacts by performing a SQL Select statement with the given where clause.
3493 * @param condition The SQL select where clause that should be used in the query.
3494 * @returns vector of matching artifacts
3495 */
getMatchingArtifacts(string condition)3496 vector<TskBlackboardArtifact> TskImgDBSqlite::getMatchingArtifacts(string condition)
3497 {
3498 if (!m_db)
3499 throw TskException("No database.");
3500
3501 vector<TskBlackboardArtifact> artifacts;
3502 std::string stmt("SELECT blackboard_artifacts.artifact_id, blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id FROM blackboard_artifacts");
3503
3504 constructStmt(stmt, condition);
3505
3506 sqlite3_stmt * statement;
3507 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
3508 {
3509 while (sqlite3_step(statement) == SQLITE_ROW)
3510 {
3511 int artifactTypeID = sqlite3_column_int(statement, 2);
3512
3513 artifacts.push_back(TskImgDB::createArtifact(sqlite3_column_int64(statement, 0), sqlite3_column_int64(statement, 1), artifactTypeID));
3514 }
3515 sqlite3_finalize(statement);
3516 } else
3517 {
3518 std::wstringstream msg;
3519 msg << L"TskImgDBSqlite::getMatchingArtifacts - Error getting artifacts: " << sqlite3_errmsg(m_db);
3520 LOGERROR(msg.str());
3521 throw TskException("TskImgDBSqlite::getMatchingArtifacts - Select failed");
3522 }
3523 return artifacts;
3524 }
3525
3526 /**
3527 * Get all attributes with that match the given where clause
3528 * @param condition where clause to use for matching
3529 * @returns vector of matching attributes
3530 */
getMatchingAttributes(string condition)3531 vector<TskBlackboardAttribute> TskImgDBSqlite::getMatchingAttributes(string condition)
3532 {
3533 if (!m_db)
3534 throw TskException("No database.");
3535
3536 vector<TskBlackboardAttribute> attributes;
3537 std::string stmt("SELECT blackboard_attributes.artifact_id, blackboard_attributes.source, blackboard_attributes.context, blackboard_attributes.attribute_type_id, blackboard_attributes.value_type, blackboard_attributes.value_byte, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double, blackboard_attributes.obj_id FROM blackboard_attributes ");
3538
3539 constructStmt(stmt, condition);
3540
3541 sqlite3_stmt * statement;
3542 if (sqlite3_prepare_v2(m_db, stmt.c_str(), -1, &statement, 0) == SQLITE_OK)
3543 {
3544 while (sqlite3_step(statement) == SQLITE_ROW)
3545 {
3546 int blobSize = sqlite3_column_bytes(statement, 6);
3547 const unsigned char *pBlob = (const unsigned char *)sqlite3_column_blob(statement, 6);
3548 vector<unsigned char> bytes;
3549 bytes.reserve(blobSize);
3550 for (int i = 0; i < blobSize; i++) {
3551 bytes.push_back((unsigned char)pBlob[i]);
3552 }
3553
3554 attributes.push_back(TskImgDB::createAttribute(sqlite3_column_int64(statement, 0),sqlite3_column_int(statement, 3), sqlite3_column_int64(statement, 10), std::string((char *)sqlite3_column_text(statement, 1)),
3555 std::string((char *)sqlite3_column_text(statement, 2)), (TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE) sqlite3_column_int(statement, 4), sqlite3_column_int(statement, 7),
3556 sqlite3_column_int64(statement, 8), sqlite3_column_double(statement, 9), std::string((char *)sqlite3_column_text(statement, 6)), bytes));
3557 }
3558 sqlite3_finalize(statement);
3559 } else {
3560 std::wstringstream msg;
3561 msg << L"TskImgDBSqlite::getMatchingAttributes - Error getting attributes: " << sqlite3_errmsg(m_db);
3562 LOGERROR(msg.str());
3563 throw TskException("TskImgDBSqlite::getMatchingAttributes - Select failed");
3564 }
3565 return attributes;
3566 }
3567
3568 /**
3569 * Create a new blackboard artifact with the given type id and file id
3570 * @param artifactTypeID artifact type id
3571 * @param file_id associated file id
3572 * @returns the new artifact
3573 */
createBlackboardArtifact(uint64_t file_id,int artifactTypeID)3574 TskBlackboardArtifact TskImgDBSqlite::createBlackboardArtifact(uint64_t file_id, int artifactTypeID)
3575 {
3576 if (!m_db)
3577 throw TskException("No database.");
3578
3579 uint64_t artifactId = 0;
3580 std::stringstream str;
3581 sqlite3_stmt * statement;
3582
3583 str << "INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_type_id) VALUES (NULL, " << file_id << ", " << artifactTypeID << ")";
3584
3585 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3586 if (!(sqlite3_step(statement) == SQLITE_DONE)) {
3587 sqlite3_finalize(statement);
3588 throw TskException("TskImgDBSqlite::addBlackboardInfo - Insert failed");
3589 }
3590 // select max(artifact_id) from blackboard
3591 str.str("");
3592 str << "SELECT artifact_id from blackboard_artifacts WHERE obj_id = " << file_id << " AND artifact_type_id = " << artifactTypeID;
3593 sqlite3_finalize(statement);
3594 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3595 while(sqlite3_step(statement) == SQLITE_ROW) {
3596 uint64_t newID = sqlite3_column_int64(statement, 0);
3597 if(newID > artifactId)
3598 artifactId = newID;
3599 }
3600 } else {
3601 sqlite3_finalize(statement);
3602 throw TskException("TskImgDBSqlite::newBlackboardArtifact - Select artifact_id failed");
3603 }
3604 sqlite3_finalize(statement);
3605 } else {
3606 std::wstringstream infoMessage;
3607 infoMessage << L"TskImgDBSqlite::newBlackboardArtifact - Error adding new artifact: " << sqlite3_errmsg(m_db);
3608 LOGERROR(infoMessage.str());
3609 throw TskException("TskImgDBSqlite::newBlackboardArtifact - Insert failed");
3610 }
3611
3612 return TskImgDB::createArtifact(artifactId, file_id, artifactTypeID);
3613 }
3614
3615 /**
3616 * Add a new artifact type with the given name, display name and id
3617 * @param artifactTypeName type name
3618 * @param displayName display name
3619 * @param typeID type id
3620 */
addArtifactType(int typeID,string artifactTypeName,string displayName)3621 void TskImgDBSqlite::addArtifactType(int typeID, string artifactTypeName, string displayName)
3622 {
3623 if (!m_db)
3624 throw TskException("No database.");
3625
3626 std::stringstream str;
3627 sqlite3_stmt * statement;
3628
3629 str << "SELECT * FROM blackboard_artifact_types WHERE type_name = '" << artifactTypeName << "'";
3630
3631 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3632 if (!(sqlite3_step(statement) == SQLITE_ROW)) {
3633 sqlite3_finalize(statement);
3634 str.str("");
3635 str << "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" << typeID << " , '" << artifactTypeName << "', '" << displayName << "')";
3636 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3637 if (!(sqlite3_step(statement) == SQLITE_DONE)) {
3638 sqlite3_finalize(statement);
3639 std::wstringstream infoMessage;
3640 infoMessage << L"TskImgDBSqlite::addArtifactType - Error adding data to blackboard table: " << sqlite3_errmsg(m_db);
3641 LOGERROR(infoMessage.str());
3642 throw TskException("TskImgDBSqlite::addArtifactType - Artifact type insert failed");
3643 }
3644 }
3645 }
3646 else{
3647 sqlite3_finalize(statement);
3648 throw TskException("TskImgDBSqlite::addArtifactType - Artifact type with that name already exists");
3649 }
3650 sqlite3_finalize(statement);
3651 } else {
3652 std::wstringstream infoMessage;
3653 infoMessage << L"TskImgDBSqlite::addArtifactType - Error adding data to blackboard table: " << sqlite3_errmsg(m_db);
3654 LOGERROR(infoMessage.str());
3655 throw TskException("TskImgDBSqlite::addArtifactType - Insert failed");
3656 }
3657 }
3658
3659 /**
3660 * Add a new attribute type with the given name, display name and id
3661 * @param attributeTypeName type name
3662 * @param displayName display name
3663 * @param typeID type id
3664 */
addAttributeType(int typeID,string attributeTypeName,string displayName)3665 void TskImgDBSqlite::addAttributeType(int typeID, string attributeTypeName, string displayName)
3666 {
3667 if (!m_db)
3668 throw TskException("No database.");
3669
3670 std::stringstream str;
3671 sqlite3_stmt * statement;
3672
3673 str << "SELECT * FROM blackboard_attribute_types WHERE type_name = '" << attributeTypeName << "'";
3674
3675 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3676 if (!(sqlite3_step(statement) == SQLITE_ROW)) {
3677 sqlite3_finalize(statement);
3678 str.str("");
3679 str << "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name) VALUES (" << typeID << " , '" << attributeTypeName << "', '" << displayName << "')";
3680 if (sqlite3_prepare_v2(m_db, str.str().c_str(), -1, &statement, 0) == SQLITE_OK) {
3681 if (!(sqlite3_step(statement) == SQLITE_DONE)) {
3682 sqlite3_finalize(statement);
3683 std::wstringstream infoMessage;
3684 infoMessage << L"TskImgDBSqlite::addAttributeType - Error adding data to blackboard table: " << sqlite3_errmsg(m_db);
3685 LOGERROR(infoMessage.str());
3686 throw TskException("TskImgDBSqlite::addAttributeType - Attribute type insert failed");
3687 }
3688 }
3689 } else {
3690 sqlite3_finalize(statement);
3691 throw TskException("TskImgDBSqlite::addAttributeType - Attribute type with that name already exists");
3692 }
3693 sqlite3_finalize(statement);
3694 } else {
3695 std::wstringstream infoMessage;
3696 infoMessage << L"TskImgDBSqlite::addAttributeType - Error adding data to blackboard table: " << sqlite3_errmsg(m_db);
3697 LOGERROR(infoMessage.str());
3698 throw TskException("TskImgDBSqlite::addAttributeType - Insert failed");
3699 }
3700 }
3701
3702 /**
3703 * Get all artifacts with the given type id, type name, and file id
3704 * @param artifactTypeID type id
3705 * @param artifactTypeName type name
3706 * @param file_id file id
3707 */
getArtifactsHelper(uint64_t file_id,int artifactTypeID,string artifactTypeName)3708 vector<TskBlackboardArtifact> TskImgDBSqlite::getArtifactsHelper(uint64_t file_id, int artifactTypeID, string artifactTypeName)
3709 {
3710 if (!m_db)
3711 throw TskException("No database.");
3712
3713 vector<TskBlackboardArtifact> artifacts;
3714 std::stringstream stmt;
3715 stmt << "SELECT artifact_id, obj_id, artifact_type_id FROM blackboard_artifacts WHERE obj_id = " << file_id << " AND artifact_type_id = " << artifactTypeID;
3716
3717 sqlite3_stmt * statement;
3718 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK)
3719 {
3720 while (sqlite3_step(statement) == SQLITE_ROW)
3721 {
3722 int artifactTypeID = sqlite3_column_int(statement, 2);
3723
3724 artifacts.push_back(TskImgDB::createArtifact(sqlite3_column_int64(statement, 0), file_id, artifactTypeID));
3725 }
3726 sqlite3_finalize(statement);
3727 } else {
3728 std::wstringstream msg;
3729 msg << L"TskImgDBSqlite::getArtifactsHelper - Error getting artifacts: " << sqlite3_errmsg(m_db);
3730 LOGERROR(msg.str());
3731 throw TskException("TskImgDBSqlite::getArtifactsHelper - Select failed");
3732 }
3733 return artifacts;
3734 }
3735
findAttributeTypes(int artifactTypeId)3736 vector<int> TskImgDBSqlite::findAttributeTypes(int artifactTypeId)
3737 {
3738 if (!m_db) {
3739 throw TskException("No database.");
3740 }
3741 vector<int> attrTypes;
3742 std::stringstream stmt;
3743 stmt << "SELECT DISTINCT(attribute_type_id) FROM blackboard_attributes JOIN blackboard_artifacts ON blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id WHERE artifact_type_id = " << artifactTypeId;
3744
3745 sqlite3_stmt * statement;
3746 if (sqlite3_prepare_v2(m_db, stmt.str().c_str(), -1, &statement, 0) == SQLITE_OK)
3747 {
3748 while (sqlite3_step(statement) == SQLITE_ROW)
3749 {
3750 int artifactTypeID = sqlite3_column_int(statement, 0);
3751
3752 attrTypes.push_back(artifactTypeID);
3753 }
3754 sqlite3_finalize(statement);
3755 } else {
3756 std::wstringstream msg;
3757 msg << L"TskImgDBSqlite::findAttributeTypes - Error finding attribute types: " << sqlite3_errmsg(m_db);
3758 LOGERROR(msg.str());
3759 throw TskException("TskImgDBSqlite::findAttributeTypes - Select failed");
3760 }
3761 return attrTypes;
3762 }
3763
quote(const std::string str) const3764 std::string TskImgDBSqlite::quote(const std::string str) const
3765 {
3766 char *item = sqlite3_mprintf("%Q", str.c_str());
3767 std::string returnStr(item);
3768 sqlite3_free(item);
3769 return returnStr;
3770 }
3771
executeStatement(const std::string & stmtToExecute,sqlite3_stmt * & statement,const std::string & caller) const3772 void TskImgDBSqlite::executeStatement(const std::string &stmtToExecute, sqlite3_stmt *&statement, const std::string &caller) const
3773 {
3774 if (sqlite3_prepare_v2(m_db, stmtToExecute.c_str(), -1, &statement, 0) != SQLITE_OK)
3775 {
3776 sqlite3_finalize(statement);
3777 std::ostringstream msg;
3778 msg << caller << " : error executing " << stmtToExecute << " : " << sqlite3_errmsg(m_db);
3779 throw TskException(msg.str());
3780 }
3781 }
3782
3783
3784