Sleuth Kit Java Bindings (JNI)  4.6.0
Java bindings for using The Sleuth Kit
SleuthkitCase.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-2017 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
21 import com.mchange.v2.c3p0.ComboPooledDataSource;
22 import com.mchange.v2.c3p0.DataSources;
23 import com.mchange.v2.c3p0.PooledDataSource;
24 import java.beans.PropertyVetoException;
25 import java.io.BufferedInputStream;
26 import java.io.BufferedOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.io.UnsupportedEncodingException;
34 import java.net.InetAddress;
35 import java.net.URLEncoder;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Paths;
38 import java.sql.Connection;
39 import java.sql.DriverManager;
40 import java.sql.PreparedStatement;
41 import java.sql.ResultSet;
42 import java.sql.SQLException;
43 import java.sql.Statement;
44 import java.text.SimpleDateFormat;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.EnumMap;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.LinkedHashMap;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.MissingResourceException;
57 import java.util.ResourceBundle;
58 import java.util.Set;
59 import java.util.UUID;
60 import java.util.concurrent.ConcurrentHashMap;
61 import java.util.concurrent.locks.ReentrantReadWriteLock;
62 import java.util.logging.Level;
63 import java.util.logging.Logger;
64 import org.postgresql.util.PSQLException;
65 import org.postgresql.util.PSQLState;
80 import org.sqlite.SQLiteConfig;
81 import org.sqlite.SQLiteDataSource;
82 import org.sqlite.SQLiteJDBCLoader;
83 
88 public class SleuthkitCase {
89 
90  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
91 
96  private static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
97  = new CaseDbSchemaVersionNumber(7, 2);
98 
99  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
100  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
101  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
102  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
103  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
104  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
105  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
106  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
107  private static final String SQL_ERROR_LIMIT_GROUP = "54";
108  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
109  private static final int MIN_USER_DEFINED_TYPE_ID = 10000;
110  private final ConnectionPool connections;
111  private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<Long, VirtualDirectory>();
112  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<Long, FileSystem>(); // Cache for file system files.
113  private final ArrayList<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<ErrorObserver>();
114  private final String databaseName;
115  private final String dbPath;
116  private final DbType dbType;
117  private final String caseDirPath;
118  private SleuthkitJNI.CaseDbHandle caseHandle;
119  private String dbBackupPath;
120  private Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap;
121  private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
122  private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
123  private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
124 
125  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
126  // This read/write lock is used to implement a layer of locking on top of
127  // the locking protocol provided by the underlying SQLite database. The Java
128  // locking protocol improves performance for reasons that are not currently
129  // understood. Note that the lock is contructed to use a fairness policy.
130  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
131 
132  private CommunicationsManager communicationsMgrInstance = null;
133 
134  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<String, Set<Long>>();
135 
150  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
151  // Check if we can talk to the database.
152  if (info.getHost() == null || info.getHost().isEmpty()) {
153  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
154  } else if (info.getPort() == null || info.getPort().isEmpty()) {
155  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
156  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
157  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
158  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
159  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
160  }
161 
162  try {
163  Class.forName("org.postgresql.Driver"); //NON-NLS
164  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
165  if (conn != null) {
166  conn.close();
167  }
168  } catch (SQLException ex) {
169  String result;
170  String sqlState = ex.getSQLState().toLowerCase();
171  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
172  try {
173  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
174  // if we can reach the host, then it's probably port problem
175  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
176  } else {
177  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
178  }
179  } catch (IOException any) {
180  // it may be anything
181  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
182  } catch (MissingResourceException any) {
183  // it may be anything
184  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
185  }
186  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
187  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
188  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
189  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
190  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
191  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
192  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
193  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
194  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
195  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
196  } else {
197  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
198  }
199  throw new TskCoreException(result);
200  } catch (ClassNotFoundException ex) {
201  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
202  }
203  }
204 
216  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
217  Class.forName("org.sqlite.JDBC");
218  this.dbPath = dbPath;
219  this.dbType = dbType;
220  File dbFile = new File(dbPath);
221  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
222  this.databaseName = dbFile.getName();
223  this.connections = new SQLiteConnections(dbPath);
224  this.caseHandle = caseHandle;
225  init();
226  logSQLiteJDBCDriverInfo();
227  }
228 
246  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
247  this.dbPath = "";
248  this.databaseName = dbName;
249  this.dbType = dbType;
250  this.caseDirPath = caseDirPath;
251  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
252  this.caseHandle = caseHandle;
253  init();
254  }
255 
256  private void init() throws Exception {
257  typeIdToArtifactTypeMap = new ConcurrentHashMap<Integer, BlackboardArtifact.Type>();
258  typeIdToAttributeTypeMap = new ConcurrentHashMap<Integer, BlackboardAttribute.Type>();
259  typeNameToArtifactTypeMap = new ConcurrentHashMap<String, BlackboardArtifact.Type>();
260  typeNameToAttributeTypeMap = new ConcurrentHashMap<String, BlackboardAttribute.Type>();
261 
262  /*
263  * The following methods need to be called before updateDatabaseSchema
264  * due to the way that updateFromSchema2toSchema3 was implemented.
265  */
266  initBlackboardArtifactTypes();
267  initBlackboardAttributeTypes();
268  initNextArtifactId();
269 
270  updateDatabaseSchema(null);
271 
272  CaseDbConnection connection = connections.getConnection();
273  initIngestModuleTypes(connection);
274  initIngestStatusTypes(connection);
275  initReviewStatuses(connection);
276  initEncodingTypes(connection);
277  connection.close();
278  }
279 
286  if (null == communicationsMgrInstance) {
287  communicationsMgrInstance = new CommunicationsManager(this);
288  }
289  return communicationsMgrInstance;
290  }
291 
298  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
299  CaseDbConnection connection = connections.getConnection();
300  Statement statement = null;
301  ResultSet resultSet = null;
303  try {
304  statement = connection.createStatement();
305  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
306  try {
307  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
308  } catch (SQLException ex) {
309  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS
310  resultSet.next();
311  if (resultSet.getLong("count") == 0) {
312  throw ex;
313  }
314  resultSet.close();
315  resultSet = null;
316  }
317  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
318  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
319  }
320  if (dbType == DbType.POSTGRESQL) {
321  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
322  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
323  }
324  } finally {
325  closeResultSet(resultSet);
326  closeStatement(statement);
327  connection.close();
329  }
330  }
331 
339  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
340  CaseDbConnection connection = connections.getConnection();
341  Statement statement = null;
342  ResultSet resultSet = null;
344  try {
345  statement = connection.createStatement();
346  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
347  try {
348  statement.execute("INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "', '" + type.getValueType().getType() + "')"); //NON-NLS
349  } catch (SQLException ex) {
350  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS
351  resultSet.next();
352  if (resultSet.getLong("count") == 0) {
353  throw ex;
354  }
355  resultSet.close();
356  resultSet = null;
357  }
358  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
359  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
360  }
361  if (this.dbType == DbType.POSTGRESQL) {
362  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
363  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
364  }
365  } finally {
366  closeResultSet(resultSet);
367  closeStatement(statement);
368  connection.close();
370  }
371  }
372 
382  private void initNextArtifactId() throws SQLException, TskCoreException {
383  CaseDbConnection connection = connections.getConnection();
384  Statement statement = null;
385  ResultSet resultSet = null;
387  try {
388  statement = connection.createStatement();
389  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
390  resultSet.next();
391  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
392  if (this.nextArtifactId == 1) {
393  this.nextArtifactId = BASE_ARTIFACT_ID;
394  }
395  } finally {
396  closeResultSet(resultSet);
397  closeStatement(statement);
398  connection.close();
400  }
401  }
402 
410  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
411  Statement statement = null;
412  ResultSet resultSet = null;
414  try {
415  statement = connection.createStatement();
416  for (IngestModuleType type : IngestModuleType.values()) {
417  try {
418  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
419  } catch (SQLException ex) {
420  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
421  resultSet.next();
422  if (resultSet.getLong("count") == 0) {
423  throw ex;
424  }
425  resultSet.close();
426  resultSet = null;
427  }
428  }
429  } finally {
430  closeResultSet(resultSet);
431  closeStatement(statement);
433  }
434  }
435 
443  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
444  Statement statement = null;
445  ResultSet resultSet = null;
447  try {
448  statement = connection.createStatement();
449  for (IngestJobStatusType type : IngestJobStatusType.values()) {
450  try {
451  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
452  } catch (SQLException ex) {
453  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
454  resultSet.next();
455  if (resultSet.getLong("count") == 0) {
456  throw ex;
457  }
458  resultSet.close();
459  resultSet = null;
460  }
461  }
462  } finally {
463  closeResultSet(resultSet);
464  closeStatement(statement);
466  }
467  }
468 
475  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
476  Statement statement = null;
477  ResultSet resultSet = null;
479  try {
480  statement = connection.createStatement();
481  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
482  try {
483  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
484  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
485  } catch (SQLException ex) {
486  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
487  resultSet.next();
488  if (resultSet.getLong("count") == 0) {
489  throw ex;
490  }
491  resultSet.close();
492  resultSet = null;
493  }
494  }
495  } finally {
496  closeResultSet(resultSet);
497  closeStatement(statement);
499  }
500  }
501 
509  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
510  Statement statement = null;
511  ResultSet resultSet = null;
513  try {
514  statement = connection.createStatement();
515  for (TskData.EncodingType type : TskData.EncodingType.values()) {
516  try {
517  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
518  } catch (SQLException ex) {
519  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
520  resultSet.next();
521  if (resultSet.getLong("count") == 0) {
522  throw ex;
523  }
524  resultSet.close();
525  resultSet = null;
526  }
527  }
528  } finally {
529  closeResultSet(resultSet);
530  closeStatement(statement);
532  }
533  }
534 
544  private void updateDatabaseSchema(String dbPath) throws Exception {
545  CaseDbConnection connection = connections.getConnection();
546  ResultSet resultSet = null;
547  Statement statement = null;
549  try {
550  connection.beginTransaction();
551 
552  boolean hasMinorVersion = false;
553  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
554  while (columns.next()) {
555  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
556  hasMinorVersion = true;
557  }
558  }
559 
560  // Get the schema version number of the case database from the tsk_db_info table.
561  int dbSchemaMajorVersion;
562  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
563 
564  statement = connection.createStatement();
565  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
566  + (hasMinorVersion ? ", schema_minor_ver" : "")
567  + " FROM tsk_db_info"); //NON-NLS
568  if (resultSet.next()) {
569  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
570  if (hasMinorVersion) {
571  //if there is a minor version column, use it, else default to zero.
572  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
573  }
574  } else {
575  throw new TskCoreException();
576  }
577  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
578 
579  resultSet.close();
580  resultSet = null;
581  statement.close();
582  statement = null;
583 
584  //check schema compatibility
585  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
586  //we cannot open a db with a major schema version higher than the current one.
587  throw new TskUnsupportedSchemaVersionException(
588  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
589  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
590  //The schema version is compatible,possibly after upgrades.
591 
592  if (null != dbPath) {
593  // Make a backup copy of the database. Client code can get the path of the backup
594  // using the getBackupDatabasePath() method.
595  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
596  copyCaseDB(backupFilePath);
597  dbBackupPath = backupFilePath;
598  }
599 
600  // ***CALL SCHEMA UPDATE METHODS HERE***
601  // Each method should examine the schema version passed to it and either:
602  // a. do nothing and return the schema version unchanged, or
603  // b. upgrade the database and return the schema version that the db was upgraded to.
604  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
605  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
606  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
607  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
608  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
609  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
610  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
611  statement = connection.createStatement();
612  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
613  statement.close();
614  statement = null;
615  }
616 
617  connection.commitTransaction();
618  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
619  connection.rollbackTransaction();
620  throw ex;
621  } finally {
622  closeResultSet(resultSet);
623  closeStatement(statement);
624  connection.close();
626  }
627  }
628 
638  public void copyCaseDB(String newDBPath) throws IOException {
639  if (dbPath.isEmpty()) {
640  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
641  }
642  InputStream in = null;
643  OutputStream out = null;
645  try {
646  InputStream inFile = new FileInputStream(dbPath);
647  in = new BufferedInputStream(inFile);
648  OutputStream outFile = new FileOutputStream(newDBPath);
649  out = new BufferedOutputStream(outFile);
650  int bytesRead = in.read();
651  while (bytesRead != -1) {
652  out.write(bytesRead);
653  bytesRead = in.read();
654  }
655  } finally {
656  try {
657  if (in != null) {
658  in.close();
659  }
660  if (out != null) {
661  out.flush();
662  out.close();
663  }
664  } catch (IOException e) {
665  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
666  }
668  }
669  }
670 
674  private void logSQLiteJDBCDriverInfo() {
675  try {
676  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
677  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
678  ? "native" : "pure-java")); //NON-NLS
679  } catch (Exception ex) {
680  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
681  }
682  }
683 
697  @SuppressWarnings("deprecation")
698  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
699  if (schemaVersion.getMajor() != 2) {
700  return schemaVersion;
701  }
702  Statement statement = null;
703  Statement updateStatement = null;
704  ResultSet resultSet = null;
706  try {
707  statement = connection.createStatement();
708 
709  // Add new tables for tags.
710  statement.execute("CREATE TABLE tag_names (tag_name_id INTEGER PRIMARY KEY, display_name TEXT UNIQUE, description TEXT NOT NULL, color TEXT NOT NULL)"); //NON-NLS
711  statement.execute("CREATE TABLE content_tags (tag_id INTEGER PRIMARY KEY, obj_id INTEGER NOT NULL, tag_name_id INTEGER NOT NULL, comment TEXT NOT NULL, begin_byte_offset INTEGER NOT NULL, end_byte_offset INTEGER NOT NULL)"); //NON-NLS
712  statement.execute("CREATE TABLE blackboard_artifact_tags (tag_id INTEGER PRIMARY KEY, artifact_id INTEGER NOT NULL, tag_name_id INTEGER NOT NULL, comment TEXT NOT NULL)"); //NON-NLS
713 
714  // Add a new table for reports.
715  statement.execute("CREATE TABLE reports (report_id INTEGER PRIMARY KEY, path TEXT NOT NULL, crtime INTEGER NOT NULL, src_module_name TEXT NOT NULL, report_name TEXT NOT NULL)"); //NON-NLS
716 
717  // Add new columns to the image info table.
718  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
719  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
720  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
721 
722  // Add a new column to the file system info table.
723  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
724 
725  // Add a new column to the file table.
726  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
727 
728  // Add new columns and indexes to the attributes table and populate the
729  // new column. Note that addition of the new column is a denormalization
730  // to optimize attribute queries.
731  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
732  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
733  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
734  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
735  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
736  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
737  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
738  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
739  + "FROM blackboard_attributes AS attrs " //NON-NLS
740  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
741  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
742  updateStatement = connection.createStatement();
743  while (resultSet.next()) {
744  long artifactId = resultSet.getLong("artifact_id");
745  int artifactTypeId = resultSet.getInt("artifact_type_id");
746  updateStatement.executeUpdate(
747  "UPDATE blackboard_attributes " //NON-NLS
748  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
749  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
750  }
751  resultSet.close();
752  resultSet = null;
753 
754  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
755  // TODO: This code depends on prepared statements that could evolve with
756  // time, breaking this upgrade. The code that follows should be rewritten
757  // to do everything with SQL specific to case database schema version 2.
758  HashMap<String, TagName> tagNames = new HashMap<String, TagName>();
759  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_FILE)) {
760  Content content = getContentById(artifact.getObjectID());
761  String name = ""; //NON-NLS
762  String comment = ""; //NON-NLS
763  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
764  for (BlackboardAttribute attribute : attributes) {
765  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
766  name = attribute.getValueString();
767  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
768  comment = attribute.getValueString();
769  }
770  }
771  if (!name.isEmpty()) {
772  TagName tagName;
773  if (tagNames.containsKey(name)) {
774  tagName = tagNames.get(name);
775  } else {
776  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
777  tagNames.put(name, tagName);
778  }
779  addContentTag(content, tagName, comment, 0, content.getSize() - 1);
780  }
781  }
782  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
783  long taggedArtifactId = -1;
784  String name = ""; //NON-NLS
785  String comment = ""; //NON-NLS
786  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
787  for (BlackboardAttribute attribute : attributes) {
788  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
789  name = attribute.getValueString();
790  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
791  comment = attribute.getValueString();
792  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
793  taggedArtifactId = attribute.getValueLong();
794  }
795  }
796  if (taggedArtifactId != -1 && !name.isEmpty()) {
797  TagName tagName;
798  if (tagNames.containsKey(name)) {
799  tagName = tagNames.get(name);
800  } else {
801  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
802  tagNames.put(name, tagName);
803  }
804  addBlackboardArtifactTag(getBlackboardArtifact(taggedArtifactId), tagName, comment);
805  }
806  }
807  statement.execute(
808  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
809  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
810  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
811  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
812  statement.execute(
813  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
814  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
815  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
816 
817  return new CaseDbSchemaVersionNumber(3, 0);
818  } finally {
819  closeStatement(updateStatement);
820  closeResultSet(resultSet);
821  closeStatement(statement);
822  connection.close();
824  }
825  }
826 
840  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
841  if (schemaVersion.getMajor() != 3) {
842  return schemaVersion;
843  }
844 
845  Statement statement = null;
846  ResultSet resultSet = null;
847  Statement queryStatement = null;
848  ResultSet queryResultSet = null;
849  Statement updateStatement = null;
851  try {
852  // Add mime_type column to tsk_files table. Populate with general
853  // info artifact file signature data.
854  statement = connection.createStatement();
855  updateStatement = connection.createStatement();
856  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
857  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
858  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
859  + "WHERE files.obj_id = arts.obj_id AND "
860  + "arts.artifact_id = attrs.artifact_id AND "
861  + "arts.artifact_type_id = 1 AND "
862  + "attrs.attribute_type_id = 62");
863  while (resultSet.next()) {
864  updateStatement.executeUpdate(
865  "UPDATE tsk_files " //NON-NLS
866  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
867  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
868  }
869  resultSet.close();
870 
871  // Add value_type column to blackboard_attribute_types table.
872  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
873  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
874  while (resultSet.next()) {
875  int attributeTypeId = resultSet.getInt("attribute_type_id");
876  String attributeLabel = resultSet.getString("type_name");
877  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
878  updateStatement.executeUpdate(
879  "UPDATE blackboard_attribute_types " //NON-NLS
880  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
881  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
882  }
883  }
884  resultSet.close();
885 
886  // Add a data_sources_info table.
887  queryStatement = connection.createStatement();
888  statement.execute("CREATE TABLE data_source_info (obj_id INTEGER PRIMARY KEY, device_id TEXT NOT NULL, time_zone TEXT NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id));");
889  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
890  while (resultSet.next()) {
891  long objectId = resultSet.getLong("obj_id");
892  String timeZone = "";
893  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
894  if (queryResultSet.next()) {
895  timeZone = queryResultSet.getString("tzone");
896  }
897  queryResultSet.close();
898  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
899  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
900  }
901  resultSet.close();
902 
903  // Add data_source_obj_id column to the tsk_files table.
904  //
905  // NOTE: A new case database will have the following FK constraint:
906  //
907  // REFERENCES data_source_info (obj_id)
908  //
909  // The constraint is sacrificed here to avoid having to create and
910  // populate a new tsk_files table.
911  //
912  // TODO: Do this right.
913  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
914  resultSet = statement.executeQuery("SELECT tsk_files.obj_id AS obj_id, par_obj_id FROM tsk_files, tsk_objects WHERE tsk_files.obj_id = tsk_objects.obj_id");
915  while (resultSet.next()) {
916  long fileId = resultSet.getLong("obj_id");
917  long dataSourceId = getDataSourceObjectId(connection, fileId);
918  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
919  }
920  resultSet.close();
921  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
922  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
923  if (this.dbType.equals(DbType.SQLITE)) {
924  statement.execute("CREATE TABLE ingest_modules (ingest_module_id INTEGER PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS
925  statement.execute("CREATE TABLE ingest_jobs (ingest_job_id INTEGER PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS
926  } else {
927  statement.execute("CREATE TABLE ingest_modules (ingest_module_id BIGSERIAL PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS
928  statement.execute("CREATE TABLE ingest_jobs (ingest_job_id BIGSERIAL PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS
929  }
930 
931  statement.execute("CREATE TABLE ingest_job_modules (ingest_job_id INTEGER, ingest_module_id INTEGER, pipeline_position INTEGER, PRIMARY KEY(ingest_job_id, ingest_module_id), FOREIGN KEY(ingest_job_id) REFERENCES ingest_jobs(ingest_job_id), FOREIGN KEY(ingest_module_id) REFERENCES ingest_modules(ingest_module_id));"); //NON-NLS
932  initIngestModuleTypes(connection);
933  initIngestStatusTypes(connection);
934 
935  return new CaseDbSchemaVersionNumber(4, 0);
936 
937  } finally {
938  closeResultSet(queryResultSet);
939  closeStatement(queryStatement);
940  closeStatement(updateStatement);
941  closeResultSet(resultSet);
942  closeStatement(statement);
944  }
945  }
946 
960  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
961  if (schemaVersion.getMajor() != 4) {
962  return schemaVersion;
963  }
964 
965  Statement statement = null;
967  try {
968  // Add the review_statuses lookup table.
969  statement = connection.createStatement();
970  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
971 
972  /*
973  * Add review_status_id column to artifacts table.
974  *
975  * NOTE: For DBs created with schema 5 we define a foreign key
976  * constraint on the review_status_column. We don't bother with this
977  * for DBs updated to schema 5 because of limitations of the SQLite
978  * ALTER TABLE command.
979  */
980  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
981 
982  // Add the encoding table
983  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
984  initEncodingTypes(connection);
985 
986  /*
987  * This needs to be done due to a Autopsy/TSK out of synch problem.
988  * Without this, it is possible to upgrade from version 4 to 5 and
989  * then 5 to 6, but not from 4 to 6.
990  */
991  initReviewStatuses(connection);
992 
993  // Add encoding type column to tsk_files_path
994  // This should really have the FOREIGN KEY constraint but there are problems
995  // getting that to work, so we don't add it on this upgrade path.
996  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
997 
998  return new CaseDbSchemaVersionNumber(5, 0);
999 
1000  } finally {
1001  closeStatement(statement);
1003  }
1004  }
1005 
1019  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1020  if (schemaVersion.getMajor() != 5) {
1021  return schemaVersion;
1022  }
1023 
1024  /*
1025  * This upgrade fixes a bug where some releases had artifact review
1026  * status support in the case database and others did not.
1027  */
1028  Statement statement = null;
1029  ResultSet resultSet = null;
1031  try {
1032  /*
1033  * Add the review_statuses lookup table, if missing.
1034  */
1035  statement = connection.createStatement();
1036  statement.execute("CREATE TABLE IF NOT EXISTS review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1037 
1038  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1039  resultSet.next();
1040  if (resultSet.getLong("count") == 0) {
1041  /*
1042  * Add review_status_id column to artifacts table.
1043  *
1044  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1045  * key constraint on the review_status_column. We don't bother
1046  * with this for DBs updated to schema 5 or 6 because of
1047  * limitations of the SQLite ALTER TABLE command.
1048  */
1049  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1050  }
1051 
1052  return new CaseDbSchemaVersionNumber(6, 0);
1053 
1054  } finally {
1055  closeResultSet(resultSet);
1056  closeStatement(statement);
1058  }
1059  }
1060 
1074  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1075  if (schemaVersion.getMajor() != 6) {
1076  return schemaVersion;
1077  }
1078 
1079  /*
1080  * This upgrade adds an indexed extension column to the tsk_files table.
1081  */
1082  Statement statement = null;
1083  Statement updstatement = null;
1084  ResultSet resultSet = null;
1086  try {
1087  statement = connection.createStatement();
1088  updstatement = connection.createStatement();
1089  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1090 
1091  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1092  while (resultSet.next()) {
1093  long objID = resultSet.getLong("obj_id");
1094  String name = resultSet.getString("name");
1095  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1096  + "WHERE obj_id = " + objID);
1097  }
1098 
1099  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1100 
1101  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1102  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1103 
1104  return new CaseDbSchemaVersionNumber(7, 0);
1105 
1106  } finally {
1107  closeResultSet(resultSet);
1108  closeStatement(statement);
1109  closeStatement(updstatement);
1111  }
1112  }
1113 
1127  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1128  if (schemaVersion.getMajor() != 7) {
1129  return schemaVersion;
1130  }
1131 
1132  if (schemaVersion.getMinor() != 0) {
1133  return schemaVersion;
1134  }
1135 
1136  /*
1137  * This upgrade adds a minor version number column.
1138  */
1139  Statement statement = null;
1140  ResultSet resultSet = null;
1142  try {
1143  statement = connection.createStatement();
1144 
1145  //add the schema minor version number column.
1146  if (schemaVersion.getMinor() == 0) {
1147  //add the schema minor version number column.
1148  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1149  }
1150  return new CaseDbSchemaVersionNumber(7, 1);
1151 
1152  } finally {
1153  closeResultSet(resultSet);
1154  closeStatement(statement);
1156  }
1157  }
1158 
1172  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1173  if (schemaVersion.getMajor() != 7) {
1174  return schemaVersion;
1175  }
1176 
1177  if (schemaVersion.getMinor() != 1) {
1178  return schemaVersion;
1179  }
1180 
1181  Statement statement = null;
1182  Statement updstatement = null;
1183  ResultSet resultSet = null;
1185  try {
1186  //add the data_source_obj_id column to blackboard_artifacts.
1187  statement = connection.createStatement();
1188  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1189 
1190  // populate data_source_obj_id for each artifact
1191  updstatement = connection.createStatement();
1192  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1193  while (resultSet.next()) {
1194  long artifact_id = resultSet.getLong("artifact_id");
1195  long obj_id = resultSet.getLong("obj_id");
1196  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1197  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1198  + "WHERE artifact_id = " + artifact_id);
1199  }
1200  closeResultSet(resultSet);
1201  closeStatement(statement);
1202  closeStatement(updstatement);
1203 
1204  /*
1205  * Add a knownStatus column to the tag_names table.
1206  */
1207  statement = connection.createStatement();
1208  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1209 
1210  // Create account_types, accounts, and account_relationships table
1211  if (this.dbType.equals(DbType.SQLITE)) {
1212  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1213  statement.execute("CREATE TABLE accounts (account_id INTEGER PRIMARY KEY, account_type_id INTEGER NOT NULL, account_unique_identifier TEXT NOT NULL, UNIQUE(account_type_id, account_unique_identifier) , FOREIGN KEY(account_type_id) REFERENCES account_types(account_type_id))");
1214  statement.execute("CREATE TABLE account_relationships (relationship_id INTEGER PRIMARY KEY, account1_id INTEGER NOT NULL, account2_id INTEGER NOT NULL, relationship_source_obj_id INTEGER NOT NULL, date_time INTEGER, relationship_type INTEGER NOT NULL, data_source_obj_id INTEGER NOT NULL, UNIQUE(account1_id, account2_id, relationship_source_obj_id), FOREIGN KEY(account1_id) REFERENCES accounts(account_id), FOREIGN KEY(account2_id) REFERENCES accounts(account_id), FOREIGN KEY(relationship_source_obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id))");
1215  }
1216  else {
1217  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1218  statement.execute("CREATE TABLE accounts (account_id BIGSERIAL PRIMARY KEY, account_type_id INTEGER NOT NULL, account_unique_identifier TEXT NOT NULL, UNIQUE(account_type_id, account_unique_identifier) , FOREIGN KEY(account_type_id) REFERENCES account_types(account_type_id))");
1219  statement.execute("CREATE TABLE account_relationships (relationship_id BIGSERIAL PRIMARY KEY, account1_id INTEGER NOT NULL, account2_id INTEGER NOT NULL, relationship_source_obj_id INTEGER NOT NULL, date_time BIGINT, relationship_type INTEGER NOT NULL, data_source_obj_id INTEGER NOT NULL, UNIQUE(account1_id, account2_id, relationship_source_obj_id), FOREIGN KEY(account1_id) REFERENCES accounts(account_id), FOREIGN KEY(account2_id) REFERENCES accounts(account_id), FOREIGN KEY(relationship_source_obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id))");
1220  }
1221 
1222  // Create indexes
1223  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1224  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1225  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1226  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1227  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1228  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1229  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1230 
1231  return new CaseDbSchemaVersionNumber(7, 2);
1232  } finally {
1233  closeResultSet(resultSet);
1234  closeStatement(statement);
1235  closeStatement(updstatement);
1237  }
1238  }
1239 
1247  static String extractExtension(final String fileName) {
1248  String ext;
1249  int i = fileName.lastIndexOf(".");
1250  // > 0 because we assume it's not an extension if period is the first character
1251  if ((i > 0) && ((i + 1) < fileName.length())) {
1252  ext = fileName.substring(i + 1);
1253  } else {
1254  return "";
1255  }
1256  // we added this at one point to deal with files that had crazy names based on URLs
1257  // it's too hard though to clean those up and not mess up basic extensions though.
1258  // We need to add '-' to the below if we use it again
1259  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
1260  // if (findNonAlphanumeric.length > 1) {
1261  // ext = findNonAlphanumeric[0];
1262  // }
1263  return ext.toLowerCase();
1264  }
1265 
1276  @Deprecated
1277  public int getSchemaVersion() {
1278  return getDBSchemaVersion().getMajor();
1279  }
1280 
1287  return CURRENT_DB_SCHEMA_VERSION;
1288  }
1289 
1296  return this.dbType;
1297  }
1298 
1305  public String getBackupDatabasePath() {
1306  return dbBackupPath;
1307  }
1308 
1319  public CaseDbTransaction beginTransaction() throws TskCoreException {
1320  return new CaseDbTransaction(connections.getConnection());
1321  }
1322 
1328  public String getDatabaseName() {
1329  return databaseName;
1330  }
1331 
1338  public String getDbDirPath() {
1339  return caseDirPath;
1340  }
1341 
1348  if (dbType == DbType.SQLITE) {
1349  rwLock.writeLock().lock();
1350  }
1351  }
1352 
1359  if (dbType == DbType.SQLITE) {
1360  rwLock.writeLock().unlock();
1361  }
1362  }
1363 
1370  if (dbType == DbType.SQLITE) {
1371  rwLock.readLock().lock();
1372  }
1373  }
1374 
1381  if (dbType == DbType.SQLITE) {
1382  rwLock.readLock().unlock();
1383  }
1384  }
1385 
1395  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
1396  try {
1397  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
1398  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
1400  //don't wrap in new TskCoreException
1401  throw ex;
1402  } catch (Exception ex) {
1403  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
1404  }
1405  }
1406 
1418  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
1419  try {
1420  /*
1421  * The flow of this method involves trying to open case and if
1422  * successful, return that case. If unsuccessful, an exception is
1423  * thrown. We catch any exceptions, and use tryConnect() to attempt
1424  * to obtain further information about the error. If tryConnect() is
1425  * unable to successfully connect, tryConnect() will throw a
1426  * TskCoreException with a message containing user-level error
1427  * reporting. If tryConnect() is able to connect, flow continues and
1428  * we rethrow the original exception obtained from trying to create
1429  * the case. In this way, we obtain more detailed information if we
1430  * are able, but do not lose any information if unable.
1431  */
1432  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
1433  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
1434  } catch (PropertyVetoException exp) {
1435  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
1436  throw new TskCoreException(exp.getMessage(), exp);
1438  //don't wrap in new TskCoreException
1439  throw ex;
1440  } catch (Exception exp) {
1441  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
1442  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
1443  }
1444  }
1445 
1455  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
1456  try {
1457  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(dbPath);
1458  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
1459  } catch (Exception ex) {
1460  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
1461  }
1462  }
1463 
1479  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
1480  String databaseName = createCaseDataBaseName(caseName);
1481  try {
1494  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(databaseName, info);
1495  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
1496  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
1497  } catch (PropertyVetoException exp) {
1498  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
1499  throw new TskCoreException(exp.getMessage(), exp);
1500  } catch (Exception exp) {
1501  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
1502  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
1503  }
1504  }
1505 
1515  private static String createCaseDataBaseName(String candidateDbName) {
1516  String dbName;
1517  if (!candidateDbName.isEmpty()) {
1518  /*
1519  * Replace all non-ASCII characters.
1520  */
1521  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
1522 
1523  /*
1524  * Replace all control characters.
1525  */
1526  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
1527 
1528  /*
1529  * Replace /, \, :, ?, space, ' ".
1530  */
1531  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
1532 
1533  /*
1534  * Make it all lowercase.
1535  */
1536  dbName = dbName.toLowerCase();
1537 
1538  /*
1539  * Must start with letter or underscore. If not, prepend an
1540  * underscore.
1541  */
1542  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
1543  dbName = "_" + dbName;
1544  }
1545 
1546  /*
1547  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
1548  * uniqueness.
1549  */
1550  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
1551  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
1552  }
1553 
1554  } else {
1555  /*
1556  * Must start with letter or underscore.
1557  */
1558  dbName = "_";
1559  }
1560  /*
1561  * Add the time stmap.
1562  */
1563  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
1564  Date date = new Date();
1565  dbName = dbName + "_" + dateFormat.format(date);
1566 
1567  return dbName;
1568  }
1569 
1587  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
1588  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath);
1589  }
1590 
1599  public List<Content> getRootObjects() throws TskCoreException {
1600  CaseDbConnection connection = connections.getConnection();
1602  Statement s = null;
1603  ResultSet rs = null;
1604  try {
1605  s = connection.createStatement();
1606  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
1607  + "WHERE par_obj_id IS NULL"); //NON-NLS
1608  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
1609  while (rs.next()) {
1610  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
1611  }
1612 
1613  List<Content> rootObjs = new ArrayList<Content>();
1614  for (ObjectInfo i : infos) {
1615  if (null != i.type) {
1616  switch (i.type) {
1617  case IMG:
1618  rootObjs.add(getImageById(i.id));
1619  break;
1620  case ABSTRACTFILE:
1621  // Check if virtual dir for local files.
1622  AbstractFile af = getAbstractFileById(i.id);
1623  if (af instanceof VirtualDirectory) {
1624  rootObjs.add(af);
1625  } else {
1626  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
1627  }
1628  break;
1629  default:
1630  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
1631  }
1632  }
1633  }
1634  return rootObjs;
1635  } catch (SQLException ex) {
1636  throw new TskCoreException("Error getting root objects", ex);
1637  } finally {
1638  closeResultSet(rs);
1639  closeStatement(s);
1640  connection.close();
1642  }
1643  }
1644 
1656  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
1657 
1658  // check cached map first
1659  synchronized (deviceIdToDatasourceObjIdMap) {
1660  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
1661  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
1662  }
1663 
1664  CaseDbConnection connection = connections.getConnection();
1666  Statement s = null;
1667  ResultSet rs = null;
1668  try {
1669  s = connection.createStatement();
1670  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
1671  List<Long> dataSourceObjIds = new ArrayList<Long>();
1672  while (rs.next()) {
1673  dataSourceObjIds.add(rs.getLong("obj_id"));
1674 
1675  // Add to map of deviceID to data_source_obj_id.
1676  long ds_obj_id = rs.getLong("obj_id");
1677  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
1678  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
1679  } else {
1680  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
1681  }
1682  }
1683  return dataSourceObjIds;
1684  } catch (SQLException ex) {
1685  throw new TskCoreException("Error getting data sources", ex);
1686  } finally {
1687  closeResultSet(rs);
1688  closeStatement(s);
1689  connection.close();
1691  }
1692  }
1693  }
1694 
1711  public List<DataSource> getDataSources() throws TskCoreException {
1712  CaseDbConnection connection = connections.getConnection();
1714  Statement statement = null;
1715  ResultSet resultSet = null;
1716  try {
1717  statement = connection.createStatement();
1718  resultSet = connection.executeQuery(statement,
1719  "SELECT ds.obj_id, ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.display_name "
1720  + "FROM data_source_info AS ds "
1721  + "LEFT JOIN tsk_image_info AS img "
1722  + "ON ds.obj_id = img.obj_id"); //NON-NLS
1723  List<DataSource> dataSourceList = new ArrayList<DataSource>();
1724  Map<Long, List<String>> imagePathsMap = getImagePaths();
1725 
1726  while (resultSet.next()) {
1727  DataSource dataSource;
1728  Long objectId = resultSet.getLong("obj_id");
1729  String deviceId = resultSet.getString("device_id");
1730  String timezone = resultSet.getString("time_zone");
1731  String type = resultSet.getString("type");
1732 
1733  if (type == null) {
1734  /*
1735  * No data found in 'tsk_image_info', so we build a
1736  * LocalFilesDataSource.
1737  */
1741  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
1742  | TSK_FS_META_FLAG_ENUM.USED.getValue());
1743  String parentPath = "/"; //NON-NLS
1744  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, deviceId, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
1745  } else {
1746  /*
1747  * Data found in 'tsk_image_info', so we build an Image.
1748  */
1749  Long ssize = resultSet.getLong("ssize");
1750  Long size = resultSet.getLong("size");
1751  String md5 = resultSet.getString("md5");
1752  String name = resultSet.getString("display_name");
1753 
1754  List<String> imagePaths = imagePathsMap.get(objectId);
1755  if (name == null) {
1756  if (imagePaths.size() > 0) {
1757  String path = imagePaths.get(0);
1758  name = (new java.io.File(path)).getName();
1759  } else {
1760  name = "";
1761  }
1762  }
1763 
1764  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name, imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, size);
1765  }
1766 
1767  dataSourceList.add(dataSource);
1768  }
1769 
1770  return dataSourceList;
1771 
1772  } catch (SQLException ex) {
1773  throw new TskCoreException("Error getting data sources", ex);
1774  } finally {
1775  closeResultSet(resultSet);
1776  closeStatement(statement);
1777  connection.close();
1779  }
1780  }
1781 
1801  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
1802  DataSource dataSource = null;
1803  CaseDbConnection connection = connections.getConnection();
1805  Statement statement = null;
1806  ResultSet resultSet = null;
1807  try {
1808  statement = connection.createStatement();
1809  resultSet = connection.executeQuery(statement,
1810  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.display_name "
1811  + "FROM data_source_info AS ds "
1812  + "LEFT JOIN tsk_image_info AS img "
1813  + "ON ds.obj_id = img.obj_id "
1814  + "WHERE ds.obj_id = " + objectId); //NON-NLS
1815  if (resultSet.next()) {
1816  String deviceId = resultSet.getString("device_id");
1817  String timezone = resultSet.getString("time_zone");
1818  String type = resultSet.getString("type");
1819 
1820  if (type == null) {
1821  /*
1822  * No data found in 'tsk_image_info', so we build an
1823  * LocalFilesDataSource.
1824  */
1828  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
1829  | TSK_FS_META_FLAG_ENUM.USED.getValue());
1830  String parentPath = "/"; //NON-NLS
1831  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, deviceId, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
1832  } else {
1833  /*
1834  * Data found in 'tsk_image_info', so we build an Image.
1835  */
1836  Long ssize = resultSet.getLong("ssize");
1837  Long size = resultSet.getLong("size");
1838  String md5 = resultSet.getString("md5");
1839  String name = resultSet.getString("display_name");
1840 
1841  List<String> imagePaths = getImagePathsById(objectId);
1842  if (name == null) {
1843  if (imagePaths.size() > 0) {
1844  String path = imagePaths.get(0);
1845  name = (new java.io.File(path)).getName();
1846  } else {
1847  name = "";
1848  }
1849  }
1850 
1851  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name, imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, size);
1852  }
1853  } else {
1854  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
1855  }
1856  } catch (SQLException ex) {
1857  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
1858  } finally {
1859  closeResultSet(resultSet);
1860  closeStatement(statement);
1861  connection.close();
1863  }
1864 
1865  return dataSource;
1866  }
1867 
1878  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
1879  return getArtifactsHelper("blackboard_artifacts.artifact_type_id = " + artifactTypeID);
1880  }
1881 
1892  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
1893  CaseDbConnection connection = connections.getConnection();
1895  ResultSet rs = null;
1896  try {
1897  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
1898  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
1899  statement.clearParameters();
1900  statement.setLong(1, objId);
1901  rs = connection.executeQuery(statement);
1902  long count = 0;
1903  if (rs.next()) {
1904  count = rs.getLong("count");
1905  }
1906  return count;
1907  } catch (SQLException ex) {
1908  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
1909  } finally {
1910  closeResultSet(rs);
1911  connection.close();
1913  }
1914  }
1915 
1926  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
1927  CaseDbConnection connection = connections.getConnection();
1929  ResultSet rs = null;
1930  try {
1931  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
1932  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
1933  statement.clearParameters();
1934  statement.setInt(1, artifactTypeID);
1935  rs = connection.executeQuery(statement);
1936  long count = 0;
1937  if (rs.next()) {
1938  count = rs.getLong("count");
1939  }
1940  return count;
1941  } catch (SQLException ex) {
1942  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
1943  } finally {
1944  closeResultSet(rs);
1945  connection.close();
1947  }
1948  }
1949 
1964  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
1965  CaseDbConnection connection = connections.getConnection();
1967  Statement s = null;
1968  ResultSet rs = null;
1969  try {
1970  s = connection.createStatement();
1971  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1972  + "arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
1973  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
1974  + " arts.review_status_id AS review_status_id " //NON-NLS
1975  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1976  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1977  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1978  + " AND attrs.value_text = '" + value + "'"
1979  + " AND types.artifact_type_id=arts.artifact_type_id"
1980  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
1981  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1982  while (rs.next()) {
1983  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
1984  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1985  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1986  }
1987  return artifacts;
1988  } catch (SQLException ex) {
1989  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
1990  } finally {
1991  closeResultSet(rs);
1992  closeStatement(s);
1993  connection.close();
1995  }
1996  }
1997 
2015  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
2016  String valSubStr = "%" + subString; //NON-NLS
2017  if (startsWith == false) {
2018  valSubStr += "%"; //NON-NLS
2019  }
2020  CaseDbConnection connection = connections.getConnection();
2022  Statement s = null;
2023  ResultSet rs = null;
2024  try {
2025  s = connection.createStatement();
2026  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2027  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, " //NON-NLS
2028  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
2029  + " arts.review_status_id AS review_status_id " //NON-NLS
2030  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2031  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2032  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2033  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
2034  + " AND types.artifact_type_id=arts.artifact_type_id "
2035  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2036  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2037  while (rs.next()) {
2038  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2039  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2040  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2041  }
2042  return artifacts;
2043  } catch (SQLException ex) {
2044  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
2045  } finally {
2046  closeResultSet(rs);
2047  closeStatement(s);
2048  connection.close();
2050  }
2051  }
2052 
2067  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
2068  CaseDbConnection connection = connections.getConnection();
2070  Statement s = null;
2071  ResultSet rs = null;
2072  try {
2073  s = connection.createStatement();
2074  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2075  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2076  + " types.type_name AS type_name, types.display_name AS display_name, "
2077  + " arts.review_status_id AS review_status_id "//NON-NLS
2078  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2079  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2080  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2081  + " AND attrs.value_int32 = " + value //NON-NLS
2082  + " AND types.artifact_type_id=arts.artifact_type_id "
2083  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2084  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2085  while (rs.next()) {
2086  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2087  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2088  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2089  }
2090  return artifacts;
2091  } catch (SQLException ex) {
2092  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
2093  } finally {
2094  closeResultSet(rs);
2095  closeStatement(s);
2096  connection.close();
2098  }
2099  }
2100 
2115  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
2116  CaseDbConnection connection = connections.getConnection();
2118  Statement s = null;
2119  ResultSet rs = null;
2120  try {
2121  s = connection.createStatement();
2122  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2123  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2124  + " types.type_name AS type_name, types.display_name AS display_name, "
2125  + " arts.review_status_id AS review_status_id "//NON-NLS
2126  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2127  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2128  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2129  + " AND attrs.value_int64 = " + value //NON-NLS
2130  + " AND types.artifact_type_id=arts.artifact_type_id "
2131  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2132  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2133  while (rs.next()) {
2134  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2135  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2136  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2137  }
2138  return artifacts;
2139  } catch (SQLException ex) {
2140  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
2141  } finally {
2142  closeResultSet(rs);
2143  closeStatement(s);
2144  connection.close();
2146  }
2147  }
2148 
2163  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
2164  CaseDbConnection connection = connections.getConnection();
2166  Statement s = null;
2167  ResultSet rs = null;
2168  try {
2169  s = connection.createStatement();
2170  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2171  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2172  + " types.type_name AS type_name, types.display_name AS display_name, "
2173  + " arts.review_status_id AS review_status_id "//NON-NLS
2174  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2175  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2176  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2177  + " AND attrs.value_double = " + value //NON-NLS
2178  + " AND types.artifact_type_id=arts.artifact_type_id "
2179  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2180  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2181  while (rs.next()) {
2182  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2183  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2184  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2185  }
2186  return artifacts;
2187  } catch (SQLException ex) {
2188  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
2189  } finally {
2190  closeResultSet(rs);
2191  closeStatement(s);
2192  connection.close();
2194  }
2195  }
2196 
2211  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
2212  CaseDbConnection connection = connections.getConnection();
2214  Statement s = null;
2215  ResultSet rs = null;
2216  try {
2217  s = connection.createStatement();
2218  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2219  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2220  + " types.type_name AS type_name, types.display_name AS display_name, "
2221  + " arts.review_status_id AS review_status_id "//NON-NLS
2222  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2223  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2224  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2225  + " AND attrs.value_byte = " + value //NON-NLS
2226  + " AND types.artifact_type_id=arts.artifact_type_id "
2227  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2228  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2229  while (rs.next()) {
2230  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2231  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2232  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2233  }
2234  return artifacts;
2235  } catch (SQLException ex) {
2236  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
2237  } finally {
2238  closeResultSet(rs);
2239  closeStatement(s);
2240  connection.close();
2242  }
2243  }
2244 
2252  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
2253  CaseDbConnection connection = connections.getConnection();
2255  Statement s = null;
2256  ResultSet rs = null;
2257  try {
2258  s = connection.createStatement();
2259  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types"); //NON-NLS
2260  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
2261  while (rs.next()) {
2262  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2263  rs.getString("type_name"), rs.getString("display_name")));
2264  }
2265  return artifactTypes;
2266  } catch (SQLException ex) {
2267  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
2268  } finally {
2269  closeResultSet(rs);
2270  closeStatement(s);
2271  connection.close();
2273  }
2274  }
2275 
2284  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
2285  String typeIdList = "";
2286  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
2287  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
2288  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
2289  typeIdList += ", ";
2290  }
2291  }
2292  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
2293  + "WHERE artifact_type_id IN (" + typeIdList + ")";
2294  CaseDbConnection connection = connections.getConnection();
2296  Statement s = null;
2297  ResultSet rs = null;
2298  try {
2299  s = connection.createStatement();
2300  rs = connection.executeQuery(s, query);
2301  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
2302  while (rs.next()) {
2303  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
2304  }
2305  return usedArts;
2306  } catch (SQLException ex) {
2307  throw new TskCoreException("Error getting artifact types in use", ex);
2308  } finally {
2309  closeResultSet(rs);
2310  closeStatement(s);
2311  connection.close();
2313  }
2314  }
2315 
2326  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
2327  CaseDbConnection connection = connections.getConnection();
2329  Statement s = null;
2330  ResultSet rs = null;
2331  try {
2332  s = connection.createStatement();
2333  rs = connection.executeQuery(s,
2334  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
2335  + "types.type_name AS type_name, types.display_name AS display_name "
2336  + "FROM blackboard_artifact_types AS types "
2337  + "INNER JOIN blackboard_artifacts AS arts "
2338  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
2339  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
2340  while (rs.next()) {
2341  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2342  rs.getString("type_name"), rs.getString("display_name")));
2343  }
2344  return uniqueArtifactTypes;
2345  } catch (SQLException ex) {
2346  throw new TskCoreException("Error getting attribute types", ex);
2347  } finally {
2348  closeResultSet(rs);
2349  closeStatement(s);
2350  connection.close();
2352  }
2353  }
2354 
2362  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
2363  CaseDbConnection connection = connections.getConnection();
2365  Statement s = null;
2366  ResultSet rs = null;
2367  try {
2368  s = connection.createStatement();
2369  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
2370  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
2371  while (rs.next()) {
2372  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
2373  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
2374  }
2375  return attribute_types;
2376  } catch (SQLException ex) {
2377  throw new TskCoreException("Error getting attribute types", ex);
2378  } finally {
2379  closeResultSet(rs);
2380  closeStatement(s);
2381  connection.close();
2383  }
2384  }
2385 
2397  public int getBlackboardAttributeTypesCount() throws TskCoreException {
2398  CaseDbConnection connection = connections.getConnection();
2400  Statement s = null;
2401  ResultSet rs = null;
2402  try {
2403  s = connection.createStatement();
2404  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
2405  int count = 0;
2406  if (rs.next()) {
2407  count = rs.getInt("count");
2408  }
2409  return count;
2410  } catch (SQLException ex) {
2411  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
2412  } finally {
2413  closeResultSet(rs);
2414  closeStatement(s);
2415  connection.close();
2417  }
2418  }
2419 
2432  private ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
2433  CaseDbConnection connection = connections.getConnection();
2435  ResultSet rs = null;
2436  try {
2437  Statement statement = connection.createStatement();
2438  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
2439  + "blackboard_artifacts.obj_id AS obj_id, "
2440  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
2441  + "blackboard_artifacts.data_source_obj_id AS data_source_obj_id, "
2442  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
2443  + "blackboard_artifact_types.type_name AS type_name, "
2444  + "blackboard_artifact_types.display_name AS display_name, "
2445  + "blackboard_artifacts.review_status_id AS review_status_id "
2446  + "FROM blackboard_artifacts, blackboard_artifact_types "
2447  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
2448  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
2449  + " AND " + whereClause;
2450  rs = connection.executeQuery(statement, query);
2451  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2452  while (rs.next()) {
2453  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2454  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2455  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2456  }
2457  return artifacts;
2458  } catch (SQLException ex) {
2459  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
2460  } finally {
2461  closeResultSet(rs);
2462  connection.close();
2464  }
2465  }
2466 
2479  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
2480  CaseDbConnection connection = connections.getConnection();
2482  ResultSet rs = null;
2483  try {
2484  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
2485  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
2486  statement.clearParameters();
2487  statement.setLong(1, obj_id);
2488  statement.setInt(2, artifactTypeID);
2489  rs = connection.executeQuery(statement);
2490  long count = 0;
2491  if (rs.next()) {
2492  count = rs.getLong("count");
2493  }
2494  return count;
2495  } catch (SQLException ex) {
2496  throw new TskCoreException("Error getting blackboard artifact count", ex);
2497  } finally {
2498  closeResultSet(rs);
2499  connection.close();
2501  }
2502  }
2503 
2516  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
2517  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
2518  }
2519 
2532  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
2533  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
2534  }
2535 
2548  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
2549  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
2550  }
2551 
2564  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
2565  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
2566  if (artifactTypeID == -1) {
2567  return 0;
2568  }
2569  return getArtifactsCountHelper(artifactTypeID, obj_id);
2570  }
2571 
2584  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
2585  return getArtifactsCountHelper(artifactTypeID, obj_id);
2586  }
2587 
2600  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
2601  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
2602  }
2603 
2615  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
2616  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
2617  }
2618 
2630  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
2631  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
2632  }
2633 
2647  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
2648  CaseDbConnection connection = connections.getConnection();
2650  Statement s = null;
2651  ResultSet rs = null;
2652  try {
2653  s = connection.createStatement();
2654  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2655  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2656  + "types.type_name AS type_name, types.display_name AS display_name,"
2657  + "arts.review_status_id AS review_status_id "//NON-NLS
2658  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2659  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2660  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2661  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
2662  + " AND attrs.value_text = '" + value + "'" //NON-NLS
2663  + " AND types.artifact_type_id=arts.artifact_type_id"
2664  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2665  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2666  while (rs.next()) {
2667  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2668  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2669  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2670  }
2671  return artifacts;
2672  } catch (SQLException ex) {
2673  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
2674  } finally {
2675  closeResultSet(rs);
2676  closeStatement(s);
2677  connection.close();
2679  }
2680  }
2681 
2692  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
2693  CaseDbConnection connection = connections.getConnection();
2695  ResultSet rs = null;
2696  Statement s;
2697  try {
2698  s = connection.createStatement();
2699  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
2700  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2701  + "types.type_name AS type_name, types.display_name AS display_name,"
2702  + "arts.review_status_id AS review_status_id "//NON-NLS
2703  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
2704  + "WHERE arts.artifact_id = " + artifactID
2705  + " AND arts.artifact_type_id = types.artifact_type_id");
2706  if (rs.next()) {
2707  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2708  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2709  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
2710  } else {
2711  /*
2712  * I think this should actually return null (or Optional) when
2713  * there is no artifact with the given id, but it looks like
2714  * existing code is not expecting that. -jm
2715  */
2716  throw new TskCoreException("No blackboard artifact with id " + artifactID);
2717  }
2718  } catch (SQLException ex) {
2719  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
2720  } finally {
2721  closeResultSet(rs);
2722  connection.close();
2724  }
2725  }
2726 
2735  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
2736  CaseDbConnection connection = connections.getConnection();
2738  try {
2739  addBlackBoardAttribute(attr, artifactTypeId, connection);
2740  } catch (SQLException ex) {
2741  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
2742  } finally {
2743  connection.close();
2745  }
2746  }
2747 
2757  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
2758  CaseDbConnection connection = connections.getConnection();
2760  try {
2761  connection.beginTransaction();
2762  for (final BlackboardAttribute attr : attributes) {
2763  addBlackBoardAttribute(attr, artifactTypeId, connection);
2764  }
2765  connection.commitTransaction();
2766  } catch (SQLException ex) {
2767  connection.rollbackTransaction();
2768  throw new TskCoreException("Error adding blackboard attributes", ex);
2769  } finally {
2770  connection.close();
2772  }
2773  }
2774 
2775  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
2776  PreparedStatement statement;
2777  switch (attr.getAttributeType().getValueType()) {
2778  case STRING:
2779  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
2780  statement.clearParameters();
2781  statement.setString(7, attr.getValueString());
2782  break;
2783  case BYTE:
2784  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
2785  statement.clearParameters();
2786  statement.setBytes(7, attr.getValueBytes());
2787  break;
2788  case INTEGER:
2789  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
2790  statement.clearParameters();
2791  statement.setInt(7, attr.getValueInt());
2792  break;
2793  case LONG:
2794  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
2795  statement.clearParameters();
2796  statement.setLong(7, attr.getValueLong());
2797  break;
2798  case DOUBLE:
2799  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
2800  statement.clearParameters();
2801  statement.setDouble(7, attr.getValueDouble());
2802  break;
2803  case DATETIME:
2804  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
2805  statement.clearParameters();
2806  statement.setLong(7, attr.getValueLong());
2807  break;
2808  default:
2809  throw new TskCoreException("Unrecognized artifact attribute value type");
2810  }
2811  statement.setLong(1, attr.getArtifactID());
2812  statement.setInt(2, artifactTypeId);
2813  statement.setString(3, attr.getSourcesCSV());
2814  statement.setString(4, "");
2815  statement.setInt(5, attr.getAttributeType().getTypeID());
2816  statement.setLong(6, attr.getAttributeType().getValueType().getType());
2817  connection.executeUpdate(statement);
2818  }
2819 
2830  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
2831  /*
2832  * WARNING: This is a temporary implementation that is not safe and
2833  * denormalizes the case datbase.
2834  *
2835  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
2836  * the sources of artifact attributes.
2837  */
2838  if (null == source || source.isEmpty()) {
2839  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
2840  }
2841  CaseDbConnection connection = connections.getConnection();
2843  Statement queryStmt = null;
2844  Statement updateStmt = null;
2845  ResultSet result = null;
2846  String newSources = "";
2847  try {
2848  connection.beginTransaction();
2849  String valueClause = "";
2850  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
2851  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
2852  switch (valueType) {
2853  case STRING:
2854  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
2855  break;
2856  case INTEGER:
2857  valueClause = " value_int32 = " + attr.getValueInt();
2858  break;
2859  case LONG:
2860  case DATETIME:
2861  valueClause = " value_int64 = " + attr.getValueLong();
2862  break;
2863  case DOUBLE:
2864  valueClause = " value_double = " + attr.getValueDouble();
2865  break;
2866  default:
2867  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
2868  }
2869  String query = "SELECT source FROM blackboard_attributes WHERE"
2870  + " artifact_id = " + attr.getArtifactID()
2871  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
2872  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
2873  + " AND " + valueClause + ";";
2874  queryStmt = connection.createStatement();
2875  updateStmt = connection.createStatement();
2876  result = connection.executeQuery(queryStmt, query);
2877  } else {
2878  /*
2879  * SELECT source FROM blackboard_attributes WHERE artifact_id =
2880  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
2881  * = ?
2882  */
2883  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
2884  statement.clearParameters();
2885  statement.setLong(1, attr.getArtifactID());
2886  statement.setLong(2, attr.getAttributeType().getTypeID());
2887  statement.setBytes(3, attr.getValueBytes());
2888  result = connection.executeQuery(statement);
2889  }
2890  while (result.next()) {
2891  String oldSources = result.getString("source");
2892  if (null != oldSources && !oldSources.isEmpty()) {
2893  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
2894  if (!uniqueSources.contains(source)) {
2895  newSources = oldSources + "," + source;
2896  } else {
2897  newSources = oldSources;
2898  }
2899  } else {
2900  newSources = source;
2901  }
2902  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
2903  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
2904  + " artifact_id = " + attr.getArtifactID()
2905  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
2906  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
2907  + " AND " + valueClause + ";";
2908  connection.executeUpdate(updateStmt, update);
2909  } else {
2910  /*
2911  * UPDATE blackboard_attributes SET source = ? WHERE
2912  * artifact_id = ? AND attribute_type_id = ? AND value_type
2913  * = 4 AND value_byte = ?
2914  */
2915  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
2916  statement.clearParameters();
2917  statement.setString(1, newSources);
2918  statement.setLong(2, attr.getArtifactID());
2919  statement.setLong(3, attr.getAttributeType().getTypeID());
2920  statement.setBytes(4, attr.getValueBytes());
2921  connection.executeUpdate(statement);
2922  }
2923  }
2924  connection.commitTransaction();
2925  return newSources;
2926  } catch (SQLException ex) {
2927  connection.rollbackTransaction();
2928  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
2929  } finally {
2930  closeResultSet(result);
2931  closeStatement(updateStmt);
2932  closeStatement(queryStmt);
2933  connection.close();
2935  }
2936  }
2937 
2952  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
2953  CaseDbConnection connection = connections.getConnection();
2955  Statement s = null;
2956  ResultSet rs = null;
2957  try {
2958  connection.beginTransaction();
2959  s = connection.createStatement();
2960  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
2961  if (!rs.next()) {
2962  rs.close();
2963  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
2964  int maxID = 0;
2965  if (rs.next()) {
2966  maxID = rs.getInt("highest_id");
2967  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
2968  maxID = MIN_USER_DEFINED_TYPE_ID;
2969  } else {
2970  maxID++;
2971  }
2972  }
2973  connection.executeUpdate(s, "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES ('" + maxID + "', '" + attrTypeString + "', '" + displayName + "', '" + valueType.getType() + "')"); //NON-NLS
2974  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
2975  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
2976  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
2977  connection.commitTransaction();
2978  return type;
2979  } else {
2980  throw new TskDataException("The attribute type that was added was already within the system.");
2981  }
2982 
2983  } catch (SQLException ex) {
2984  connection.rollbackTransaction();
2985  throw new TskCoreException("Error adding attribute type", ex);
2986  } finally {
2987  closeResultSet(rs);
2988  closeStatement(s);
2989  connection.close();
2991  }
2992  }
2993 
3004  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
3005  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
3006  return this.typeNameToAttributeTypeMap.get(attrTypeName);
3007  }
3008  CaseDbConnection connection = connections.getConnection();
3010  Statement s = null;
3011  ResultSet rs = null;
3012  try {
3013  s = connection.createStatement();
3014  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
3015  BlackboardAttribute.Type type = null;
3016  if (rs.next()) {
3017  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3018  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
3019  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
3020  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
3021  }
3022  return type;
3023  } catch (SQLException ex) {
3024  throw new TskCoreException("Error getting attribute type id", ex);
3025  } finally {
3026  closeResultSet(rs);
3027  closeStatement(s);
3028  connection.close();
3030  }
3031  }
3032 
3043  private BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
3044  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
3045  return this.typeIdToAttributeTypeMap.get(typeID);
3046  }
3047  CaseDbConnection connection = connections.getConnection();
3049  Statement s = null;
3050  ResultSet rs = null;
3051  try {
3052  s = connection.createStatement();
3053  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE attribute_type_id = " + typeID + ""); //NON-NLS
3054  BlackboardAttribute.Type type = null;
3055  if (rs.next()) {
3056  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3057  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
3058  this.typeIdToAttributeTypeMap.put(typeID, type);
3059  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
3060  }
3061  return type;
3062  } catch (SQLException ex) {
3063  throw new TskCoreException("Error getting attribute type id", ex);
3064  } finally {
3065  closeResultSet(rs);
3066  closeStatement(s);
3067  connection.close();
3069  }
3070  }
3071 
3082  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
3083  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
3084  return this.typeNameToArtifactTypeMap.get(artTypeName);
3085  }
3086  CaseDbConnection connection = connections.getConnection();
3088  Statement s = null;
3089  ResultSet rs = null;
3090  try {
3091  s = connection.createStatement();
3092  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
3093  BlackboardArtifact.Type type = null;
3094  if (rs.next()) {
3095  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3096  rs.getString("type_name"), rs.getString("display_name"));
3097  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
3098  this.typeNameToArtifactTypeMap.put(artTypeName, type);
3099  }
3100  return type;
3101  } catch (SQLException ex) {
3102  throw new TskCoreException("Error getting artifact type from the database", ex);
3103  } finally {
3104  closeResultSet(rs);
3105  closeStatement(s);
3106  connection.close();
3108  }
3109  }
3110 
3121  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
3122  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
3123  return typeIdToArtifactTypeMap.get(artTypeId);
3124  }
3125  CaseDbConnection connection = connections.getConnection();
3127  Statement s = null;
3128  ResultSet rs = null;
3129  try {
3130  s = connection.createStatement();
3131  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
3132  BlackboardArtifact.Type type = null;
3133  if (rs.next()) {
3134  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3135  rs.getString("type_name"), rs.getString("display_name"));
3136  this.typeIdToArtifactTypeMap.put(artTypeId, type);
3137  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
3138  }
3139  return type;
3140  } catch (SQLException ex) {
3141  throw new TskCoreException("Error getting artifact type from the database", ex);
3142  } finally {
3143  closeResultSet(rs);
3144  closeStatement(s);
3145  connection.close();
3147  }
3148  }
3149 
3162  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
3163  CaseDbConnection connection = connections.getConnection();
3165  Statement s = null;
3166  ResultSet rs = null;
3167  try {
3168  connection.beginTransaction();
3169  s = connection.createStatement();
3170  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
3171  if (!rs.next()) {
3172  rs.close();
3173  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
3174  int maxID = 0;
3175  if (rs.next()) {
3176  maxID = rs.getInt("highest_id");
3177  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
3178  maxID = MIN_USER_DEFINED_TYPE_ID;
3179  } else {
3180  maxID++;
3181  }
3182  }
3183  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
3184  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName);
3185  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
3186  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
3187  connection.commitTransaction();
3188  return type;
3189  } else {
3190  throw new TskDataException("The attribute type that was added was already within the system.");
3191  }
3192  } catch (SQLException ex) {
3193  connection.rollbackTransaction();
3194  throw new TskCoreException("Error adding artifact type", ex);
3195  } finally {
3196  closeResultSet(rs);
3197  closeStatement(s);
3198  connection.close();
3200  }
3201  }
3202 
3203  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
3204  CaseDbConnection connection = connections.getConnection();
3206  ResultSet rs = null;
3207  try {
3208  Statement statement = connection.createStatement();
3209  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
3210  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
3211  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
3212  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
3213  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
3214  + "types.type_name AS type_name, types.display_name AS display_name "
3215  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
3216  + " AND attrs.attribute_type_id = types.attribute_type_id");
3217  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
3218  while (rs.next()) {
3219  int attributeTypeId = rs.getInt("attribute_type_id");
3220  String attributeTypeName = rs.getString("type_name");
3221  BlackboardAttribute.Type attributeType;
3222  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
3223  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
3224  } else {
3225  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
3226  rs.getString("display_name"),
3228  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
3229  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
3230  }
3231 
3232  final BlackboardAttribute attr = new BlackboardAttribute(
3233  rs.getLong("artifact_id"),
3234  attributeType,
3235  rs.getString("source"),
3236  rs.getString("context"),
3237  rs.getInt("value_int32"),
3238  rs.getLong("value_int64"),
3239  rs.getDouble("value_double"),
3240  rs.getString("value_text"),
3241  rs.getBytes("value_byte"), this
3242  );
3243  attributes.add(attr);
3244  }
3245  return attributes;
3246  } catch (SQLException ex) {
3247  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
3248  } finally {
3249  closeResultSet(rs);
3250  connection.close();
3252  }
3253  }
3254 
3267  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
3268  CaseDbConnection connection = connections.getConnection();
3270  Statement s = null;
3271  ResultSet rs = null;
3272  try {
3273  s = connection.createStatement();
3274  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
3275  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
3276  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
3277  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
3278  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
3279  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
3280  + "FROM blackboard_attributes " + whereClause); //NON-NLS
3281  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
3282  while (rs.next()) {
3284  // attribute type is cached, so this does not necessarily call to the db
3285  type = this.getAttributeType(rs.getInt("attribute_type_id"));
3287  rs.getLong("artifact_id"),
3288  type,
3289  rs.getString("source"),
3290  rs.getString("context"),
3291  rs.getInt("value_int32"),
3292  rs.getLong("value_int64"),
3293  rs.getDouble("value_double"),
3294  rs.getString("value_text"),
3295  rs.getBytes("value_byte"), this
3296  );
3297  matches.add(attr);
3298  }
3299  return matches;
3300  } catch (SQLException ex) {
3301  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
3302  } finally {
3303  closeResultSet(rs);
3304  closeStatement(s);
3305  connection.close();
3307  }
3308  }
3309 
3321  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
3322  CaseDbConnection connection = connections.getConnection();
3324  ResultSet rs = null;
3325  Statement s = null;
3326  try {
3327  s = connection.createStatement();
3328  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
3329  + "blackboard_artifacts.obj_id AS obj_id, blackboard_artifacts.artifact_obj_id AS artifact_obj_id, blackboard_artifacts.data_source_obj_id AS data_source_obj_id, blackboard_artifacts.artifact_type_id AS artifact_type_id, "
3330  + "blackboard_artifacts.review_status_id AS review_status_id "
3331  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
3332  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
3333  while (rs.next()) {
3334  BlackboardArtifact.Type type;
3335  // artifact type is cached, so this does not necessarily call to the db
3336  type = this.getArtifactType(rs.getInt("artifact_type_id"));
3337  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3338  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
3339  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
3340  matches.add(artifact);
3341  }
3342  return matches;
3343  } catch (SQLException ex) {
3344  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
3345  } finally {
3346  closeResultSet(rs);
3347  closeStatement(s);
3348  connection.close();
3350  }
3351  }
3352 
3366  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
3367  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
3368  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName());
3369  }
3370 
3382  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3383  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
3384  }
3385 
3386  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
3387  CaseDbConnection connection = connections.getConnection();
3389  ResultSet resultSet = null;
3390  try {
3391 
3392  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
3393  statement.clearParameters();
3394  statement.setLong(1, obj_id);
3395  statement.setInt(2, TskData.ObjectType.ARTIFACT.getObjectType());
3396  connection.executeUpdate(statement);
3397  resultSet = statement.getGeneratedKeys();
3398  resultSet.next();
3399  long artifact_obj_id = resultSet.getLong(1); //last_insert_rowid()
3400  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
3401 
3402  if (dbType == DbType.POSTGRESQL) {
3403  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
3404  statement.clearParameters();
3405  statement.setLong(1, obj_id);
3406  statement.setLong(2, artifact_obj_id);
3407  statement.setLong(3, data_source_obj_id);
3408  statement.setInt(4, artifact_type_id);
3409 
3410  } else {
3411  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
3412  statement.clearParameters();
3413  this.nextArtifactId++;
3414  statement.setLong(1, this.nextArtifactId);
3415  statement.setLong(2, obj_id);
3416  statement.setLong(3, artifact_obj_id);
3417  statement.setLong(4, data_source_obj_id);
3418  statement.setInt(5, artifact_type_id);
3419 
3420  }
3421  connection.executeUpdate(statement);
3422  resultSet = statement.getGeneratedKeys();
3423  resultSet.next();
3424  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
3425  obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
3426  } catch (SQLException ex) {
3427  throw new TskCoreException("Error creating a blackboard artifact", ex);
3428  } finally {
3429  closeResultSet(resultSet);
3430  connection.close();
3432  }
3433  }
3434 
3447  boolean getContentHasChildren(Content content) throws TskCoreException {
3448  CaseDbConnection connection = connections.getConnection();
3450  ResultSet rs = null;
3451  try {
3452  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
3453  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
3454  statement.clearParameters();
3455  statement.setLong(1, content.getId());
3456  rs = connection.executeQuery(statement);
3457  boolean hasChildren = false;
3458  if (rs.next()) {
3459  hasChildren = rs.getInt("count") > 0;
3460  }
3461  return hasChildren;
3462  } catch (SQLException e) {
3463  throw new TskCoreException("Error checking for children of parent " + content, e);
3464  } finally {
3465  closeResultSet(rs);
3466  connection.close();
3468  }
3469  }
3470 
3483  int getContentChildrenCount(Content content) throws TskCoreException {
3484  CaseDbConnection connection = connections.getConnection();
3486  ResultSet rs = null;
3487  try {
3488  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
3489  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
3490  statement.clearParameters();
3491  statement.setLong(1, content.getId());
3492  rs = connection.executeQuery(statement);
3493  int countChildren = -1;
3494  if (rs.next()) {
3495  countChildren = rs.getInt("count");
3496  }
3497  return countChildren;
3498  } catch (SQLException e) {
3499  throw new TskCoreException("Error checking for children of parent " + content, e);
3500  } finally {
3501  closeResultSet(rs);
3502  connection.close();
3504  }
3505  }
3506 
3518  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
3519  CaseDbConnection connection = connections.getConnection();
3521  ResultSet rs = null;
3522  try {
3523  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
3524  statement.clearParameters();
3525  long parentId = parent.getId();
3526  statement.setLong(1, parentId);
3527  statement.setShort(2, type.getFileType());
3528  rs = connection.executeQuery(statement);
3529  return fileChildren(rs, connection, parentId);
3530  } catch (SQLException ex) {
3531  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3532  } finally {
3533  closeResultSet(rs);
3534  connection.close();
3536  }
3537  }
3538 
3548  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
3549  CaseDbConnection connection = connections.getConnection();
3551  ResultSet rs = null;
3552  try {
3553  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
3554  statement.clearParameters();
3555  long parentId = parent.getId();
3556  statement.setLong(1, parentId);
3557  rs = connection.executeQuery(statement);
3558  return fileChildren(rs, connection, parentId);
3559  } catch (SQLException ex) {
3560  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3561  } finally {
3562  closeResultSet(rs);
3563  connection.close();
3565  }
3566  }
3567 
3579  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
3580  CaseDbConnection connection = connections.getConnection();
3582  ResultSet rs = null;
3583  try {
3584  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
3585  statement.clearParameters();
3586  statement.setLong(1, parent.getId());
3587  statement.setShort(2, type.getFileType());
3588  rs = connection.executeQuery(statement);
3589  List<Long> children = new ArrayList<Long>();
3590  while (rs.next()) {
3591  children.add(rs.getLong("obj_id"));
3592  }
3593  return children;
3594  } catch (SQLException ex) {
3595  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3596  } finally {
3597  closeResultSet(rs);
3598  connection.close();
3600  }
3601  }
3602 
3612  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
3613  CaseDbConnection connection = connections.getConnection();
3615  ResultSet rs = null;
3616  try {
3617  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
3618  statement.clearParameters();
3619  statement.setLong(1, parent.getId());
3620  rs = connection.executeQuery(statement);
3621  List<Long> children = new ArrayList<Long>();
3622  while (rs.next()) {
3623  children.add(rs.getLong("obj_id"));
3624  }
3625  return children;
3626  } catch (SQLException ex) {
3627  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3628  } finally {
3629  closeResultSet(rs);
3630  connection.close();
3632  }
3633  }
3634 
3645  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
3646  CaseDbConnection connection = connections.getConnection();
3648  ResultSet rs = null;
3649  try {
3650  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
3651  statement.clearParameters();
3652  statement.setLong(1, parent.getId());
3653  rs = connection.executeQuery(statement);
3654  List<Long> children = new ArrayList<Long>();
3655  while (rs.next()) {
3656  children.add(rs.getLong("obj_id"));
3657  }
3658  return children;
3659  } catch (SQLException ex) {
3660  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
3661  } finally {
3662  closeResultSet(rs);
3663  connection.close();
3665  }
3666  }
3667 
3677  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
3678 
3679  long parentId = parent.getId();
3680  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
3681 
3682  List<Content> lc = new ArrayList<Content>();
3683  lc.addAll(artsArray);
3684  return lc;
3685  }
3686 
3695  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
3696  CaseDbConnection connection = connections.getConnection();
3698  Statement s = null;
3699  ResultSet rs = null;
3700  try {
3701  s = connection.createStatement();
3702  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
3703  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
3704  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
3705  + "WHERE tsk_objects.par_obj_id = " + c.getId()
3706  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
3707  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3708  while (rs.next()) {
3709  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3710  }
3711  return infos;
3712  } catch (SQLException ex) {
3713  throw new TskCoreException("Error getting Children Info for Content", ex);
3714  } finally {
3715  closeResultSet(rs);
3716  closeStatement(s);
3717  connection.close();
3719  }
3720  }
3721 
3732  ObjectInfo getParentInfo(Content c) throws TskCoreException {
3733  // TODO: This should not throw an exception if Content has no parent,
3734  // return null instead.
3735  CaseDbConnection connection = connections.getConnection();
3737  Statement s = null;
3738  ResultSet rs = null;
3739  try {
3740  s = connection.createStatement();
3741  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
3742  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
3743  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
3744  + "WHERE child.obj_id = " + c.getId()); //NON-NLS
3745  if (rs.next()) {
3746  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
3747  } else {
3748  throw new TskCoreException("Given content (id: " + c.getId() + ") has no parent");
3749  }
3750  } catch (SQLException ex) {
3751  throw new TskCoreException("Error getting Parent Info for Content", ex);
3752  } finally {
3753  closeResultSet(rs);
3754  closeStatement(s);
3755  connection.close();
3757  }
3758  }
3759 
3770  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
3771  // TODO: This should not throw an exception if Content has no parent,
3772  // return null instead.
3773  CaseDbConnection connection = connections.getConnection();
3775  Statement s = null;
3776  ResultSet rs = null;
3777  try {
3778  s = connection.createStatement();
3779  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
3780  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
3781  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
3782  + "WHERE child.obj_id = " + contentId); //NON-NLS
3783  if (rs.next()) {
3784  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
3785  } else {
3786  throw new TskCoreException("Given content (id: " + contentId + ") has no parent.");
3787  }
3788  } catch (SQLException ex) {
3789  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
3790  } finally {
3791  closeResultSet(rs);
3792  closeStatement(s);
3793  connection.close();
3795  }
3796  }
3797 
3808  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
3809  // TODO: This should not throw an exception if Content has no parent,
3810  // return null instead.
3811  if (fsc.isRoot()) {
3812  throw new TskCoreException("Given FsContent (id: " + fsc.getId() + ") is a root object (can't have parent directory).");
3813  } else {
3814  ObjectInfo parentInfo = getParentInfo(fsc);
3815  Directory parent = null;
3816  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
3817  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
3818  } else {
3819  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
3820  }
3821  return parent;
3822  }
3823  }
3824 
3836  public Content getContentById(long id) throws TskCoreException {
3837  CaseDbConnection connection = connections.getConnection();
3839  Statement s = null;
3840  ResultSet rs = null;
3841  try {
3842  s = connection.createStatement();
3843  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
3844  if (!rs.next()) {
3845  return null;
3846  }
3847 
3848  Content content = null;
3849  long parentId = rs.getLong("par_obj_id"); //NON-NLS
3850  final TskData.ObjectType type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
3851  switch (type) {
3852  case IMG:
3853  content = getImageById(id);
3854  break;
3855  case VS:
3856  content = getVolumeSystemById(id, parentId);
3857  break;
3858  case VOL:
3859  content = getVolumeById(id, parentId);
3860  break;
3861  case FS:
3862  content = getFileSystemById(id, parentId);
3863  break;
3864  case ABSTRACTFILE:
3865  content = getAbstractFileById(id);
3866  break;
3867  case ARTIFACT:
3868  content = getArtifactById(id);
3869  break;
3870  default:
3871  throw new TskCoreException("Could not obtain Content object with ID: " + id);
3872  }
3873  return content;
3874  } catch (SQLException ex) {
3875  throw new TskCoreException("Error getting Content by ID.", ex);
3876  } finally {
3877  closeResultSet(rs);
3878  closeStatement(s);
3879  connection.close();
3881  }
3882  }
3883 
3891  String getFilePath(long id) {
3892  CaseDbConnection connection;
3893  try {
3894  connection = connections.getConnection();
3895  } catch (TskCoreException ex) {
3896  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3897  return null;
3898  }
3899  String filePath = null;
3901  ResultSet rs = null;
3902  try {
3903  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
3904  statement.clearParameters();
3905  statement.setLong(1, id);
3906  rs = connection.executeQuery(statement);
3907  if (rs.next()) {
3908  filePath = rs.getString("path");
3909  }
3910  } catch (SQLException ex) {
3911  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3912  } finally {
3913  closeResultSet(rs);
3914  connection.close();
3916  }
3917  return filePath;
3918  }
3919 
3927  TskData.EncodingType getEncodingType(long id) {
3928  CaseDbConnection connection;
3929  try {
3930  connection = connections.getConnection();
3931  } catch (TskCoreException ex) {
3932  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3933  return null;
3934  }
3935  TskData.EncodingType type = TskData.EncodingType.NONE;
3937  ResultSet rs = null;
3938  try {
3939  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
3940  statement.clearParameters();
3941  statement.setLong(1, id);
3942  rs = connection.executeQuery(statement);
3943  if (rs.next()) {
3944  type = TskData.EncodingType.valueOf(rs.getInt(1));
3945  }
3946  } catch (SQLException ex) {
3947  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
3948  } finally {
3949  closeResultSet(rs);
3950  connection.close();
3952  }
3953  return type;
3954  }
3955 
3964  String getFileParentPath(long objectId, CaseDbConnection connection) {
3965  String parentPath = null;
3967  ResultSet rs = null;
3968  try {
3969  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
3970  statement.clearParameters();
3971  statement.setLong(1, objectId);
3972  rs = connection.executeQuery(statement);
3973  if (rs.next()) {
3974  parentPath = rs.getString("parent_path");
3975  }
3976  } catch (SQLException ex) {
3977  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
3978  } finally {
3979  closeResultSet(rs);
3981  }
3982  return parentPath;
3983  }
3984 
3993  String getFileName(long objectId, CaseDbConnection connection) {
3994  String fileName = null;
3996  ResultSet rs = null;
3997  try {
3998  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
3999  statement.clearParameters();
4000  statement.setLong(1, objectId);
4001  rs = connection.executeQuery(statement);
4002  if (rs.next()) {
4003  fileName = rs.getString("name");
4004  }
4005  } catch (SQLException ex) {
4006  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
4007  } finally {
4008  closeResultSet(rs);
4010  }
4011  return fileName;
4012  }
4013 
4024  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
4025  CaseDbConnection connection = connections.getConnection();
4026  DerivedFile.DerivedMethod method = null;
4028  ResultSet rs1 = null;
4029  ResultSet rs2 = null;
4030  try {
4031  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
4032  statement.clearParameters();
4033  statement.setLong(1, id);
4034  rs1 = connection.executeQuery(statement);
4035  if (rs1.next()) {
4036  int method_id = rs1.getInt("derived_id");
4037  String rederive = rs1.getString("rederive");
4038  method = new DerivedFile.DerivedMethod(method_id, rederive);
4039  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
4040  statement.clearParameters();
4041  statement.setInt(1, method_id);
4042  rs2 = connection.executeQuery(statement);
4043  if (rs2.next()) {
4044  method.setToolName(rs2.getString("tool_name"));
4045  method.setToolVersion(rs2.getString("tool_version"));
4046  method.setOther(rs2.getString("other"));
4047  }
4048  }
4049  } catch (SQLException e) {
4050  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
4051  } finally {
4052  closeResultSet(rs2);
4053  closeResultSet(rs1);
4054  connection.close();
4056  }
4057  return method;
4058  }
4059 
4070  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
4071  CaseDbConnection connection = connections.getConnection();
4073  ResultSet rs = null;
4074  try {
4075  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
4076  statement.clearParameters();
4077  statement.setLong(1, id);
4078  rs = connection.executeQuery(statement);
4079  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
4080  if (files.size() > 0) {
4081  return files.get(0);
4082  } else {
4083  return null;
4084  }
4085  } catch (SQLException ex) {
4086  throw new TskCoreException("Error getting file by id, id = " + id, ex);
4087  } finally {
4088  closeResultSet(rs);
4089  connection.close();
4091  }
4092  }
4093 
4104  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
4105  CaseDbConnection connection = connections.getConnection();
4107  ResultSet rs = null;
4108  try {
4109  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID);
4110  statement.clearParameters();
4111  statement.setLong(1, id);
4112  rs = connection.executeQuery(statement);
4113  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
4114  if (artifacts.size() > 0) {
4115  return artifacts.get(0);
4116  } else {
4117  return null;
4118  }
4119  } catch (SQLException ex) {
4120  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
4121  } finally {
4122  closeResultSet(rs);
4123  connection.close();
4125  }
4126  }
4127 
4138  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
4139  CaseDbConnection connection = connections.getConnection();
4141  ResultSet rs = null;
4142  try {
4143  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_ID);
4144  statement.clearParameters();
4145  statement.setLong(1, id);
4146  rs = connection.executeQuery(statement);
4147  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
4148  if (artifacts.size() > 0) {
4149  return artifacts.get(0);
4150  } else {
4151  return null;
4152  }
4153  } catch (SQLException ex) {
4154  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
4155  } finally {
4156  closeResultSet(rs);
4157  connection.close();
4159  }
4160  }
4161 
4174  private long getFileSystemId(long fileId, CaseDbConnection connection) {
4176  ResultSet rs = null;
4177  long ret = -1;
4178  try {
4179  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
4180  statement.clearParameters();
4181  statement.setLong(1, fileId);
4182  rs = connection.executeQuery(statement);
4183  if (rs.next()) {
4184  ret = rs.getLong("fs_obj_id");
4185  if (ret == 0) {
4186  ret = -1;
4187  }
4188  }
4189  } catch (SQLException e) {
4190  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
4191  } finally {
4192  closeResultSet(rs);
4194  }
4195  return ret;
4196  }
4197 
4209  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
4210  String query = String.format("SELECT COUNT(*) AS count FROM tsk_files WHERE obj_id = %d AND data_source_obj_id = %d", fileId, dataSource.getId()); //NON-NLS
4211  CaseDbConnection connection = connections.getConnection();
4213  Statement statement = null;
4214  ResultSet resultSet = null;
4215  try {
4216  statement = connection.createStatement();
4217  resultSet = connection.executeQuery(statement, query);
4218  resultSet.next();
4219  return (resultSet.getLong("count") > 0L);
4220  } catch (SQLException ex) {
4221  throw new TskCoreException(String.format("Error executing query %s", query), ex);
4222  } finally {
4223  closeResultSet(resultSet);
4224  closeStatement(statement);
4225  connection.close();
4227  }
4228  }
4229 
4241  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
4242  List<AbstractFile> files = new ArrayList<AbstractFile>();
4243  CaseDbConnection connection = connections.getConnection();
4245  ResultSet resultSet = null;
4246  try {
4247  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
4248  statement.clearParameters();
4249  statement.setString(1, fileName.toLowerCase());
4250  statement.setLong(2, dataSource.getId());
4251  resultSet = connection.executeQuery(statement);
4252  files.addAll(resultSetToAbstractFiles(resultSet, connection));
4253  } catch (SQLException e) {
4254  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
4255  } finally {
4256  closeResultSet(resultSet);
4257  connection.close();
4259  }
4260  return files;
4261  }
4262 
4276  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirName) throws TskCoreException {
4277  List<AbstractFile> files = new ArrayList<AbstractFile>();
4278  CaseDbConnection connection = connections.getConnection();
4280  ResultSet resultSet = null;
4281  try {
4282  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
4283  statement.clearParameters();
4284  statement.setString(1, fileName.toLowerCase());
4285  statement.setString(2, "%" + dirName.toLowerCase() + "%"); //NON-NLS
4286  statement.setLong(3, dataSource.getId());
4287  resultSet = connection.executeQuery(statement);
4288  files.addAll(resultSetToAbstractFiles(resultSet, connection));
4289  } catch (SQLException e) {
4290  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
4291  } finally {
4292  closeResultSet(resultSet);
4293  connection.close();
4295  }
4296  return files;
4297  }
4298 
4310  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
4312  CaseDbTransaction localTrans = beginTransaction();
4313  try {
4314  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
4315  localTrans.commit();
4316  return newVD;
4317  } catch (TskCoreException ex) {
4318  try {
4319  localTrans.rollback();
4320  } catch (TskCoreException ex2) {
4321  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4322  }
4323  throw ex;
4324  } finally {
4326  }
4327  }
4328 
4346  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
4347  if (transaction == null) {
4348  throw new TskCoreException("Passed null CaseDbTransaction");
4349  }
4350 
4352  ResultSet resultSet = null;
4353  try {
4354  // Get the parent path.
4355  CaseDbConnection connection = transaction.getConnection();
4356  String parentPath = getFileParentPath(parentId, connection);
4357  if (parentPath == null) {
4358  parentPath = "/"; //NON-NLS
4359  }
4360  String parentName = getFileName(parentId, connection);
4361  if (parentName != null && !parentName.isEmpty()) {
4362  parentPath = parentPath + parentName + "/"; //NON-NLS
4363  }
4364 
4365  // Insert a row for the virtual directory into the tsk_objects table.
4366  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4367  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4368  statement.clearParameters();
4369  if (parentId != 0) {
4370  statement.setLong(1, parentId);
4371  } else {
4372  statement.setNull(1, java.sql.Types.BIGINT);
4373  }
4374  statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4375  connection.executeUpdate(statement);
4376  resultSet = statement.getGeneratedKeys();
4377  resultSet.next();
4378  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4379 
4380  // Insert a row for the virtual directory into the tsk_files table.
4381  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
4382  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
4383  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
4384  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4385  statement.clearParameters();
4386  statement.setLong(1, newObjId);
4387 
4388  // If the parent is part of a file system, grab its file system ID
4389  if (0 != parentId) {
4390  long parentFs = this.getFileSystemId(parentId, connection);
4391  if (parentFs != -1) {
4392  statement.setLong(2, parentFs);
4393  } else {
4394  statement.setNull(2, java.sql.Types.BIGINT);
4395  }
4396  } else {
4397  statement.setNull(2, java.sql.Types.BIGINT);
4398  }
4399 
4400  // name
4401  statement.setString(3, directoryName);
4402 
4403  //type
4404  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
4405  statement.setShort(5, (short) 1);
4406 
4407  //flags
4409  statement.setShort(6, dirType.getValue());
4411  statement.setShort(7, metaType.getValue());
4412 
4413  //allocated
4415  statement.setShort(8, dirFlag.getValue());
4416  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4417  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4418  statement.setShort(9, metaFlags);
4419 
4420  //size
4421  statement.setLong(10, 0);
4422 
4423  // nulls for params 11-14
4424  statement.setNull(11, java.sql.Types.BIGINT);
4425  statement.setNull(12, java.sql.Types.BIGINT);
4426  statement.setNull(13, java.sql.Types.BIGINT);
4427  statement.setNull(14, java.sql.Types.BIGINT);
4428 
4429  // parent path
4430  statement.setString(15, parentPath);
4431 
4432  // data source object id (same as object id if this is a data source)
4433  long dataSourceObjectId;
4434  if (0 == parentId) {
4435  dataSourceObjectId = newObjId;
4436  } else {
4437  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
4438  }
4439  statement.setLong(16, dataSourceObjectId);
4440 
4441  //extension, since this is not really file we just set it to null
4442  statement.setString(17, null);
4443  connection.executeUpdate(statement);
4444 
4445  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
4446  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
4447  parentPath);
4448  } catch (SQLException e) {
4449  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
4450  } finally {
4451  closeResultSet(resultSet);
4453  }
4454  }
4455 
4468  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
4470  CaseDbTransaction localTrans = beginTransaction();
4471  try {
4472  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
4473  localTrans.commit();
4474  return newLD;
4475  } catch (TskCoreException ex) {
4476  try {
4477  localTrans.rollback();
4478  } catch (TskCoreException ex2) {
4479  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4480  }
4481  throw ex;
4482  } finally {
4484  }
4485  }
4486 
4504  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
4505  if (transaction == null) {
4506  throw new TskCoreException("Passed null CaseDbTransaction");
4507  }
4508 
4510  ResultSet resultSet = null;
4511  try {
4512  // Get the parent path.
4513  CaseDbConnection connection = transaction.getConnection();
4514  String parentPath = getFileParentPath(parentId, connection);
4515  if (parentPath == null) {
4516  parentPath = "/"; //NON-NLS
4517  }
4518  String parentName = getFileName(parentId, connection);
4519  if (parentName != null && !parentName.isEmpty()) {
4520  parentPath = parentPath + parentName + "/"; //NON-NLS
4521  }
4522 
4523  // Insert a row for the local directory into the tsk_objects table.
4524  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4525  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4526  statement.clearParameters();
4527  if (parentId != 0) {
4528  statement.setLong(1, parentId);
4529  } else {
4530  statement.setNull(1, java.sql.Types.BIGINT);
4531  }
4532  statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4533  connection.executeUpdate(statement);
4534  resultSet = statement.getGeneratedKeys();
4535  resultSet.next();
4536  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4537 
4538  // Insert a row for the local directory into the tsk_files table.
4539  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
4540  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id)
4541  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
4542  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4543  statement.clearParameters();
4544  statement.setLong(1, newObjId);
4545 
4546  // The parent of a local directory will never be a file system
4547  statement.setNull(2, java.sql.Types.BIGINT);
4548 
4549  // name
4550  statement.setString(3, directoryName);
4551 
4552  //type
4553  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
4554  statement.setShort(5, (short) 1);
4555 
4556  //flags
4558  statement.setShort(6, dirType.getValue());
4560  statement.setShort(7, metaType.getValue());
4561 
4562  //allocated
4564  statement.setShort(8, dirFlag.getValue());
4565  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4566  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4567  statement.setShort(9, metaFlags);
4568 
4569  //size
4570  statement.setLong(10, 0);
4571 
4572  // nulls for params 11-14
4573  statement.setNull(11, java.sql.Types.BIGINT);
4574  statement.setNull(12, java.sql.Types.BIGINT);
4575  statement.setNull(13, java.sql.Types.BIGINT);
4576  statement.setNull(14, java.sql.Types.BIGINT);
4577 
4578  // parent path
4579  statement.setString(15, parentPath);
4580 
4581  // data source object id
4582  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
4583  statement.setLong(16, dataSourceObjectId);
4584 
4585  //extension, since this is a directory we just set it to null
4586  statement.setString(17, null);
4587 
4588  connection.executeUpdate(statement);
4589 
4590  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
4591  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
4592  parentPath);
4593  } catch (SQLException e) {
4594  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
4595  } finally {
4596  closeResultSet(resultSet);
4598  }
4599  }
4600 
4620  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
4622  Statement statement = null;
4623  ResultSet resultSet = null;
4624  try {
4625  // Insert a row for the root virtual directory of the data source
4626  // into the tsk_objects table.
4627  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4628  CaseDbConnection connection = transaction.getConnection();
4629  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4630  preparedStatement.clearParameters();
4631  preparedStatement.setNull(1, java.sql.Types.BIGINT);
4632  preparedStatement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4633  connection.executeUpdate(preparedStatement);
4634  resultSet = preparedStatement.getGeneratedKeys();
4635  resultSet.next();
4636  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4637  resultSet.close();
4638  resultSet = null;
4639 
4640  // Insert a row for the virtual directory of the data source into
4641  // the data_source_info table.
4642  statement = connection.createStatement();
4643  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
4644  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');");
4645 
4646  // Insert a row for the root virtual directory of the data source
4647  // into the tsk_files table. Note that its data source object id is
4648  // its own object id.
4649  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
4650  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
4651  // atime, mtime, parent_path, data_source_obj_id, extension)
4652  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
4653  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4654  preparedStatement.clearParameters();
4655  preparedStatement.setLong(1, newObjId);
4656  preparedStatement.setNull(2, java.sql.Types.BIGINT);
4657  preparedStatement.setString(3, rootDirectoryName);
4658  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
4659  preparedStatement.setShort(5, (short) 1);
4661  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
4663  preparedStatement.setShort(7, metaType.getValue());
4665  preparedStatement.setShort(8, dirFlag.getValue());
4666  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4667  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4668  preparedStatement.setShort(9, metaFlags);
4669  preparedStatement.setLong(10, 0);
4670  preparedStatement.setNull(11, java.sql.Types.BIGINT);
4671  preparedStatement.setNull(12, java.sql.Types.BIGINT);
4672  preparedStatement.setNull(13, java.sql.Types.BIGINT);
4673  preparedStatement.setNull(14, java.sql.Types.BIGINT);
4674  String parentPath = "/"; //NON-NLS
4675  preparedStatement.setString(15, parentPath);
4676  preparedStatement.setLong(16, newObjId);
4677  preparedStatement.setString(17, null); //extension, just set it to null
4678  connection.executeUpdate(preparedStatement);
4679 
4680  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, FileKnown.UNKNOWN, parentPath);
4681 
4682  } catch (SQLException ex) {
4683  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
4684  } finally {
4685  closeResultSet(resultSet);
4686  closeStatement(statement);
4688  }
4689  }
4690 
4699  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
4700  CaseDbConnection connection = connections.getConnection();
4702  Statement s = null;
4703  ResultSet rs = null;
4704  try {
4705  s = connection.createStatement();
4706  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
4707  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
4708  + " AND obj_id = data_source_obj_id"
4709  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
4710  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
4711  while (rs.next()) {
4712  virtDirRootIds.add(virtualDirectory(rs));
4713  }
4714  return virtDirRootIds;
4715  } catch (SQLException ex) {
4716  throw new TskCoreException("Error getting local files virtual folder id", ex);
4717  } finally {
4718  closeResultSet(rs);
4719  closeStatement(s);
4720  connection.close();
4722  }
4723  }
4724 
4737  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
4738  assert (null != fileRanges);
4739  if (null == fileRanges) {
4740  throw new TskCoreException("TskFileRange object is null");
4741  }
4742 
4743  assert (null != parent);
4744  if (null == parent) {
4745  throw new TskCoreException("Conent is null");
4746  }
4747 
4748  CaseDbTransaction transaction = null;
4749  Statement statement = null;
4750  ResultSet resultSet = null;
4752 
4753  try {
4754  transaction = beginTransaction();
4755  CaseDbConnection connection = transaction.getConnection();
4756 
4757  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
4758  for (TskFileRange fileRange : fileRanges) {
4759  /*
4760  * Insert a row for the Tsk file range into the tsk_objects
4761  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
4762  * ?)
4763  */
4764  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4765  prepStmt.clearParameters();
4766  prepStmt.setLong(1, parent.getId()); // par_obj_id
4767  prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
4768  connection.executeUpdate(prepStmt);
4769  resultSet = prepStmt.getGeneratedKeys();
4770  resultSet.next();
4771  long fileRangeId = resultSet.getLong(1); //last_insert_rowid()
4772  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
4773  /*
4774  * Insert a row for the Tsk file range into the tsk_files table:
4775  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
4776  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
4777  * ctime, crtime, atime, mtime, parent_path,
4778  * data_source_obj_id,extension) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
4779  * ?, ?, ?, ?, ?, ?, ?, ?,?)
4780  */
4781  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4782  prepStmt.clearParameters();
4783  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
4784  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
4785  prepStmt.setString(3, "Unalloc_" + parent.getId() + "_" + fileRange.getByteStart() + "_" + end_byte_in_parent); // name of form Unalloc_[image obj_id]_[start byte in parent]_[end byte in parent]
4786  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
4787  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
4788  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
4789  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
4790  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
4791  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
4792  prepStmt.setLong(10, fileRange.getByteLen()); // size
4793  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
4794  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
4795  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
4796  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
4797  prepStmt.setNull(15, java.sql.Types.VARCHAR); // parent path
4798  prepStmt.setLong(16, parent.getId()); // data_source_obj_id
4799 
4800  //extension, since this is not a FS file we just set it to null
4801  prepStmt.setString(17, null);
4802  connection.executeUpdate(prepStmt);
4803 
4804  /*
4805  * Insert a row in the tsk_layout_file table for each chunk of
4806  * the carved file. INSERT INTO tsk_file_layout (obj_id,
4807  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
4808  */
4809  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
4810  prepStmt.clearParameters();
4811  prepStmt.setLong(1, fileRangeId); // obj_id
4812  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
4813  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
4814  prepStmt.setLong(4, fileRange.getSequence()); // sequence
4815  connection.executeUpdate(prepStmt);
4816 
4817  /*
4818  * Create a layout file representation of the carved file.
4819  */
4820  fileRangeLayoutFiles.add(new LayoutFile(this,
4821  fileRangeId,
4822  parent.getId(),
4823  Long.toString(fileRange.getSequence()),
4828  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
4829  fileRange.getByteLen(),
4830  null,
4832  parent.getUniquePath(),
4833  null));
4834  }
4835 
4836  transaction.commit();
4837  return fileRangeLayoutFiles;
4838 
4839  } catch (SQLException ex) {
4840  if (null != transaction) {
4841  try {
4842  transaction.rollback();
4843  } catch (TskCoreException ex2) {
4844  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4845  }
4846  }
4847  throw new TskCoreException("Failed to add layout files to case database", ex);
4848 
4849  } catch (TskCoreException ex) {
4850  if (null != transaction) {
4851  try {
4852  transaction.rollback();
4853  } catch (TskCoreException ex2) {
4854  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4855  }
4856  }
4857  throw ex;
4858 
4859  } finally {
4860  closeResultSet(resultSet);
4861  closeStatement(statement);
4863  }
4864  }
4865 
4877  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
4878  assert (null != carvingResult);
4879  if (null == carvingResult) {
4880  throw new TskCoreException("Carving is null");
4881  }
4882  assert (null != carvingResult.getParent());
4883  if (null == carvingResult.getParent()) {
4884  throw new TskCoreException("Carving result has null parent");
4885  }
4886  assert (null != carvingResult.getCarvedFiles());
4887  if (null == carvingResult.getCarvedFiles()) {
4888  throw new TskCoreException("Carving result has null carved files");
4889  }
4890  CaseDbTransaction transaction = null;
4891  Statement statement = null;
4892  ResultSet resultSet = null;
4894  long newCacheKey = 0; // Used to roll back cache if transaction is rolled back.
4895  try {
4896  transaction = beginTransaction();
4897  CaseDbConnection connection = transaction.getConnection();
4898 
4899  /*
4900  * Carved files are "re-parented" as children of the $CarvedFiles
4901  * virtual directory of the root file system, volume, or image
4902  * ancestor of the carved files parent, but if no such ancestor is
4903  * found, then the parent specified in the carving result is used.
4904  */
4905  Content root = carvingResult.getParent();
4906  while (null != root) {
4907  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
4908  break;
4909  }
4910  root = root.getParent();
4911  }
4912  if (null == root) {
4913  root = carvingResult.getParent();
4914  }
4915 
4916  /*
4917  * Get or create the $CarvedFiles virtual directory for the root
4918  * ancestor.
4919  */
4920  VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
4921  if (null == carvedFilesDir) {
4922  List<Content> rootChildren;
4923  if (root instanceof FileSystem) {
4924  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
4925  } else {
4926  rootChildren = root.getChildren();
4927  }
4928  for (Content child : rootChildren) {
4929  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
4930  carvedFilesDir = (VirtualDirectory) child;
4931  break;
4932  }
4933  }
4934  if (null == carvedFilesDir) {
4935  long parId = root.getId();
4936  // $CarvedFiles should be a child of the root directory, not the file system
4937  if (root instanceof FileSystem) {
4938  Content rootDir = ((FileSystem) root).getRootDirectory();
4939  parId = rootDir.getId();
4940  }
4941  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED, transaction);
4942  }
4943  newCacheKey = root.getId();
4944  rootIdsToCarvedFileDirs.put(newCacheKey, carvedFilesDir);
4945  }
4946 
4947  /*
4948  * Add the carved files to the database as children of the
4949  * $CarvedFile directory of the root ancestor.
4950  */
4951  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
4952  List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>();
4953  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
4954  /*
4955  * Insert a row for the carved file into the tsk_objects table:
4956  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4957  */
4958  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4959  prepStmt.clearParameters();
4960  prepStmt.setLong(1, carvedFilesDir.getId()); // par_obj_id
4961  prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
4962  connection.executeUpdate(prepStmt);
4963  resultSet = prepStmt.getGeneratedKeys();
4964  resultSet.next();
4965  long carvedFileId = resultSet.getLong(1); //last_insert_rowid()
4966 
4967  /*
4968  * Insert a row for the carved file into the tsk_files table:
4969  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
4970  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
4971  * ctime, crtime, atime, mtime, parent_path,
4972  * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
4973  * ?, ?, ?, ?, ?, ?, ?, ?,?)
4974  */
4975  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4976  prepStmt.clearParameters();
4977  prepStmt.setLong(1, carvedFileId); // obj_id
4978  if (root instanceof FileSystem) {
4979  prepStmt.setLong(2, root.getId()); // fs_obj_id
4980  } else {
4981  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
4982  }
4983  prepStmt.setString(3, carvedFile.getName()); // name
4984  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
4985  prepStmt.setShort(5, (short) 1); // has_path
4986  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
4987  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
4988  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
4989  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
4990  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
4991  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
4992  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
4993  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
4994  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
4995  prepStmt.setString(15, parentPath); // parent path
4996  prepStmt.setLong(16, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
4997 
4998  prepStmt.setString(17, extractExtension(carvedFile.getName())); //extension
4999  connection.executeUpdate(prepStmt);
5000 
5001  /*
5002  * Insert a row in the tsk_layout_file table for each chunk of
5003  * the carved file. INSERT INTO tsk_file_layout (obj_id,
5004  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
5005  */
5006  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
5007  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
5008  prepStmt.clearParameters();
5009  prepStmt.setLong(1, carvedFileId); // obj_id
5010  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
5011  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
5012  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
5013  connection.executeUpdate(prepStmt);
5014  }
5015 
5016  /*
5017  * Create a layout file representation of the carved file.
5018  */
5019  carvedFiles.add(new LayoutFile(this,
5020  carvedFileId,
5021  carvedFilesDir.getDataSourceObjectId(),
5022  carvedFile.getName(),
5027  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
5028  carvedFile.getSizeInBytes(),
5029  null,
5031  parentPath,
5032  null));
5033  }
5034 
5035  transaction.commit();
5036  return carvedFiles;
5037 
5038  } catch (SQLException ex) {
5039  if (null != transaction) {
5040  try {
5041  transaction.rollback();
5042  } catch (TskCoreException ex2) {
5043  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5044  }
5045  if (0 != newCacheKey) {
5046  rootIdsToCarvedFileDirs.remove(newCacheKey);
5047  }
5048  }
5049  throw new TskCoreException("Failed to add carved files to case database", ex);
5050 
5051  } catch (TskCoreException ex) {
5052  if (null != transaction) {
5053  try {
5054  transaction.rollback();
5055  } catch (TskCoreException ex2) {
5056  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5057  }
5058  if (0 != newCacheKey) {
5059  rootIdsToCarvedFileDirs.remove(newCacheKey);
5060  }
5061  }
5062  throw ex;
5063 
5064  } finally {
5065  closeResultSet(resultSet);
5066  closeStatement(statement);
5068  }
5069  }
5070 
5101  public DerivedFile addDerivedFile(String fileName, String localPath,
5102  long size, long ctime, long crtime, long atime, long mtime,
5103  boolean isFile, Content parentObj,
5104  String rederiveDetails, String toolName, String toolVersion,
5105  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
5106  CaseDbConnection connection = connections.getConnection();
5108  ResultSet rs = null;
5109  try {
5110  connection.beginTransaction();
5111 
5112  final long parentId = parentObj.getId();
5113  String parentPath = "";
5114  if (parentObj instanceof BlackboardArtifact) {
5115  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
5116  } else if (parentObj instanceof AbstractFile) {
5117  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
5118  }
5119 
5120  // Insert a row for the derived file into the tsk_objects table.
5121  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5122  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5123  statement.clearParameters();
5124  statement.setLong(1, parentId);
5125  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
5126  connection.executeUpdate(statement);
5127  rs = statement.getGeneratedKeys();
5128  rs.next();
5129  long newObjId = rs.getLong(1); //last_insert_rowid()
5130  rs.close();
5131  rs = null;
5132 
5133  // Insert a row for the virtual directory into the tsk_files table.
5134  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5135  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id, extension)
5136  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5137  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5138  statement.clearParameters();
5139  statement.setLong(1, newObjId);
5140 
5141  // If the parentFile is part of a file system, use its file system object ID.
5142  long fsObjId = this.getFileSystemId(parentId, connection);
5143  if (fsObjId != -1) {
5144  statement.setLong(2, fsObjId);
5145  } else {
5146  statement.setNull(2, java.sql.Types.BIGINT);
5147  }
5148  statement.setString(3, fileName);
5149 
5150  //type, has_path
5151  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
5152  statement.setShort(5, (short) 1);
5153 
5154  //flags
5156  statement.setShort(6, dirType.getValue());
5158  statement.setShort(7, metaType.getValue());
5159 
5160  //note: using alloc under assumption that derived files derive from alloc files
5162  statement.setShort(8, dirFlag.getValue());
5163  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5164  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5165  statement.setShort(9, metaFlags);
5166 
5167  //size
5168  statement.setLong(10, size);
5169 
5170  //mactimes
5171  //long ctime, long crtime, long atime, long mtime,
5172  statement.setLong(11, ctime);
5173  statement.setLong(12, crtime);
5174  statement.setLong(13, atime);
5175  statement.setLong(14, mtime);
5176 
5177  //parent path
5178  statement.setString(15, parentPath);
5179 
5180  // root data source object id
5181  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
5182  statement.setLong(16, dataSourceObjId);
5183  final String extension = extractExtension(fileName);
5184  //extension
5185  statement.setString(17, extension);
5186 
5187  connection.executeUpdate(statement);
5188 
5189  //add localPath
5190  addFilePath(connection, newObjId, localPath, encodingType);
5191 
5192  connection.commitTransaction();
5193 
5194  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
5195  return new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
5196  size, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
5197  } catch (SQLException ex) {
5198  connection.rollbackTransaction();
5199  throw new TskCoreException("Failed to add derived file to case database", ex);
5200  } finally {
5201  closeResultSet(rs);
5202  connection.close();
5204  }
5205  }
5206 
5226  public LocalFile addLocalFile(String fileName, String localPath,
5227  long size, long ctime, long crtime, long atime, long mtime,
5228  boolean isFile, TskData.EncodingType encodingType,
5229  AbstractFile parent) throws TskCoreException {
5231  CaseDbTransaction localTrans = beginTransaction();
5232  try {
5233  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
5234  localTrans.commit();
5235  return created;
5236  } catch (TskCoreException ex) {
5237  try {
5238  localTrans.rollback();
5239  } catch (TskCoreException ex2) {
5240  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5241  }
5242  throw ex;
5243  } finally {
5245  }
5246  }
5247 
5272  public LocalFile addLocalFile(String fileName, String localPath,
5273  long size, long ctime, long crtime, long atime, long mtime,
5274  boolean isFile, TskData.EncodingType encodingType,
5275  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
5276 
5277  CaseDbConnection connection = transaction.getConnection();
5279  Statement queryStatement = null;
5280  ResultSet resultSet = null;
5281  try {
5282 
5283  // Insert a row for the local/logical file into the tsk_objects table.
5284  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5285  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5286  statement.clearParameters();
5287  statement.setLong(1, parent.getId());
5288  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
5289  connection.executeUpdate(statement);
5290  resultSet = statement.getGeneratedKeys();
5291  if (!resultSet.next()) {
5292  throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_objects table", fileName, localPath, parent.getId()));
5293  }
5294  long objectId = resultSet.getLong(1); //last_insert_rowid()
5295  resultSet.close();
5296  resultSet = null;
5297 
5298  // Insert a row for the local/logical file into the tsk_files table.
5299  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5300  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
5301  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5302  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5303  statement.clearParameters();
5304  statement.setLong(1, objectId);
5305  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
5306  statement.setString(3, fileName);
5307  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
5308  statement.setShort(5, (short) 1);
5310  statement.setShort(6, dirType.getValue());
5312  statement.setShort(7, metaType.getValue());
5314  statement.setShort(8, dirFlag.getValue());
5315  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
5316  statement.setShort(9, metaFlags);
5317  statement.setLong(10, size);
5318  statement.setLong(11, ctime);
5319  statement.setLong(12, crtime);
5320  statement.setLong(13, atime);
5321  statement.setLong(14, mtime);
5322  String parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
5323  statement.setString(15, parentPath);
5324  long dataSourceObjId = getDataSourceObjectId(connection, parent.getId());
5325  statement.setLong(16, dataSourceObjId);
5326  final String extension = extractExtension(fileName);
5327  statement.setString(17, extension);
5328 
5329  connection.executeUpdate(statement);
5330  addFilePath(connection, objectId, localPath, encodingType);
5331  return new LocalFile(this,
5332  objectId,
5333  fileName,
5335  dirType,
5336  metaType,
5337  dirFlag,
5338  metaFlags,
5339  size,
5340  ctime, crtime, atime, mtime,
5341  null, null, null,
5342  parent.getId(), parentPath,
5343  dataSourceObjId,
5344  localPath,
5345  encodingType, extension);
5346 
5347  } catch (SQLException ex) {
5348  throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_files table", fileName, localPath, parent.getId()), ex);
5349  } finally {
5350  closeResultSet(resultSet);
5351  closeStatement(queryStatement);
5353  }
5354  }
5355 
5368  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
5370  Statement statement = null;
5371  ResultSet resultSet = null;
5372  try {
5373  statement = connection.createStatement();
5374  long dataSourceObjId;
5375  long ancestorId = objectId;
5376  do {
5377  dataSourceObjId = ancestorId;
5378  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
5379  resultSet = statement.executeQuery(query);
5380  if (resultSet.next()) {
5381  ancestorId = resultSet.getLong("par_obj_id");
5382  } else {
5383  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
5384  }
5385  resultSet.close();
5386  resultSet = null;
5387  } while (0 != ancestorId); // Not NULL
5388  return dataSourceObjId;
5389  } catch (SQLException ex) {
5390  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
5391  } finally {
5392  closeResultSet(resultSet);
5393  closeStatement(statement);
5395  }
5396  }
5397 
5409  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
5410  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
5411  statement.clearParameters();
5412  statement.setLong(1, objId);
5413  statement.setString(2, path);
5414  statement.setInt(3, type.getType());
5415  connection.executeUpdate(statement);
5416  }
5417 
5433  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
5434  return findFiles(dataSource, fileName, parentFile.getName());
5435  }
5436 
5448  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
5449  CaseDbConnection connection = connections.getConnection();
5451  Statement s = null;
5452  ResultSet rs = null;
5453  try {
5454  s = connection.createStatement();
5455  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5456  rs.next();
5457  return rs.getLong("count");
5458  } catch (SQLException e) {
5459  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
5460  } finally {
5461  closeResultSet(rs);
5462  closeStatement(s);
5463  connection.close();
5465  }
5466  }
5467 
5485  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
5486  CaseDbConnection connection = connections.getConnection();
5488  Statement s = null;
5489  ResultSet rs = null;
5490  try {
5491  s = connection.createStatement();
5492  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5493  return resultSetToAbstractFiles(rs, connection);
5494  } catch (SQLException e) {
5495  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
5496  } finally {
5497  closeResultSet(rs);
5498  closeStatement(s);
5499  connection.close();
5501  }
5502  }
5503 
5516  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
5517  CaseDbConnection connection = connections.getConnection();
5519  Statement s = null;
5520  ResultSet rs = null;
5521  try {
5522  s = connection.createStatement();
5523  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5524  List<Long> ret = new ArrayList<Long>();
5525  while (rs.next()) {
5526  ret.add(rs.getLong("obj_id"));
5527  }
5528  return ret;
5529  } catch (SQLException e) {
5530  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
5531  } finally {
5532  closeResultSet(rs);
5533  closeStatement(s);
5534  connection.close();
5536  }
5537  }
5538 
5550  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
5551 
5552  // get the non-unique path (strip of image and volume path segments, if
5553  // the exist.
5554  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
5555 
5556  // split the file name from the parent path
5557  int lastSlash = path.lastIndexOf('/'); //NON-NLS
5558 
5559  // if the last slash is at the end, strip it off
5560  if (lastSlash == path.length()) {
5561  path = path.substring(0, lastSlash - 1);
5562  lastSlash = path.lastIndexOf('/'); //NON-NLS
5563  }
5564 
5565  String parentPath = path.substring(0, lastSlash);
5566  String fileName = path.substring(lastSlash);
5567 
5568  return findFiles(dataSource, fileName, parentPath);
5569  }
5570 
5581  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
5582  CaseDbConnection connection = connections.getConnection();
5584  Statement s = null;
5585  ResultSet rs = null;
5586  try {
5587  s = connection.createStatement();
5588  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
5589  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
5590  while (rs.next()) {
5591  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
5592  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
5593  ranges.add(range);
5594  }
5595  return ranges;
5596  } catch (SQLException ex) {
5597  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
5598  } finally {
5599  closeResultSet(rs);
5600  closeStatement(s);
5601  connection.close();
5603  }
5604  }
5605 
5616  public Image getImageById(long id) throws TskCoreException {
5617  CaseDbConnection connection = connections.getConnection();
5619  Statement s1 = null;
5620  ResultSet rs1 = null;
5621  Statement s2 = null;
5622  ResultSet rs2 = null;
5623  try {
5624  s1 = connection.createStatement();
5625  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.type, tsk_image_info.ssize, tsk_image_info.tzone, tsk_image_info.size, tsk_image_info.md5, tsk_image_info.display_name, data_source_info.device_id "
5626  + "FROM tsk_image_info "
5627  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
5628  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
5629  if (rs1.next()) {
5630  s2 = connection.createStatement();
5631  rs2 = connection.executeQuery(s2, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + id); //NON-NLS
5632  List<String> imagePaths = new ArrayList<String>();
5633  while (rs2.next()) {
5634  imagePaths.add(rs2.getString("name"));
5635  }
5636  long type = rs1.getLong("type"); //NON-NLS
5637  long ssize = rs1.getLong("ssize"); //NON-NLS
5638  String tzone = rs1.getString("tzone"); //NON-NLS
5639  long size = rs1.getLong("size"); //NON-NLS
5640  String md5 = rs1.getString("md5"); //NON-NLS
5641  String name = rs1.getString("display_name");
5642  if (name == null) {
5643  if (imagePaths.size() > 0) {
5644  String path = imagePaths.get(0);
5645  name = (new java.io.File(path)).getName();
5646  } else {
5647  name = "";
5648  }
5649  }
5650  String device_id = rs1.getString("device_id");
5651 
5652  return new Image(this, id, type, device_id, ssize, name,
5653  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, size);
5654  } else {
5655  throw new TskCoreException("No image found for id: " + id);
5656  }
5657  } catch (SQLException ex) {
5658  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
5659  } finally {
5660  closeResultSet(rs2);
5661  closeStatement(s2);
5662  closeResultSet(rs1);
5663  closeStatement(s1);
5664  connection.close();
5666  }
5667  }
5668 
5680  VolumeSystem getVolumeSystemById(long id, Image parent) throws TskCoreException {
5681  CaseDbConnection connection = connections.getConnection();
5683  Statement s = null;
5684  ResultSet rs = null;
5685  try {
5686  s = connection.createStatement();
5687  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
5688  + "where obj_id = " + id); //NON-NLS
5689  if (rs.next()) {
5690  long type = rs.getLong("vs_type"); //NON-NLS
5691  long imgOffset = rs.getLong("img_offset"); //NON-NLS
5692  long blockSize = rs.getLong("block_size"); //NON-NLS
5693  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
5694  vs.setParent(parent);
5695  return vs;
5696  } else {
5697  throw new TskCoreException("No volume system found for id:" + id);
5698  }
5699  } catch (SQLException ex) {
5700  throw new TskCoreException("Error getting Volume System by ID.", ex);
5701  } finally {
5702  closeResultSet(rs);
5703  closeStatement(s);
5704  connection.close();
5706  }
5707  }
5708 
5717  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
5718  VolumeSystem vs = getVolumeSystemById(id, null);
5719  vs.setParentId(parentId);
5720  return vs;
5721  }
5722 
5734  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
5735  return getFileSystemByIdHelper(id, parent);
5736  }
5737 
5746  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
5747  Volume vol = null;
5748  FileSystem fs = getFileSystemById(id, vol);
5749  fs.setParentId(parentId);
5750  return fs;
5751  }
5752 
5764  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
5765  return getFileSystemByIdHelper(id, parent);
5766  }
5767 
5779  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
5780  // see if we already have it
5781  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
5782  // but it should be the same...
5783  synchronized (fileSystemIdMap) {
5784  if (fileSystemIdMap.containsKey(id)) {
5785  return fileSystemIdMap.get(id);
5786  }
5787  }
5788  CaseDbConnection connection = connections.getConnection();
5790  Statement s = null;
5791  ResultSet rs = null;
5792  try {
5793  s = connection.createStatement();
5794  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
5795  + "where obj_id = " + id); //NON-NLS
5796  if (rs.next()) {
5797  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
5798  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
5799  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
5800  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
5801  fs.setParent(parent);
5802  // save it for the next call
5803  synchronized (fileSystemIdMap) {
5804  fileSystemIdMap.put(id, fs);
5805  }
5806  return fs;
5807  } else {
5808  throw new TskCoreException("No file system found for id:" + id);
5809  }
5810  } catch (SQLException ex) {
5811  throw new TskCoreException("Error getting File System by ID", ex);
5812  } finally {
5813  closeResultSet(rs);
5814  closeStatement(s);
5815  connection.close();
5817  }
5818  }
5819 
5831  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
5832  CaseDbConnection connection = connections.getConnection();
5834  Statement s = null;
5835  ResultSet rs = null;
5836  try {
5837  s = connection.createStatement();
5838  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
5839  + "where obj_id = " + id); //NON-NLS
5840  if (rs.next()) {
5848  String description;
5849  try {
5850  description = rs.getString("desc");
5851  } catch (Exception ex) {
5852  description = rs.getString("descr");
5853  }
5854  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
5855  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
5856  description);
5857  vol.setParent(parent);
5858  return vol;
5859  } else {
5860  throw new TskCoreException("No volume found for id:" + id);
5861  }
5862  } catch (SQLException ex) {
5863  throw new TskCoreException("Error getting Volume by ID", ex);
5864  } finally {
5865  closeResultSet(rs);
5866  closeStatement(s);
5867  connection.close();
5869  }
5870  }
5871 
5880  Volume getVolumeById(long id, long parentId) throws TskCoreException {
5881  Volume vol = getVolumeById(id, null);
5882  vol.setParentId(parentId);
5883  return vol;
5884  }
5885 
5897  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
5898  CaseDbConnection connection = connections.getConnection();
5900  Statement s = null;
5901  ResultSet rs = null;
5902  try {
5903  s = connection.createStatement();
5904  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
5905  + "WHERE obj_id = " + id);
5906  Directory temp = null; //NON-NLS
5907  if (rs.next()) {
5908  final short type = rs.getShort("type"); //NON-NLS
5909  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
5910  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
5911  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
5912  temp = directory(rs, parentFs);
5913  }
5914  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
5915  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
5916  }
5917  } else {
5918  throw new TskCoreException("No Directory found for id:" + id);
5919  }
5920  return temp;
5921  } catch (SQLException ex) {
5922  throw new TskCoreException("Error getting Directory by ID", ex);
5923  } finally {
5924  closeResultSet(rs);
5925  closeStatement(s);
5926  connection.close();
5928  }
5929  }
5930 
5938  public Collection<FileSystem> getFileSystems(Image image) {
5939  List<FileSystem> fileSystems = new ArrayList<FileSystem>();
5940  CaseDbConnection connection;
5941  try {
5942  connection = connections.getConnection();
5943  } catch (TskCoreException ex) {
5944  logger.log(Level.SEVERE, "Error getting file systems for image " + image.getId(), ex); //NON-NLS
5945  return fileSystems;
5946  }
5948  Statement s = null;
5949  ResultSet rs = null;
5950  try {
5951  s = connection.createStatement();
5952 
5953  // Get all the file systems.
5954  List<FileSystem> allFileSystems = new ArrayList<FileSystem>();
5955  try {
5956  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info"); //NON-NLS
5957  while (rs.next()) {
5958  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
5959  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
5960  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
5961  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
5962  fs.setParent(null);
5963  allFileSystems.add(fs);
5964  }
5965  } catch (SQLException ex) {
5966  logger.log(Level.SEVERE, "There was a problem while trying to obtain all file systems", ex); //NON-NLS
5967  } finally {
5968  closeResultSet(rs);
5969  rs = null;
5970  }
5971 
5972  // For each file system, find the image to which it belongs by iteratively
5973  // climbing the tsk_ojbects hierarchy only taking those file systems
5974  // that belong to this image.
5975  for (FileSystem fs : allFileSystems) {
5976  Long imageID = null;
5977  Long currentObjID = fs.getId();
5978  while (imageID == null) {
5979  try {
5980  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS
5981  rs.next();
5982  currentObjID = rs.getLong("par_obj_id"); //NON-NLS
5983  if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS
5984  imageID = rs.getLong("obj_id"); //NON-NLS
5985  }
5986  } catch (SQLException ex) {
5987  logger.log(Level.SEVERE, "There was a problem while trying to obtain this image's file systems", ex); //NON-NLS
5988  } finally {
5989  closeResultSet(rs);
5990  rs = null;
5991  }
5992  }
5993 
5994  // see if imageID is this image's ID
5995  if (imageID == image.getId()) {
5996  fileSystems.add(fs);
5997  }
5998  }
5999  } catch (SQLException ex) {
6000  logger.log(Level.SEVERE, "Error getting case database connection", ex); //NON-NLS
6001  } finally {
6002  closeResultSet(rs);
6003  closeStatement(s);
6004  connection.close();
6006  }
6007  return fileSystems;
6008  }
6009 
6020  List<Content> getImageChildren(Image img) throws TskCoreException {
6021  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
6022  List<Content> children = new ArrayList<Content>();
6023  for (ObjectInfo info : childInfos) {
6024  if (null != info.type) {
6025  switch (info.type) {
6026  case VS:
6027  children.add(getVolumeSystemById(info.id, img));
6028  break;
6029  case FS:
6030  children.add(getFileSystemById(info.id, img));
6031  break;
6032  case ABSTRACTFILE:
6033  AbstractFile f = getAbstractFileById(info.id);
6034  if (f != null) {
6035  children.add(f);
6036  }
6037  break;
6038  case ARTIFACT:
6039  BlackboardArtifact art = getArtifactById(info.id);
6040  if (art != null) {
6041  children.add(art);
6042  }
6043  break;
6044  default:
6045  throw new TskCoreException("Image has child of invalid type: " + info.type);
6046  }
6047  }
6048  }
6049  return children;
6050  }
6051 
6062  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
6063  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
6064  List<Long> children = new ArrayList<Long>();
6065  for (ObjectInfo info : childInfos) {
6066  if (info.type == ObjectType.VS
6067  || info.type == ObjectType.FS
6068  || info.type == ObjectType.ABSTRACTFILE
6069  || info.type == ObjectType.ARTIFACT) {
6070  children.add(info.id);
6071  } else {
6072  throw new TskCoreException("Image has child of invalid type: " + info.type);
6073  }
6074  }
6075  return children;
6076  }
6077 
6088  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
6089  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
6090  List<Content> children = new ArrayList<Content>();
6091  for (ObjectInfo info : childInfos) {
6092  if (null != info.type) {
6093  switch (info.type) {
6094  case VOL:
6095  children.add(getVolumeById(info.id, vs));
6096  break;
6097  case ABSTRACTFILE:
6098  AbstractFile f = getAbstractFileById(info.id);
6099  if (f != null) {
6100  children.add(f);
6101  }
6102  break;
6103  case ARTIFACT:
6104  BlackboardArtifact art = getArtifactById(info.id);
6105  if (art != null) {
6106  children.add(art);
6107  }
6108  break;
6109  default:
6110  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
6111  }
6112  }
6113  }
6114  return children;
6115  }
6116 
6127  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
6128  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
6129  List<Long> children = new ArrayList<Long>();
6130  for (ObjectInfo info : childInfos) {
6131  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
6132  children.add(info.id);
6133  } else {
6134  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
6135  }
6136  }
6137  return children;
6138  }
6139 
6150  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
6151  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
6152  List<Content> children = new ArrayList<Content>();
6153  for (ObjectInfo info : childInfos) {
6154  if (null != info.type) {
6155  switch (info.type) {
6156  case FS:
6157  children.add(getFileSystemById(info.id, vol));
6158  break;
6159  case ABSTRACTFILE:
6160  AbstractFile f = getAbstractFileById(info.id);
6161  if (f != null) {
6162  children.add(f);
6163  }
6164  break;
6165  case ARTIFACT:
6166  BlackboardArtifact art = getArtifactById(info.id);
6167  if (art != null) {
6168  children.add(art);
6169  }
6170  break;
6171  default:
6172  throw new TskCoreException("Volume has child of invalid type: " + info.type);
6173  }
6174  }
6175  }
6176  return children;
6177  }
6178 
6189  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
6190  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
6191  final List<Long> children = new ArrayList<Long>();
6192  for (ObjectInfo info : childInfos) {
6193  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
6194  children.add(info.id);
6195  } else {
6196  throw new TskCoreException("Volume has child of invalid type: " + info.type);
6197  }
6198  }
6199  return children;
6200  }
6201 
6215  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
6216  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone);
6217  return getImageById(imageId);
6218  }
6219 
6229  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
6230  CaseDbConnection connection = connections.getConnection();
6232  Statement s1 = null;
6233  Statement s2 = null;
6234  ResultSet rs1 = null;
6235  ResultSet rs2 = null;
6236  try {
6237  s1 = connection.createStatement();
6238  rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
6239  s2 = connection.createStatement();
6240  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
6241  while (rs1.next()) {
6242  long obj_id = rs1.getLong("obj_id"); //NON-NLS
6243  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
6244  List<String> paths = new ArrayList<String>();
6245  while (rs2.next()) {
6246  paths.add(rs2.getString("name"));
6247  }
6248  rs2.close();
6249  rs2 = null;
6250  imgPaths.put(obj_id, paths);
6251  }
6252  return imgPaths;
6253  } catch (SQLException ex) {
6254  throw new TskCoreException("Error getting image paths.", ex);
6255  } finally {
6256  closeResultSet(rs2);
6257  closeStatement(s2);
6258  closeResultSet(rs1);
6259  closeStatement(s1);
6260  connection.close();
6262  }
6263  }
6264 
6275  private List<String> getImagePathsById(long objectId) throws TskCoreException {
6276  List<String> imagePaths = new ArrayList<String>();
6277  CaseDbConnection connection = connections.getConnection();
6279  Statement statement = null;
6280  ResultSet resultSet = null;
6281  try {
6282  statement = connection.createStatement();
6283  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
6284  while (resultSet.next()) {
6285  imagePaths.add(resultSet.getString("name"));
6286  }
6287  } catch (SQLException ex) {
6288  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
6289  } finally {
6290  closeResultSet(resultSet);
6291  closeStatement(statement);
6292  connection.close();
6294  }
6295 
6296  return imagePaths;
6297  }
6298 
6305  public List<Image> getImages() throws TskCoreException {
6306  CaseDbConnection connection = connections.getConnection();
6308  Statement s = null;
6309  ResultSet rs = null;
6310  try {
6311  s = connection.createStatement();
6312  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
6313  Collection<Long> imageIDs = new ArrayList<Long>();
6314  while (rs.next()) {
6315  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
6316  }
6317  List<Image> images = new ArrayList<Image>();
6318  for (long id : imageIDs) {
6319  images.add(getImageById(id));
6320  }
6321  return images;
6322  } catch (SQLException ex) {
6323  throw new TskCoreException("Error retrieving images.", ex);
6324  } finally {
6325  closeResultSet(rs);
6326  closeStatement(s);
6327  connection.close();
6329  }
6330  }
6331 
6342  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
6343  CaseDbConnection connection = connections.getConnection();
6345  Statement statement = null;
6346  try {
6347  connection.beginTransaction();
6348  statement = connection.createStatement();
6349  connection.executeUpdate(statement, "DELETE FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
6350  for (int i = 0; i < paths.size(); i++) {
6351  connection.executeUpdate(statement, "INSERT INTO tsk_image_names VALUES (" + obj_id + ", '" + paths.get(i) + "', " + i + ")"); //NON-NLS
6352  }
6353  connection.commitTransaction();
6354  } catch (SQLException ex) {
6355  connection.rollbackTransaction();
6356  throw new TskCoreException("Error updating image paths.", ex);
6357  } finally {
6358  closeStatement(statement);
6359  connection.close();
6361  }
6362  }
6363 
6389  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
6390  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
6391  try {
6392  while (rs.next()) {
6393  final short type = rs.getShort("type"); //NON-NLS
6394  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
6395  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
6396  FsContent result;
6397  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
6398  result = directory(rs, null);
6399  } else {
6400  result = file(rs, null);
6401  }
6402  results.add(result);
6403  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
6404  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
6405  final VirtualDirectory virtDir = virtualDirectory(rs);
6406  results.add(virtDir);
6407  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
6408  final LocalDirectory localDir = localDirectory(rs);
6409  results.add(localDir);
6410  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
6411  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
6412  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()) {
6413  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
6414  String parentPath = rs.getString("parent_path"); //NON-NLS
6415  if (parentPath == null) {
6416  parentPath = "/"; //NON-NLS
6417  }
6418  LayoutFile lf = new LayoutFile(this,
6419  rs.getLong("obj_id"), //NON-NLS
6420  rs.getLong("data_source_obj_id"),
6421  rs.getString("name"), //NON-NLS
6422  atype,
6423  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6424  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6425  rs.getLong("size"), //NON-NLS
6426  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS
6427  results.add(lf);
6428  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
6429  final DerivedFile df;
6430  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
6431  results.add(df);
6432  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
6433  final LocalFile lf;
6434  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
6435  results.add(lf);
6436  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
6437  final SlackFile sf = slackFile(rs, null);
6438  results.add(sf);
6439  }
6440  } //end for each resultSet
6441  } catch (SQLException e) {
6442  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
6443  }
6444 
6445  return results;
6446  }
6447 
6448  // This following methods generate AbstractFile objects from a ResultSet
6460  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
6461  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
6462  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6463  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6464  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6465  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6466  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6467  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6468  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6469  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6470  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6471  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6472  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
6473  f.setFileSystem(fs);
6474  return f;
6475  }
6476 
6488  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
6489  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6490  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6491  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6492  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6493  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6494  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6495  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6496  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6497  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6498  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6499  rs.getString("parent_path")); //NON-NLS
6500  dir.setFileSystem(fs);
6501  return dir;
6502  }
6503 
6513  VirtualDirectory virtualDirectory(ResultSet rs) throws SQLException {
6514  String parentPath = rs.getString("parent_path"); //NON-NLS
6515  if (parentPath == null) {
6516  parentPath = "";
6517  }
6518  final VirtualDirectory vd = new VirtualDirectory(this, rs.getLong("obj_id"), //NON-NLS
6519  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
6520  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6521  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6522  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6523  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
6524  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
6525  return vd;
6526  }
6527 
6537  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
6538  String parentPath = rs.getString("parent_path"); //NON-NLS
6539  if (parentPath == null) {
6540  parentPath = "";
6541  }
6542  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
6543  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
6544  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6545  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6546  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6547  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
6548  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
6549  return ld;
6550  }
6551 
6565  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6566  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
6567  long objId = rs.getLong("obj_id"); //NON-NLS
6568  String localPath = null;
6569  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
6570  if (hasLocalPath) {
6571  ResultSet rsFilePath = null;
6573  try {
6574  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
6575  statement.clearParameters();
6576  statement.setLong(1, objId);
6577  rsFilePath = connection.executeQuery(statement);
6578  if (rsFilePath.next()) {
6579  localPath = rsFilePath.getString("path");
6580  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
6581  }
6582  } catch (SQLException ex) {
6583  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
6584  } finally {
6585  closeResultSet(rsFilePath);
6587  }
6588  }
6589  String parentPath = rs.getString("parent_path"); //NON-NLS
6590  if (parentPath == null) {
6591  parentPath = "";
6592  }
6593  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
6594  rs.getString("name"), //NON-NLS
6595  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6596  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6597  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6598  rs.getLong("size"), //NON-NLS
6599  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6600  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6601  parentPath, localPath, parentId, rs.getString("mime_type"),
6602  encodingType, rs.getString("extension"));
6603  return df;
6604  }
6605 
6619  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6620  long objId = rs.getLong("obj_id"); //NON-NLS
6621  String localPath = null;
6622  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
6623  if (rs.getBoolean("has_path")) {
6624  ResultSet rsFilePath = null;
6626  try {
6627  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
6628  statement.clearParameters();
6629  statement.setLong(1, objId);
6630  rsFilePath = connection.executeQuery(statement);
6631  if (rsFilePath.next()) {
6632  localPath = rsFilePath.getString("path");
6633  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
6634  }
6635  } catch (SQLException ex) {
6636  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
6637  } finally {
6638  closeResultSet(rsFilePath);
6640  }
6641  }
6642  String parentPath = rs.getString("parent_path"); //NON-NLS
6643  if (null == parentPath) {
6644  parentPath = "";
6645  }
6646  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
6647  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
6648  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6649  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6650  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6651  rs.getLong("size"), //NON-NLS
6652  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6653  rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6654  parentId, parentPath, rs.getLong("data_source_obj_id"),
6655  localPath, encodingType, rs.getString("extension"));
6656  return file;
6657  }
6658 
6670  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
6671  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
6672  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6673  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6674  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6675  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6676  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6677  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6678  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6679  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6680  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6681  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6682  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
6683  f.setFileSystem(fs);
6684  return f;
6685  }
6686 
6698  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6699  List<Content> children = new ArrayList<Content>();
6700 
6701  while (rs.next()) {
6702  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
6703 
6704  if (null != type) {
6705  switch (type) {
6706  case FS:
6707  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
6708  FsContent result;
6709  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
6710  result = directory(rs, null);
6711  } else {
6712  result = file(rs, null);
6713  }
6714  children.add(result);
6715  } else {
6716  VirtualDirectory virtDir = virtualDirectory(rs);
6717  children.add(virtDir);
6718  }
6719  break;
6720  case VIRTUAL_DIR:
6721  VirtualDirectory virtDir = virtualDirectory(rs);
6722  children.add(virtDir);
6723  break;
6724  case LOCAL_DIR:
6725  LocalDirectory localDir = localDirectory(rs);
6726  children.add(localDir);
6727  break;
6728  case UNALLOC_BLOCKS:
6729  case UNUSED_BLOCKS:
6730  case CARVED: {
6731  String parentPath = rs.getString("parent_path");
6732  if (parentPath == null) {
6733  parentPath = "";
6734  }
6735  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
6736  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
6737  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
6738  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
6739  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
6740  rs.getLong("size"), rs.getString("md5"),
6741  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"));
6742  children.add(lf);
6743  break;
6744  }
6745  case DERIVED:
6746  final DerivedFile df = derivedFile(rs, connection, parentId);
6747  children.add(df);
6748  break;
6749  case LOCAL: {
6750  final LocalFile lf = localFile(rs, connection, parentId);
6751  children.add(lf);
6752  break;
6753  }
6754  case SLACK: {
6755  final SlackFile sf = slackFile(rs, null);
6756  children.add(sf);
6757  break;
6758  }
6759  default:
6760  break;
6761  }
6762  }
6763  }
6764  return children;
6765  }
6766 
6780  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException {
6781  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
6782  try {
6783  while (rs.next()) {
6784  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
6785  rs.getInt("artifact_type_id"), BlackboardArtifact.ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")).getLabel(), BlackboardArtifact.ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")).getDisplayName(),
6786  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
6787  } //end for each resultSet
6788  } catch (SQLException e) {
6789  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
6790  }
6791 
6792  return artifacts;
6793  }
6794 
6816  public CaseDbQuery executeQuery(String query) throws TskCoreException {
6817  return new CaseDbQuery(query);
6818  }
6819 
6841  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
6842  return new CaseDbQuery(query, true);
6843  }
6844 
6852  CaseDbConnection getConnection() throws TskCoreException {
6853  return connections.getConnection();
6854  }
6855 
6856  @Override
6857  protected void finalize() throws Throwable {
6858  try {
6859  close();
6860  } finally {
6861  super.finalize();
6862  }
6863  }
6864 
6868  public synchronized void close() {
6870 
6871  try {
6872  connections.close();
6873  } catch (TskCoreException ex) {
6874  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
6875  }
6876 
6877  fileSystemIdMap.clear();
6878 
6879  try {
6880  if (this.caseHandle != null) {
6881  this.caseHandle.free();
6882  this.caseHandle = null;
6883  }
6884  } catch (TskCoreException ex) {
6885  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
6886  } finally {
6888  }
6889  }
6890 
6903  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
6904  long id = file.getId();
6905  FileKnown currentKnown = file.getKnown();
6906  if (currentKnown.compareTo(fileKnown) > 0) {
6907  return false;
6908  }
6909  CaseDbConnection connection = connections.getConnection();
6911  Statement statement = null;
6912  try {
6913  statement = connection.createStatement();
6914  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
6915  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
6916  + "WHERE obj_id=" + id); //NON-NLS
6917  file.setKnown(fileKnown);
6918  } catch (SQLException ex) {
6919  throw new TskCoreException("Error setting Known status.", ex);
6920  } finally {
6921  closeStatement(statement);
6922  connection.close();
6924  }
6925  return true;
6926  }
6927 
6937  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
6938  CaseDbConnection connection = connections.getConnection();
6939  Statement statement = null;
6940  ResultSet rs = null;
6942  try {
6943  statement = connection.createStatement();
6944  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
6945  file.setMIMEType(mimeType);
6946  } catch (SQLException ex) {
6947  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
6948  } finally {
6949  closeResultSet(rs);
6950  closeStatement(statement);
6951  connection.close();
6953  }
6954  }
6955 
6965  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
6966  if (md5Hash == null) {
6967  return;
6968  }
6969  long id = file.getId();
6970  CaseDbConnection connection = connections.getConnection();
6972  try {
6973  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
6974  statement.clearParameters();
6975  statement.setString(1, md5Hash.toLowerCase());
6976  statement.setLong(2, id);
6977  connection.executeUpdate(statement);
6978  file.setMd5Hash(md5Hash.toLowerCase());
6979  } catch (SQLException ex) {
6980  throw new TskCoreException("Error setting MD5 hash", ex);
6981  } finally {
6982  connection.close();
6984  }
6985  }
6986 
6997  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
6998  if (newStatus == null) {
6999  return;
7000  }
7001  CaseDbConnection connection = connections.getConnection();
7003  Statement statement = null;
7004  try {
7005  statement = connection.createStatement();
7006  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
7007  + " SET review_status_id=" + newStatus.getID()
7008  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
7009  } catch (SQLException ex) {
7010  throw new TskCoreException("Error setting review status", ex);
7011  } finally {
7012  closeStatement(statement);
7013  connection.close();
7015  }
7016  }
7017 
7028  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
7029  CaseDbConnection connection = connections.getConnection();
7031  Statement s = null;
7032  ResultSet rs = null;
7033  try {
7034  s = connection.createStatement();
7035  Short contentShort = contentType.getValue();
7036  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
7037  int count = 0;
7038  if (rs.next()) {
7039  count = rs.getInt("count");
7040  }
7041  return count;
7042  } catch (SQLException ex) {
7043  throw new TskCoreException("Error getting number of objects.", ex);
7044  } finally {
7045  closeResultSet(rs);
7046  closeStatement(s);
7047  connection.close();
7049  }
7050  }
7051 
7060  public static String escapeSingleQuotes(String text) {
7061  String escapedText = null;
7062  if (text != null) {
7063  escapedText = text.replaceAll("'", "''");
7064  }
7065  return escapedText;
7066  }
7067 
7075  public List<AbstractFile> findFilesByMd5(String md5Hash) {
7076  if (md5Hash == null) {
7077  return Collections.<AbstractFile>emptyList();
7078  }
7079  CaseDbConnection connection;
7080  try {
7081  connection = connections.getConnection();
7082  } catch (TskCoreException ex) {
7083  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
7084  return Collections.<AbstractFile>emptyList();
7085  }
7087  Statement s = null;
7088  ResultSet rs = null;
7089  try {
7090  s = connection.createStatement();
7091  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
7092  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
7093  + "AND size > 0"); //NON-NLS
7094  return resultSetToAbstractFiles(rs, connection);
7095  } catch (SQLException ex) {
7096  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
7097  return Collections.<AbstractFile>emptyList();
7098  } finally {
7099  closeResultSet(rs);
7100  closeStatement(s);
7101  connection.close();
7103  }
7104  }
7105 
7112  public boolean allFilesMd5Hashed() {
7113  CaseDbConnection connection;
7114  try {
7115  connection = connections.getConnection();
7116  } catch (TskCoreException ex) {
7117  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
7118  return false;
7119  }
7120  boolean allFilesAreHashed = false;
7122  Statement s = null;
7123  ResultSet rs = null;
7124  try {
7125  s = connection.createStatement();
7126  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
7127  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
7128  + "AND md5 IS NULL " //NON-NLS
7129  + "AND size > '0'"); //NON-NLS
7130  if (rs.next() && rs.getInt("count") == 0) {
7131  allFilesAreHashed = true;
7132  }
7133  } catch (SQLException ex) {
7134  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
7135  } finally {
7136  closeResultSet(rs);
7137  closeStatement(s);
7138  connection.close();
7140  }
7141  return allFilesAreHashed;
7142  }
7143 
7149  public int countFilesMd5Hashed() {
7150  CaseDbConnection connection;
7151  try {
7152  connection = connections.getConnection();
7153  } catch (TskCoreException ex) {
7154  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
7155  return 0;
7156  }
7157  int count = 0;
7159  Statement s = null;
7160  ResultSet rs = null;
7161  try {
7162  s = connection.createStatement();
7163  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
7164  + "WHERE md5 IS NOT NULL " //NON-NLS
7165  + "AND size > '0'"); //NON-NLS
7166  if (rs.next()) {
7167  count = rs.getInt("count");
7168  }
7169  } catch (SQLException ex) {
7170  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
7171  } finally {
7172  closeResultSet(rs);
7173  closeStatement(s);
7174  connection.close();
7176  }
7177  return count;
7178 
7179  }
7180 
7189  public List<TagName> getAllTagNames() throws TskCoreException {
7190  CaseDbConnection connection = connections.getConnection();
7192  ResultSet resultSet = null;
7193  try {
7194  // SELECT * FROM tag_names
7195  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
7196  resultSet = connection.executeQuery(statement);
7197  ArrayList<TagName> tagNames = new ArrayList<TagName>();
7198  while (resultSet.next()) {
7199  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7200  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7201  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
7202  }
7203  return tagNames;
7204  } catch (SQLException ex) {
7205  throw new TskCoreException("Error selecting rows from tag_names table", ex);
7206  } finally {
7207  closeResultSet(resultSet);
7208  connection.close();
7210  }
7211  }
7212 
7223  public List<TagName> getTagNamesInUse() throws TskCoreException {
7224  CaseDbConnection connection = connections.getConnection();
7226  ResultSet resultSet = null;
7227  try {
7228  // SELECT * FROM tag_names WHERE tag_name_id IN (SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)
7229  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
7230  resultSet = connection.executeQuery(statement);
7231  ArrayList<TagName> tagNames = new ArrayList<TagName>();
7232  while (resultSet.next()) {
7233  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7234  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7235  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
7236  }
7237  return tagNames;
7238  } catch (SQLException ex) {
7239  throw new TskCoreException("Error selecting rows from tag_names table", ex);
7240  } finally {
7241  closeResultSet(resultSet);
7242  connection.close();
7244  }
7245  }
7246 
7260  @Deprecated
7261  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
7262  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
7263  }
7264 
7279  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
7280  CaseDbConnection connection = connections.getConnection();
7282  ResultSet resultSet = null;
7283  try {
7284  PreparedStatement statement;
7285  if (dbType == DbType.POSTGRESQL) {
7286  // INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?
7287  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME_POSTGRES, Statement.RETURN_GENERATED_KEYS);
7288  statement.clearParameters();
7289  statement.setString(5, description);
7290  statement.setString(6, color.getName());
7291  statement.setByte(7, knownStatus.getFileKnownValue());
7292  } else {
7293  // WITH new (display_name, description, color, knownStatus)
7294  // AS ( VALUES(?, ?, ?, ?)) INSERT OR REPLACE INTO tag_names
7295  // (tag_name_id, display_name, description, color, knownStatus)
7296  // SELECT old.tag_name_id, new.display_name, new.description, new.color, new.knownStatus
7297  // FROM new LEFT JOIN tag_names AS old ON new.display_name = old.display_name
7298  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME_SQLITE, Statement.RETURN_GENERATED_KEYS);
7299  statement.clearParameters();
7300  }
7301  statement.setString(1, displayName);
7302  statement.setString(2, description);
7303  statement.setString(3, color.getName());
7304  statement.setByte(4, knownStatus.getFileKnownValue());
7305  connection.executeUpdate(statement);
7306  resultSet = statement.getGeneratedKeys();
7307  resultSet.next();
7308  return new TagName(resultSet.getLong(1), //last_insert_rowid()
7309  displayName, description, color, knownStatus);
7310  } catch (SQLException ex) {
7311  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
7312  } finally {
7313  closeResultSet(resultSet);
7314  connection.close();
7316  }
7317  }
7318 
7332  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
7333  CaseDbConnection connection = connections.getConnection();
7335  ResultSet resultSet = null;
7336  try {
7337  // INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
7338  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_CONTENT_TAG, Statement.RETURN_GENERATED_KEYS);
7339  statement.clearParameters();
7340  statement.setLong(1, content.getId());
7341  statement.setLong(2, tagName.getId());
7342  statement.setString(3, comment);
7343  statement.setLong(4, beginByteOffset);
7344  statement.setLong(5, endByteOffset);
7345  connection.executeUpdate(statement);
7346  resultSet = statement.getGeneratedKeys();
7347  resultSet.next();
7348  return new ContentTag(resultSet.getLong(1), //last_insert_rowid()
7349  content, tagName, comment, beginByteOffset, endByteOffset);
7350  } catch (SQLException ex) {
7351  throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex);
7352  } finally {
7353  closeResultSet(resultSet);
7354  connection.close();
7356  }
7357  }
7358 
7359  /*
7360  * Deletes a row from the content_tags table in the case database. @param
7361  * tag A ContentTag data transfer object (DTO) for the row to delete.
7362  * @throws TskCoreException
7363  */
7364  public void deleteContentTag(ContentTag tag) throws TskCoreException {
7365  CaseDbConnection connection = connections.getConnection();
7367  try {
7368  // DELETE FROM content_tags WHERE tag_id = ?
7369  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
7370  statement.clearParameters();
7371  statement.setLong(1, tag.getId());
7372  connection.executeUpdate(statement);
7373  } catch (SQLException ex) {
7374  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
7375  } finally {
7376  connection.close();
7378  }
7379  }
7380 
7389  public List<ContentTag> getAllContentTags() throws TskCoreException {
7390  CaseDbConnection connection = connections.getConnection();
7392  ResultSet resultSet = null;
7393  try {
7394  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
7395  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
7396  resultSet = connection.executeQuery(statement);
7397  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7398  while (resultSet.next()) {
7399  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7400  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7401  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
7402  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
7403  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
7404  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"))); //NON-NLS
7405  }
7406  return tags;
7407  } catch (SQLException ex) {
7408  throw new TskCoreException("Error selecting rows from content_tags table", ex);
7409  } finally {
7410  closeResultSet(resultSet);
7411  connection.close();
7413  }
7414  }
7415 
7426  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
7427  if (tagName.getId() == Tag.ID_NOT_SET) {
7428  throw new TskCoreException("TagName object is invalid, id not set");
7429  }
7430  CaseDbConnection connection = connections.getConnection();
7432  ResultSet resultSet = null;
7433  try {
7434  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
7435  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
7436  statement.clearParameters();
7437  statement.setLong(1, tagName.getId());
7438  resultSet = connection.executeQuery(statement);
7439  if (resultSet.next()) {
7440  return resultSet.getLong("count");
7441  } else {
7442  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
7443  }
7444  } catch (SQLException ex) {
7445  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
7446  } finally {
7447  closeResultSet(resultSet);
7448  connection.close();
7450  }
7451  }
7452 
7463  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
7464 
7465  CaseDbConnection connection = connections.getConnection();
7467  ResultSet resultSet = null;
7468  ContentTag tag = null;
7469  try {
7470  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE tag_id = ?
7471  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
7472  statement.clearParameters();
7473  statement.setLong(1, contentTagID);
7474  resultSet = connection.executeQuery(statement);
7475 
7476  while (resultSet.next()) {
7477  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7478  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7479  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
7480  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
7481  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"));
7482  }
7483  resultSet.close();
7484 
7485  } catch (SQLException ex) {
7486  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
7487  } finally {
7488  closeResultSet(resultSet);
7489  connection.close();
7491  }
7492  return tag;
7493  }
7494 
7506  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
7507  if (tagName.getId() == Tag.ID_NOT_SET) {
7508  throw new TskCoreException("TagName object is invalid, id not set");
7509  }
7510  CaseDbConnection connection = connections.getConnection();
7512  ResultSet resultSet = null;
7513  try {
7514  // SELECT * FROM content_tags WHERE tag_name_id = ?
7515  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
7516  statement.clearParameters();
7517  statement.setLong(1, tagName.getId());
7518  resultSet = connection.executeQuery(statement);
7519  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7520  while (resultSet.next()) {
7521  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
7522  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
7523  tags.add(tag);
7524  }
7525  resultSet.close();
7526  return tags;
7527  } catch (SQLException ex) {
7528  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
7529  } finally {
7530  closeResultSet(resultSet);
7531  connection.close();
7533  }
7534  }
7535 
7547  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
7548  CaseDbConnection connection = connections.getConnection();
7550  ResultSet resultSet = null;
7551  try {
7552  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE content_tags.obj_id = ?
7553  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
7554  statement.clearParameters();
7555  statement.setLong(1, content.getId());
7556  resultSet = connection.executeQuery(statement);
7557  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7558  while (resultSet.next()) {
7559  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7560  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7561  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
7562  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
7563  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
7564  tags.add(tag);
7565  }
7566  return tags;
7567  } catch (SQLException ex) {
7568  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
7569  } finally {
7570  closeResultSet(resultSet);
7571  connection.close();
7573  }
7574  }
7575 
7589  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
7590  CaseDbConnection connection = connections.getConnection();
7592  ResultSet resultSet = null;
7593  try {
7594  // INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
7595  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT_TAG, Statement.RETURN_GENERATED_KEYS);
7596  statement.clearParameters();
7597  statement.setLong(1, artifact.getArtifactID());
7598  statement.setLong(2, tagName.getId());
7599  statement.setString(3, comment);
7600  connection.executeUpdate(statement);
7601  resultSet = statement.getGeneratedKeys();
7602  resultSet.next();
7603  return new BlackboardArtifactTag(resultSet.getLong(1), //last_insert_rowid()
7604  artifact, getContentById(artifact.getObjectID()), tagName, comment);
7605  } catch (SQLException ex) {
7606  throw new TskCoreException("Error adding row to blackboard_artifact_tags table (obj_id = " + artifact.getArtifactID() + ", tag_name_id = " + tagName.getId() + ")", ex);
7607  } finally {
7608  closeResultSet(resultSet);
7609  connection.close();
7611  }
7612  }
7613 
7614  /*
7615  * Deletes a row from the blackboard_artifact_tags table in the case
7616  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
7617  * representing the row to delete. @throws TskCoreException
7618  */
7619  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
7620  CaseDbConnection connection = connections.getConnection();
7622  try {
7623  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
7624  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
7625  statement.clearParameters();
7626  statement.setLong(1, tag.getId());
7627  connection.executeUpdate(statement);
7628  } catch (SQLException ex) {
7629  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
7630  } finally {
7631  connection.close();
7633  }
7634  }
7635 
7645  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
7646  CaseDbConnection connection = connections.getConnection();
7648  ResultSet resultSet = null;
7649  try {
7650  // SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
7651  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
7652  resultSet = connection.executeQuery(statement);
7653  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7654  while (resultSet.next()) {
7655  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7656  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7657  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
7658  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7659  Content content = getContentById(artifact.getObjectID());
7660  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7661  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7662  tags.add(tag);
7663  }
7664  return tags;
7665  } catch (SQLException ex) {
7666  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
7667  } finally {
7668  closeResultSet(resultSet);
7669  connection.close();
7671  }
7672  }
7673 
7684  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
7685  if (tagName.getId() == Tag.ID_NOT_SET) {
7686  throw new TskCoreException("TagName object is invalid, id not set");
7687  }
7688  CaseDbConnection connection = connections.getConnection();
7690  ResultSet resultSet = null;
7691  try {
7692  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
7693  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
7694  statement.clearParameters();
7695  statement.setLong(1, tagName.getId());
7696  resultSet = connection.executeQuery(statement);
7697  if (resultSet.next()) {
7698  return resultSet.getLong("count");
7699  } else {
7700  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
7701  }
7702  } catch (SQLException ex) {
7703  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
7704  } finally {
7705  closeResultSet(resultSet);
7706  connection.close();
7708  }
7709  }
7710 
7722  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
7723  if (tagName.getId() == Tag.ID_NOT_SET) {
7724  throw new TskCoreException("TagName object is invalid, id not set");
7725  }
7726  CaseDbConnection connection = connections.getConnection();
7728  ResultSet resultSet = null;
7729  try {
7730  // SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?
7731  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
7732  statement.clearParameters();
7733  statement.setLong(1, tagName.getId());
7734  resultSet = connection.executeQuery(statement);
7735  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7736  while (resultSet.next()) {
7737  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7738  Content content = getContentById(artifact.getObjectID());
7739  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7740  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7741  tags.add(tag);
7742  }
7743  return tags;
7744  } catch (SQLException ex) {
7745  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
7746  } finally {
7747  closeResultSet(resultSet);
7748  connection.close();
7750  }
7751  }
7752 
7764  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
7765 
7766  CaseDbConnection connection = connections.getConnection();
7768  ResultSet resultSet = null;
7769  BlackboardArtifactTag tag = null;
7770  try {
7771  // SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id WHERE blackboard_artifact_tags.tag_id = ?
7772  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
7773  statement.clearParameters();
7774  statement.setLong(1, artifactTagID);
7775  resultSet = connection.executeQuery(statement);
7776 
7777  while (resultSet.next()) {
7778  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7779  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7780  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
7781  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7782  Content content = getContentById(artifact.getObjectID());
7783  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7784  artifact, content, tagName, resultSet.getString("comment"));
7785  }
7786  resultSet.close();
7787 
7788  } catch (SQLException ex) {
7789  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
7790  } finally {
7791  closeResultSet(resultSet);
7792  connection.close();
7794  }
7795  return tag;
7796  }
7797 
7810  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
7811  CaseDbConnection connection = connections.getConnection();
7813  ResultSet resultSet = null;
7814  try {
7815  // SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id WHERE blackboard_artifact_tags.artifact_id = ?
7816  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
7817  statement.clearParameters();
7818  statement.setLong(1, artifact.getArtifactID());
7819  resultSet = connection.executeQuery(statement);
7820  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7821  while (resultSet.next()) {
7822  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7823  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
7824  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
7825  Content content = getContentById(artifact.getObjectID());
7826  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7827  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7828  tags.add(tag);
7829  }
7830  return tags;
7831  } catch (SQLException ex) {
7832  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
7833  } finally {
7834  closeResultSet(resultSet);
7835  connection.close();
7837  }
7838  }
7839 
7848  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
7849  CaseDbConnection connection = connections.getConnection();
7851  try {
7852  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
7853  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
7854  statement.clearParameters();
7855  statement.setString(1, newPath);
7856  statement.setLong(2, objectId);
7857  connection.executeUpdate(statement);
7858  } catch (SQLException ex) {
7859  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
7860  } finally {
7861  connection.close();
7863  }
7864  }
7865 
7879  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
7880  // Make sure the local path of the report is in the database directory
7881  // or one of its subdirectories.
7882  String relativePath = ""; //NON-NLS
7883  try {
7884  /*
7885  * Note: The following call to .relativize() may be dangerous in
7886  * case-sensitive operating systems and should be looked at. For
7887  * now, we are simply relativizing the paths as all lower case, then
7888  * using the length of the result to pull out the appropriate number
7889  * of characters from the localPath String.
7890  */
7891  String casePathLower = getDbDirPath().toLowerCase();
7892  String localPathLower = localPath.toLowerCase();
7893  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
7894  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
7895  } catch (IllegalArgumentException ex) {
7896  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
7897  throw new TskCoreException(errorMessage, ex);
7898  }
7899 
7900  // Figure out the create time of the report.
7901  long createTime = 0;
7902  try {
7903  java.io.File tempFile = new java.io.File(localPath);
7904  // Convert to UNIX epoch (seconds, not milliseconds).
7905  createTime = tempFile.lastModified() / 1000;
7906  } catch (Exception ex) {
7907  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
7908  }
7909 
7910  // Write the report data to the database.
7911  CaseDbConnection connection = connections.getConnection();
7913  ResultSet resultSet = null;
7914  try {
7915  // INSERT INTO reports (path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?)
7916  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT, Statement.RETURN_GENERATED_KEYS);
7917  statement.clearParameters();
7918  statement.setString(1, relativePath);
7919  statement.setLong(2, createTime);
7920  statement.setString(3, sourceModuleName);
7921  statement.setString(4, reportName);
7922  connection.executeUpdate(statement);
7923  resultSet = statement.getGeneratedKeys();
7924  resultSet.next();
7925  return new Report(resultSet.getLong(1), //last_insert_rowid()
7926  localPath, createTime, sourceModuleName, reportName);
7927  } catch (SQLException ex) {
7928  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
7929  } finally {
7930  closeResultSet(resultSet);
7931  connection.close();
7933  }
7934  }
7935 
7944  public List<Report> getAllReports() throws TskCoreException {
7945  CaseDbConnection connection = connections.getConnection();
7947  ResultSet resultSet = null;
7948  try {
7949  // SELECT * FROM reports
7950  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
7951  resultSet = connection.executeQuery(statement);
7952  ArrayList<Report> reports = new ArrayList<Report>();
7953  while (resultSet.next()) {
7954  reports.add(new Report(resultSet.getLong("report_id"), //NON-NLS
7955  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
7956  resultSet.getLong("crtime"), //NON-NLS
7957  resultSet.getString("src_module_name"), //NON-NLS
7958  resultSet.getString("report_name"))); //NON-NLS
7959  }
7960  return reports;
7961  } catch (SQLException ex) {
7962  throw new TskCoreException("Error querying reports table", ex);
7963  } finally {
7964  closeResultSet(resultSet);
7965  connection.close();
7967  }
7968  }
7969 
7977  public void deleteReport(Report report) throws TskCoreException {
7978  CaseDbConnection connection = connections.getConnection();
7980  try {
7981  // DELETE FROM reports WHERE reports.report_id = ?
7982  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
7983  statement.setLong(1, report.getId());
7984  connection.executeUpdate(statement);
7985  } catch (SQLException ex) {
7986  throw new TskCoreException("Error querying reports table", ex);
7987  } finally {
7989  }
7990  }
7991 
7992  static void closeResultSet(ResultSet resultSet) {
7993  if (resultSet != null) {
7994  try {
7995  resultSet.close();
7996  } catch (SQLException ex) {
7997  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
7998  }
7999  }
8000  }
8001 
8002  static void closeStatement(Statement statement) {
8003  if (statement != null) {
8004  try {
8005  statement.close();
8006  } catch (SQLException ex) {
8007  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
8008 
8009  }
8010  }
8011  }
8012 
8021  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
8022  CaseDbConnection connection = connections.getConnection();
8024  try {
8025  Statement statement = connection.createStatement();
8026  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
8027  } catch (SQLException ex) {
8028  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
8029  } finally {
8030  connection.close();
8032  }
8033  }
8034 
8035  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
8036  CaseDbConnection connection = connections.getConnection();
8038  try {
8039  Statement statement = connection.createStatement();
8040  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
8041  } catch (SQLException ex) {
8042  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
8043  } finally {
8044  connection.close();
8046  }
8047  }
8048 
8065  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
8066  CaseDbConnection connection = connections.getConnection();
8068  ResultSet resultSet = null;
8069  Statement statement;
8070  try {
8071  connection.beginTransaction();
8072  statement = connection.createStatement();
8073  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
8074  insertStatement.setLong(1, dataSource.getId());
8075  insertStatement.setString(2, hostName);
8076  insertStatement.setLong(3, jobStart.getTime());
8077  insertStatement.setLong(4, jobEnd.getTime());
8078  insertStatement.setInt(5, status.ordinal());
8079  insertStatement.setString(6, settingsDir);
8080  connection.executeUpdate(insertStatement);
8081  resultSet = insertStatement.getGeneratedKeys();
8082  resultSet.next();
8083  long id = resultSet.getLong(1); //last_insert_rowid()
8084  for (int i = 0; i < ingestModules.size(); i++) {
8085  IngestModuleInfo ingestModule = ingestModules.get(i);
8086  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
8087  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
8088  }
8089  resultSet.close();
8090  resultSet = null;
8091  connection.commitTransaction();
8092  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
8093  } catch (SQLException ex) {
8094  connection.rollbackTransaction();
8095  throw new TskCoreException("Error adding the ingest job.", ex);
8096  } finally {
8097  closeResultSet(resultSet);
8098  connection.close();
8100  }
8101  }
8102 
8116  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
8117  CaseDbConnection connection = connections.getConnection();
8118  ResultSet resultSet = null;
8119  Statement statement = null;
8120  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
8122  try {
8123  statement = connection.createStatement();
8124  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
8125  if (!resultSet.next()) {
8126  resultSet.close();
8127  resultSet = null;
8128  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
8129  insertStatement.setString(1, displayName);
8130  insertStatement.setString(2, uniqueName);
8131  insertStatement.setInt(3, type.ordinal());
8132  insertStatement.setString(4, version);
8133  connection.executeUpdate(insertStatement);
8134  resultSet = statement.getGeneratedKeys();
8135  resultSet.next();
8136  long id = resultSet.getLong(1); //last_insert_rowid()
8137  resultSet.close();
8138  resultSet = null;
8139  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
8140  } else {
8141  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
8142  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
8143  }
8144  } catch (SQLException ex) {
8145  try {
8146  closeStatement(statement);
8147  statement = connection.createStatement();
8148  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
8149  if (resultSet.next()) {
8150  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
8151  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
8152  } else {
8153  throw new TskCoreException("Couldn't add new module to database.", ex);
8154  }
8155  } catch (SQLException ex1) {
8156  throw new TskCoreException("Couldn't add new module to database.", ex1);
8157  }
8158  } finally {
8159  closeResultSet(resultSet);
8160  closeStatement(statement);
8161  connection.close();
8163  }
8164  }
8165 
8173  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
8174  CaseDbConnection connection = connections.getConnection();
8175  ResultSet resultSet = null;
8176  Statement statement = null;
8177  List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>();
8179  try {
8180  statement = connection.createStatement();
8181  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
8182  while (resultSet.next()) {
8183  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
8184  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
8185  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
8186  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
8187  }
8188  return ingestJobs;
8189  } catch (SQLException ex) {
8190  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
8191  } finally {
8192  closeResultSet(resultSet);
8193  closeStatement(statement);
8194  connection.close();
8196  }
8197  }
8198 
8209  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
8210  ResultSet resultSet = null;
8211  Statement statement = null;
8212  List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>();
8214  try {
8215  statement = connection.createStatement();
8216  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
8217  + "ingest_job_modules.pipeline_position AS pipeline_position, "
8218  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
8219  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
8220  + "FROM ingest_job_modules, ingest_modules "
8221  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
8222  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
8223  + "ORDER BY (ingest_job_modules.pipeline_position);");
8224  while (resultSet.next()) {
8225  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
8226  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
8227  }
8228  return ingestModules;
8229  } finally {
8230  closeResultSet(resultSet);
8231  closeStatement(statement);
8233  }
8234  }
8235 
8239  static class ObjectInfo {
8240 
8241  private long id;
8242  private TskData.ObjectType type;
8243 
8244  ObjectInfo(long id, ObjectType type) {
8245  this.id = id;
8246  this.type = type;
8247  }
8248 
8249  long getId() {
8250  return id;
8251  }
8252 
8253  TskData.ObjectType getType() {
8254  return type;
8255  }
8256  }
8257 
8258  private interface DbCommand {
8259 
8260  void execute() throws SQLException;
8261  }
8262 
8263  private enum PREPARED_STATEMENT {
8264 
8265  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
8266  + "WHERE artifact_type_id = ?"), //NON-NLS
8267  COUNT_ARTIFACTS_OF_TYPE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
8268  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
8269  COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
8270  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
8271  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
8272  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
8273  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
8274  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
8275  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
8276  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
8277  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
8278  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
8279  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
8280  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
8281  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
8282  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
8283  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
8284  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
8285  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
8286  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
8287  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
8288  + "AND tsk_files.type = ? )"), //NON-NLS
8289  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
8290  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
8291  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
8292  INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, review_status_id) " //NON-NLS
8293  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
8294  POSTGRESQL_INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, review_status_id) " //NON-NLS
8295  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
8296  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
8297  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
8298  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
8299  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
8300  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
8301  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
8302  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
8303  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
8304  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
8305  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
8306  SELECT_FILES_BY_DATA_SOURCE_AND_NAME("SELECT * FROM tsk_files WHERE LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND data_source_obj_id = ?"), //NON-NLS
8307  SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME("SELECT * FROM tsk_files WHERE LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND LOWER(parent_path) LIKE LOWER(?) AND data_source_obj_id = ?"), //NON-NLS
8308  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
8309  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
8310  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
8311  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
8312  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
8313  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
8314  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
8315  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
8316  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
8317  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
8318  INSERT_FILE("INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension) " //NON-NLS
8319  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)"), //NON-NLS
8320  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
8321  + "VALUES (?, ?, ?, ?)"), //NON-NLS
8322  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
8323  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
8324  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
8325  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
8326  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
8327  + "WHERE tag_name_id IN " //NON-NLS
8328  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
8329  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
8330  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
8331  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
8332  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
8333  SELECT_CONTENT_TAGS("SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id"), //NON-NLS
8334  SELECT_CONTENT_TAGS_BY_TAG_NAME("SELECT * FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
8335  SELECT_CONTENT_TAG_BY_ID("SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE tag_id = ?"), //NON-NLS
8336  SELECT_CONTENT_TAGS_BY_CONTENT("SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE content_tags.obj_id = ?"), //NON-NLS
8337  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) VALUES (?, ?, ?)"), //NON-NLS
8338  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
8339  SELECT_ARTIFACT_TAGS("SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id"), //NON-NLS
8340  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
8341  SELECT_ARTIFACT_TAGS_BY_TAG_NAME("SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
8342  SELECT_ARTIFACT_TAG_BY_ID("SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
8343  SELECT_ARTIFACT_TAGS_BY_ARTIFACT("SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
8344  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
8345  INSERT_REPORT("INSERT INTO reports (path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?)"), //NON-NLS
8346  DELETE_REPORT("DELETE FROM reports WHERE reports.report_id = ?"), //NON-NLS
8347  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
8348  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
8349  SELECT_ATTR_BY_VALUE_BYTE("SELECT source FROM blackboard_attributes WHERE artifact_id = ? AND attribute_type_id = ? AND value_type = 4 AND value_byte = ?"), //NON-NLS
8350  UPDATE_ATTR_BY_VALUE_BYTE("UPDATE blackboard_attributes SET source = ? WHERE artifact_id = ? AND attribute_type_id = ? AND value_type = 4 AND value_byte = ?"), //NON-NLS
8351  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
8352  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
8353  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
8354  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
8355  + "WHERE (tsk_objects.par_obj_id = ?)"),
8356  INSERT_OR_UPDATE_TAG_NAME_POSTGRES("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?"),
8357  INSERT_OR_UPDATE_TAG_NAME_SQLITE("WITH new (display_name, description, color, knownStatus) "
8358  + "AS ( VALUES(?, ?, ?, ?)) INSERT OR REPLACE INTO tag_names "
8359  + "(tag_name_id, display_name, description, color, knownStatus) "
8360  + "SELECT old.tag_name_id, new.display_name, new.description, new.color, new.knownStatus "
8361  + "FROM new LEFT JOIN tag_names AS old ON new.display_name = old.display_name");
8362  private final String sql;
8363 
8364  private PREPARED_STATEMENT(String sql) {
8365  this.sql = sql;
8366  }
8367 
8368  String getSQL() {
8369  return sql;
8370  }
8371  }
8372 
8378  abstract private class ConnectionPool {
8379 
8380  private PooledDataSource pooledDataSource;
8381 
8382  public ConnectionPool() {
8383  pooledDataSource = null;
8384  }
8385 
8386  CaseDbConnection getConnection() throws TskCoreException {
8387  if (pooledDataSource == null) {
8388  throw new TskCoreException("Error getting case database connection - case is closed");
8389  }
8390  try {
8391  return getPooledConnection();
8392  } catch (SQLException exp) {
8393  throw new TskCoreException(exp.getMessage());
8394  }
8395  }
8396 
8397  void close() throws TskCoreException {
8398  if (pooledDataSource != null) {
8399  try {
8400  pooledDataSource.close();
8401  } catch (SQLException exp) {
8402  throw new TskCoreException(exp.getMessage());
8403  } finally {
8404  pooledDataSource = null;
8405  }
8406  }
8407  }
8408 
8409  abstract CaseDbConnection getPooledConnection() throws SQLException;
8410 
8411  public PooledDataSource getPooledDataSource() {
8412  return pooledDataSource;
8413  }
8414 
8415  public void setPooledDataSource(PooledDataSource pooledDataSource) {
8416  this.pooledDataSource = pooledDataSource;
8417  }
8418  }
8419 
8424  private final class SQLiteConnections extends ConnectionPool {
8425 
8426  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
8427 
8428  SQLiteConnections(String dbPath) throws SQLException {
8429  configurationOverrides.put("acquireIncrement", "2");
8430  configurationOverrides.put("initialPoolSize", "5");
8431  configurationOverrides.put("maxPoolSize", "20");
8432  configurationOverrides.put("minPoolSize", "5");
8433  configurationOverrides.put("maxStatements", "100");
8434  configurationOverrides.put("maxStatementsPerConnection", "20");
8435 
8436  SQLiteConfig config = new SQLiteConfig();
8437  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
8438  config.setReadUncommited(true);
8439  config.enforceForeignKeys(true); // Enforce foreign key constraints.
8440  SQLiteDataSource unpooled = new SQLiteDataSource(config);
8441  unpooled.setUrl("jdbc:sqlite:" + dbPath);
8442  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
8443  }
8444 
8445  @Override
8446  public CaseDbConnection getPooledConnection() throws SQLException {
8447  return new SQLiteConnection(getPooledDataSource().getConnection());
8448  }
8449  }
8450 
8455  private final class PostgreSQLConnections extends ConnectionPool {
8456 
8457  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
8458  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
8459  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
8460  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
8461  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
8462  comboPooledDataSource.setUser(userName);
8463  comboPooledDataSource.setPassword(password);
8464  comboPooledDataSource.setAcquireIncrement(2);
8465  comboPooledDataSource.setInitialPoolSize(5);
8466  comboPooledDataSource.setMaxPoolSize(20);
8467  comboPooledDataSource.setMinPoolSize(5);
8468  comboPooledDataSource.setMaxStatements(100);
8469  comboPooledDataSource.setMaxStatementsPerConnection(20);
8470  setPooledDataSource(comboPooledDataSource);
8471  }
8472 
8473  @Override
8474  public CaseDbConnection getPooledConnection() throws SQLException {
8475  return new PostgreSQLConnection(getPooledDataSource().getConnection());
8476  }
8477  }
8478 
8482  abstract class CaseDbConnection {
8483 
8484  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
8485 
8486  private class CreateStatement implements DbCommand {
8487 
8488  private final Connection connection;
8489  private Statement statement = null;
8490 
8491  CreateStatement(Connection connection) {
8492  this.connection = connection;
8493  }
8494 
8495  Statement getStatement() {
8496  return statement;
8497  }
8498 
8499  @Override
8500  public void execute() throws SQLException {
8501  statement = connection.createStatement();
8502  }
8503  }
8504 
8505  private class SetAutoCommit implements DbCommand {
8506 
8507  private final Connection connection;
8508  private final boolean mode;
8509 
8510  SetAutoCommit(Connection connection, boolean mode) {
8511  this.connection = connection;
8512  this.mode = mode;
8513  }
8514 
8515  @Override
8516  public void execute() throws SQLException {
8517  connection.setAutoCommit(mode);
8518  }
8519  }
8520 
8521  private class Commit implements DbCommand {
8522 
8523  private final Connection connection;
8524 
8525  Commit(Connection connection) {
8526  this.connection = connection;
8527  }
8528 
8529  @Override
8530  public void execute() throws SQLException {
8531  connection.commit();
8532  }
8533  }
8534 
8535  private class ExecuteQuery implements DbCommand {
8536 
8537  private final Statement statement;
8538  private final String query;
8539  private ResultSet resultSet;
8540 
8541  ExecuteQuery(Statement statement, String query) {
8542  this.statement = statement;
8543  this.query = query;
8544  }
8545 
8546  ResultSet getResultSet() {
8547  return resultSet;
8548  }
8549 
8550  @Override
8551  public void execute() throws SQLException {
8552  resultSet = statement.executeQuery(query);
8553  }
8554  }
8555 
8556  private class ExecutePreparedStatementQuery implements DbCommand {
8557 
8558  private final PreparedStatement preparedStatement;
8559  private ResultSet resultSet;
8560 
8561  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
8562  this.preparedStatement = preparedStatement;
8563  }
8564 
8565  ResultSet getResultSet() {
8566  return resultSet;
8567  }
8568 
8569  @Override
8570  public void execute() throws SQLException {
8571  resultSet = preparedStatement.executeQuery();
8572  }
8573  }
8574 
8575  private class ExecutePreparedStatementUpdate implements DbCommand {
8576 
8577  private final PreparedStatement preparedStatement;
8578 
8579  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
8580  this.preparedStatement = preparedStatement;
8581  }
8582 
8583  @Override
8584  public void execute() throws SQLException {
8585  preparedStatement.executeUpdate();
8586  }
8587  }
8588 
8589  private class ExecuteStatementUpdate implements DbCommand {
8590 
8591  private final Statement statement;
8592  private final String updateCommand;
8593 
8594  ExecuteStatementUpdate(Statement statement, String updateCommand) {
8595  this.statement = statement;
8596  this.updateCommand = updateCommand;
8597  }
8598 
8599  @Override
8600  public void execute() throws SQLException {
8601  statement.executeUpdate(updateCommand);
8602  }
8603  }
8604 
8605  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
8606 
8607  private final Statement statement;
8608  private final int generateKeys;
8609  private final String updateCommand;
8610 
8611  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
8612  this.statement = statement;
8613  this.generateKeys = generateKeys;
8614  this.updateCommand = updateCommand;
8615  }
8616 
8617  @Override
8618  public void execute() throws SQLException {
8619  statement.executeUpdate(updateCommand, generateKeys);
8620  }
8621  }
8622 
8623  private class PrepareStatement implements DbCommand {
8624 
8625  private final Connection connection;
8626  private final String input;
8627  private PreparedStatement preparedStatement = null;
8628 
8629  PrepareStatement(Connection connection, String input) {
8630  this.connection = connection;
8631  this.input = input;
8632  }
8633 
8634  PreparedStatement getPreparedStatement() {
8635  return preparedStatement;
8636  }
8637 
8638  @Override
8639  public void execute() throws SQLException {
8640  preparedStatement = connection.prepareStatement(input);
8641  }
8642  }
8643 
8644  private class PrepareStatementGenerateKeys implements DbCommand {
8645 
8646  private final Connection connection;
8647  private final String input;
8648  private final int generateKeys;
8649  private PreparedStatement preparedStatement = null;
8650 
8651  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
8652  this.connection = connection;
8653  this.input = input;
8654  this.generateKeys = generateKeysInput;
8655  }
8656 
8657  PreparedStatement getPreparedStatement() {
8658  return preparedStatement;
8659  }
8660 
8661  @Override
8662  public void execute() throws SQLException {
8663  preparedStatement = connection.prepareStatement(input, generateKeys);
8664  }
8665  }
8666 
8667  abstract void executeCommand(DbCommand command) throws SQLException;
8668 
8669  private final Connection connection;
8670  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
8671 
8672  CaseDbConnection(Connection connection) {
8673  this.connection = connection;
8674  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
8675  }
8676 
8677  boolean isOpen() {
8678  return this.connection != null;
8679  }
8680 
8681  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
8682  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
8683  }
8684 
8685  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
8686  // Lazy statement preparation.
8687  PreparedStatement statement;
8688  if (this.preparedStatements.containsKey(statementKey)) {
8689  statement = this.preparedStatements.get(statementKey);
8690  } else {
8691  statement = prepareStatement(statementKey.getSQL(), generateKeys);
8692  this.preparedStatements.put(statementKey, statement);
8693  }
8694  return statement;
8695  }
8696 
8697  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
8698  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
8699  executeCommand(prepareStatement);
8700  return prepareStatement.getPreparedStatement();
8701  }
8702 
8703  Statement createStatement() throws SQLException {
8704  CreateStatement createStatement = new CreateStatement(this.connection);
8705  executeCommand(createStatement);
8706  return createStatement.getStatement();
8707  }
8708 
8709  void beginTransaction() throws SQLException {
8710  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
8711  executeCommand(setAutoCommit);
8712  }
8713 
8714  void commitTransaction() throws SQLException {
8715  Commit commit = new Commit(connection);
8716  executeCommand(commit);
8717  // You must turn auto commit back on when done with the transaction.
8718  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
8719  executeCommand(setAutoCommit);
8720  }
8721 
8727  void rollbackTransaction() {
8728  try {
8729  connection.rollback();
8730  } catch (SQLException e) {
8731  logger.log(Level.SEVERE, "Error rolling back transaction", e);
8732  }
8733  try {
8734  connection.setAutoCommit(true);
8735  } catch (SQLException e) {
8736  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
8737  }
8738  }
8739 
8747  void rollbackTransactionWithThrow() throws SQLException {
8748  try {
8749  connection.rollback();
8750  } finally {
8751  connection.setAutoCommit(true);
8752  }
8753  }
8754 
8755  ResultSet executeQuery(Statement statement, String query) throws SQLException {
8756  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
8757  executeCommand(queryCommand);
8758  return queryCommand.getResultSet();
8759  }
8760 
8770  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
8771  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
8772  executeCommand(executePreparedStatementQuery);
8773  return executePreparedStatementQuery.getResultSet();
8774  }
8775 
8776  void executeUpdate(Statement statement, String update) throws SQLException {
8777  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
8778  }
8779 
8780  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
8781  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
8782  executeCommand(executeStatementUpdate);
8783  }
8784 
8785  void executeUpdate(PreparedStatement statement) throws SQLException {
8786  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
8787  executeCommand(executePreparedStatementUpdate);
8788  }
8789 
8793  void close() {
8794  try {
8795  connection.close();
8796  } catch (SQLException ex) {
8797  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
8798  }
8799  }
8800 
8801  Connection getConnection() {
8802  return this.connection;
8803  }
8804  }
8805 
8809  private final class SQLiteConnection extends CaseDbConnection {
8810 
8811  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
8812  private static final int SQLITE_BUSY_ERROR = 5;
8813 
8814  SQLiteConnection(Connection conn) {
8815  super(conn);
8816  }
8817 
8818  @Override
8819  void executeCommand(DbCommand command) throws SQLException {
8820  while (true) {
8821  try {
8822  command.execute(); // Perform the operation
8823  break;
8824  } catch (SQLException ex) {
8825  if (ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) {
8826  try {
8827  // We do not notify of error here, as this is not an
8828  // error condition. It is likely a temporary busy or
8829  // locked issue and we will retry.
8830  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
8831  } catch (InterruptedException exp) {
8832  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
8833  }
8834  } else {
8835  throw ex;
8836  }
8837  }
8838  }
8839  }
8840  }
8841 
8845  private final class PostgreSQLConnection extends CaseDbConnection {
8846 
8847  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
8848  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
8849  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
8850  private static final int MAX_RETRIES = 3;
8851 
8852  PostgreSQLConnection(Connection conn) {
8853  super(conn);
8854  }
8855 
8856  @Override
8857  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
8858  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
8859  executeCommand(executeStatementUpdateGenerateKeys);
8860  }
8861 
8862  @Override
8863  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
8864  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
8865  executeCommand(prepareStatementGenerateKeys);
8866  return prepareStatementGenerateKeys.getPreparedStatement();
8867  }
8868 
8869  @Override
8870  void executeCommand(DbCommand command) throws SQLException {
8871  for (int retries = 0; retries < MAX_RETRIES; retries++) {
8872  try {
8873  command.execute();
8874  break;
8875  } catch (SQLException ex) {
8876  String sqlState = ((PSQLException) ex).getSQLState();
8877  if (sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
8878  try {
8879  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
8880  } catch (InterruptedException exp) {
8881  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
8882  }
8883  } else {
8884  throw ex;
8885  }
8886  }
8887  }
8888  }
8889  }
8890 
8899  public static final class CaseDbTransaction {
8900 
8901  private final CaseDbConnection connection;
8902 
8903  private CaseDbTransaction(CaseDbConnection connection) throws TskCoreException {
8904  this.connection = connection;
8905  try {
8906  this.connection.beginTransaction();
8907  } catch (SQLException ex) {
8908  throw new TskCoreException("Failed to create transaction on case database", ex);
8909  }
8910  }
8911 
8919  private CaseDbConnection getConnection() {
8920  return this.connection;
8921  }
8922 
8929  public void commit() throws TskCoreException {
8930  try {
8931  this.connection.commitTransaction();
8932  } catch (SQLException ex) {
8933  throw new TskCoreException("Failed to commit transaction on case database", ex);
8934  } finally {
8935  close();
8936  }
8937  }
8938 
8945  public void rollback() throws TskCoreException {
8946  try {
8947  this.connection.rollbackTransactionWithThrow();
8948  } catch (SQLException ex) {
8949  throw new TskCoreException("Case database transaction rollback failed", ex);
8950  } finally {
8951  close();
8952  }
8953  }
8954 
8959  void close() {
8960  this.connection.close();
8961  }
8962  }
8963 
8973  public final class CaseDbQuery implements AutoCloseable {
8974 
8975  private ResultSet resultSet;
8976  private CaseDbConnection connection;
8977 
8978  private CaseDbQuery(String query) throws TskCoreException {
8979  this(query, false);
8980  }
8981 
8982  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
8983  if (!allowWriteQuery) {
8984  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
8985  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
8986  }
8987  }
8988  try {
8989  connection = connections.getConnection();
8990  } catch (TskCoreException ex) {
8991  throw new TskCoreException("Error getting connection for query: ", ex);
8992  }
8993 
8994  try {
8996  resultSet = connection.executeQuery(connection.createStatement(), query);
8997  } catch (SQLException ex) {
8999  throw new TskCoreException("Error executing query: ", ex);
9000  }
9001  }
9002 
9008  public ResultSet getResultSet() {
9009  return resultSet;
9010  }
9011 
9012  @Override
9013  public void close() throws TskCoreException {
9014  try {
9015  if (resultSet != null) {
9016  final Statement statement = resultSet.getStatement();
9017  if (statement != null) {
9018  statement.close();
9019  }
9020  resultSet.close();
9021  }
9022  connection.close();
9023  } catch (SQLException ex) {
9024  throw new TskCoreException("Error closing query: ", ex);
9025  } finally {
9027  }
9028  }
9029  }
9030 
9038  @Deprecated
9039  public void addErrorObserver(ErrorObserver observer) {
9040  sleuthkitCaseErrorObservers.add(observer);
9041  }
9042 
9050  @Deprecated
9051  public void removeErrorObserver(ErrorObserver observer) {
9052  int i = sleuthkitCaseErrorObservers.indexOf(observer);
9053  if (i >= 0) {
9054  sleuthkitCaseErrorObservers.remove(i);
9055  }
9056  }
9057 
9066  @Deprecated
9067  public void submitError(String context, String errorMessage) {
9068  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
9069  if (observer != null) {
9070  try {
9071  observer.receiveError(context, errorMessage);
9072  } catch (Exception ex) {
9073  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
9074 
9075  }
9076  }
9077  }
9078  }
9079 
9085  @Deprecated
9086  public interface ErrorObserver {
9087 
9094  public enum Context {
9095 
9099  IMAGE_READ_ERROR("Image File Read Error"),
9103  DATABASE_READ_ERROR("Database Read Error");
9104 
9105  private final String contextString;
9106 
9107  private Context(String context) {
9108  this.contextString = context;
9109  }
9110 
9111  public String getContextString() {
9112  return contextString;
9113  }
9114  };
9115 
9116  void receiveError(String context, String errorMessage);
9117  }
9118 
9132  @Deprecated
9133  long getDataSourceObjectId(long objectId) {
9134  try {
9135  CaseDbConnection connection = connections.getConnection();
9136  try {
9137  return getDataSourceObjectId(connection, objectId);
9138  } finally {
9139  connection.close();
9140  }
9141  } catch (TskCoreException ex) {
9142  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
9143  return 0;
9144  }
9145  }
9146 
9156  @Deprecated
9157  public long getLastObjectId() throws TskCoreException {
9158  CaseDbConnection connection = connections.getConnection();
9160  ResultSet rs = null;
9161  try {
9162  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
9163  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
9164  rs = connection.executeQuery(statement);
9165  long id = -1;
9166  if (rs.next()) {
9167  id = rs.getLong("max_obj_id");
9168  }
9169  return id;
9170  } catch (SQLException e) {
9171  throw new TskCoreException("Error getting last object id", e);
9172  } finally {
9173  closeResultSet(rs);
9174  connection.close();
9176  }
9177  }
9178 
9192  @Deprecated
9193  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
9194  CaseDbConnection connection = connections.getConnection();
9196  Statement s = null;
9197  ResultSet rs = null;
9198  try {
9199  s = connection.createStatement();
9200  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9201  List<FsContent> results = new ArrayList<FsContent>();
9202  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
9203  for (AbstractFile f : temp) {
9204  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
9205  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
9206  results.add((FsContent) f);
9207  }
9208  }
9209  return results;
9210  } catch (SQLException e) {
9211  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
9212  } finally {
9213  closeResultSet(rs);
9214  closeStatement(s);
9215  connection.close();
9217  }
9218  }
9219 
9231  @Deprecated
9232  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
9233  CaseDbConnection connection = connections.getConnection();
9235  Statement s = null;
9236  ResultSet rs = null;
9237  try {
9238  s = connection.createStatement();
9239  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
9240  int typeId = -1;
9241  if (rs.next()) {
9242  typeId = rs.getInt("artifact_type_id");
9243  }
9244  return typeId;
9245  } catch (SQLException ex) {
9246  throw new TskCoreException("Error getting artifact type id", ex);
9247  } finally {
9248  closeResultSet(rs);
9249  closeStatement(s);
9250  connection.close();
9252  }
9253  }
9254 
9264  @Deprecated
9265  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
9266  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
9267  }
9268 
9282  @Deprecated
9283  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
9284  try {
9285  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
9286  } catch (TskDataException ex) {
9287  throw new TskCoreException("Failed to add artifact type.", ex);
9288  }
9289  }
9290 
9304  @Deprecated
9305  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
9306  try {
9307  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
9308  } catch (TskDataException ex) {
9309  throw new TskCoreException("Couldn't add new attribute type");
9310  }
9311  }
9312 
9323  @Deprecated
9324  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
9325  CaseDbConnection connection = connections.getConnection();
9327  Statement s = null;
9328  ResultSet rs = null;
9329  try {
9330  s = connection.createStatement();
9331  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
9332  int typeId = -1;
9333  if (rs.next()) {
9334  typeId = rs.getInt("attribute_type_id");
9335  }
9336  return typeId;
9337  } catch (SQLException ex) {
9338  throw new TskCoreException("Error getting attribute type id", ex);
9339  } finally {
9340  closeResultSet(rs);
9341  closeStatement(s);
9342  connection.close();
9344  }
9345  }
9346 
9359  @Deprecated
9360  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
9361  CaseDbConnection connection = connections.getConnection();
9363  Statement s = null;
9364  ResultSet rs = null;
9365  try {
9366  s = connection.createStatement();
9367  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
9368  if (rs.next()) {
9369  return rs.getString("type_name");
9370  } else {
9371  throw new TskCoreException("No type with that id");
9372  }
9373  } catch (SQLException ex) {
9374  throw new TskCoreException("Error getting or creating a attribute type name", ex);
9375  } finally {
9376  closeResultSet(rs);
9377  closeStatement(s);
9378  connection.close();
9380  }
9381  }
9382 
9395  @Deprecated
9396  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
9397  CaseDbConnection connection = connections.getConnection();
9399  Statement s = null;
9400  ResultSet rs = null;
9401  try {
9402  s = connection.createStatement();
9403  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
9404  if (rs.next()) {
9405  return rs.getString("display_name");
9406  } else {
9407  throw new TskCoreException("No type with that id");
9408  }
9409  } catch (SQLException ex) {
9410  throw new TskCoreException("Error getting or creating a attribute type name", ex);
9411  } finally {
9412  closeResultSet(rs);
9413  closeStatement(s);
9414  connection.close();
9416  }
9417  }
9418 
9428  @Deprecated
9429  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
9430  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
9431  }
9432 
9448  @Deprecated
9449  public ResultSet runQuery(String query) throws SQLException {
9450  CaseDbConnection connection;
9451  try {
9452  connection = connections.getConnection();
9453  } catch (TskCoreException ex) {
9454  throw new SQLException("Error getting connection for ad hoc query", ex);
9455  }
9457  try {
9458  return connection.executeQuery(connection.createStatement(), query);
9459  } finally {
9460  //TODO unlock should be done in closeRunQuery()
9461  //but currently not all code calls closeRunQuery - need to fix this
9462  connection.close();
9464  }
9465  }
9466 
9476  @Deprecated
9477  public void closeRunQuery(ResultSet resultSet) throws SQLException {
9478  final Statement statement = resultSet.getStatement();
9479  resultSet.close();
9480  if (statement != null) {
9481  statement.close();
9482  }
9483  }
9484 
9501  @Deprecated
9502  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
9503  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
9504  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
9505  files.add(carvedFile);
9506  CarvingResult carvingResult;
9507  Content parent = getContentById(containerId);
9508  if (parent instanceof FileSystem
9509  || parent instanceof Volume
9510  || parent instanceof Image) {
9511  carvingResult = new CarvingResult(parent, files);
9512  } else {
9513  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
9514  }
9515  return addCarvedFiles(carvingResult).get(0);
9516  }
9517 
9531  @Deprecated
9532  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
9533  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
9534  for (CarvedFileContainer container : filesToAdd) {
9535  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
9536  carvedFiles.add(carvedFile);
9537  }
9538  CarvingResult carvingResult;
9539  Content parent = getContentById(filesToAdd.get(0).getId());
9540  if (parent instanceof FileSystem
9541  || parent instanceof Volume
9542  || parent instanceof Image) {
9543  carvingResult = new CarvingResult(parent, carvedFiles);
9544  } else {
9545  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
9546  }
9547  return addCarvedFiles(carvingResult);
9548  }
9549 
9579  @Deprecated
9580  public DerivedFile addDerivedFile(String fileName, String localPath,
9581  long size, long ctime, long crtime, long atime, long mtime,
9582  boolean isFile, AbstractFile parentFile,
9583  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
9584  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
9585  isFile, parentFile, rederiveDetails, toolName, toolVersion,
9586  otherDetails, TskData.EncodingType.NONE);
9587  }
9588 
9613  @Deprecated
9614  public LocalFile addLocalFile(String fileName, String localPath,
9615  long size, long ctime, long crtime, long atime, long mtime,
9616  boolean isFile,
9617  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
9618  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
9619  TskData.EncodingType.NONE, parent, transaction);
9620  }
9621 
9641  @Deprecated
9642  public LocalFile addLocalFile(String fileName, String localPath,
9643  long size, long ctime, long crtime, long atime, long mtime,
9644  boolean isFile,
9645  AbstractFile parent) throws TskCoreException {
9646  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
9647  isFile, TskData.EncodingType.NONE, parent);
9648  }
9649 
9666  @Deprecated
9667  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
9668  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "");
9669  }
9670 
9678  @Deprecated
9679  public void acquireExclusiveLock() {
9681  }
9682 
9690  @Deprecated
9691  public void releaseExclusiveLock() {
9693  }
9694 
9702  @Deprecated
9703  public void acquireSharedLock() {
9705  }
9706 
9714  @Deprecated
9715  public void releaseSharedLock() {
9717  }
9718 
9719 };
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value)
final IngestJobInfo addIngestJob(Content dataSource, String hostName, List< IngestModuleInfo > ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir)
FS
File that can be found in file system tree.
Definition: TskData.java:670
static FileKnown valueOf(byte known)
Definition: TskData.java:745
BlackboardArtifact getArtifactByArtifactId(long id)
AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans)
BlackboardArtifact getArtifactById(long id)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType)
LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value)
void addBlackboardAttributes(Collection< BlackboardAttribute > attributes, int artifactTypeId)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails)
synchronized CommunicationsManager getCommunicationsManager()
boolean isCompatible(CaseDbSchemaVersionNumber dbSchemaVersion)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:206
static TSK_FS_TYPE_ENUM valueOf(int fsTypeValue)
Definition: TskData.java:499
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
void addErrorObserver(ErrorObserver observer)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
void setFileMIMEType(AbstractFile file, String mimeType)
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:207
void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent, CaseDbTransaction transaction)
final List< LayoutFile > addLayoutFiles(Content parent, List< TskFileRange > fileRanges)
int addArtifactType(String artifactTypeName, String displayName)
BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value)
TSK_FS_META_TYPE_VIRT_DIR
"Virtual Directory" created by TSK for Orphan Files NON-NLS
Definition: TskData.java:114
List< AbstractFile > openFiles(Content dataSource, String filePath)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)
final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version)
long getBlackboardArtifactsCount(String artifactTypeName, long obj_id)
static IngestJobStatusType fromID(int typeId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value)
static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir)
List< VirtualDirectory > getVirtualDirectoryRoots()
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
ContentTag getContentTagByID(long contentTagID)
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:673
Map< Long, List< String > > getImagePaths()
List< Long > findAllFileIdsWhere(String sqlWhereClause)
BlackboardArtifact getBlackboardArtifact(long artifactID)
List< BlackboardArtifact.Type > getArtifactTypesInUse()
BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
CARVED
Set of blocks for a file found from carving. Could be on top of a TSK_DB_FILES_TYPE_UNALLOC_BLOCKS ra...
Definition: TskData.java:671
BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
long countFilesWhere(String sqlWhereClause)
long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id)
boolean isFileFromSource(Content dataSource, long fileId)
ArrayList< BlackboardArtifact > getMatchingArtifacts(String whereClause)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypesInUse()
int getAttrTypeID(String attrTypeName)
List< Content > getChildren()
USED
Metadata structure has been allocated at least once.
Definition: TskData.java:208
LOCAL_DIR
Local directory that was added (not from a disk image)
Definition: TskData.java:678
final List< LayoutFile > addCarvedFiles(CarvingResult carvingResult)
void closeRunQuery(ResultSet resultSet)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
int addAttrType(String attrTypeString, String displayName)
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag)
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static String escapeSingleQuotes(String text)
String getAttrTypeDisplayName(int attrTypeID)
List< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
List< AbstractFile > findFiles(Content dataSource, String fileName)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:70
List< AbstractFile > findFilesByMd5(String md5Hash)
BlackboardArtifact.Type getArtifactType(String artTypeName)
BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:672
List< LayoutFile > addCarvedFiles(List< CarvedFileContainer > filesToAdd)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName)
static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath)
Report addReport(String localPath, String sourceModuleName, String reportName)
List< BlackboardArtifactTag > getAllBlackboardArtifactTags()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName, long obj_id)
void removeErrorObserver(ErrorObserver observer)
String getAttrTypeString(int attrTypeID)
List< AbstractFile > findFiles(Content dataSource, String fileName, String dirName)
LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List< TskFileRange > data)
ArrayList< BlackboardAttribute.ATTRIBUTE_TYPE > getBlackboardAttributeTypes()
UNALLOC_BLOCKS
Set of blocks not allocated by file system. Parent should be image, volume, or file system...
Definition: TskData.java:674
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
ArrayList< BlackboardAttribute > getMatchingAttributes(String whereClause)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
long getBlackboardArtifactsTypeCount(int artifactTypeID)
static ObjectType valueOf(short objectType)
Definition: TskData.java:653
long getContentTagsCountByTagName(TagName tagName)
void updateImagePath(String newPath, long objectId)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:726
List< AbstractFile > findAllFilesWhere(String sqlWhereClause)
boolean setKnown(AbstractFile file, FileKnown fileKnown)
static void tryConnect(CaseDbConnectionInfo info)
static SleuthkitCase openCase(String dbPath)
CaseDbQuery executeInsertOrUpdate(String query)
static String createNonUniquePath(String uniquePath)
long getBlackboardArtifactsCount(int artifactTypeID, long obj_id)
void submitError(String context, String errorMessage)
final List< IngestJobInfo > getIngestJobs()
VIRTUAL_DIR
Virtual directory (not on fs) with no meta-data entry that can be used to group files of types other ...
Definition: TskData.java:676
static SleuthkitCase newCase(String dbPath)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
List< ContentTag > getContentTagsByContent(Content content)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id)
int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType)
TagName addTagName(String displayName, String description, TagName.HTML_COLOR color)
ABSTRACTFILE
File - see tsk_files for more details.
Definition: TskData.java:628
ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
DataSource getDataSource(long objectId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith)
Iterable< BlackboardArtifact.Type > getArtifactTypes()
List< BlackboardAttribute.Type > getAttributeTypes()
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction)
AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath)
List< FsContent > findFilesWhere(String sqlWhereClause)
List< TskFileRange > getFileRanges(long id)
BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent, CaseDbTransaction transaction)
CaseDbQuery executeQuery(String query)
void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus)
void setImagePaths(long obj_id, List< String > paths)
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:624
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:157
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

Copyright © 2011-2018 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.