Sleuth Kit Java Bindings (JNI)  4.4.1
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 
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;
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;
119  private String dbBackupPath;
124  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
125  // This read/write lock is used to implement a layer of locking on top of
126  // the locking protocol provided by the underlying SQLite database. The Java
127  // locking protocol improves performance for reasons that are not currently
128  // understood. Note that the lock is contructed to use a fairness policy.
129  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
130 
142  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
143  Class.forName("org.sqlite.JDBC");
144  this.dbPath = dbPath;
145  this.dbType = dbType;
146  File dbFile = new File(dbPath);
147  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
148  this.databaseName = dbFile.getName();
149  this.connections = new SQLiteConnections(dbPath);
150  this.caseHandle = caseHandle;
151  init();
153  }
154 
172  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
173  this.dbPath = "";
174  this.databaseName = dbName;
175  this.dbType = dbType;
176  this.caseDirPath = caseDirPath;
177  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
178  this.caseHandle = caseHandle;
179  init();
180  }
181 
182  private void init() throws Exception {
183  typeIdToArtifactTypeMap = new ConcurrentHashMap<Integer, BlackboardArtifact.Type>();
184  typeIdToAttributeTypeMap = new ConcurrentHashMap<Integer, BlackboardAttribute.Type>();
185  typeNameToArtifactTypeMap = new ConcurrentHashMap<String, BlackboardArtifact.Type>();
186  typeNameToAttributeTypeMap = new ConcurrentHashMap<String, BlackboardAttribute.Type>();
187 
188  /*
189  * The following methods need to be called before updateDatabaseSchema
190  * due to the way that updateFromSchema2toSchema3 was implemented.
191  */
195 
196  updateDatabaseSchema(null);
197 
199 
200  CaseDbConnection connection = connections.getConnection();
201  initIngestModuleTypes(connection);
202  initIngestStatusTypes(connection);
203  initReviewStatuses(connection);
204  initEncodingTypes(connection);
205  connection.close();
206  }
207 
214  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
215  CaseDbConnection connection = connections.getConnection();
216  Statement statement = null;
217  ResultSet resultSet = null;
218  try {
219  statement = connection.createStatement();
220  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
221  try {
222  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
223  } catch (SQLException ex) {
224  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS
225  resultSet.next();
226  if (resultSet.getLong("count") == 0) {
227  throw ex;
228  }
229  resultSet.close();
230  resultSet = null;
231  }
232  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
233  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
234  }
235  if (dbType == DbType.POSTGRESQL) {
236  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
237  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
238  }
239  } finally {
240  closeResultSet(resultSet);
241  closeStatement(statement);
242  connection.close();
243  }
244  }
245 
253  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
254  CaseDbConnection connection = connections.getConnection();
255  Statement statement = null;
256  ResultSet resultSet = null;
257  try {
258  statement = connection.createStatement();
259  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
260  try {
261  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
262  } catch (SQLException ex) {
263  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS
264  resultSet.next();
265  if (resultSet.getLong("count") == 0) {
266  throw ex;
267  }
268  resultSet.close();
269  resultSet = null;
270  }
271  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
272  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
273  }
274  if (this.dbType == DbType.POSTGRESQL) {
275  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
276  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
277  }
278  } finally {
279  closeResultSet(resultSet);
280  closeStatement(statement);
281  connection.close();
282  }
283  }
284 
294  private void initNextArtifactId() throws SQLException, TskCoreException {
295  CaseDbConnection connection = connections.getConnection();
296  Statement statement = null;
297  ResultSet resultSet = null;
298  try {
299  statement = connection.createStatement();
300  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
301  resultSet.next();
302  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
303  if (this.nextArtifactId == 1) {
304  this.nextArtifactId = BASE_ARTIFACT_ID;
305  }
306  } finally {
307  closeResultSet(resultSet);
308  closeStatement(statement);
309  connection.close();
310  }
311  }
312 
320  private void initStandardTagNames() throws SQLException, TskCoreException {
321  String bookmarkDisplayName = bundle.getString("SleuthkitCase.initStandardTagNames.bookmark.text");
322  CaseDbConnection connection = connections.getConnection();
323  Statement statement = null;
324  ResultSet resultSet = null;
325  try {
326  statement = connection.createStatement();
327  statement.execute("INSERT INTO tag_names (display_name, description, color) VALUES ('" + bookmarkDisplayName + "', '', '" + TagName.HTML_COLOR.NONE.getName() + "');"); //NON-NLS
328  } catch (SQLException ex) {
329  /*
330  * If the exception is a violation of the tag names uniqueness
331  * constraint, it can be ignored because another user has added the
332  * tag name. Otherwise, propagate the exception.
333  */
334  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM tag_names WHERE display_name = '" + bookmarkDisplayName + "'"); //NON-NLS
335  resultSet.next();
336  if (resultSet.getLong("count") == 0) {
337  throw ex;
338  }
339  } finally {
340  closeResultSet(resultSet);
341  closeStatement(statement);
342  connection.close();
343  }
344  }
345 
353  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
354  Statement statement = null;
355  ResultSet resultSet = null;
356  try {
357  statement = connection.createStatement();
358  for (IngestModuleType type : IngestModuleType.values()) {
359  try {
360  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
361  } catch (SQLException ex) {
362  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
363  resultSet.next();
364  if (resultSet.getLong("count") == 0) {
365  throw ex;
366  }
367  resultSet.close();
368  resultSet = null;
369  }
370  }
371  } finally {
372  closeResultSet(resultSet);
373  closeStatement(statement);
374  }
375  }
376 
384  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
385  Statement statement = null;
386  ResultSet resultSet = null;
387  try {
388  statement = connection.createStatement();
389  for (IngestJobStatusType type : IngestJobStatusType.values()) {
390  try {
391  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
392  } catch (SQLException ex) {
393  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
394  resultSet.next();
395  if (resultSet.getLong("count") == 0) {
396  throw ex;
397  }
398  resultSet.close();
399  resultSet = null;
400  }
401  }
402  } finally {
403  closeResultSet(resultSet);
404  closeStatement(statement);
405  }
406  }
407 
414  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
415  Statement statement = null;
416  ResultSet resultSet = null;
417  try {
418  statement = connection.createStatement();
420  try {
421  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
422  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
423  } catch (SQLException ex) {
424  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
425  resultSet.next();
426  if (resultSet.getLong("count") == 0) {
427  throw ex;
428  }
429  resultSet.close();
430  resultSet = null;
431  }
432  }
433  } finally {
434  closeResultSet(resultSet);
435  closeStatement(statement);
436  }
437  }
438 
446  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
447  Statement statement = null;
448  ResultSet resultSet = null;
449  try {
450  statement = connection.createStatement();
451  for (TskData.EncodingType type : TskData.EncodingType.values()) {
452  try {
453  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
454  } catch (SQLException ex) {
455  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
456  resultSet.next();
457  if (resultSet.getLong("count") == 0) {
458  throw ex;
459  }
460  resultSet.close();
461  resultSet = null;
462  }
463  }
464  } finally {
465  closeResultSet(resultSet);
466  closeStatement(statement);
467  }
468  }
469 
479  private void updateDatabaseSchema(String dbPath) throws Exception {
480  CaseDbConnection connection = connections.getConnection();
481  ResultSet resultSet = null;
482  Statement statement = null;
483  try {
484  connection.beginTransaction();
485 
486  boolean hasMinorVersion = false;
487  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
488  while (columns.next()) {
489  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
490  hasMinorVersion = true;
491  }
492  }
493 
494  // Get the schema version number of the case database from the tsk_db_info table.
495  int dbSchemaMajorVersion;
496  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
497 
498  statement = connection.createStatement();
499  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
500  + (hasMinorVersion ? ", schema_minor_ver" : "")
501  + " FROM tsk_db_info"); //NON-NLS
502  if (resultSet.next()) {
503  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
504  if (hasMinorVersion) {
505  //if there is a minor version column, use it, else default to zero.
506  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
507  }
508  } else {
509  throw new TskCoreException();
510  }
511  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
512 
513  resultSet.close();
514  resultSet = null;
515  statement.close();
516  statement = null;
517 
518  //check schema compatibility
519  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
520  //we cannot open a db with a major schema version higher than the current one.
522  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
523  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
524  //The schema version is compatible,possibly after upgrades.
525 
526  if (null != dbPath) {
527  // Make a backup copy of the database. Client code can get the path of the backup
528  // using the getBackupDatabasePath() method.
529  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
530  copyCaseDB(backupFilePath);
531  dbBackupPath = backupFilePath;
532  }
533 
534  // ***CALL SCHEMA UPDATE METHODS HERE***
535  // Each method should examine the schema version passed to it and either:
536  // a. do nothing and return the schema version unchanged, or
537  // b. upgrade the database and return the schema version that the db was upgraded to.
538  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
539  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
540  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
541  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
542  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
543  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
544 
545  // Write the updated schema version number to the the tsk_db_info table.
546  statement = connection.createStatement();
547  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
548  statement.close();
549  statement = null;
550  }
551 
552  connection.commitTransaction();
553  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
554  connection.rollbackTransaction();
555  throw ex;
556  } finally {
557  closeResultSet(resultSet);
558  closeStatement(statement);
559  connection.close();
560  }
561  }
562 
572  public void copyCaseDB(String newDBPath) throws IOException {
573  if (dbPath.isEmpty()) {
574  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
575  }
576  InputStream in = null;
577  OutputStream out = null;
579  try {
580  InputStream inFile = new FileInputStream(dbPath);
581  in = new BufferedInputStream(inFile);
582  OutputStream outFile = new FileOutputStream(newDBPath);
583  out = new BufferedOutputStream(outFile);
584  int bytesRead = in.read();
585  while (bytesRead != -1) {
586  out.write(bytesRead);
587  bytesRead = in.read();
588  }
589  } finally {
590  try {
591  if (in != null) {
592  in.close();
593  }
594  if (out != null) {
595  out.flush();
596  out.close();
597  }
598  } catch (IOException e) {
599  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
600  }
602  }
603  }
604 
608  private void logSQLiteJDBCDriverInfo() {
609  try {
610  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
611  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
612  ? "native" : "pure-java")); //NON-NLS
613  } catch (Exception ex) {
614  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
615  }
616  }
617 
631  @SuppressWarnings("deprecation")
633  if (schemaVersion.getMajor() != 2) {
634  return schemaVersion;
635  }
636  Statement statement = null;
637  Statement updateStatement = null;
638  ResultSet resultSet = null;
639  try {
640  statement = connection.createStatement();
641 
642  // Add new tables for tags.
643  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
644  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
645  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
646 
647  // Add a new table for reports.
648  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
649 
650  // Add new columns to the image info table.
651  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
652  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
653  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
654 
655  // Add a new column to the file system info table.
656  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
657 
658  // Add a new column to the file table.
659  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
660 
661  // Add new columns and indexes to the attributes table and populate the
662  // new column. Note that addition of the new column is a denormalization
663  // to optimize attribute queries.
664  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
665  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
666  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
667  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
668  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
669  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
670  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
671  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
672  + "FROM blackboard_attributes AS attrs " //NON-NLS
673  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
674  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
675  updateStatement = connection.createStatement();
676  while (resultSet.next()) {
677  long artifactId = resultSet.getLong("artifact_id");
678  int artifactTypeId = resultSet.getInt("artifact_type_id");
679  updateStatement.executeUpdate(
680  "UPDATE blackboard_attributes " //NON-NLS
681  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
682  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
683  }
684  resultSet.close();
685  resultSet = null;
686 
687  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
688  // TODO: This code depends on prepared statements that could evolve with
689  // time, breaking this upgrade. The code that follows should be rewritten
690  // to do everything with SQL specific to case database schema version 2.
691  HashMap<String, TagName> tagNames = new HashMap<String, TagName>();
693  Content content = getContentById(artifact.getObjectID());
694  String name = ""; //NON-NLS
695  String comment = ""; //NON-NLS
696  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
697  for (BlackboardAttribute attribute : attributes) {
698  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
699  name = attribute.getValueString();
700  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
701  comment = attribute.getValueString();
702  }
703  }
704  if (!name.isEmpty()) {
705  TagName tagName;
706  if (tagNames.containsKey(name)) {
707  tagName = tagNames.get(name);
708  } else {
709  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
710  tagNames.put(name, tagName);
711  }
712  addContentTag(content, tagName, comment, 0, content.getSize() - 1);
713  }
714  }
716  long taggedArtifactId = -1;
717  String name = ""; //NON-NLS
718  String comment = ""; //NON-NLS
719  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
720  for (BlackboardAttribute attribute : attributes) {
721  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
722  name = attribute.getValueString();
723  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
724  comment = attribute.getValueString();
725  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
726  taggedArtifactId = attribute.getValueLong();
727  }
728  }
729  if (taggedArtifactId != -1 && !name.isEmpty()) {
730  TagName tagName;
731  if (tagNames.containsKey(name)) {
732  tagName = tagNames.get(name);
733  } else {
734  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
735  tagNames.put(name, tagName);
736  }
737  addBlackboardArtifactTag(getBlackboardArtifact(taggedArtifactId), tagName, comment);
738  }
739  }
740  statement.execute(
741  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
742  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
743  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
744  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
745  statement.execute(
746  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
747  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
748  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
749 
750  return new CaseDbSchemaVersionNumber(3, 0);
751  } finally {
752  closeStatement(updateStatement);
753  closeResultSet(resultSet);
754  closeStatement(statement);
755  connection.close();
756  }
757  }
758 
773  if (schemaVersion.getMajor() != 3) {
774  return schemaVersion;
775  }
776 
777  Statement statement = null;
778  ResultSet resultSet = null;
779  Statement queryStatement = null;
780  ResultSet queryResultSet = null;
781  Statement updateStatement = null;
782  try {
783  // Add mime_type column to tsk_files table. Populate with general
784  // info artifact file signature data.
785  statement = connection.createStatement();
786  updateStatement = connection.createStatement();
787  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
788  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
789  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
790  + "WHERE files.obj_id = arts.obj_id AND "
791  + "arts.artifact_id = attrs.artifact_id AND "
792  + "arts.artifact_type_id = 1 AND "
793  + "attrs.attribute_type_id = 62");
794  while (resultSet.next()) {
795  updateStatement.executeUpdate(
796  "UPDATE tsk_files " //NON-NLS
797  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
798  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
799  }
800  resultSet.close();
801 
802  // Add value_type column to blackboard_attribute_types table.
803  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
804  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
805  while (resultSet.next()) {
806  int attributeTypeId = resultSet.getInt("attribute_type_id");
807  String attributeLabel = resultSet.getString("type_name");
808  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
809  updateStatement.executeUpdate(
810  "UPDATE blackboard_attribute_types " //NON-NLS
811  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
812  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
813  }
814  }
815  resultSet.close();
816 
817  // Add a data_sources_info table.
818  queryStatement = connection.createStatement();
819  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));");
820  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
821  while (resultSet.next()) {
822  long objectId = resultSet.getLong("obj_id");
823  String timeZone = "";
824  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
825  if (queryResultSet.next()) {
826  timeZone = queryResultSet.getString("tzone");
827  }
828  queryResultSet.close();
829  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
830  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
831  }
832  resultSet.close();
833 
834  // Add data_source_obj_id column to the tsk_files table.
835  //
836  // NOTE: A new case database will have the following FK constraint:
837  //
838  // REFERENCES data_source_info (obj_id)
839  //
840  // The constraint is sacrificed here to avoid having to create and
841  // populate a new tsk_files table.
842  //
843  // TODO: Do this right.
844  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
845  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");
846  while (resultSet.next()) {
847  long fileId = resultSet.getLong("obj_id");
848  long dataSourceId = getDataSourceObjectId(connection, fileId);
849  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
850  }
851  resultSet.close();
852  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
853  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
854  if (this.dbType.equals(DbType.SQLITE)) {
855  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
856  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
857  } else {
858  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
859  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
860  }
861 
862  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
863  initIngestModuleTypes(connection);
864  initIngestStatusTypes(connection);
865 
866  return new CaseDbSchemaVersionNumber(4, 0);
867 
868  } finally {
869  closeResultSet(queryResultSet);
870  closeStatement(queryStatement);
871  closeStatement(updateStatement);
872  closeResultSet(resultSet);
873  closeStatement(statement);
874  }
875  }
876 
891  if (schemaVersion.getMajor() != 4) {
892  return schemaVersion;
893  }
894 
895  Statement statement = null;
896  try {
897  // Add the review_statuses lookup table.
898  statement = connection.createStatement();
899  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
900 
901  /*
902  * Add review_status_id column to artifacts table.
903  *
904  * NOTE: For DBs created with schema 5 we define a foreign key
905  * constraint on the review_status_column. We don't bother with this
906  * for DBs updated to schema 5 because of limitations of the SQLite
907  * ALTER TABLE command.
908  */
909  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
910 
911  // Add the encoding table
912  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
913  initEncodingTypes(connection);
914 
915  /*
916  * This needs to be done due to a Autopsy/TSK out of synch problem.
917  * Without this, it is possible to upgrade from version 4 to 5 and
918  * then 5 to 6, but not from 4 to 6.
919  */
920  initReviewStatuses(connection);
921 
922  // Add encoding type column to tsk_files_path
923  // This should really have the FOREIGN KEY constraint but there are problems
924  // getting that to work, so we don't add it on this upgrade path.
925  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
926 
927  return new CaseDbSchemaVersionNumber(5, 0);
928 
929  } finally {
930  closeStatement(statement);
931  }
932  }
933 
948  if (schemaVersion.getMajor() != 5) {
949  return schemaVersion;
950  }
951 
952  /*
953  * This upgrade fixes a bug where some releases had artifact review
954  * status support in the case database and others did not.
955  */
956  Statement statement = null;
957  ResultSet resultSet = null;
958  try {
959  /*
960  * Add the review_statuses lookup table, if missing.
961  */
962  statement = connection.createStatement();
963  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)");
964 
965  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
966  resultSet.next();
967  if (resultSet.getLong("count") == 0) {
968  /*
969  * Add review_status_id column to artifacts table.
970  *
971  * NOTE: For DBs created with schema 5 or 6 we define a foreign
972  * key constraint on the review_status_column. We don't bother
973  * with this for DBs updated to schema 5 or 6 because of
974  * limitations of the SQLite ALTER TABLE command.
975  */
976  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
977  }
978 
979  return new CaseDbSchemaVersionNumber(6, 0);
980 
981  } finally {
982  closeResultSet(resultSet);
983  closeStatement(statement);
984  }
985  }
986 
1001  if (schemaVersion.getMajor() != 6) {
1002  return schemaVersion;
1003  }
1004 
1005  /*
1006  * This upgrade adds an indexed extension column to the tsk_files table.
1007  */
1008  Statement statement = null;
1009  Statement updstatement = null;
1010  ResultSet resultSet = null;
1011  try {
1012  statement = connection.createStatement();
1013  updstatement = connection.createStatement();
1014  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1015 
1016  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1017  while (resultSet.next()) {
1018  long objID = resultSet.getLong("obj_id");
1019  String name = resultSet.getString("name");
1020  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1021  + "WHERE obj_id = " + objID);
1022  }
1023 
1024  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1025 
1026  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1027  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1028 
1029  return new CaseDbSchemaVersionNumber(7, 0);
1030 
1031  } finally {
1032  closeResultSet(resultSet);
1033  closeStatement(statement);
1034  closeStatement(updstatement);
1035  }
1036  }
1037 
1052  if (schemaVersion.getMajor() != 7) {
1053  return schemaVersion;
1054  }
1055 
1056  if(schemaVersion.getMinor() != 0){
1057  return schemaVersion;
1058  }
1059 
1060  /*
1061  * This upgrade adds a minor version number column.
1062  */
1063  Statement statement = null;
1064  ResultSet resultSet = null;
1065  try {
1066  statement = connection.createStatement();
1067 
1068  //add the schema minor version number column.
1069  if (schemaVersion.getMinor() == 0) {
1070  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1071  }
1072  return new CaseDbSchemaVersionNumber(7, 1);
1073 
1074  } finally {
1075  closeResultSet(resultSet);
1076  closeStatement(statement);
1077  }
1078  }
1079 
1087  static String extractExtension(final String fileName) {
1088  String ext;
1089  int i = fileName.lastIndexOf(".");
1090  // > 0 because we assume it's not an extension if period is the first character
1091  if ((i > 0) && ((i + 1) < fileName.length())) {
1092  ext = fileName.substring(i + 1);
1093  } else {
1094  return "";
1095  }
1096  // we added this at one point to deal with files that had crazy names based on URLs
1097  // it's too hard though to clean those up and not mess up basic extensions though.
1098  // We need to add '-' to the below if we use it again
1099  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
1100  // if (findNonAlphanumeric.length > 1) {
1101  // ext = findNonAlphanumeric[0];
1102  // }
1103  return ext.toLowerCase();
1104  }
1105 
1120  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
1121  // Check if we can talk to the database.
1122  if (info.getHost() == null || info.getHost().isEmpty()) {
1123  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
1124  } else if (info.getPort() == null || info.getPort().isEmpty()) {
1125  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
1126  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
1127  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
1128  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
1129  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
1130  }
1131 
1132  try {
1133  Class.forName("org.postgresql.Driver"); //NON-NLS
1134  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
1135  if (conn != null) {
1136  conn.close();
1137  }
1138  } catch (SQLException ex) {
1139  String result;
1140  String sqlState = ex.getSQLState().toLowerCase();
1141  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
1142  try {
1143  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
1144  // if we can reach the host, then it's probably port problem
1145  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
1146  } else {
1147  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
1148  }
1149  } catch (IOException any) {
1150  // it may be anything
1151  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
1152  } catch (MissingResourceException any) {
1153  // it may be anything
1154  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
1155  }
1156  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
1157  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
1158  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
1159  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
1160  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
1161  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
1162  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
1163  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
1164  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
1165  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
1166  } else {
1167  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
1168  }
1169  throw new TskCoreException(result);
1170  } catch (ClassNotFoundException ex) {
1171  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
1172  }
1173  }
1174 
1185  @Deprecated
1186  public int getSchemaVersion() {
1187  return getDBSchemaVersion().getMajor();
1188  }
1189 
1197  }
1198 
1205  return this.dbType;
1206  }
1207 
1214  public String getBackupDatabasePath() {
1215  return dbBackupPath;
1216  }
1217 
1229  return new CaseDbTransaction(connections.getConnection());
1230  }
1231 
1237  public String getDatabaseName() {
1238  return databaseName;
1239  }
1240 
1247  public String getDbDirPath() {
1248  return caseDirPath;
1249  }
1250 
1256  public void acquireExclusiveLock() {
1257  if (dbType == DbType.SQLITE) {
1258  rwLock.writeLock().lock();
1259  }
1260  }
1261 
1267  public void releaseExclusiveLock() {
1268  if (dbType == DbType.SQLITE) {
1269  rwLock.writeLock().unlock();
1270  }
1271  }
1272 
1278  public void acquireSharedLock() {
1279  if (dbType == DbType.SQLITE) {
1280  rwLock.readLock().lock();
1281  }
1282  }
1283 
1289  public void releaseSharedLock() {
1290  if (dbType == DbType.SQLITE) {
1291  rwLock.readLock().unlock();
1292  }
1293  }
1294 
1304  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
1305  try {
1306  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
1307  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
1309  //don't wrap in new TskCoreException
1310  throw ex;
1311  } catch (Exception ex) {
1312  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
1313  }
1314  }
1315 
1327  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
1328  try {
1329  /*
1330  * The flow of this method involves trying to open case and if
1331  * successful, return that case. If unsuccessful, an exception is
1332  * thrown. We catch any exceptions, and use tryConnect() to attempt
1333  * to obtain further information about the error. If tryConnect() is
1334  * unable to successfully connect, tryConnect() will throw a
1335  * TskCoreException with a message containing user-level error
1336  * reporting. If tryConnect() is able to connect, flow continues and
1337  * we rethrow the original exception obtained from trying to create
1338  * the case. In this way, we obtain more detailed information if we
1339  * are able, but do not lose any information if unable.
1340  */
1341  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
1342  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
1343  } catch (PropertyVetoException exp) {
1344  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
1345  throw new TskCoreException(exp.getMessage(), exp);
1347  //don't wrap in new TskCoreException
1348  throw ex;
1349  } catch (Exception exp) {
1350  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
1351  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
1352  }
1353  }
1354 
1364  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
1365  try {
1366  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(dbPath);
1367  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
1368  } catch (Exception ex) {
1369  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
1370  }
1371  }
1372 
1388  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
1389  String databaseName = createCaseDataBaseName(caseName);
1390  try {
1403  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(databaseName, info);
1404  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
1405  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
1406  } catch (PropertyVetoException exp) {
1407  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
1408  throw new TskCoreException(exp.getMessage(), exp);
1409  } catch (Exception exp) {
1410  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
1411  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
1412  }
1413  }
1414 
1424  private static String createCaseDataBaseName(String candidateDbName) {
1425  String dbName;
1426  if (!candidateDbName.isEmpty()) {
1427  /*
1428  * Replace all non-ASCII characters.
1429  */
1430  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
1431 
1432  /*
1433  * Replace all control characters.
1434  */
1435  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
1436 
1437  /*
1438  * Replace /, \, :, ?, space, ' ".
1439  */
1440  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
1441 
1442  /*
1443  * Make it all lowercase.
1444  */
1445  dbName = dbName.toLowerCase();
1446 
1447  /*
1448  * Must start with letter or underscore. If not, prepend an
1449  * underscore.
1450  */
1451  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
1452  dbName = "_" + dbName;
1453  }
1454 
1455  /*
1456  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
1457  * uniqueness.
1458  */
1459  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
1460  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
1461  }
1462 
1463  } else {
1464  /*
1465  * Must start with letter or underscore.
1466  */
1467  dbName = "_";
1468  }
1469  /*
1470  * Add the time stmap.
1471  */
1472  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
1473  Date date = new Date();
1474  dbName = dbName + "_" + dateFormat.format(date);
1475 
1476  return dbName;
1477  }
1478 
1496  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
1497  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath);
1498  }
1499 
1508  public List<Content> getRootObjects() throws TskCoreException {
1509  CaseDbConnection connection = connections.getConnection();
1511  Statement s = null;
1512  ResultSet rs = null;
1513  try {
1514  s = connection.createStatement();
1515  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
1516  + "WHERE par_obj_id IS NULL"); //NON-NLS
1517  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
1518  while (rs.next()) {
1519  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
1520  }
1521 
1522  List<Content> rootObjs = new ArrayList<Content>();
1523  for (ObjectInfo i : infos) {
1524  if (null != i.type) {
1525  switch (i.type) {
1526  case IMG:
1527  rootObjs.add(getImageById(i.id));
1528  break;
1529  case ABSTRACTFILE:
1530  // Check if virtual dir for local files.
1531  AbstractFile af = getAbstractFileById(i.id);
1532  if (af instanceof VirtualDirectory) {
1533  rootObjs.add(af);
1534  } else {
1535  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
1536  }
1537  break;
1538  default:
1539  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
1540  }
1541  }
1542  }
1543  return rootObjs;
1544  } catch (SQLException ex) {
1545  throw new TskCoreException("Error getting root objects", ex);
1546  } finally {
1547  closeResultSet(rs);
1548  closeStatement(s);
1549  connection.close();
1551  }
1552  }
1553 
1569  public List<DataSource> getDataSources() throws TskCoreException {
1570  CaseDbConnection connection = connections.getConnection();
1572  Statement s = null;
1573  ResultSet rs = null;
1574  try {
1575  s = connection.createStatement();
1576  rs = connection.executeQuery(s, "SELECT obj_id, device_id, time_zone FROM data_source_info"); //NON-NLS
1577  List<DataSource> dataSources = new ArrayList<DataSource>();
1578  while (rs.next()) {
1579  dataSources.add(new AbstractDataSource(rs.getLong("obj_id"), rs.getString("device_id"), rs.getString("time_zone")));
1580  }
1581  return dataSources;
1582  } catch (SQLException ex) {
1583  throw new TskCoreException("Error getting data sources", ex);
1584  } finally {
1585  closeResultSet(rs);
1586  closeStatement(s);
1587  connection.close();
1589  }
1590  }
1591 
1611  CaseDbConnection connection = connections.getConnection();
1613  Statement s = null;
1614  ResultSet rs = null;
1615  try {
1616  s = connection.createStatement();
1617  rs = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objectId); //NON-NLS
1618  if (rs.next()) {
1619  return new AbstractDataSource(objectId, rs.getString("device_id"), rs.getString("time_zone"));
1620  } else {
1621  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
1622  }
1623  } catch (SQLException ex) {
1624  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
1625  } finally {
1626  closeResultSet(rs);
1627  closeStatement(s);
1628  connection.close();
1630  }
1631  }
1632 
1643  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
1644  return getArtifactsHelper("blackboard_artifacts.artifact_type_id = " + artifactTypeID);
1645  }
1646 
1657  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
1658  CaseDbConnection connection = connections.getConnection();
1660  ResultSet rs = null;
1661  try {
1662  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
1663  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
1664  statement.clearParameters();
1665  statement.setLong(1, objId);
1666  rs = connection.executeQuery(statement);
1667  long count = 0;
1668  if (rs.next()) {
1669  count = rs.getLong("count");
1670  }
1671  return count;
1672  } catch (SQLException ex) {
1673  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
1674  } finally {
1675  closeResultSet(rs);
1676  connection.close();
1678  }
1679  }
1680 
1691  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
1692  CaseDbConnection connection = connections.getConnection();
1694  ResultSet rs = null;
1695  try {
1696  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
1697  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
1698  statement.clearParameters();
1699  statement.setInt(1, artifactTypeID);
1700  rs = connection.executeQuery(statement);
1701  long count = 0;
1702  if (rs.next()) {
1703  count = rs.getLong("count");
1704  }
1705  return count;
1706  } catch (SQLException ex) {
1707  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
1708  } finally {
1709  closeResultSet(rs);
1710  connection.close();
1712  }
1713  }
1714 
1729  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
1730  CaseDbConnection connection = connections.getConnection();
1732  Statement s = null;
1733  ResultSet rs = null;
1734  try {
1735  s = connection.createStatement();
1736  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1737  + "arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
1738  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
1739  + " arts.review_status_id AS review_status_id " //NON-NLS
1740  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1741  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1742  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1743  + " AND attrs.value_text = '" + value + "'"
1744  + " AND types.artifact_type_id=arts.artifact_type_id"
1745  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
1746  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1747  while (rs.next()) {
1748  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1749  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1750  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1751  }
1752  return artifacts;
1753  } catch (SQLException ex) {
1754  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
1755  } finally {
1756  closeResultSet(rs);
1757  closeStatement(s);
1758  connection.close();
1760  }
1761  }
1762 
1780  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
1781  String valSubStr = "%" + subString; //NON-NLS
1782  if (startsWith == false) {
1783  valSubStr += "%"; //NON-NLS
1784  }
1785  CaseDbConnection connection = connections.getConnection();
1787  Statement s = null;
1788  ResultSet rs = null;
1789  try {
1790  s = connection.createStatement();
1791  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1792  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, " //NON-NLS
1793  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
1794  + " arts.review_status_id AS review_status_id " //NON-NLS
1795  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1796  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1797  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1798  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
1799  + " AND types.artifact_type_id=arts.artifact_type_id "
1800  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
1801  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1802  while (rs.next()) {
1803  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1804  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1805  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1806  }
1807  return artifacts;
1808  } catch (SQLException ex) {
1809  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
1810  } finally {
1811  closeResultSet(rs);
1812  closeStatement(s);
1813  connection.close();
1815  }
1816  }
1817 
1832  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
1833  CaseDbConnection connection = connections.getConnection();
1835  Statement s = null;
1836  ResultSet rs = null;
1837  try {
1838  s = connection.createStatement();
1839  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1840  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
1841  + " types.type_name AS type_name, types.display_name AS display_name, "
1842  + " arts.review_status_id AS review_status_id "//NON-NLS
1843  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1844  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1845  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1846  + " AND attrs.value_int32 = " + value //NON-NLS
1847  + " AND types.artifact_type_id=arts.artifact_type_id "
1848  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
1849  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1850  while (rs.next()) {
1851  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1852  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1853  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1854  }
1855  return artifacts;
1856  } catch (SQLException ex) {
1857  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
1858  } finally {
1859  closeResultSet(rs);
1860  closeStatement(s);
1861  connection.close();
1863  }
1864  }
1865 
1880  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
1881  CaseDbConnection connection = connections.getConnection();
1883  Statement s = null;
1884  ResultSet rs = null;
1885  try {
1886  s = connection.createStatement();
1887  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1888  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
1889  + " types.type_name AS type_name, types.display_name AS display_name, "
1890  + " arts.review_status_id AS review_status_id "//NON-NLS
1891  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1892  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1893  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1894  + " AND attrs.value_int64 = " + value //NON-NLS
1895  + " AND types.artifact_type_id=arts.artifact_type_id "
1896  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
1897  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1898  while (rs.next()) {
1899  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1900  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1901  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1902  }
1903  return artifacts;
1904  } catch (SQLException ex) {
1905  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
1906  } finally {
1907  closeResultSet(rs);
1908  closeStatement(s);
1909  connection.close();
1911  }
1912  }
1913 
1928  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
1929  CaseDbConnection connection = connections.getConnection();
1931  Statement s = null;
1932  ResultSet rs = null;
1933  try {
1934  s = connection.createStatement();
1935  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1936  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
1937  + " types.type_name AS type_name, types.display_name AS display_name, "
1938  + " arts.review_status_id AS review_status_id "//NON-NLS
1939  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1940  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1941  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1942  + " AND attrs.value_double = " + value //NON-NLS
1943  + " AND types.artifact_type_id=arts.artifact_type_id "
1944  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
1945  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1946  while (rs.next()) {
1947  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1948  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1949  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1950  }
1951  return artifacts;
1952  } catch (SQLException ex) {
1953  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
1954  } finally {
1955  closeResultSet(rs);
1956  closeStatement(s);
1957  connection.close();
1959  }
1960  }
1961 
1976  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
1977  CaseDbConnection connection = connections.getConnection();
1979  Statement s = null;
1980  ResultSet rs = null;
1981  try {
1982  s = connection.createStatement();
1983  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
1984  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
1985  + " types.type_name AS type_name, types.display_name AS display_name, "
1986  + " arts.review_status_id AS review_status_id "//NON-NLS
1987  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
1988  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
1989  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
1990  + " AND attrs.value_byte = " + value //NON-NLS
1991  + " AND types.artifact_type_id=arts.artifact_type_id "
1992  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
1993  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1994  while (rs.next()) {
1995  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
1996  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
1997  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
1998  }
1999  return artifacts;
2000  } catch (SQLException ex) {
2001  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
2002  } finally {
2003  closeResultSet(rs);
2004  closeStatement(s);
2005  connection.close();
2007  }
2008  }
2009 
2018  CaseDbConnection connection = connections.getConnection();
2020  Statement s = null;
2021  ResultSet rs = null;
2022  try {
2023  s = connection.createStatement();
2024  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types"); //NON-NLS
2025  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
2026  while (rs.next()) {
2027  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2028  rs.getString("type_name"), rs.getString("display_name")));
2029  }
2030  return artifactTypes;
2031  } catch (SQLException ex) {
2032  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
2033  } finally {
2034  closeResultSet(rs);
2035  closeStatement(s);
2036  connection.close();
2038  }
2039  }
2040 
2050  String typeIdList = "";
2051  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
2052  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
2053  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
2054  typeIdList += ", ";
2055  }
2056  }
2057  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
2058  + "WHERE artifact_type_id IN (" + typeIdList + ")";
2059  CaseDbConnection connection = connections.getConnection();
2061  Statement s = null;
2062  ResultSet rs = null;
2063  try {
2064  s = connection.createStatement();
2065  rs = connection.executeQuery(s, query);
2066  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
2067  while (rs.next()) {
2068  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
2069  }
2070  return usedArts;
2071  } catch (SQLException ex) {
2072  throw new TskCoreException("Error getting artifact types in use", ex);
2073  } finally {
2074  closeResultSet(rs);
2075  closeStatement(s);
2076  connection.close();
2078  }
2079  }
2080 
2092  CaseDbConnection connection = connections.getConnection();
2094  Statement s = null;
2095  ResultSet rs = null;
2096  try {
2097  s = connection.createStatement();
2098  rs = connection.executeQuery(s,
2099  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
2100  + "types.type_name AS type_name, types.display_name AS display_name "
2101  + "FROM blackboard_artifact_types AS types "
2102  + "INNER JOIN blackboard_artifacts AS arts "
2103  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
2104  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
2105  while (rs.next()) {
2106  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2107  rs.getString("type_name"), rs.getString("display_name")));
2108  }
2109  return uniqueArtifactTypes;
2110  } catch (SQLException ex) {
2111  throw new TskCoreException("Error getting attribute types", ex);
2112  } finally {
2113  closeResultSet(rs);
2114  closeStatement(s);
2115  connection.close();
2117  }
2118  }
2119 
2128  CaseDbConnection connection = connections.getConnection();
2130  Statement s = null;
2131  ResultSet rs = null;
2132  try {
2133  s = connection.createStatement();
2134  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
2135  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
2136  while (rs.next()) {
2137  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
2138  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
2139  }
2140  return attribute_types;
2141  } catch (SQLException ex) {
2142  throw new TskCoreException("Error getting attribute types", ex);
2143  } finally {
2144  closeResultSet(rs);
2145  closeStatement(s);
2146  connection.close();
2148  }
2149  }
2150 
2163  CaseDbConnection connection = connections.getConnection();
2165  Statement s = null;
2166  ResultSet rs = null;
2167  try {
2168  s = connection.createStatement();
2169  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
2170  int count = 0;
2171  if (rs.next()) {
2172  count = rs.getInt("count");
2173  }
2174  return count;
2175  } catch (SQLException ex) {
2176  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
2177  } finally {
2178  closeResultSet(rs);
2179  closeStatement(s);
2180  connection.close();
2182  }
2183  }
2184 
2197  private ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
2198  CaseDbConnection connection = connections.getConnection();
2200  ResultSet rs = null;
2201  try {
2202  Statement statement = connection.createStatement();
2203  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
2204  + "blackboard_artifacts.obj_id AS obj_id, "
2205  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
2206  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
2207  + "blackboard_artifact_types.type_name AS type_name, "
2208  + "blackboard_artifact_types.display_name AS display_name, "
2209  + "blackboard_artifacts.review_status_id AS review_status_id "
2210  + "FROM blackboard_artifacts, blackboard_artifact_types "
2211  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
2212  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
2213  + " AND " + whereClause;
2214  rs = connection.executeQuery(statement, query);
2215  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2216  while (rs.next()) {
2217  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
2218  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2219  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2220  }
2221  return artifacts;
2222  } catch (SQLException ex) {
2223  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
2224  } finally {
2225  closeResultSet(rs);
2226  connection.close();
2228  }
2229  }
2230 
2243  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
2244  CaseDbConnection connection = connections.getConnection();
2246  ResultSet rs = null;
2247  try {
2248  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
2249  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
2250  statement.clearParameters();
2251  statement.setLong(1, obj_id);
2252  statement.setInt(2, artifactTypeID);
2253  rs = connection.executeQuery(statement);
2254  long count = 0;
2255  if (rs.next()) {
2256  count = rs.getLong("count");
2257  }
2258  return count;
2259  } catch (SQLException ex) {
2260  throw new TskCoreException("Error getting blackboard artifact count", ex);
2261  } finally {
2262  closeResultSet(rs);
2263  connection.close();
2265  }
2266  }
2267 
2280  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
2281  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
2282  }
2283 
2296  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
2297  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
2298  }
2299 
2312  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
2313  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
2314  }
2315 
2328  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
2329  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
2330  if (artifactTypeID == -1) {
2331  return 0;
2332  }
2333  return getArtifactsCountHelper(artifactTypeID, obj_id);
2334  }
2335 
2348  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
2349  return getArtifactsCountHelper(artifactTypeID, obj_id);
2350  }
2351 
2364  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
2365  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
2366  }
2367 
2379  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
2380  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
2381  }
2382 
2394  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
2395  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
2396  }
2397 
2411  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
2412  CaseDbConnection connection = connections.getConnection();
2414  Statement s = null;
2415  ResultSet rs = null;
2416  try {
2417  s = connection.createStatement();
2418  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2419  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
2420  + "types.type_name AS type_name, types.display_name AS display_name,"
2421  + "arts.review_status_id AS review_status_id "//NON-NLS
2422  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2423  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2424  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2425  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
2426  + " AND attrs.value_text = '" + value + "'" //NON-NLS
2427  + " AND types.artifact_type_id=arts.artifact_type_id"
2428  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
2429  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2430  while (rs.next()) {
2431  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
2432  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2433  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2434  }
2435  return artifacts;
2436  } catch (SQLException ex) {
2437  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
2438  } finally {
2439  closeResultSet(rs);
2440  closeStatement(s);
2441  connection.close();
2443  }
2444  }
2445 
2457  CaseDbConnection connection = connections.getConnection();
2459  ResultSet rs = null;
2460  Statement s = null;
2461  try {
2462  s = connection.createStatement();
2463  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
2464  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.artifact_type_id AS artifact_type_id, "
2465  + "types.type_name AS type_name, types.display_name AS display_name,"
2466  + "arts.review_status_id AS review_status_id "//NON-NLS
2467  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
2468  + "WHERE arts.artifact_id = " + artifactID
2469  + " AND arts.artifact_type_id = types.artifact_type_id");
2470  if (rs.next()) {
2471  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
2472  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2473  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
2474  } else {
2475  /*
2476  * I think this should actually return null (or Optional) when
2477  * there is no artifact with the given id, but it looks like
2478  * existing code is not expecting that. -jm
2479  */
2480  throw new TskCoreException("No blackboard artifact with id " + artifactID);
2481  }
2482  } catch (SQLException ex) {
2483  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
2484  } finally {
2485  closeResultSet(rs);
2486  connection.close();
2488  }
2489  }
2490 
2499  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
2500  CaseDbConnection connection = connections.getConnection();
2502  try {
2503  addBlackBoardAttribute(attr, artifactTypeId, connection);
2504  } catch (SQLException ex) {
2505  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
2506  } finally {
2507  connection.close();
2509  }
2510  }
2511 
2521  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
2522  CaseDbConnection connection = connections.getConnection();
2524  try {
2525  connection.beginTransaction();
2526  for (final BlackboardAttribute attr : attributes) {
2527  addBlackBoardAttribute(attr, artifactTypeId, connection);
2528  }
2529  connection.commitTransaction();
2530  } catch (SQLException ex) {
2531  connection.rollbackTransaction();
2532  throw new TskCoreException("Error adding blackboard attributes", ex);
2533  } finally {
2534  connection.close();
2536  }
2537  }
2538 
2539  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
2540  PreparedStatement statement;
2541  switch (attr.getAttributeType().getValueType()) {
2542  case STRING:
2543  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
2544  statement.clearParameters();
2545  statement.setString(7, attr.getValueString());
2546  break;
2547  case BYTE:
2548  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
2549  statement.clearParameters();
2550  statement.setBytes(7, attr.getValueBytes());
2551  break;
2552  case INTEGER:
2553  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
2554  statement.clearParameters();
2555  statement.setInt(7, attr.getValueInt());
2556  break;
2557  case LONG:
2558  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
2559  statement.clearParameters();
2560  statement.setLong(7, attr.getValueLong());
2561  break;
2562  case DOUBLE:
2563  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
2564  statement.clearParameters();
2565  statement.setDouble(7, attr.getValueDouble());
2566  break;
2567  case DATETIME:
2568  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
2569  statement.clearParameters();
2570  statement.setLong(7, attr.getValueLong());
2571  break;
2572  default:
2573  throw new TskCoreException("Unrecognized artifact attribute value type");
2574  }
2575  statement.setLong(1, attr.getArtifactID());
2576  statement.setInt(2, artifactTypeId);
2577  statement.setString(3, attr.getSourcesCSV());
2578  statement.setString(4, "");
2579  statement.setInt(5, attr.getAttributeType().getTypeID());
2580  statement.setLong(6, attr.getAttributeType().getValueType().getType());
2581  connection.executeUpdate(statement);
2582  }
2583 
2594  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
2595  /*
2596  * WARNING: This is a temporary implementation that is not safe and
2597  * denormalizes the case datbase.
2598  *
2599  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
2600  * the sources of artifact attributes.
2601  */
2602  if (null == source || source.isEmpty()) {
2603  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
2604  }
2605  CaseDbConnection connection = connections.getConnection();
2607  Statement queryStmt = null;
2608  Statement updateStmt = null;
2609  ResultSet result = null;
2610  String newSources = "";
2611  try {
2612  connection.beginTransaction();
2613  String valueClause = "";
2614  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
2615  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
2616  switch (valueType) {
2617  case STRING:
2618  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
2619  break;
2620  case INTEGER:
2621  valueClause = " value_int32 = " + attr.getValueInt();
2622  break;
2623  case LONG:
2624  case DATETIME:
2625  valueClause = " value_int64 = " + attr.getValueLong();
2626  break;
2627  case DOUBLE:
2628  valueClause = " value_double = " + attr.getValueDouble();
2629  break;
2630  default:
2631  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
2632  }
2633  String query = "SELECT source FROM blackboard_attributes WHERE"
2634  + " artifact_id = " + attr.getArtifactID()
2635  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
2636  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
2637  + " AND " + valueClause + ";";
2638  queryStmt = connection.createStatement();
2639  updateStmt = connection.createStatement();
2640  result = connection.executeQuery(queryStmt, query);
2641  } else {
2642  /*
2643  * SELECT source FROM blackboard_attributes WHERE artifact_id =
2644  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
2645  * = ?
2646  */
2647  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
2648  statement.clearParameters();
2649  statement.setLong(1, attr.getArtifactID());
2650  statement.setLong(2, attr.getAttributeType().getTypeID());
2651  statement.setBytes(3, attr.getValueBytes());
2652  result = connection.executeQuery(statement);
2653  }
2654  while (result.next()) {
2655  String oldSources = result.getString("source");
2656  if (null != oldSources && !oldSources.isEmpty()) {
2657  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
2658  if (!uniqueSources.contains(source)) {
2659  newSources = oldSources + "," + source;
2660  } else {
2661  newSources = oldSources;
2662  }
2663  } else {
2664  newSources = source;
2665  }
2666  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
2667  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
2668  + " artifact_id = " + attr.getArtifactID()
2669  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
2670  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
2671  + " AND " + valueClause + ";";
2672  connection.executeUpdate(updateStmt, update);
2673  } else {
2674  /*
2675  * UPDATE blackboard_attributes SET source = ? WHERE
2676  * artifact_id = ? AND attribute_type_id = ? AND value_type
2677  * = 4 AND value_byte = ?
2678  */
2679  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
2680  statement.clearParameters();
2681  statement.setString(1, newSources);
2682  statement.setLong(2, attr.getArtifactID());
2683  statement.setLong(3, attr.getAttributeType().getTypeID());
2684  statement.setBytes(4, attr.getValueBytes());
2685  connection.executeUpdate(statement);
2686  }
2687  }
2688  connection.commitTransaction();
2689  return newSources;
2690  } catch (SQLException ex) {
2691  connection.rollbackTransaction();
2692  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
2693  } finally {
2694  closeResultSet(result);
2695  closeStatement(updateStmt);
2696  closeStatement(queryStmt);
2697  connection.close();
2699  }
2700  }
2701 
2716  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
2717  CaseDbConnection connection = connections.getConnection();
2719  Statement s = null;
2720  ResultSet rs = null;
2721  try {
2722  connection.beginTransaction();
2723  s = connection.createStatement();
2724  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
2725  if (!rs.next()) {
2726  rs.close();
2727  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
2728  int maxID = 0;
2729  if (rs.next()) {
2730  maxID = rs.getInt("highest_id");
2731  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
2732  maxID = MIN_USER_DEFINED_TYPE_ID;
2733  } else {
2734  maxID++;
2735  }
2736  }
2737  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
2738  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
2739  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
2740  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
2741  connection.commitTransaction();
2742  return type;
2743  } else {
2744  throw new TskDataException("The attribute type that was added was already within the system.");
2745  }
2746 
2747  } catch (SQLException ex) {
2748  connection.rollbackTransaction();
2749  throw new TskCoreException("Error adding attribute type", ex);
2750  } finally {
2751  closeResultSet(rs);
2752  closeStatement(s);
2753  connection.close();
2755  }
2756  }
2757 
2768  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
2769  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
2770  return this.typeNameToAttributeTypeMap.get(attrTypeName);
2771  }
2772  CaseDbConnection connection = connections.getConnection();
2774  Statement s = null;
2775  ResultSet rs = null;
2776  try {
2777  s = connection.createStatement();
2778  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
2779  BlackboardAttribute.Type type = null;
2780  if (rs.next()) {
2781  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
2782  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
2783  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
2784  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
2785  }
2786  return type;
2787  } catch (SQLException ex) {
2788  throw new TskCoreException("Error getting attribute type id", ex);
2789  } finally {
2790  closeResultSet(rs);
2791  closeStatement(s);
2792  connection.close();
2794  }
2795  }
2796 
2808  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
2809  return this.typeIdToAttributeTypeMap.get(typeID);
2810  }
2811  CaseDbConnection connection = connections.getConnection();
2813  Statement s = null;
2814  ResultSet rs = null;
2815  try {
2816  s = connection.createStatement();
2817  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
2818  BlackboardAttribute.Type type = null;
2819  if (rs.next()) {
2820  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
2821  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
2822  this.typeIdToAttributeTypeMap.put(typeID, type);
2823  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
2824  }
2825  return type;
2826  } catch (SQLException ex) {
2827  throw new TskCoreException("Error getting attribute type id", ex);
2828  } finally {
2829  closeResultSet(rs);
2830  closeStatement(s);
2831  connection.close();
2833  }
2834  }
2835 
2846  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
2847  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
2848  return this.typeNameToArtifactTypeMap.get(artTypeName);
2849  }
2850  CaseDbConnection connection = connections.getConnection();
2852  Statement s = null;
2853  ResultSet rs = null;
2854  try {
2855  s = connection.createStatement();
2856  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
2857  BlackboardArtifact.Type type = null;
2858  if (rs.next()) {
2859  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2860  rs.getString("type_name"), rs.getString("display_name"));
2861  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
2862  this.typeNameToArtifactTypeMap.put(artTypeName, type);
2863  }
2864  return type;
2865  } catch (SQLException ex) {
2866  throw new TskCoreException("Error getting artifact type from the database", ex);
2867  } finally {
2868  closeResultSet(rs);
2869  closeStatement(s);
2870  connection.close();
2872  }
2873  }
2874 
2886  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
2887  return typeIdToArtifactTypeMap.get(artTypeId);
2888  }
2889  CaseDbConnection connection = connections.getConnection();
2891  Statement s = null;
2892  ResultSet rs = null;
2893  try {
2894  s = connection.createStatement();
2895  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
2896  BlackboardArtifact.Type type = null;
2897  if (rs.next()) {
2898  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
2899  rs.getString("type_name"), rs.getString("display_name"));
2900  this.typeIdToArtifactTypeMap.put(artTypeId, type);
2901  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
2902  }
2903  return type;
2904  } catch (SQLException ex) {
2905  throw new TskCoreException("Error getting artifact type from the database", ex);
2906  } finally {
2907  closeResultSet(rs);
2908  closeStatement(s);
2909  connection.close();
2911  }
2912  }
2913 
2926  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
2927  CaseDbConnection connection = connections.getConnection();
2929  Statement s = null;
2930  ResultSet rs = null;
2931  try {
2932  connection.beginTransaction();
2933  s = connection.createStatement();
2934  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
2935  if (!rs.next()) {
2936  rs.close();
2937  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
2938  int maxID = 0;
2939  if (rs.next()) {
2940  maxID = rs.getInt("highest_id");
2941  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
2942  maxID = MIN_USER_DEFINED_TYPE_ID;
2943  } else {
2944  maxID++;
2945  }
2946  }
2947  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
2948  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName);
2949  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
2950  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
2951  connection.commitTransaction();
2952  return type;
2953  } else {
2954  throw new TskDataException("The attribute type that was added was already within the system.");
2955  }
2956  } catch (SQLException ex) {
2957  connection.rollbackTransaction();
2958  throw new TskCoreException("Error adding artifact type", ex);
2959  } finally {
2960  closeResultSet(rs);
2961  closeStatement(s);
2962  connection.close();
2964  }
2965  }
2966 
2967  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
2968  CaseDbConnection connection = connections.getConnection();
2970  ResultSet rs = null;
2971  try {
2972  Statement statement = connection.createStatement();
2973  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
2974  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
2975  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
2976  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
2977  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
2978  + "types.type_name AS type_name, types.display_name AS display_name "
2979  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
2980  + " AND attrs.attribute_type_id = types.attribute_type_id");
2981  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
2982  while (rs.next()) {
2983  int attributeTypeId = rs.getInt("attribute_type_id");
2984  String attributeTypeName = rs.getString("type_name");
2985  BlackboardAttribute.Type attributeType;
2986  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
2987  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
2988  } else {
2989  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
2990  rs.getString("display_name"),
2992  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
2993  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
2994  }
2995 
2996  final BlackboardAttribute attr = new BlackboardAttribute(
2997  rs.getLong("artifact_id"),
2998  attributeType,
2999  rs.getString("source"),
3000  rs.getString("context"),
3001  rs.getInt("value_int32"),
3002  rs.getLong("value_int64"),
3003  rs.getDouble("value_double"),
3004  rs.getString("value_text"),
3005  rs.getBytes("value_byte"), this
3006  );
3007  attributes.add(attr);
3008  }
3009  return attributes;
3010  } catch (SQLException ex) {
3011  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
3012  } finally {
3013  closeResultSet(rs);
3014  connection.close();
3016  }
3017  }
3018 
3031  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
3032  CaseDbConnection connection = connections.getConnection();
3034  Statement s = null;
3035  ResultSet rs = null;
3036  try {
3037  s = connection.createStatement();
3038  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
3039  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
3040  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
3041  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
3042  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
3043  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
3044  + "FROM blackboard_attributes " + whereClause); //NON-NLS
3045  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
3046  while (rs.next()) {
3048  // attribute type is cached, so this does not necessarily call to the db
3049  type = this.getAttributeType(rs.getInt("attribute_type_id"));
3051  rs.getLong("artifact_id"),
3052  type,
3053  rs.getString("source"),
3054  rs.getString("context"),
3055  rs.getInt("value_int32"),
3056  rs.getLong("value_int64"),
3057  rs.getDouble("value_double"),
3058  rs.getString("value_text"),
3059  rs.getBytes("value_byte"), this
3060  );
3061  matches.add(attr);
3062  }
3063  return matches;
3064  } catch (SQLException ex) {
3065  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
3066  } finally {
3067  closeResultSet(rs);
3068  closeStatement(s);
3069  connection.close();
3071  }
3072  }
3073 
3085  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
3086  CaseDbConnection connection = connections.getConnection();
3088  ResultSet rs = null;
3089  Statement s = null;
3090  try {
3091  s = connection.createStatement();
3092  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
3093  + "blackboard_artifacts.obj_id AS obj_id, blackboard_artifacts.artifact_obj_id AS artifact_obj_id, blackboard_artifacts.artifact_type_id AS artifact_type_id, "
3094  + "blackboard_artifacts.review_status_id AS review_status_id "
3095  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
3096  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
3097  while (rs.next()) {
3098  BlackboardArtifact.Type type;
3099  // artifact type is cached, so this does not necessarily call to the db
3100  type = this.getArtifactType(rs.getInt("artifact_type_id"));
3101  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3102  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
3103  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
3104  matches.add(artifact);
3105  }
3106  return matches;
3107  } catch (SQLException ex) {
3108  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
3109  } finally {
3110  closeResultSet(rs);
3111  closeStatement(s);
3112  connection.close();
3114  }
3115  }
3116 
3130  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
3131  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
3132  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName());
3133  }
3134 
3146  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3147  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
3148  }
3149 
3150  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
3151  CaseDbConnection connection = connections.getConnection();
3153  ResultSet resultSet = null;
3154  try {
3155 
3156  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
3157  statement.clearParameters();
3158  statement.setLong(1, obj_id);
3159  statement.setInt(2, TskData.ObjectType.ARTIFACT.getObjectType());
3160  connection.executeUpdate(statement);
3161  resultSet = statement.getGeneratedKeys();
3162  resultSet.next();
3163  long artifact_obj_id = resultSet.getLong(1); //last_insert_rowid()
3164 
3165  if (dbType == DbType.POSTGRESQL) {
3166  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
3167  statement.clearParameters();
3168  statement.setLong(1, obj_id);
3169  statement.setLong(2, artifact_obj_id);
3170  statement.setInt(3, artifact_type_id);
3171 
3172  } else {
3173  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
3174  statement.clearParameters();
3175  this.nextArtifactId++;
3176  statement.setLong(1, this.nextArtifactId);
3177  statement.setLong(2, obj_id);
3178  statement.setLong(3, artifact_obj_id);
3179  statement.setInt(4, artifact_type_id);
3180 
3181  }
3182  connection.executeUpdate(statement);
3183  resultSet = statement.getGeneratedKeys();
3184  resultSet.next();
3185  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
3186  obj_id, artifact_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
3187  } catch (SQLException ex) {
3188  throw new TskCoreException("Error creating a blackboard artifact", ex);
3189  } finally {
3190  closeResultSet(resultSet);
3191  connection.close();
3193  }
3194  }
3195 
3208  boolean getContentHasChildren(Content content) throws TskCoreException {
3209  CaseDbConnection connection = connections.getConnection();
3211  ResultSet rs = null;
3212  try {
3213  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
3214  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
3215  statement.clearParameters();
3216  statement.setLong(1, content.getId());
3217  rs = connection.executeQuery(statement);
3218  boolean hasChildren = false;
3219  if (rs.next()) {
3220  hasChildren = rs.getInt("count") > 0;
3221  }
3222  return hasChildren;
3223  } catch (SQLException e) {
3224  throw new TskCoreException("Error checking for children of parent " + content, e);
3225  } finally {
3226  closeResultSet(rs);
3227  connection.close();
3229  }
3230  }
3231 
3244  int getContentChildrenCount(Content content) throws TskCoreException {
3245  CaseDbConnection connection = connections.getConnection();
3247  ResultSet rs = null;
3248  try {
3249  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
3250  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
3251  statement.clearParameters();
3252  statement.setLong(1, content.getId());
3253  rs = connection.executeQuery(statement);
3254  int countChildren = -1;
3255  if (rs.next()) {
3256  countChildren = rs.getInt("count");
3257  }
3258  return countChildren;
3259  } catch (SQLException e) {
3260  throw new TskCoreException("Error checking for children of parent " + content, e);
3261  } finally {
3262  closeResultSet(rs);
3263  connection.close();
3265  }
3266  }
3267 
3279  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
3280  CaseDbConnection connection = connections.getConnection();
3282  ResultSet rs = null;
3283  try {
3284  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
3285  statement.clearParameters();
3286  long parentId = parent.getId();
3287  statement.setLong(1, parentId);
3288  statement.setShort(2, type.getFileType());
3289  rs = connection.executeQuery(statement);
3290  return fileChildren(rs, connection, parentId);
3291  } catch (SQLException ex) {
3292  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3293  } finally {
3294  closeResultSet(rs);
3295  connection.close();
3297  }
3298  }
3299 
3309  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
3310  CaseDbConnection connection = connections.getConnection();
3312  ResultSet rs = null;
3313  try {
3314  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
3315  statement.clearParameters();
3316  long parentId = parent.getId();
3317  statement.setLong(1, parentId);
3318  rs = connection.executeQuery(statement);
3319  return fileChildren(rs, connection, parentId);
3320  } catch (SQLException ex) {
3321  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3322  } finally {
3323  closeResultSet(rs);
3324  connection.close();
3326  }
3327  }
3328 
3340  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
3341  CaseDbConnection connection = connections.getConnection();
3343  ResultSet rs = null;
3344  try {
3345  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
3346  statement.clearParameters();
3347  statement.setLong(1, parent.getId());
3348  statement.setShort(2, type.getFileType());
3349  rs = connection.executeQuery(statement);
3350  List<Long> children = new ArrayList<Long>();
3351  while (rs.next()) {
3352  children.add(rs.getLong("obj_id"));
3353  }
3354  return children;
3355  } catch (SQLException ex) {
3356  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3357  } finally {
3358  closeResultSet(rs);
3359  connection.close();
3361  }
3362  }
3363 
3373  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
3374  CaseDbConnection connection = connections.getConnection();
3376  ResultSet rs = null;
3377  try {
3378  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
3379  statement.clearParameters();
3380  statement.setLong(1, parent.getId());
3381  rs = connection.executeQuery(statement);
3382  List<Long> children = new ArrayList<Long>();
3383  while (rs.next()) {
3384  children.add(rs.getLong("obj_id"));
3385  }
3386  return children;
3387  } catch (SQLException ex) {
3388  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
3389  } finally {
3390  closeResultSet(rs);
3391  connection.close();
3393  }
3394  }
3395 
3406  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
3407  CaseDbConnection connection = connections.getConnection();
3409  ResultSet rs = null;
3410  try {
3411  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
3412  statement.clearParameters();
3413  statement.setLong(1, parent.getId());
3414  rs = connection.executeQuery(statement);
3415  List<Long> children = new ArrayList<Long>();
3416  while (rs.next()) {
3417  children.add(rs.getLong("obj_id"));
3418  }
3419  return children;
3420  } catch (SQLException ex) {
3421  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
3422  } finally {
3423  closeResultSet(rs);
3424  connection.close();
3426  }
3427  }
3428 
3438  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
3439 
3440  long parentId = parent.getId();
3441  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
3442 
3443  List<Content> lc = new ArrayList<Content>();
3444  lc.addAll(artsArray);
3445  return lc;
3446  }
3447 
3456  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
3457  CaseDbConnection connection = connections.getConnection();
3459  Statement s = null;
3460  ResultSet rs = null;
3461  try {
3462  s = connection.createStatement();
3463  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
3464  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
3465  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
3466  + "WHERE tsk_objects.par_obj_id = " + c.getId()
3467  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
3468  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3469  while (rs.next()) {
3470  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3471  }
3472  return infos;
3473  } catch (SQLException ex) {
3474  throw new TskCoreException("Error getting Children Info for Content", ex);
3475  } finally {
3476  closeResultSet(rs);
3477  closeStatement(s);
3478  connection.close();
3480  }
3481  }
3482 
3493  ObjectInfo getParentInfo(Content c) throws TskCoreException {
3494  // TODO: This should not throw an exception if Content has no parent,
3495  // return null instead.
3496  CaseDbConnection connection = connections.getConnection();
3498  Statement s = null;
3499  ResultSet rs = null;
3500  try {
3501  s = connection.createStatement();
3502  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
3503  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
3504  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
3505  + "WHERE child.obj_id = " + c.getId()); //NON-NLS
3506  if (rs.next()) {
3507  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
3508  } else {
3509  throw new TskCoreException("Given content (id: " + c.getId() + ") has no parent");
3510  }
3511  } catch (SQLException ex) {
3512  throw new TskCoreException("Error getting Parent Info for Content", ex);
3513  } finally {
3514  closeResultSet(rs);
3515  closeStatement(s);
3516  connection.close();
3518  }
3519  }
3520 
3531  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
3532  // TODO: This should not throw an exception if Content has no parent,
3533  // return null instead.
3534  CaseDbConnection connection = connections.getConnection();
3536  Statement s = null;
3537  ResultSet rs = null;
3538  try {
3539  s = connection.createStatement();
3540  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
3541  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
3542  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
3543  + "WHERE child.obj_id = " + contentId); //NON-NLS
3544  if (rs.next()) {
3545  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
3546  } else {
3547  throw new TskCoreException("Given content (id: " + contentId + ") has no parent.");
3548  }
3549  } catch (SQLException ex) {
3550  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
3551  } finally {
3552  closeResultSet(rs);
3553  closeStatement(s);
3554  connection.close();
3556  }
3557  }
3558 
3569  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
3570  // TODO: This should not throw an exception if Content has no parent,
3571  // return null instead.
3572  if (fsc.isRoot()) {
3573  throw new TskCoreException("Given FsContent (id: " + fsc.getId() + ") is a root object (can't have parent directory).");
3574  } else {
3575  ObjectInfo parentInfo = getParentInfo(fsc);
3576  Directory parent = null;
3577  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
3578  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
3579  } else {
3580  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
3581  }
3582  return parent;
3583  }
3584  }
3585 
3597  public Content getContentById(long id) throws TskCoreException {
3598  CaseDbConnection connection = connections.getConnection();
3600  Statement s = null;
3601  ResultSet rs = null;
3602  try {
3603  s = connection.createStatement();
3604  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
3605  if (!rs.next()) {
3606  return null;
3607  }
3608 
3609  Content content = null;
3610  long parentId = rs.getLong("par_obj_id"); //NON-NLS
3611  final TskData.ObjectType type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
3612  switch (type) {
3613  case IMG:
3614  content = getImageById(id);
3615  break;
3616  case VS:
3617  content = getVolumeSystemById(id, parentId);
3618  break;
3619  case VOL:
3620  content = getVolumeById(id, parentId);
3621  break;
3622  case FS:
3623  content = getFileSystemById(id, parentId);
3624  break;
3625  case ABSTRACTFILE:
3626  content = getAbstractFileById(id);
3627  break;
3628  case ARTIFACT:
3629  content = getArtifactById(id);
3630  break;
3631  default:
3632  throw new TskCoreException("Could not obtain Content object with ID: " + id);
3633  }
3634  return content;
3635  } catch (SQLException ex) {
3636  throw new TskCoreException("Error getting Content by ID.", ex);
3637  } finally {
3638  closeResultSet(rs);
3639  closeStatement(s);
3640  connection.close();
3642  }
3643  }
3644 
3652  String getFilePath(long id) {
3653  CaseDbConnection connection;
3654  try {
3655  connection = connections.getConnection();
3656  } catch (TskCoreException ex) {
3657  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3658  return null;
3659  }
3660  String filePath = null;
3662  ResultSet rs = null;
3663  try {
3664  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
3665  statement.clearParameters();
3666  statement.setLong(1, id);
3667  rs = connection.executeQuery(statement);
3668  if (rs.next()) {
3669  filePath = rs.getString("path");
3670  }
3671  } catch (SQLException ex) {
3672  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3673  } finally {
3674  closeResultSet(rs);
3675  connection.close();
3677  }
3678  return filePath;
3679  }
3680 
3688  TskData.EncodingType getEncodingType(long id) {
3689  CaseDbConnection connection;
3690  try {
3691  connection = connections.getConnection();
3692  } catch (TskCoreException ex) {
3693  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
3694  return null;
3695  }
3696  TskData.EncodingType type = TskData.EncodingType.NONE;
3698  ResultSet rs = null;
3699  try {
3700  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
3701  statement.clearParameters();
3702  statement.setLong(1, id);
3703  rs = connection.executeQuery(statement);
3704  if (rs.next()) {
3705  type = TskData.EncodingType.valueOf(rs.getInt(1));
3706  }
3707  } catch (SQLException ex) {
3708  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
3709  } finally {
3710  closeResultSet(rs);
3711  connection.close();
3713  }
3714  return type;
3715  }
3716 
3725  String getFileParentPath(long objectId, CaseDbConnection connection) {
3726  String parentPath = null;
3728  ResultSet rs = null;
3729  try {
3730  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
3731  statement.clearParameters();
3732  statement.setLong(1, objectId);
3733  rs = connection.executeQuery(statement);
3734  if (rs.next()) {
3735  parentPath = rs.getString("parent_path");
3736  }
3737  } catch (SQLException ex) {
3738  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
3739  } finally {
3740  closeResultSet(rs);
3742  }
3743  return parentPath;
3744  }
3745 
3754  String getFileName(long objectId, CaseDbConnection connection) {
3755  String fileName = null;
3757  ResultSet rs = null;
3758  try {
3759  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
3760  statement.clearParameters();
3761  statement.setLong(1, objectId);
3762  rs = connection.executeQuery(statement);
3763  if (rs.next()) {
3764  fileName = rs.getString("name");
3765  }
3766  } catch (SQLException ex) {
3767  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
3768  } finally {
3769  closeResultSet(rs);
3771  }
3772  return fileName;
3773  }
3774 
3785  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
3786  CaseDbConnection connection = connections.getConnection();
3787  DerivedFile.DerivedMethod method = null;
3789  ResultSet rs1 = null;
3790  ResultSet rs2 = null;
3791  try {
3792  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
3793  statement.clearParameters();
3794  statement.setLong(1, id);
3795  rs1 = connection.executeQuery(statement);
3796  if (rs1.next()) {
3797  int method_id = rs1.getInt("derived_id");
3798  String rederive = rs1.getString("rederive");
3799  method = new DerivedFile.DerivedMethod(method_id, rederive);
3800  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
3801  statement.clearParameters();
3802  statement.setInt(1, method_id);
3803  rs2 = connection.executeQuery(statement);
3804  if (rs2.next()) {
3805  method.setToolName(rs2.getString("tool_name"));
3806  method.setToolVersion(rs2.getString("tool_version"));
3807  method.setOther(rs2.getString("other"));
3808  }
3809  }
3810  } catch (SQLException e) {
3811  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
3812  } finally {
3813  closeResultSet(rs2);
3814  closeResultSet(rs1);
3815  connection.close();
3817  }
3818  return method;
3819  }
3820 
3832  CaseDbConnection connection = connections.getConnection();
3834  ResultSet rs = null;
3835  try {
3836  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
3837  statement.clearParameters();
3838  statement.setLong(1, id);
3839  rs = connection.executeQuery(statement);
3840  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
3841  if (files.size() > 0) {
3842  return files.get(0);
3843  } else {
3844  return null;
3845  }
3846  } catch (SQLException ex) {
3847  throw new TskCoreException("Error getting file by id, id = " + id, ex);
3848  } finally {
3849  closeResultSet(rs);
3850  connection.close();
3852  }
3853  }
3854 
3866  CaseDbConnection connection = connections.getConnection();
3868  ResultSet rs = null;
3869  try {
3870  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID);
3871  statement.clearParameters();
3872  statement.setLong(1, id);
3873  rs = connection.executeQuery(statement);
3874  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
3875  if (artifacts.size() > 0) {
3876  return artifacts.get(0);
3877  } else {
3878  return null;
3879  }
3880  } catch (SQLException ex) {
3881  throw new TskCoreException("Error getting artifacts by id, id = " + id, ex);
3882  } finally {
3883  closeResultSet(rs);
3884  connection.close();
3886  }
3887  }
3888 
3901  private long getFileSystemId(long fileId, CaseDbConnection connection) {
3903  ResultSet rs = null;
3904  long ret = -1;
3905  try {
3906  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
3907  statement.clearParameters();
3908  statement.setLong(1, fileId);
3909  rs = connection.executeQuery(statement);
3910  if (rs.next()) {
3911  ret = rs.getLong("fs_obj_id");
3912  if (ret == 0) {
3913  ret = -1;
3914  }
3915  }
3916  } catch (SQLException e) {
3917  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
3918  } finally {
3919  closeResultSet(rs);
3921  }
3922  return ret;
3923  }
3924 
3936  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
3937  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
3938  CaseDbConnection connection = connections.getConnection();
3940  Statement statement = null;
3941  ResultSet resultSet = null;
3942  try {
3943  statement = connection.createStatement();
3944  resultSet = connection.executeQuery(statement, query);
3945  resultSet.next();
3946  return (resultSet.getLong("count") > 0L);
3947  } catch (SQLException ex) {
3948  throw new TskCoreException(String.format("Error executing query %s", query), ex);
3949  } finally {
3950  closeResultSet(resultSet);
3951  closeStatement(statement);
3952  connection.close();
3954  }
3955  }
3956 
3968  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
3969  List<AbstractFile> files = new ArrayList<AbstractFile>();
3970  CaseDbConnection connection = connections.getConnection();
3972  ResultSet resultSet = null;
3973  try {
3974  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
3975  statement.clearParameters();
3976  statement.setString(1, fileName.toLowerCase());
3977  statement.setLong(2, dataSource.getId());
3978  resultSet = connection.executeQuery(statement);
3979  files.addAll(resultSetToAbstractFiles(resultSet, connection));
3980  } catch (SQLException e) {
3981  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
3982  } finally {
3983  closeResultSet(resultSet);
3984  connection.close();
3986  }
3987  return files;
3988  }
3989 
4003  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirName) throws TskCoreException {
4004  List<AbstractFile> files = new ArrayList<AbstractFile>();
4005  CaseDbConnection connection = connections.getConnection();
4007  ResultSet resultSet = null;
4008  try {
4009  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
4010  statement.clearParameters();
4011  statement.setString(1, fileName.toLowerCase());
4012  statement.setString(2, "%" + dirName.toLowerCase() + "%"); //NON-NLS
4013  statement.setLong(3, dataSource.getId());
4014  resultSet = connection.executeQuery(statement);
4015  files.addAll(resultSetToAbstractFiles(resultSet, connection));
4016  } catch (SQLException e) {
4017  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
4018  } finally {
4019  closeResultSet(resultSet);
4020  connection.close();
4022  }
4023  return files;
4024  }
4025 
4037  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
4039  CaseDbTransaction localTrans = beginTransaction();
4040  try {
4041  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
4042  localTrans.commit();
4043  return newVD;
4044  } catch (TskCoreException ex) {
4045  try {
4046  localTrans.rollback();
4047  } catch (TskCoreException ex2) {
4048  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4049  }
4050  throw ex;
4051  } finally {
4053  }
4054  }
4055 
4073  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
4074  if (transaction == null) {
4075  throw new TskCoreException("Passed null CaseDbTransaction");
4076  }
4077 
4079  ResultSet resultSet = null;
4080  try {
4081  // Get the parent path.
4082  CaseDbConnection connection = transaction.getConnection();
4083  String parentPath = getFileParentPath(parentId, connection);
4084  if (parentPath == null) {
4085  parentPath = "/"; //NON-NLS
4086  }
4087  String parentName = getFileName(parentId, connection);
4088  if (parentName != null && !parentName.isEmpty()) {
4089  parentPath = parentPath + parentName + "/"; //NON-NLS
4090  }
4091 
4092  // Insert a row for the virtual directory into the tsk_objects table.
4093  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4094  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4095  statement.clearParameters();
4096  if (parentId != 0) {
4097  statement.setLong(1, parentId);
4098  } else {
4099  statement.setNull(1, java.sql.Types.BIGINT);
4100  }
4101  statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4102  connection.executeUpdate(statement);
4103  resultSet = statement.getGeneratedKeys();
4104  resultSet.next();
4105  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4106 
4107  // Insert a row for the virtual directory into the tsk_files table.
4108  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
4109  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
4110  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
4111  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4112  statement.clearParameters();
4113  statement.setLong(1, newObjId);
4114 
4115  // If the parent is part of a file system, grab its file system ID
4116  if (0 != parentId) {
4117  long parentFs = this.getFileSystemId(parentId, connection);
4118  if (parentFs != -1) {
4119  statement.setLong(2, parentFs);
4120  } else {
4121  statement.setNull(2, java.sql.Types.BIGINT);
4122  }
4123  } else {
4124  statement.setNull(2, java.sql.Types.BIGINT);
4125  }
4126 
4127  // name
4128  statement.setString(3, directoryName);
4129 
4130  //type
4131  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
4132  statement.setShort(5, (short) 1);
4133 
4134  //flags
4136  statement.setShort(6, dirType.getValue());
4138  statement.setShort(7, metaType.getValue());
4139 
4140  //allocated
4142  statement.setShort(8, dirFlag.getValue());
4143  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4144  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4145  statement.setShort(9, metaFlags);
4146 
4147  //size
4148  statement.setLong(10, 0);
4149 
4150  // nulls for params 11-14
4151  statement.setNull(11, java.sql.Types.BIGINT);
4152  statement.setNull(12, java.sql.Types.BIGINT);
4153  statement.setNull(13, java.sql.Types.BIGINT);
4154  statement.setNull(14, java.sql.Types.BIGINT);
4155 
4156  // parent path
4157  statement.setString(15, parentPath);
4158 
4159  // data source object id (same as object id if this is a data source)
4160  long dataSourceObjectId;
4161  if (0 == parentId) {
4162  dataSourceObjectId = newObjId;
4163  } else {
4164  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
4165  }
4166  statement.setLong(16, dataSourceObjectId);
4167 
4168  //extension, since this is not really file we just set it to null
4169  statement.setString(17, null);
4170  connection.executeUpdate(statement);
4171 
4172  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
4173  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
4174  parentPath);
4175  } catch (SQLException e) {
4176  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
4177  } finally {
4178  closeResultSet(resultSet);
4180  }
4181  }
4182 
4195  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
4197  CaseDbTransaction localTrans = beginTransaction();
4198  try {
4199  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
4200  localTrans.commit();
4201  return newLD;
4202  } catch (TskCoreException ex) {
4203  try {
4204  localTrans.rollback();
4205  } catch (TskCoreException ex2) {
4206  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4207  }
4208  throw ex;
4209  } finally {
4211  }
4212  }
4213 
4231  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
4232  if (transaction == null) {
4233  throw new TskCoreException("Passed null CaseDbTransaction");
4234  }
4235 
4237  ResultSet resultSet = null;
4238  try {
4239  // Get the parent path.
4240  CaseDbConnection connection = transaction.getConnection();
4241  String parentPath = getFileParentPath(parentId, connection);
4242  if (parentPath == null) {
4243  parentPath = "/"; //NON-NLS
4244  }
4245  String parentName = getFileName(parentId, connection);
4246  if (parentName != null && !parentName.isEmpty()) {
4247  parentPath = parentPath + parentName + "/"; //NON-NLS
4248  }
4249 
4250  // Insert a row for the local directory into the tsk_objects table.
4251  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4252  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4253  statement.clearParameters();
4254  if (parentId != 0) {
4255  statement.setLong(1, parentId);
4256  } else {
4257  statement.setNull(1, java.sql.Types.BIGINT);
4258  }
4259  statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4260  connection.executeUpdate(statement);
4261  resultSet = statement.getGeneratedKeys();
4262  resultSet.next();
4263  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4264 
4265  // Insert a row for the local directory into the tsk_files table.
4266  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
4267  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id)
4268  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
4269  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4270  statement.clearParameters();
4271  statement.setLong(1, newObjId);
4272 
4273  // The parent of a local directory will never be a file system
4274  statement.setNull(2, java.sql.Types.BIGINT);
4275 
4276  // name
4277  statement.setString(3, directoryName);
4278 
4279  //type
4280  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
4281  statement.setShort(5, (short) 1);
4282 
4283  //flags
4285  statement.setShort(6, dirType.getValue());
4287  statement.setShort(7, metaType.getValue());
4288 
4289  //allocated
4291  statement.setShort(8, dirFlag.getValue());
4292  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4293  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4294  statement.setShort(9, metaFlags);
4295 
4296  //size
4297  statement.setLong(10, 0);
4298 
4299  // nulls for params 11-14
4300  statement.setNull(11, java.sql.Types.BIGINT);
4301  statement.setNull(12, java.sql.Types.BIGINT);
4302  statement.setNull(13, java.sql.Types.BIGINT);
4303  statement.setNull(14, java.sql.Types.BIGINT);
4304 
4305  // parent path
4306  statement.setString(15, parentPath);
4307 
4308  // data source object id
4309  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
4310  statement.setLong(16, dataSourceObjectId);
4311 
4312  //extension, since this is a directory we just set it to null
4313  statement.setString(17, null);
4314 
4315  connection.executeUpdate(statement);
4316 
4317  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
4318  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
4319  parentPath);
4320  } catch (SQLException e) {
4321  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
4322  } finally {
4323  closeResultSet(resultSet);
4325  }
4326  }
4327 
4347  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
4349  Statement statement = null;
4350  ResultSet resultSet = null;
4351  try {
4352  // Insert a row for the root virtual directory of the data source
4353  // into the tsk_objects table.
4354  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4355  CaseDbConnection connection = transaction.getConnection();
4356  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4357  preparedStatement.clearParameters();
4358  preparedStatement.setNull(1, java.sql.Types.BIGINT);
4359  preparedStatement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4360  connection.executeUpdate(preparedStatement);
4361  resultSet = preparedStatement.getGeneratedKeys();
4362  resultSet.next();
4363  long newObjId = resultSet.getLong(1); //last_insert_rowid()
4364  resultSet.close();
4365  resultSet = null;
4366 
4367  // Insert a row for the virtual directory of the data source into
4368  // the data_source_info table.
4369  statement = connection.createStatement();
4370  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
4371  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');");
4372 
4373  // Insert a row for the root virtual directory of the data source
4374  // into the tsk_files table. Note that its data source object id is
4375  // its own object id.
4376  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
4377  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
4378  // atime, mtime, parent_path, data_source_obj_id, extension)
4379  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
4380  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4381  preparedStatement.clearParameters();
4382  preparedStatement.setLong(1, newObjId);
4383  preparedStatement.setNull(2, java.sql.Types.BIGINT);
4384  preparedStatement.setString(3, rootDirectoryName);
4385  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
4386  preparedStatement.setShort(5, (short) 1);
4388  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
4390  preparedStatement.setShort(7, metaType.getValue());
4392  preparedStatement.setShort(8, dirFlag.getValue());
4393  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4394  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4395  preparedStatement.setShort(9, metaFlags);
4396  preparedStatement.setLong(10, 0);
4397  preparedStatement.setNull(11, java.sql.Types.BIGINT);
4398  preparedStatement.setNull(12, java.sql.Types.BIGINT);
4399  preparedStatement.setNull(13, java.sql.Types.BIGINT);
4400  preparedStatement.setNull(14, java.sql.Types.BIGINT);
4401  String parentPath = "/"; //NON-NLS
4402  preparedStatement.setString(15, parentPath);
4403  preparedStatement.setLong(16, newObjId);
4404  preparedStatement.setString(17, null); //extension, just set it to null
4405  connection.executeUpdate(preparedStatement);
4406 
4407  VirtualDirectory rootDirectory = new VirtualDirectory(this,
4408  newObjId, newObjId, rootDirectoryName,
4409  dirType, metaType, dirFlag, metaFlags, null,
4410  FileKnown.UNKNOWN, parentPath);
4411  return new LocalFilesDataSource(deviceId, rootDirectory, timeZone);
4412 
4413  } catch (SQLException ex) {
4414  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
4415  } finally {
4416  closeResultSet(resultSet);
4417  closeStatement(statement);
4419  }
4420  }
4421 
4430  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
4431  CaseDbConnection connection = connections.getConnection();
4433  Statement s = null;
4434  ResultSet rs = null;
4435  try {
4436  s = connection.createStatement();
4437  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
4438  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
4439  + " AND obj_id = data_source_obj_id"
4440  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
4441  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
4442  while (rs.next()) {
4443  virtDirRootIds.add(virtualDirectory(rs));
4444  }
4445  return virtDirRootIds;
4446  } catch (SQLException ex) {
4447  throw new TskCoreException("Error getting local files virtual folder id", ex);
4448  } finally {
4449  closeResultSet(rs);
4450  closeStatement(s);
4451  connection.close();
4453  }
4454  }
4455 
4468  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
4469  assert (null != fileRanges);
4470  if (null == fileRanges) {
4471  throw new TskCoreException("TskFileRange object is null");
4472  }
4473 
4474  assert (null != parent);
4475  if (null == parent) {
4476  throw new TskCoreException("Conent is null");
4477  }
4478 
4479  CaseDbTransaction transaction = null;
4480  Statement statement = null;
4481  ResultSet resultSet = null;
4483 
4484  try {
4485  transaction = beginTransaction();
4486  CaseDbConnection connection = transaction.getConnection();
4487 
4488  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
4489  for (TskFileRange fileRange : fileRanges) {
4490  /*
4491  * Insert a row for the Tsk file range into the tsk_objects
4492  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
4493  * ?)
4494  */
4495  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4496  prepStmt.clearParameters();
4497  prepStmt.setLong(1, parent.getId()); // par_obj_id
4498  prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
4499  connection.executeUpdate(prepStmt);
4500  resultSet = prepStmt.getGeneratedKeys();
4501  resultSet.next();
4502  long fileRangeId = resultSet.getLong(1); //last_insert_rowid()
4503  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
4504  /*
4505  * Insert a row for the Tsk file range into the tsk_files table:
4506  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
4507  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
4508  * ctime, crtime, atime, mtime, parent_path,
4509  * data_source_obj_id,extension) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
4510  * ?, ?, ?, ?, ?, ?, ?, ?,?)
4511  */
4512  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4513  prepStmt.clearParameters();
4514  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
4515  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
4516  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]
4517  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
4518  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
4519  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
4520  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
4521  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
4522  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
4523  prepStmt.setLong(10, fileRange.getByteLen()); // size
4524  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
4525  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
4526  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
4527  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
4528  prepStmt.setNull(15, java.sql.Types.VARCHAR); // parent path
4529  prepStmt.setLong(16, parent.getId()); // data_source_obj_id
4530 
4531  //extension, since this is not a FS file we just set it to null
4532  prepStmt.setString(17, null);
4533  connection.executeUpdate(prepStmt);
4534 
4535  /*
4536  * Insert a row in the tsk_layout_file table for each chunk of
4537  * the carved file. INSERT INTO tsk_file_layout (obj_id,
4538  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
4539  */
4540  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
4541  prepStmt.clearParameters();
4542  prepStmt.setLong(1, fileRangeId); // obj_id
4543  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
4544  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
4545  prepStmt.setLong(4, fileRange.getSequence()); // sequence
4546  connection.executeUpdate(prepStmt);
4547 
4548  /*
4549  * Create a layout file representation of the carved file.
4550  */
4551  fileRangeLayoutFiles.add(new LayoutFile(this,
4552  fileRangeId,
4553  parent.getId(),
4554  Long.toString(fileRange.getSequence()),
4559  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
4560  fileRange.getByteLen(),
4561  null,
4563  parent.getUniquePath(),
4564  null));
4565  }
4566 
4567  transaction.commit();
4568  return fileRangeLayoutFiles;
4569 
4570  } catch (SQLException ex) {
4571  if (null != transaction) {
4572  try {
4573  transaction.rollback();
4574  } catch (TskCoreException ex2) {
4575  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4576  }
4577  }
4578  throw new TskCoreException("Failed to add layout files to case database", ex);
4579 
4580  } catch (TskCoreException ex) {
4581  if (null != transaction) {
4582  try {
4583  transaction.rollback();
4584  } catch (TskCoreException ex2) {
4585  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4586  }
4587  }
4588  throw ex;
4589 
4590  } finally {
4591  closeResultSet(resultSet);
4592  closeStatement(statement);
4594  }
4595  }
4596 
4608  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
4609  assert (null != carvingResult);
4610  if (null == carvingResult) {
4611  throw new TskCoreException("Carving is null");
4612  }
4613  assert (null != carvingResult.getParent());
4614  if (null == carvingResult.getParent()) {
4615  throw new TskCoreException("Carving result has null parent");
4616  }
4617  assert (null != carvingResult.getCarvedFiles());
4618  if (null == carvingResult.getCarvedFiles()) {
4619  throw new TskCoreException("Carving result has null carved files");
4620  }
4621  CaseDbTransaction transaction = null;
4622  Statement statement = null;
4623  ResultSet resultSet = null;
4625  long newCacheKey = 0; // Used to roll back cache if transaction is rolled back.
4626  try {
4627  transaction = beginTransaction();
4628  CaseDbConnection connection = transaction.getConnection();
4629 
4630  /*
4631  * Carved files are "re-parented" as children of the $CarvedFiles
4632  * virtual directory of the root file system, volume, or image
4633  * ancestor of the carved files parent, but if no such ancestor is
4634  * found, then the parent specified in the carving result is used.
4635  */
4636  Content root = carvingResult.getParent();
4637  while (null != root) {
4638  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
4639  break;
4640  }
4641  root = root.getParent();
4642  }
4643  if (null == root) {
4644  root = carvingResult.getParent();
4645  }
4646 
4647  /*
4648  * Get or create the $CarvedFiles virtual directory for the root
4649  * ancestor.
4650  */
4651  VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
4652  if (null == carvedFilesDir) {
4653  List<Content> rootChildren;
4654  if (root instanceof FileSystem) {
4655  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
4656  } else {
4657  rootChildren = root.getChildren();
4658  }
4659  for (Content child : rootChildren) {
4660  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
4661  carvedFilesDir = (VirtualDirectory) child;
4662  break;
4663  }
4664  }
4665  if (null == carvedFilesDir) {
4666  long parId = root.getId();
4667  // $CarvedFiles should be a child of the root directory, not the file system
4668  if (root instanceof FileSystem) {
4669  Content rootDir = ((FileSystem) root).getRootDirectory();
4670  parId = rootDir.getId();
4671  }
4672  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED, transaction);
4673  }
4674  newCacheKey = root.getId();
4675  rootIdsToCarvedFileDirs.put(newCacheKey, carvedFilesDir);
4676  }
4677 
4678  /*
4679  * Add the carved files to the database as children of the
4680  * $CarvedFile directory of the root ancestor.
4681  */
4682  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
4683  List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>();
4684  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
4685  /*
4686  * Insert a row for the carved file into the tsk_objects table:
4687  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4688  */
4689  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4690  prepStmt.clearParameters();
4691  prepStmt.setLong(1, carvedFilesDir.getId()); // par_obj_id
4692  prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
4693  connection.executeUpdate(prepStmt);
4694  resultSet = prepStmt.getGeneratedKeys();
4695  resultSet.next();
4696  long carvedFileId = resultSet.getLong(1); //last_insert_rowid()
4697 
4698  /*
4699  * Insert a row for the carved file into the tsk_files table:
4700  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
4701  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
4702  * ctime, crtime, atime, mtime, parent_path,
4703  * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
4704  * ?, ?, ?, ?, ?, ?, ?, ?,?)
4705  */
4706  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4707  prepStmt.clearParameters();
4708  prepStmt.setLong(1, carvedFileId); // obj_id
4709  if (root instanceof FileSystem) {
4710  prepStmt.setLong(2, root.getId()); // fs_obj_id
4711  } else {
4712  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
4713  }
4714  prepStmt.setString(3, carvedFile.getName()); // name
4715  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
4716  prepStmt.setShort(5, (short) 1); // has_path
4717  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
4718  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
4719  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
4720  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
4721  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
4722  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
4723  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
4724  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
4725  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
4726  prepStmt.setString(15, parentPath); // parent path
4727  prepStmt.setLong(16, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
4728 
4729  prepStmt.setString(17, extractExtension(carvedFile.getName())); //extension
4730  connection.executeUpdate(prepStmt);
4731 
4732  /*
4733  * Insert a row in the tsk_layout_file table for each chunk of
4734  * the carved file. INSERT INTO tsk_file_layout (obj_id,
4735  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
4736  */
4737  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
4738  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
4739  prepStmt.clearParameters();
4740  prepStmt.setLong(1, carvedFileId); // obj_id
4741  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
4742  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
4743  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
4744  connection.executeUpdate(prepStmt);
4745  }
4746 
4747  /*
4748  * Create a layout file representation of the carved file.
4749  */
4750  carvedFiles.add(new LayoutFile(this,
4751  carvedFileId,
4752  carvedFilesDir.getDataSourceObjectId(),
4753  carvedFile.getName(),
4758  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
4759  carvedFile.getSizeInBytes(),
4760  null,
4762  parentPath,
4763  null));
4764  }
4765 
4766  transaction.commit();
4767  return carvedFiles;
4768 
4769  } catch (SQLException ex) {
4770  if (null != transaction) {
4771  try {
4772  transaction.rollback();
4773  } catch (TskCoreException ex2) {
4774  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4775  }
4776  if (0 != newCacheKey) {
4777  rootIdsToCarvedFileDirs.remove(newCacheKey);
4778  }
4779  }
4780  throw new TskCoreException("Failed to add carved files to case database", ex);
4781 
4782  } catch (TskCoreException ex) {
4783  if (null != transaction) {
4784  try {
4785  transaction.rollback();
4786  } catch (TskCoreException ex2) {
4787  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4788  }
4789  if (0 != newCacheKey) {
4790  rootIdsToCarvedFileDirs.remove(newCacheKey);
4791  }
4792  }
4793  throw ex;
4794 
4795  } finally {
4796  closeResultSet(resultSet);
4797  closeStatement(statement);
4799  }
4800  }
4801 
4832  public DerivedFile addDerivedFile(String fileName, String localPath,
4833  long size, long ctime, long crtime, long atime, long mtime,
4834  boolean isFile, Content parentObj,
4835  String rederiveDetails, String toolName, String toolVersion,
4836  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
4837  CaseDbConnection connection = connections.getConnection();
4839  ResultSet rs = null;
4840  try {
4841  connection.beginTransaction();
4842 
4843  final long parentId = parentObj.getId();
4844  String parentPath = "";
4845  if (parentObj instanceof BlackboardArtifact) {
4846  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
4847  } else if (parentObj instanceof AbstractFile) {
4848  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
4849  }
4850 
4851  // Insert a row for the derived file into the tsk_objects table.
4852  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
4853  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
4854  statement.clearParameters();
4855  statement.setLong(1, parentId);
4856  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
4857  connection.executeUpdate(statement);
4858  rs = statement.getGeneratedKeys();
4859  rs.next();
4860  long newObjId = rs.getLong(1); //last_insert_rowid()
4861  rs.close();
4862  rs = null;
4863 
4864  // Insert a row for the virtual directory into the tsk_files table.
4865  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
4866  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id, extension)
4867  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
4868  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
4869  statement.clearParameters();
4870  statement.setLong(1, newObjId);
4871 
4872  // If the parentFile is part of a file system, use its file system object ID.
4873  long fsObjId = this.getFileSystemId(parentId, connection);
4874  if (fsObjId != -1) {
4875  statement.setLong(2, fsObjId);
4876  } else {
4877  statement.setNull(2, java.sql.Types.BIGINT);
4878  }
4879  statement.setString(3, fileName);
4880 
4881  //type, has_path
4882  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
4883  statement.setShort(5, (short) 1);
4884 
4885  //flags
4887  statement.setShort(6, dirType.getValue());
4889  statement.setShort(7, metaType.getValue());
4890 
4891  //note: using alloc under assumption that derived files derive from alloc files
4893  statement.setShort(8, dirFlag.getValue());
4894  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
4895  | TSK_FS_META_FLAG_ENUM.USED.getValue());
4896  statement.setShort(9, metaFlags);
4897 
4898  //size
4899  statement.setLong(10, size);
4900 
4901  //mactimes
4902  //long ctime, long crtime, long atime, long mtime,
4903  statement.setLong(11, ctime);
4904  statement.setLong(12, crtime);
4905  statement.setLong(13, atime);
4906  statement.setLong(14, mtime);
4907 
4908  //parent path
4909  statement.setString(15, parentPath);
4910 
4911  // root data source object id
4912  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
4913  statement.setLong(16, dataSourceObjId);
4914  final String extension = extractExtension(fileName);
4915  //extension
4916  statement.setString(17, extension);
4917 
4918  connection.executeUpdate(statement);
4919 
4920  //add localPath
4921  addFilePath(connection, newObjId, localPath, encodingType);
4922 
4923  connection.commitTransaction();
4924 
4925  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
4926  return new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
4927  size, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
4928  } catch (SQLException ex) {
4929  connection.rollbackTransaction();
4930  throw new TskCoreException("Failed to add derived file to case database", ex);
4931  } finally {
4932  closeResultSet(rs);
4933  connection.close();
4935  }
4936  }
4937 
4957  public LocalFile addLocalFile(String fileName, String localPath,
4958  long size, long ctime, long crtime, long atime, long mtime,
4959  boolean isFile, TskData.EncodingType encodingType,
4960  AbstractFile parent) throws TskCoreException {
4962  CaseDbTransaction localTrans = beginTransaction();
4963  try {
4964  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
4965  localTrans.commit();
4966  return created;
4967  } catch (TskCoreException ex) {
4968  try {
4969  localTrans.rollback();
4970  } catch (TskCoreException ex2) {
4971  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
4972  }
4973  throw ex;
4974  } finally {
4976  }
4977  }
4978 
5003  public LocalFile addLocalFile(String fileName, String localPath,
5004  long size, long ctime, long crtime, long atime, long mtime,
5005  boolean isFile, TskData.EncodingType encodingType,
5006  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
5007 
5008  CaseDbConnection connection = transaction.getConnection();
5010  Statement queryStatement = null;
5011  ResultSet resultSet = null;
5012  try {
5013 
5014  // Insert a row for the local/logical file into the tsk_objects table.
5015  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5016  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5017  statement.clearParameters();
5018  statement.setLong(1, parent.getId());
5019  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
5020  connection.executeUpdate(statement);
5021  resultSet = statement.getGeneratedKeys();
5022  if (!resultSet.next()) {
5023  throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_objects table", fileName, localPath, parent.getId()));
5024  }
5025  long objectId = resultSet.getLong(1); //last_insert_rowid()
5026  resultSet.close();
5027  resultSet = null;
5028 
5029  // Insert a row for the local/logical file into the tsk_files table.
5030  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5031  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
5032  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5033  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5034  statement.clearParameters();
5035  statement.setLong(1, objectId);
5036  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
5037  statement.setString(3, fileName);
5038  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
5039  statement.setShort(5, (short) 1);
5041  statement.setShort(6, dirType.getValue());
5043  statement.setShort(7, metaType.getValue());
5045  statement.setShort(8, dirFlag.getValue());
5046  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
5047  statement.setShort(9, metaFlags);
5048  statement.setLong(10, size);
5049  statement.setLong(11, ctime);
5050  statement.setLong(12, crtime);
5051  statement.setLong(13, atime);
5052  statement.setLong(14, mtime);
5053  String parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
5054  statement.setString(15, parentPath);
5055  long dataSourceObjId = getDataSourceObjectId(connection, parent.getId());
5056  statement.setLong(16, dataSourceObjId);
5057  final String extension = extractExtension(fileName);
5058  statement.setString(17, extension);
5059 
5060  connection.executeUpdate(statement);
5061  addFilePath(connection, objectId, localPath, encodingType);
5062  return new LocalFile(this,
5063  objectId,
5064  fileName,
5066  dirType,
5067  metaType,
5068  dirFlag,
5069  metaFlags,
5070  size,
5071  ctime, crtime, atime, mtime,
5072  null, null, null,
5073  parent.getId(), parentPath,
5074  dataSourceObjId,
5075  localPath,
5076  encodingType, extension);
5077 
5078  } catch (SQLException ex) {
5079  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);
5080  } finally {
5081  closeResultSet(resultSet);
5082  closeStatement(queryStatement);
5084  }
5085  }
5086 
5099  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
5101  Statement statement = null;
5102  ResultSet resultSet = null;
5103  try {
5104  statement = connection.createStatement();
5105  long dataSourceObjId;
5106  long ancestorId = objectId;
5107  do {
5108  dataSourceObjId = ancestorId;
5109  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
5110  resultSet = statement.executeQuery(query);
5111  if (resultSet.next()) {
5112  ancestorId = resultSet.getLong("par_obj_id");
5113  } else {
5114  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
5115  }
5116  resultSet.close();
5117  resultSet = null;
5118  } while (0 != ancestorId); // Not NULL
5119  return dataSourceObjId;
5120  } catch (SQLException ex) {
5121  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
5122  } finally {
5123  closeResultSet(resultSet);
5124  closeStatement(statement);
5126  }
5127  }
5128 
5140  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
5141  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
5142  statement.clearParameters();
5143  statement.setLong(1, objId);
5144  statement.setString(2, path);
5145  statement.setInt(3, type.getType());
5146  connection.executeUpdate(statement);
5147  }
5148 
5164  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
5165  return findFiles(dataSource, fileName, parentFile.getName());
5166  }
5167 
5179  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
5180  CaseDbConnection connection = connections.getConnection();
5182  Statement s = null;
5183  ResultSet rs = null;
5184  try {
5185  s = connection.createStatement();
5186  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5187  rs.next();
5188  return rs.getLong("count");
5189  } catch (SQLException e) {
5190  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
5191  } finally {
5192  closeResultSet(rs);
5193  closeStatement(s);
5194  connection.close();
5196  }
5197  }
5198 
5216  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
5217  CaseDbConnection connection = connections.getConnection();
5219  Statement s = null;
5220  ResultSet rs = null;
5221  try {
5222  s = connection.createStatement();
5223  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5224  return resultSetToAbstractFiles(rs, connection);
5225  } catch (SQLException e) {
5226  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
5227  } finally {
5228  closeResultSet(rs);
5229  closeStatement(s);
5230  connection.close();
5232  }
5233  }
5234 
5247  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
5248  CaseDbConnection connection = connections.getConnection();
5250  Statement s = null;
5251  ResultSet rs = null;
5252  try {
5253  s = connection.createStatement();
5254  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
5255  List<Long> ret = new ArrayList<Long>();
5256  while (rs.next()) {
5257  ret.add(rs.getLong("obj_id"));
5258  }
5259  return ret;
5260  } catch (SQLException e) {
5261  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
5262  } finally {
5263  closeResultSet(rs);
5264  closeStatement(s);
5265  connection.close();
5267  }
5268  }
5269 
5281  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
5282 
5283  // get the non-unique path (strip of image and volume path segments, if
5284  // the exist.
5285  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
5286 
5287  // split the file name from the parent path
5288  int lastSlash = path.lastIndexOf('/'); //NON-NLS
5289 
5290  // if the last slash is at the end, strip it off
5291  if (lastSlash == path.length()) {
5292  path = path.substring(0, lastSlash - 1);
5293  lastSlash = path.lastIndexOf('/'); //NON-NLS
5294  }
5295 
5296  String parentPath = path.substring(0, lastSlash);
5297  String fileName = path.substring(lastSlash);
5298 
5299  return findFiles(dataSource, fileName, parentPath);
5300  }
5301 
5312  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
5313  CaseDbConnection connection = connections.getConnection();
5315  Statement s = null;
5316  ResultSet rs = null;
5317  try {
5318  s = connection.createStatement();
5319  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
5320  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
5321  while (rs.next()) {
5322  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
5323  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
5324  ranges.add(range);
5325  }
5326  return ranges;
5327  } catch (SQLException ex) {
5328  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
5329  } finally {
5330  closeResultSet(rs);
5331  closeStatement(s);
5332  connection.close();
5334  }
5335  }
5336 
5347  public Image getImageById(long id) throws TskCoreException {
5348  CaseDbConnection connection = connections.getConnection();
5350  Statement s1 = null;
5351  ResultSet rs1 = null;
5352  Statement s2 = null;
5353  ResultSet rs2 = null;
5354  try {
5355  s1 = connection.createStatement();
5356  rs1 = connection.executeQuery(s1, "SELECT * FROM tsk_image_info WHERE obj_id = " + id); //NON-NLS
5357  if (rs1.next()) {
5358  s2 = connection.createStatement();
5359  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + rs1.getLong("obj_id")); //NON-NLS
5360  List<String> imagePaths = new ArrayList<String>();
5361  while (rs2.next()) {
5362  imagePaths.add(rs2.getString("name"));
5363  }
5364  long obj_id = rs1.getLong("obj_id"); //NON-NLS
5365  long type = rs1.getLong("type"); //NON-NLS
5366  long ssize = rs1.getLong("ssize"); //NON-NLS
5367  String tzone = rs1.getString("tzone"); //NON-NLS
5368  String md5 = rs1.getString("md5"); //NON-NLS
5369  String name = rs1.getString("display_name");
5370  if (name == null) {
5371  if (imagePaths.size() > 0) {
5372  String path = imagePaths.get(0);
5373  name = (new java.io.File(path)).getName();
5374  } else {
5375  name = "";
5376  }
5377  }
5378  long size = rs1.getLong("size"); //NON-NLS
5379  return new Image(this, obj_id, type, ssize, name,
5380  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, size);
5381  } else {
5382  throw new TskCoreException("No image found for id: " + id);
5383  }
5384  } catch (SQLException ex) {
5385  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
5386  } finally {
5387  closeResultSet(rs2);
5388  closeStatement(s2);
5389  closeResultSet(rs1);
5390  closeStatement(s1);
5391  connection.close();
5393  }
5394  }
5395 
5407  VolumeSystem getVolumeSystemById(long id, Image parent) throws TskCoreException {
5408  CaseDbConnection connection = connections.getConnection();
5410  Statement s = null;
5411  ResultSet rs = null;
5412  try {
5413  s = connection.createStatement();
5414  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
5415  + "where obj_id = " + id); //NON-NLS
5416  if (rs.next()) {
5417  long type = rs.getLong("vs_type"); //NON-NLS
5418  long imgOffset = rs.getLong("img_offset"); //NON-NLS
5419  long blockSize = rs.getLong("block_size"); //NON-NLS
5420  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
5421  vs.setParent(parent);
5422  return vs;
5423  } else {
5424  throw new TskCoreException("No volume system found for id:" + id);
5425  }
5426  } catch (SQLException ex) {
5427  throw new TskCoreException("Error getting Volume System by ID.", ex);
5428  } finally {
5429  closeResultSet(rs);
5430  closeStatement(s);
5431  connection.close();
5433  }
5434  }
5435 
5444  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
5445  VolumeSystem vs = getVolumeSystemById(id, null);
5446  vs.setParentId(parentId);
5447  return vs;
5448  }
5449 
5461  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
5462  return getFileSystemByIdHelper(id, parent);
5463  }
5464 
5473  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
5474  Volume vol = null;
5475  FileSystem fs = getFileSystemById(id, vol);
5476  fs.setParentId(parentId);
5477  return fs;
5478  }
5479 
5491  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
5492  return getFileSystemByIdHelper(id, parent);
5493  }
5494 
5507  // see if we already have it
5508  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
5509  // but it should be the same...
5510  synchronized (fileSystemIdMap) {
5511  if (fileSystemIdMap.containsKey(id)) {
5512  return fileSystemIdMap.get(id);
5513  }
5514  }
5515  CaseDbConnection connection = connections.getConnection();
5517  Statement s = null;
5518  ResultSet rs = null;
5519  try {
5520  s = connection.createStatement();
5521  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
5522  + "where obj_id = " + id); //NON-NLS
5523  if (rs.next()) {
5524  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
5525  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
5526  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
5527  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
5528  fs.setParent(parent);
5529  // save it for the next call
5530  synchronized (fileSystemIdMap) {
5531  fileSystemIdMap.put(id, fs);
5532  }
5533  return fs;
5534  } else {
5535  throw new TskCoreException("No file system found for id:" + id);
5536  }
5537  } catch (SQLException ex) {
5538  throw new TskCoreException("Error getting File System by ID", ex);
5539  } finally {
5540  closeResultSet(rs);
5541  closeStatement(s);
5542  connection.close();
5544  }
5545  }
5546 
5558  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
5559  CaseDbConnection connection = connections.getConnection();
5561  Statement s = null;
5562  ResultSet rs = null;
5563  try {
5564  s = connection.createStatement();
5565  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
5566  + "where obj_id = " + id); //NON-NLS
5567  if (rs.next()) {
5575  String description;
5576  try {
5577  description = rs.getString("desc");
5578  } catch (Exception ex) {
5579  description = rs.getString("descr");
5580  }
5581  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
5582  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
5583  description);
5584  vol.setParent(parent);
5585  return vol;
5586  } else {
5587  throw new TskCoreException("No volume found for id:" + id);
5588  }
5589  } catch (SQLException ex) {
5590  throw new TskCoreException("Error getting Volume by ID", ex);
5591  } finally {
5592  closeResultSet(rs);
5593  closeStatement(s);
5594  connection.close();
5596  }
5597  }
5598 
5607  Volume getVolumeById(long id, long parentId) throws TskCoreException {
5608  Volume vol = getVolumeById(id, null);
5609  vol.setParentId(parentId);
5610  return vol;
5611  }
5612 
5624  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
5625  CaseDbConnection connection = connections.getConnection();
5627  Statement s = null;
5628  ResultSet rs = null;
5629  try {
5630  s = connection.createStatement();
5631  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
5632  + "WHERE obj_id = " + id);
5633  Directory temp = null; //NON-NLS
5634  if (rs.next()) {
5635  final short type = rs.getShort("type"); //NON-NLS
5636  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
5637  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
5638  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
5639  temp = directory(rs, parentFs);
5640  }
5641  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
5642  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
5643  }
5644  } else {
5645  throw new TskCoreException("No Directory found for id:" + id);
5646  }
5647  return temp;
5648  } catch (SQLException ex) {
5649  throw new TskCoreException("Error getting Directory by ID", ex);
5650  } finally {
5651  closeResultSet(rs);
5652  closeStatement(s);
5653  connection.close();
5655  }
5656  }
5657 
5665  public Collection<FileSystem> getFileSystems(Image image) {
5666  List<FileSystem> fileSystems = new ArrayList<FileSystem>();
5667  CaseDbConnection connection;
5668  try {
5669  connection = connections.getConnection();
5670  } catch (TskCoreException ex) {
5671  logger.log(Level.SEVERE, "Error getting file systems for image " + image.getId(), ex); //NON-NLS
5672  return fileSystems;
5673  }
5675  Statement s = null;
5676  ResultSet rs = null;
5677  try {
5678  s = connection.createStatement();
5679 
5680  // Get all the file systems.
5681  List<FileSystem> allFileSystems = new ArrayList<FileSystem>();
5682  try {
5683  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info"); //NON-NLS
5684  while (rs.next()) {
5685  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
5686  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
5687  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
5688  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
5689  fs.setParent(null);
5690  allFileSystems.add(fs);
5691  }
5692  } catch (SQLException ex) {
5693  logger.log(Level.SEVERE, "There was a problem while trying to obtain all file systems", ex); //NON-NLS
5694  } finally {
5695  closeResultSet(rs);
5696  rs = null;
5697  }
5698 
5699  // For each file system, find the image to which it belongs by iteratively
5700  // climbing the tsk_ojbects hierarchy only taking those file systems
5701  // that belong to this image.
5702  for (FileSystem fs : allFileSystems) {
5703  Long imageID = null;
5704  Long currentObjID = fs.getId();
5705  while (imageID == null) {
5706  try {
5707  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS
5708  rs.next();
5709  currentObjID = rs.getLong("par_obj_id"); //NON-NLS
5710  if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS
5711  imageID = rs.getLong("obj_id"); //NON-NLS
5712  }
5713  } catch (SQLException ex) {
5714  logger.log(Level.SEVERE, "There was a problem while trying to obtain this image's file systems", ex); //NON-NLS
5715  } finally {
5716  closeResultSet(rs);
5717  rs = null;
5718  }
5719  }
5720 
5721  // see if imageID is this image'statement ID
5722  if (imageID == image.getId()) {
5723  fileSystems.add(fs);
5724  }
5725  }
5726  } catch (SQLException ex) {
5727  logger.log(Level.SEVERE, "Error getting case database connection", ex); //NON-NLS
5728  } finally {
5729  closeResultSet(rs);
5730  closeStatement(s);
5731  connection.close();
5733  }
5734  return fileSystems;
5735  }
5736 
5747  List<Content> getImageChildren(Image img) throws TskCoreException {
5748  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
5749  List<Content> children = new ArrayList<Content>();
5750  for (ObjectInfo info : childInfos) {
5751  if (info.type == ObjectType.VS) {
5752  children.add(getVolumeSystemById(info.id, img));
5753  } else if (info.type == ObjectType.FS) {
5754  children.add(getFileSystemById(info.id, img));
5755  } else if (info.type == ObjectType.ABSTRACTFILE) {
5756  AbstractFile f = getAbstractFileById(info.id);
5757  if (f != null) {
5758  children.add(f);
5759  }
5760  } else if (info.type == ObjectType.ARTIFACT) {
5761  BlackboardArtifact art = getArtifactById(info.id);
5762  if (art != null) {
5763  children.add(art);
5764  }
5765  } else {
5766  throw new TskCoreException("Image has child of invalid type: " + info.type);
5767  }
5768  }
5769  return children;
5770  }
5771 
5782  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
5783  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
5784  List<Long> children = new ArrayList<Long>();
5785  for (ObjectInfo info : childInfos) {
5786  if (info.type == ObjectType.VS
5787  || info.type == ObjectType.FS
5788  || info.type == ObjectType.ABSTRACTFILE
5789  || info.type == ObjectType.ARTIFACT) {
5790  children.add(info.id);
5791  } else {
5792  throw new TskCoreException("Image has child of invalid type: " + info.type);
5793  }
5794  }
5795  return children;
5796  }
5797 
5808  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
5809  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
5810  List<Content> children = new ArrayList<Content>();
5811  for (ObjectInfo info : childInfos) {
5812  if (null != info.type) {
5813  switch (info.type) {
5814  case VOL:
5815  children.add(getVolumeById(info.id, vs));
5816  break;
5817  case ABSTRACTFILE:
5818  AbstractFile f = getAbstractFileById(info.id);
5819  if (f != null) {
5820  children.add(f);
5821  }
5822  break;
5823  case ARTIFACT:
5824  BlackboardArtifact art = getArtifactById(info.id);
5825  if (art != null) {
5826  children.add(art);
5827  }
5828  break;
5829  default:
5830  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
5831  }
5832  }
5833  }
5834  return children;
5835  }
5836 
5847  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
5848  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
5849  List<Long> children = new ArrayList<Long>();
5850  for (ObjectInfo info : childInfos) {
5851  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
5852  children.add(info.id);
5853  } else {
5854  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
5855  }
5856  }
5857  return children;
5858  }
5859 
5870  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
5871  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
5872  List<Content> children = new ArrayList<Content>();
5873  for (ObjectInfo info : childInfos) {
5874  if (null != info.type) {
5875  switch (info.type) {
5876  case FS:
5877  children.add(getFileSystemById(info.id, vol));
5878  break;
5879  case ABSTRACTFILE:
5880  AbstractFile f = getAbstractFileById(info.id);
5881  if (f != null) {
5882  children.add(f);
5883  }
5884  break;
5885  case ARTIFACT:
5886  BlackboardArtifact art = getArtifactById(info.id);
5887  if (art != null) {
5888  children.add(art);
5889  }
5890  break;
5891  default:
5892  throw new TskCoreException("Volume has child of invalid type: " + info.type);
5893  }
5894  }
5895  }
5896  return children;
5897  }
5898 
5909  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
5910  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
5911  final List<Long> children = new ArrayList<Long>();
5912  for (ObjectInfo info : childInfos) {
5913  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
5914  children.add(info.id);
5915  } else {
5916  throw new TskCoreException("Volume has child of invalid type: " + info.type);
5917  }
5918  }
5919  return children;
5920  }
5921 
5935  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
5936  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone);
5937  return getImageById(imageId);
5938  }
5939 
5949  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
5950  CaseDbConnection connection = connections.getConnection();
5952  Statement s1 = null;
5953  Statement s2 = null;
5954  ResultSet rs1 = null;
5955  ResultSet rs2 = null;
5956  try {
5957  s1 = connection.createStatement();
5958  rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
5959  s2 = connection.createStatement();
5960  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
5961  while (rs1.next()) {
5962  long obj_id = rs1.getLong("obj_id"); //NON-NLS
5963  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
5964  List<String> paths = new ArrayList<String>();
5965  while (rs2.next()) {
5966  paths.add(rs2.getString("name"));
5967  }
5968  rs2.close();
5969  rs2 = null;
5970  imgPaths.put(obj_id, paths);
5971  }
5972  return imgPaths;
5973  } catch (SQLException ex) {
5974  throw new TskCoreException("Error getting image paths.", ex);
5975  } finally {
5976  closeResultSet(rs2);
5977  closeStatement(s2);
5978  closeResultSet(rs1);
5979  closeStatement(s1);
5980  connection.close();
5982  }
5983  }
5984 
5991  public List<Image> getImages() throws TskCoreException {
5992  CaseDbConnection connection = connections.getConnection();
5994  Statement s = null;
5995  ResultSet rs = null;
5996  try {
5997  s = connection.createStatement();
5998  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
5999  Collection<Long> imageIDs = new ArrayList<Long>();
6000  while (rs.next()) {
6001  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
6002  }
6003  List<Image> images = new ArrayList<Image>();
6004  for (long id : imageIDs) {
6005  images.add(getImageById(id));
6006  }
6007  return images;
6008  } catch (SQLException ex) {
6009  throw new TskCoreException("Error retrieving images.", ex);
6010  } finally {
6011  closeResultSet(rs);
6012  closeStatement(s);
6013  connection.close();
6015  }
6016  }
6017 
6028  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
6029  CaseDbConnection connection = connections.getConnection();
6031  Statement statement = null;
6032  try {
6033  connection.beginTransaction();
6034  statement = connection.createStatement();
6035  connection.executeUpdate(statement, "DELETE FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
6036  for (int i = 0; i < paths.size(); i++) {
6037  connection.executeUpdate(statement, "INSERT INTO tsk_image_names VALUES (" + obj_id + ", '" + paths.get(i) + "', " + i + ")"); //NON-NLS
6038  }
6039  connection.commitTransaction();
6040  } catch (SQLException ex) {
6041  connection.rollbackTransaction();
6042  throw new TskCoreException("Error updating image paths.", ex);
6043  } finally {
6044  closeStatement(statement);
6045  connection.close();
6047  }
6048  }
6049 
6075  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
6076  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
6077  try {
6078  while (rs.next()) {
6079  final short type = rs.getShort("type"); //NON-NLS
6080  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
6081  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
6082  FsContent result;
6083  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
6084  result = directory(rs, null);
6085  } else {
6086  result = file(rs, null);
6087  }
6088  results.add(result);
6089  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
6090  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
6091  final VirtualDirectory virtDir = virtualDirectory(rs);
6092  results.add(virtDir);
6093  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
6094  final LocalDirectory localDir = localDirectory(rs);
6095  results.add(localDir);
6096  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
6097  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
6098  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()) {
6100  String parentPath = rs.getString("parent_path"); //NON-NLS
6101  if (parentPath == null) {
6102  parentPath = "/"; //NON-NLS
6103  }
6104  LayoutFile lf = new LayoutFile(this,
6105  rs.getLong("obj_id"), //NON-NLS
6106  rs.getLong("data_source_obj_id"),
6107  rs.getString("name"), //NON-NLS
6108  atype,
6109  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6110  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6111  rs.getLong("size"), //NON-NLS
6112  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS
6113  results.add(lf);
6114  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
6115  final DerivedFile df;
6116  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
6117  results.add(df);
6118  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
6119  final LocalFile lf;
6120  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
6121  results.add(lf);
6122  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
6123  final SlackFile sf = slackFile(rs, null);
6124  results.add(sf);
6125  }
6126  } //end for each resultSet
6127  } catch (SQLException e) {
6128  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
6129  }
6130 
6131  return results;
6132  }
6133 
6134  // This following methods generate AbstractFile objects from a ResultSet
6146  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
6147  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
6148  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6149  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6150  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6151  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6152  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6153  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6154  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6155  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6156  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6157  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6158  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
6159  f.setFileSystem(fs);
6160  return f;
6161  }
6162 
6174  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
6175  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6176  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6177  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6178  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6179  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6180  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6181  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6182  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6183  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6184  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6185  rs.getString("parent_path")); //NON-NLS
6186  dir.setFileSystem(fs);
6187  return dir;
6188  }
6189 
6199  VirtualDirectory virtualDirectory(ResultSet rs) throws SQLException {
6200  String parentPath = rs.getString("parent_path"); //NON-NLS
6201  if (parentPath == null) {
6202  parentPath = "";
6203  }
6204  final VirtualDirectory vd = new VirtualDirectory(this, rs.getLong("obj_id"), //NON-NLS
6205  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
6206  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6207  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6208  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6209  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
6210  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
6211  return vd;
6212  }
6213 
6223  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
6224  String parentPath = rs.getString("parent_path"); //NON-NLS
6225  if (parentPath == null) {
6226  parentPath = "";
6227  }
6228  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
6229  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
6230  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6231  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6232  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6233  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
6234  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
6235  return ld;
6236  }
6237 
6251  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6252  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
6253  long objId = rs.getLong("obj_id"); //NON-NLS
6254  String localPath = null;
6255  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
6256  if (hasLocalPath) {
6257  ResultSet rsFilePath = null;
6258  try {
6259  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
6260  statement.clearParameters();
6261  statement.setLong(1, objId);
6262  rsFilePath = connection.executeQuery(statement);
6263  if (rsFilePath.next()) {
6264  localPath = rsFilePath.getString("path");
6265  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
6266  }
6267  } catch (SQLException ex) {
6268  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
6269  } finally {
6270  closeResultSet(rsFilePath);
6271  }
6272  }
6273  String parentPath = rs.getString("parent_path"); //NON-NLS
6274  if (parentPath == null) {
6275  parentPath = "";
6276  }
6277  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
6278  rs.getString("name"), //NON-NLS
6279  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6280  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6281  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6282  rs.getLong("size"), //NON-NLS
6283  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6284  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6285  parentPath, localPath, parentId, rs.getString("mime_type"),
6286  encodingType, rs.getString("extension"));
6287  return df;
6288  }
6289 
6303  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6304  long objId = rs.getLong("obj_id"); //NON-NLS
6305  String localPath = null;
6306  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
6307  if (rs.getBoolean("has_path")) {
6308  ResultSet rsFilePath = null;
6309  try {
6310  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
6311  statement.clearParameters();
6312  statement.setLong(1, objId);
6313  rsFilePath = connection.executeQuery(statement);
6314  if (rsFilePath.next()) {
6315  localPath = rsFilePath.getString("path");
6316  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
6317  }
6318  } catch (SQLException ex) {
6319  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
6320  } finally {
6321  closeResultSet(rsFilePath);
6322  }
6323  }
6324  String parentPath = rs.getString("parent_path"); //NON-NLS
6325  if (null == parentPath) {
6326  parentPath = "";
6327  }
6328  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
6329  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
6330  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6331  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6332  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
6333  rs.getLong("size"), //NON-NLS
6334  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6335  rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6336  parentId, parentPath, rs.getLong("data_source_obj_id"),
6337  localPath, encodingType, rs.getString("extension"));
6338  return file;
6339  }
6340 
6352  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
6353  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
6354  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
6355  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
6356  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
6357  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
6358  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
6359  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
6360  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
6361  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
6362  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
6363  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
6364  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
6365  f.setFileSystem(fs);
6366  return f;
6367  }
6368 
6380  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
6381  List<Content> children = new ArrayList<Content>();
6382 
6383  while (rs.next()) {
6384  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
6385 
6386  if (null != type) {
6387  switch (type) {
6388  case FS:
6389  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
6390  FsContent result;
6391  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
6392  result = directory(rs, null);
6393  } else {
6394  result = file(rs, null);
6395  }
6396  children.add(result);
6397  } else {
6398  VirtualDirectory virtDir = virtualDirectory(rs);
6399  children.add(virtDir);
6400  }
6401  break;
6402  case VIRTUAL_DIR:
6403  VirtualDirectory virtDir = virtualDirectory(rs);
6404  children.add(virtDir);
6405  break;
6406  case LOCAL_DIR:
6407  LocalDirectory localDir = localDirectory(rs);
6408  children.add(localDir);
6409  break;
6410  case UNALLOC_BLOCKS:
6411  case UNUSED_BLOCKS:
6412  case CARVED: {
6413  String parentPath = rs.getString("parent_path");
6414  if (parentPath == null) {
6415  parentPath = "";
6416  }
6417  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
6418  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
6419  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
6420  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
6421  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
6422  rs.getLong("size"), rs.getString("md5"),
6423  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"));
6424  children.add(lf);
6425  break;
6426  }
6427  case DERIVED:
6428  final DerivedFile df = derivedFile(rs, connection, parentId);
6429  children.add(df);
6430  break;
6431  case LOCAL: {
6432  final LocalFile lf = localFile(rs, connection, parentId);
6433  children.add(lf);
6434  break;
6435  }
6436  case SLACK: {
6437  final SlackFile sf = slackFile(rs, null);
6438  children.add(sf);
6439  break;
6440  }
6441  default:
6442  break;
6443  }
6444  }
6445  }
6446  return children;
6447  }
6448 
6462  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException {
6463  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
6464  try {
6465  while (rs.next()) {
6466  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
6467  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(),
6468  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
6469  } //end for each resultSet
6470  } catch (SQLException e) {
6471  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
6472  }
6473 
6474  return artifacts;
6475  }
6476 
6498  public CaseDbQuery executeQuery(String query) throws TskCoreException {
6499  return new CaseDbQuery(query);
6500  }
6501 
6502  @Override
6503  protected void finalize() throws Throwable {
6504  try {
6505  close();
6506  } finally {
6507  super.finalize();
6508  }
6509  }
6510 
6514  public synchronized void close() {
6516 
6517  try {
6518  connections.close();
6519  } catch (TskCoreException ex) {
6520  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
6521  }
6522 
6523  fileSystemIdMap.clear();
6524 
6525  try {
6526  if (this.caseHandle != null) {
6527  this.caseHandle.free();
6528  this.caseHandle = null;
6529  }
6530  } catch (TskCoreException ex) {
6531  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
6532  } finally {
6534  }
6535  }
6536 
6549  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
6550  long id = file.getId();
6551  FileKnown currentKnown = file.getKnown();
6552  if (currentKnown.compareTo(fileKnown) > 0) {
6553  return false;
6554  }
6555  CaseDbConnection connection = connections.getConnection();
6557  Statement statement = null;
6558  try {
6559  statement = connection.createStatement();
6560  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
6561  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
6562  + "WHERE obj_id=" + id); //NON-NLS
6563  file.setKnown(fileKnown);
6564  } catch (SQLException ex) {
6565  throw new TskCoreException("Error setting Known status.", ex);
6566  } finally {
6567  closeStatement(statement);
6568  connection.close();
6570  }
6571  return true;
6572  }
6573 
6583  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
6584  CaseDbConnection connection = connections.getConnection();
6585  Statement statement = null;
6586  ResultSet rs = null;
6588  try {
6589  statement = connection.createStatement();
6590  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
6591  file.setMIMEType(mimeType);
6592  } catch (SQLException ex) {
6593  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
6594  } finally {
6595  closeResultSet(rs);
6596  closeStatement(statement);
6597  connection.close();
6599  }
6600  }
6601 
6611  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
6612  if (md5Hash == null) {
6613  return;
6614  }
6615  long id = file.getId();
6616  CaseDbConnection connection = connections.getConnection();
6618  try {
6619  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
6620  statement.clearParameters();
6621  statement.setString(1, md5Hash.toLowerCase());
6622  statement.setLong(2, id);
6623  connection.executeUpdate(statement);
6624  file.setMd5Hash(md5Hash.toLowerCase());
6625  } catch (SQLException ex) {
6626  throw new TskCoreException("Error setting MD5 hash", ex);
6627  } finally {
6628  connection.close();
6630  }
6631  }
6632 
6644  if (newStatus == null) {
6645  return;
6646  }
6647  CaseDbConnection connection = connections.getConnection();
6649  Statement statement = null;
6650  try {
6651  statement = connection.createStatement();
6652  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
6653  + " SET review_status_id=" + newStatus.getID()
6654  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
6655  } catch (SQLException ex) {
6656  throw new TskCoreException("Error setting review status", ex);
6657  } finally {
6658  closeStatement(statement);
6659  connection.close();
6661  }
6662  }
6663 
6675  CaseDbConnection connection = connections.getConnection();
6677  Statement s = null;
6678  ResultSet rs = null;
6679  try {
6680  s = connection.createStatement();
6681  Short contentShort = contentType.getValue();
6682  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
6683  int count = 0;
6684  if (rs.next()) {
6685  count = rs.getInt("count");
6686  }
6687  return count;
6688  } catch (SQLException ex) {
6689  throw new TskCoreException("Error getting number of objects.", ex);
6690  } finally {
6691  closeResultSet(rs);
6692  closeStatement(s);
6693  connection.close();
6695  }
6696  }
6697 
6706  public static String escapeSingleQuotes(String text) {
6707  String escapedText = null;
6708  if (text != null) {
6709  escapedText = text.replaceAll("'", "''");
6710  }
6711  return escapedText;
6712  }
6713 
6721  public List<AbstractFile> findFilesByMd5(String md5Hash) {
6722  if (md5Hash == null) {
6723  return Collections.<AbstractFile>emptyList();
6724  }
6725  CaseDbConnection connection;
6726  try {
6727  connection = connections.getConnection();
6728  } catch (TskCoreException ex) {
6729  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
6730  return Collections.<AbstractFile>emptyList();
6731  }
6733  Statement s = null;
6734  ResultSet rs = null;
6735  try {
6736  s = connection.createStatement();
6737  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
6738  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
6739  + "AND size > 0"); //NON-NLS
6740  return resultSetToAbstractFiles(rs, connection);
6741  } catch (SQLException ex) {
6742  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
6743  return Collections.<AbstractFile>emptyList();
6744  } finally {
6745  closeResultSet(rs);
6746  closeStatement(s);
6747  connection.close();
6749  }
6750  }
6751 
6758  public boolean allFilesMd5Hashed() {
6759  CaseDbConnection connection;
6760  try {
6761  connection = connections.getConnection();
6762  } catch (TskCoreException ex) {
6763  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
6764  return false;
6765  }
6766  boolean allFilesAreHashed = false;
6768  Statement s = null;
6769  ResultSet rs = null;
6770  try {
6771  s = connection.createStatement();
6772  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
6773  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
6774  + "AND md5 IS NULL " //NON-NLS
6775  + "AND size > '0'"); //NON-NLS
6776  if (rs.next() && rs.getInt("count") == 0) {
6777  allFilesAreHashed = true;
6778  }
6779  } catch (SQLException ex) {
6780  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
6781  } finally {
6782  closeResultSet(rs);
6783  closeStatement(s);
6784  connection.close();
6786  }
6787  return allFilesAreHashed;
6788  }
6789 
6795  public int countFilesMd5Hashed() {
6796  CaseDbConnection connection;
6797  try {
6798  connection = connections.getConnection();
6799  } catch (TskCoreException ex) {
6800  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
6801  return 0;
6802  }
6803  int count = 0;
6805  Statement s = null;
6806  ResultSet rs = null;
6807  try {
6808  s = connection.createStatement();
6809  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
6810  + "WHERE md5 IS NOT NULL " //NON-NLS
6811  + "AND size > '0'"); //NON-NLS
6812  if (rs.next()) {
6813  count = rs.getInt("count");
6814  }
6815  } catch (SQLException ex) {
6816  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
6817  } finally {
6818  closeResultSet(rs);
6819  closeStatement(s);
6820  connection.close();
6822  }
6823  return count;
6824 
6825  }
6826 
6835  public List<TagName> getAllTagNames() throws TskCoreException {
6836  CaseDbConnection connection = connections.getConnection();
6838  ResultSet resultSet = null;
6839  try {
6840  // SELECT * FROM tag_names
6841  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
6842  resultSet = connection.executeQuery(statement);
6843  ArrayList<TagName> tagNames = new ArrayList<TagName>();
6844  while (resultSet.next()) {
6845  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")))); //NON-NLS
6846  }
6847  return tagNames;
6848  } catch (SQLException ex) {
6849  throw new TskCoreException("Error selecting rows from tag_names table", ex);
6850  } finally {
6851  closeResultSet(resultSet);
6852  connection.close();
6854  }
6855  }
6856 
6867  public List<TagName> getTagNamesInUse() throws TskCoreException {
6868  CaseDbConnection connection = connections.getConnection();
6870  ResultSet resultSet = null;
6871  try {
6872  // 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)
6873  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
6874  resultSet = connection.executeQuery(statement);
6875  ArrayList<TagName> tagNames = new ArrayList<TagName>();
6876  while (resultSet.next()) {
6877  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")))); //NON-NLS
6878  }
6879  return tagNames;
6880  } catch (SQLException ex) {
6881  throw new TskCoreException("Error selecting rows from tag_names table", ex);
6882  } finally {
6883  closeResultSet(resultSet);
6884  connection.close();
6886  }
6887  }
6888 
6900  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
6901  CaseDbConnection connection = connections.getConnection();
6903  ResultSet resultSet = null;
6904  try {
6905  // INSERT INTO tag_names (display_name, description, color) VALUES (?, ?, ?)
6906  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_TAG_NAME, Statement.RETURN_GENERATED_KEYS);
6907  statement.clearParameters();
6908  statement.setString(1, displayName);
6909  statement.setString(2, description);
6910  statement.setString(3, color.getName());
6911  connection.executeUpdate(statement);
6912  resultSet = statement.getGeneratedKeys();
6913  resultSet.next();
6914  return new TagName(resultSet.getLong(1), //last_insert_rowid()
6915  displayName, description, color);
6916  } catch (SQLException ex) {
6917  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
6918  } finally {
6919  closeResultSet(resultSet);
6920  connection.close();
6922  }
6923  }
6924 
6938  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
6939  CaseDbConnection connection = connections.getConnection();
6941  ResultSet resultSet = null;
6942  try {
6943  // INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
6944  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_CONTENT_TAG, Statement.RETURN_GENERATED_KEYS);
6945  statement.clearParameters();
6946  statement.setLong(1, content.getId());
6947  statement.setLong(2, tagName.getId());
6948  statement.setString(3, comment);
6949  statement.setLong(4, beginByteOffset);
6950  statement.setLong(5, endByteOffset);
6951  connection.executeUpdate(statement);
6952  resultSet = statement.getGeneratedKeys();
6953  resultSet.next();
6954  return new ContentTag(resultSet.getLong(1), //last_insert_rowid()
6955  content, tagName, comment, beginByteOffset, endByteOffset);
6956  } catch (SQLException ex) {
6957  throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex);
6958  } finally {
6959  closeResultSet(resultSet);
6960  connection.close();
6962  }
6963  }
6964 
6965  /*
6966  * Deletes a row from the content_tags table in the case database. @param
6967  * tag A ContentTag data transfer object (DTO) for the row to delete.
6968  * @throws TskCoreException
6969  */
6971  CaseDbConnection connection = connections.getConnection();
6973  try {
6974  // DELETE FROM content_tags WHERE tag_id = ?
6975  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
6976  statement.clearParameters();
6977  statement.setLong(1, tag.getId());
6978  connection.executeUpdate(statement);
6979  } catch (SQLException ex) {
6980  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
6981  } finally {
6982  connection.close();
6984  }
6985  }
6986 
6995  public List<ContentTag> getAllContentTags() throws TskCoreException {
6996  CaseDbConnection connection = connections.getConnection();
6998  ResultSet resultSet = null;
6999  try {
7000  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
7001  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
7002  resultSet = connection.executeQuery(statement);
7003  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7004  while (resultSet.next()) {
7005  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7006  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
7007  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
7008  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
7009  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"))); //NON-NLS
7010  }
7011  return tags;
7012  } catch (SQLException ex) {
7013  throw new TskCoreException("Error selecting rows from content_tags table", ex);
7014  } finally {
7015  closeResultSet(resultSet);
7016  connection.close();
7018  }
7019  }
7020 
7032  if (tagName.getId() == Tag.ID_NOT_SET) {
7033  throw new TskCoreException("TagName object is invalid, id not set");
7034  }
7035  CaseDbConnection connection = connections.getConnection();
7037  ResultSet resultSet = null;
7038  try {
7039  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
7040  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
7041  statement.clearParameters();
7042  statement.setLong(1, tagName.getId());
7043  resultSet = connection.executeQuery(statement);
7044  if (resultSet.next()) {
7045  return resultSet.getLong("count");
7046  } else {
7047  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
7048  }
7049  } catch (SQLException ex) {
7050  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
7051  } finally {
7052  closeResultSet(resultSet);
7053  connection.close();
7055  }
7056  }
7057 
7066  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
7067 
7068  CaseDbConnection connection = connections.getConnection();
7070  ResultSet resultSet = null;
7071  ContentTag tag = null;
7072  try {
7073  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE tag_id = ?
7074  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
7075  statement.clearParameters();
7076  statement.setLong(1, contentTagID);
7077  resultSet = connection.executeQuery(statement);
7078 
7079  while (resultSet.next()) {
7080  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7081  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")));
7082  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
7083  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"));
7084  }
7085  resultSet.close();
7086 
7087  } catch (SQLException ex) {
7088  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
7089  } finally {
7090  closeResultSet(resultSet);
7091  connection.close();
7093  }
7094  return tag;
7095  }
7096 
7108  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
7109  if (tagName.getId() == Tag.ID_NOT_SET) {
7110  throw new TskCoreException("TagName object is invalid, id not set");
7111  }
7112  CaseDbConnection connection = connections.getConnection();
7114  ResultSet resultSet = null;
7115  try {
7116  // SELECT * FROM content_tags WHERE tag_name_id = ?
7117  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
7118  statement.clearParameters();
7119  statement.setLong(1, tagName.getId());
7120  resultSet = connection.executeQuery(statement);
7121  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7122  while (resultSet.next()) {
7123  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
7124  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
7125  tags.add(tag);
7126  }
7127  resultSet.close();
7128  return tags;
7129  } catch (SQLException ex) {
7130  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
7131  } finally {
7132  closeResultSet(resultSet);
7133  connection.close();
7135  }
7136  }
7137 
7149  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
7150  CaseDbConnection connection = connections.getConnection();
7152  ResultSet resultSet = null;
7153  try {
7154  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE content_tags.obj_id = ?
7155  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
7156  statement.clearParameters();
7157  statement.setLong(1, content.getId());
7158  resultSet = connection.executeQuery(statement);
7159  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
7160  while (resultSet.next()) {
7161  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7162  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
7163  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
7164  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
7165  tags.add(tag);
7166  }
7167  return tags;
7168  } catch (SQLException ex) {
7169  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
7170  } finally {
7171  closeResultSet(resultSet);
7172  connection.close();
7174  }
7175  }
7176 
7191  CaseDbConnection connection = connections.getConnection();
7193  ResultSet resultSet = null;
7194  try {
7195  // INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
7196  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT_TAG, Statement.RETURN_GENERATED_KEYS);
7197  statement.clearParameters();
7198  statement.setLong(1, artifact.getArtifactID());
7199  statement.setLong(2, tagName.getId());
7200  statement.setString(3, comment);
7201  connection.executeUpdate(statement);
7202  resultSet = statement.getGeneratedKeys();
7203  resultSet.next();
7204  return new BlackboardArtifactTag(resultSet.getLong(1), //last_insert_rowid()
7205  artifact, getContentById(artifact.getObjectID()), tagName, comment);
7206  } catch (SQLException ex) {
7207  throw new TskCoreException("Error adding row to blackboard_artifact_tags table (obj_id = " + artifact.getArtifactID() + ", tag_name_id = " + tagName.getId() + ")", ex);
7208  } finally {
7209  closeResultSet(resultSet);
7210  connection.close();
7212  }
7213  }
7214 
7215  /*
7216  * Deletes a row from the blackboard_artifact_tags table in the case
7217  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
7218  * representing the row to delete. @throws TskCoreException
7219  */
7221  CaseDbConnection connection = connections.getConnection();
7223  try {
7224  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
7225  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
7226  statement.clearParameters();
7227  statement.setLong(1, tag.getId());
7228  connection.executeUpdate(statement);
7229  } catch (SQLException ex) {
7230  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
7231  } finally {
7232  connection.close();
7234  }
7235  }
7236 
7246  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
7247  CaseDbConnection connection = connections.getConnection();
7249  ResultSet resultSet = null;
7250  try {
7251  // SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
7252  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
7253  resultSet = connection.executeQuery(statement);
7254  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7255  while (resultSet.next()) {
7256  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7257  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
7258  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7259  Content content = getContentById(artifact.getObjectID());
7260  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7261  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7262  tags.add(tag);
7263  }
7264  return tags;
7265  } catch (SQLException ex) {
7266  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
7267  } finally {
7268  closeResultSet(resultSet);
7269  connection.close();
7271  }
7272  }
7273 
7285  if (tagName.getId() == Tag.ID_NOT_SET) {
7286  throw new TskCoreException("TagName object is invalid, id not set");
7287  }
7288  CaseDbConnection connection = connections.getConnection();
7290  ResultSet resultSet = null;
7291  try {
7292  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
7293  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
7294  statement.clearParameters();
7295  statement.setLong(1, tagName.getId());
7296  resultSet = connection.executeQuery(statement);
7297  if (resultSet.next()) {
7298  return resultSet.getLong("count");
7299  } else {
7300  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
7301  }
7302  } catch (SQLException ex) {
7303  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
7304  } finally {
7305  closeResultSet(resultSet);
7306  connection.close();
7308  }
7309  }
7310 
7322  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
7323  if (tagName.getId() == Tag.ID_NOT_SET) {
7324  throw new TskCoreException("TagName object is invalid, id not set");
7325  }
7326  CaseDbConnection connection = connections.getConnection();
7328  ResultSet resultSet = null;
7329  try {
7330  // SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?
7331  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
7332  statement.clearParameters();
7333  statement.setLong(1, tagName.getId());
7334  resultSet = connection.executeQuery(statement);
7335  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7336  while (resultSet.next()) {
7337  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7338  Content content = getContentById(artifact.getObjectID());
7339  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7340  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7341  tags.add(tag);
7342  }
7343  return tags;
7344  } catch (SQLException ex) {
7345  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
7346  } finally {
7347  closeResultSet(resultSet);
7348  connection.close();
7350  }
7351  }
7352 
7365 
7366  CaseDbConnection connection = connections.getConnection();
7368  ResultSet resultSet = null;
7369  BlackboardArtifactTag tag = null;
7370  try {
7371  // 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 = ?
7372  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
7373  statement.clearParameters();
7374  statement.setLong(1, artifactTagID);
7375  resultSet = connection.executeQuery(statement);
7376 
7377  while (resultSet.next()) {
7378  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7379  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")));
7380  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
7381  Content content = getContentById(artifact.getObjectID());
7382  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7383  artifact, content, tagName, resultSet.getString("comment"));
7384  }
7385  resultSet.close();
7386 
7387  } catch (SQLException ex) {
7388  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
7389  } finally {
7390  closeResultSet(resultSet);
7391  connection.close();
7393  }
7394  return tag;
7395  }
7396 
7409  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
7410  CaseDbConnection connection = connections.getConnection();
7412  ResultSet resultSet = null;
7413  try {
7414  // 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 = ?
7415  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
7416  statement.clearParameters();
7417  statement.setLong(1, artifact.getArtifactID());
7418  resultSet = connection.executeQuery(statement);
7419  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
7420  while (resultSet.next()) {
7421  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
7422  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
7423  Content content = getContentById(artifact.getObjectID());
7424  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
7425  artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
7426  tags.add(tag);
7427  }
7428  return tags;
7429  } catch (SQLException ex) {
7430  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
7431  } finally {
7432  closeResultSet(resultSet);
7433  connection.close();
7435  }
7436  }
7437 
7446  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
7447  CaseDbConnection connection = connections.getConnection();
7449  try {
7450  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
7451  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
7452  statement.clearParameters();
7453  statement.setString(1, newPath);
7454  statement.setLong(2, objectId);
7455  connection.executeUpdate(statement);
7456  } catch (SQLException ex) {
7457  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
7458  } finally {
7459  connection.close();
7461  }
7462  }
7463 
7477  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
7478  // Make sure the local path of the report is in the database directory
7479  // or one of its subdirectories.
7480  String relativePath = ""; //NON-NLS
7481  try {
7482  /*
7483  * Note: The following call to .relativize() may be dangerous in
7484  * case-sensitive operating systems and should be looked at. For
7485  * now, we are simply relativizing the paths as all lower case, then
7486  * using the length of the result to pull out the appropriate number
7487  * of characters from the localPath String.
7488  */
7489  String casePathLower = getDbDirPath().toLowerCase();
7490  String localPathLower = localPath.toLowerCase();
7491  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
7492  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
7493  } catch (IllegalArgumentException ex) {
7494  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
7495  throw new TskCoreException(errorMessage, ex);
7496  }
7497 
7498  // Figure out the create time of the report.
7499  long createTime = 0;
7500  try {
7501  java.io.File tempFile = new java.io.File(localPath);
7502  // Convert to UNIX epoch (seconds, not milliseconds).
7503  createTime = tempFile.lastModified() / 1000;
7504  } catch (Exception ex) {
7505  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
7506  }
7507 
7508  // Write the report data to the database.
7509  CaseDbConnection connection = connections.getConnection();
7511  ResultSet resultSet = null;
7512  try {
7513  // INSERT INTO reports (path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?)
7514  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT, Statement.RETURN_GENERATED_KEYS);
7515  statement.clearParameters();
7516  statement.setString(1, relativePath);
7517  statement.setLong(2, createTime);
7518  statement.setString(3, sourceModuleName);
7519  statement.setString(4, reportName);
7520  connection.executeUpdate(statement);
7521  resultSet = statement.getGeneratedKeys();
7522  resultSet.next();
7523  return new Report(resultSet.getLong(1), //last_insert_rowid()
7524  localPath, createTime, sourceModuleName, reportName);
7525  } catch (SQLException ex) {
7526  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
7527  } finally {
7528  closeResultSet(resultSet);
7529  connection.close();
7531  }
7532  }
7533 
7542  public List<Report> getAllReports() throws TskCoreException {
7543  CaseDbConnection connection = connections.getConnection();
7545  ResultSet resultSet = null;
7546  try {
7547  // SELECT * FROM reports
7548  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
7549  resultSet = connection.executeQuery(statement);
7550  ArrayList<Report> reports = new ArrayList<Report>();
7551  while (resultSet.next()) {
7552  reports.add(new Report(resultSet.getLong("report_id"), //NON-NLS
7553  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
7554  resultSet.getLong("crtime"), //NON-NLS
7555  resultSet.getString("src_module_name"), //NON-NLS
7556  resultSet.getString("report_name"))); //NON-NLS
7557  }
7558  return reports;
7559  } catch (SQLException ex) {
7560  throw new TskCoreException("Error querying reports table", ex);
7561  } finally {
7562  closeResultSet(resultSet);
7563  connection.close();
7565  }
7566  }
7567 
7575  public void deleteReport(Report report) throws TskCoreException {
7576  CaseDbConnection connection = connections.getConnection();
7578  try {
7579  // DELETE FROM reports WHERE reports.report_id = ?
7580  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
7581  statement.setLong(1, report.getId());
7582  connection.executeUpdate(statement);
7583  } catch (SQLException ex) {
7584  throw new TskCoreException("Error querying reports table", ex);
7585  } finally {
7587  }
7588  }
7589 
7590  private static void closeResultSet(ResultSet resultSet) {
7591  if (resultSet != null) {
7592  try {
7593  resultSet.close();
7594  } catch (SQLException ex) {
7595  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
7596  }
7597  }
7598  }
7599 
7600  private static void closeStatement(Statement statement) {
7601  if (statement != null) {
7602  try {
7603  statement.close();
7604  } catch (SQLException ex) {
7605  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
7606 
7607  }
7608  }
7609  }
7610 
7619  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
7620  CaseDbConnection connection = connections.getConnection();
7622  try {
7623  Statement statement = connection.createStatement();
7624  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
7625  } catch (SQLException ex) {
7626  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
7627  } finally {
7628  connection.close();
7630  }
7631  }
7632 
7633  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
7634  CaseDbConnection connection = connections.getConnection();
7636  try {
7637  Statement statement = connection.createStatement();
7638  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
7639  } catch (SQLException ex) {
7640  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
7641  } finally {
7642  connection.close();
7644  }
7645  }
7646 
7663  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
7664  CaseDbConnection connection = connections.getConnection();
7666  ResultSet resultSet = null;
7667  Statement statement = null;
7668  try {
7669  connection.beginTransaction();
7670  statement = connection.createStatement();
7671  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
7672  insertStatement.setLong(1, dataSource.getId());
7673  insertStatement.setString(2, hostName);
7674  insertStatement.setLong(3, jobStart.getTime());
7675  insertStatement.setLong(4, jobEnd.getTime());
7676  insertStatement.setInt(5, status.ordinal());
7677  insertStatement.setString(6, settingsDir);
7678  connection.executeUpdate(insertStatement);
7679  resultSet = insertStatement.getGeneratedKeys();
7680  resultSet.next();
7681  long id = resultSet.getLong(1); //last_insert_rowid()
7682  for (int i = 0; i < ingestModules.size(); i++) {
7683  IngestModuleInfo ingestModule = ingestModules.get(i);
7684  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
7685  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
7686  }
7687  resultSet.close();
7688  resultSet = null;
7689  connection.commitTransaction();
7690  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
7691  } catch (SQLException ex) {
7692  connection.rollbackTransaction();
7693  throw new TskCoreException("Error adding the ingest job.", ex);
7694  } finally {
7695  closeResultSet(resultSet);
7696  connection.close();
7698  }
7699  }
7700 
7714  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
7715  CaseDbConnection connection = connections.getConnection();
7716  ResultSet resultSet = null;
7717  Statement statement = null;
7718  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
7719  try {
7720  statement = connection.createStatement();
7721  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
7722  if (!resultSet.next()) {
7723  resultSet.close();
7724  resultSet = null;
7725  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
7726  insertStatement.setString(1, displayName);
7727  insertStatement.setString(2, uniqueName);
7728  insertStatement.setInt(3, type.ordinal());
7729  insertStatement.setString(4, version);
7730  connection.executeUpdate(insertStatement);
7731  resultSet = statement.getGeneratedKeys();
7732  resultSet.next();
7733  long id = resultSet.getLong(1); //last_insert_rowid()
7734  resultSet.close();
7735  resultSet = null;
7736  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
7737  } else {
7738  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
7739  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
7740  }
7741  } catch (SQLException ex) {
7742  try {
7743  closeStatement(statement);
7744  statement = connection.createStatement();
7745  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
7746  if (resultSet.next()) {
7747  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
7748  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
7749  } else {
7750  throw new TskCoreException("Couldn't add new module to database.", ex);
7751  }
7752  } catch (SQLException ex1) {
7753  throw new TskCoreException("Couldn't add new module to database.", ex1);
7754  }
7755  } finally {
7756  closeResultSet(resultSet);
7757  closeStatement(statement);
7758  connection.close();
7759  }
7760  }
7761 
7769  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
7770  CaseDbConnection connection = connections.getConnection();
7771  ResultSet resultSet = null;
7772  Statement statement = null;
7773  List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>();
7774  try {
7775  statement = connection.createStatement();
7776  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
7777  while (resultSet.next()) {
7778  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
7779  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
7780  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
7781  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
7782  }
7783  return ingestJobs;
7784  } catch (SQLException ex) {
7785  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
7786  } finally {
7787  closeResultSet(resultSet);
7788  closeStatement(statement);
7789  connection.close();
7790  }
7791  }
7792 
7803  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
7804  ResultSet resultSet = null;
7805  Statement statement = null;
7806  List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>();
7807  try {
7808  statement = connection.createStatement();
7809  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
7810  + "ingest_job_modules.pipeline_position AS pipeline_position, "
7811  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
7812  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
7813  + "FROM ingest_job_modules, ingest_modules "
7814  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
7815  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
7816  + "ORDER BY (ingest_job_modules.pipeline_position);");
7817  while (resultSet.next()) {
7818  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
7819  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
7820  }
7821  return ingestModules;
7822  } finally {
7823  closeResultSet(resultSet);
7824  closeStatement(statement);
7825  }
7826  }
7827 
7831  static class ObjectInfo {
7832 
7833  private long id;
7834  private TskData.ObjectType type;
7835 
7836  ObjectInfo(long id, ObjectType type) {
7837  this.id = id;
7838  this.type = type;
7839  }
7840 
7841  long getId() {
7842  return id;
7843  }
7844 
7845  TskData.ObjectType getType() {
7846  return type;
7847  }
7848  }
7849 
7850  private interface DbCommand {
7851 
7852  void execute() throws SQLException;
7853  }
7854 
7855  private enum PREPARED_STATEMENT {
7856 
7857  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
7858  + "WHERE artifact_type_id = ?"), //NON-NLS
7859  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
7860  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
7861  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
7862  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
7863  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
7864  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
7865  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
7866  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
7867  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
7868  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
7869  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
7870  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
7871  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
7872  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
7873  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
7874  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
7875  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
7876  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
7877  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
7878  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
7879  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
7880  + "AND tsk_files.type = ? )"), //NON-NLS
7881  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
7882  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
7883  INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, artifact_type_id, review_status_id) " //NON-NLS
7884  + "VALUES (?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
7885  POSTGRESQL_INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, artifact_type_id, review_status_id) " //NON-NLS
7886  + "VALUES (DEFAULT, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
7887  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
7888  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
7889  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
7890  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
7891  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
7892  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
7893  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
7894  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
7895  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
7896  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
7897  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
7898  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
7899  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
7900  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
7901  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
7902  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
7903  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
7904  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
7905  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
7906  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
7907  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
7908  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
7909  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
7910  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)"), //NON-NLS
7911  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
7912  + "VALUES (?, ?, ?, ?)"), //NON-NLS
7913  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
7914  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
7915  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
7916  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
7917  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
7918  + "WHERE tag_name_id IN " //NON-NLS
7919  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
7920  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color) VALUES (?, ?, ?)"), //NON-NLS
7921  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
7922  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
7923  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
7924  SELECT_CONTENT_TAGS("SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id"), //NON-NLS
7925  SELECT_CONTENT_TAGS_BY_TAG_NAME("SELECT * FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
7926  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
7927  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
7928  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) VALUES (?, ?, ?)"), //NON-NLS
7929  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
7930  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
7931  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
7932  SELECT_ARTIFACT_TAGS_BY_TAG_NAME("SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
7933  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
7934  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
7935  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
7936  INSERT_REPORT("INSERT INTO reports (path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?)"), //NON-NLS
7937  DELETE_REPORT("DELETE FROM reports WHERE reports.report_id = ?"), //NON-NLS
7938  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
7939  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
7940  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
7941  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
7942  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
7943  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
7944  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
7945  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
7946  + "WHERE (tsk_objects.par_obj_id = ?)"); //NON-NLS;
7947  private final String sql;
7948 
7949  private PREPARED_STATEMENT(String sql) {
7950  this.sql = sql;
7951  }
7952 
7953  String getSQL() {
7954  return sql;
7955  }
7956  }
7957 
7963  abstract private class ConnectionPool {
7964 
7965  private PooledDataSource pooledDataSource;
7966 
7967  public ConnectionPool() {
7968  pooledDataSource = null;
7969  }
7970 
7971  CaseDbConnection getConnection() throws TskCoreException {
7972  if (pooledDataSource == null) {
7973  throw new TskCoreException("Error getting case database connection - case is closed");
7974  }
7975  try {
7976  return getPooledConnection();
7977  } catch (SQLException exp) {
7978  throw new TskCoreException(exp.getMessage());
7979  }
7980  }
7981 
7982  void close() throws TskCoreException {
7983  if (pooledDataSource != null) {
7984  try {
7985  pooledDataSource.close();
7986  } catch (SQLException exp) {
7987  throw new TskCoreException(exp.getMessage());
7988  } finally {
7989  pooledDataSource = null;
7990  }
7991  }
7992  }
7993 
7994  abstract CaseDbConnection getPooledConnection() throws SQLException;
7995 
7996  public PooledDataSource getPooledDataSource() {
7997  return pooledDataSource;
7998  }
7999 
8000  public void setPooledDataSource(PooledDataSource pooledDataSource) {
8001  this.pooledDataSource = pooledDataSource;
8002  }
8003  }
8004 
8009  private final class SQLiteConnections extends ConnectionPool {
8010 
8011  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
8012 
8013  SQLiteConnections(String dbPath) throws SQLException {
8014  configurationOverrides.put("acquireIncrement", "2");
8015  configurationOverrides.put("initialPoolSize", "5");
8016  configurationOverrides.put("maxPoolSize", "20");
8017  configurationOverrides.put("minPoolSize", "5");
8018  configurationOverrides.put("maxStatements", "100");
8019  configurationOverrides.put("maxStatementsPerConnection", "20");
8020 
8021  SQLiteConfig config = new SQLiteConfig();
8022  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
8023  config.setReadUncommited(true);
8024  config.enforceForeignKeys(true); // Enforce foreign key constraints.
8025  SQLiteDataSource unpooled = new SQLiteDataSource(config);
8026  unpooled.setUrl("jdbc:sqlite:" + dbPath);
8027  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
8028  }
8029 
8030  @Override
8031  public CaseDbConnection getPooledConnection() throws SQLException {
8032  return new SQLiteConnection(getPooledDataSource().getConnection());
8033  }
8034  }
8035 
8040  private final class PostgreSQLConnections extends ConnectionPool {
8041 
8042  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
8043  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
8044  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
8045  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
8046  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
8047  comboPooledDataSource.setUser(userName);
8048  comboPooledDataSource.setPassword(password);
8049  comboPooledDataSource.setAcquireIncrement(2);
8050  comboPooledDataSource.setInitialPoolSize(5);
8051  comboPooledDataSource.setMaxPoolSize(20);
8052  comboPooledDataSource.setMinPoolSize(5);
8053  comboPooledDataSource.setMaxStatements(100);
8054  comboPooledDataSource.setMaxStatementsPerConnection(20);
8055  setPooledDataSource(comboPooledDataSource);
8056  }
8057 
8058  @Override
8059  public CaseDbConnection getPooledConnection() throws SQLException {
8060  return new PostgreSQLConnection(getPooledDataSource().getConnection());
8061  }
8062  }
8063 
8067  private abstract class CaseDbConnection {
8068 
8069  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
8070 
8071  final class CreateStatement implements DbCommand {
8072 
8073  private final Connection connection;
8074  private Statement statement = null;
8075 
8076  CreateStatement(Connection connection) {
8077  this.connection = connection;
8078  }
8079 
8080  Statement getStatement() {
8081  return statement;
8082  }
8083 
8084  @Override
8085  public void execute() throws SQLException {
8086  statement = connection.createStatement();
8087  }
8088  }
8089 
8090  final class SetAutoCommit implements DbCommand {
8091 
8092  private final Connection connection;
8093  private final boolean mode;
8094 
8095  SetAutoCommit(Connection connection, boolean mode) {
8096  this.connection = connection;
8097  this.mode = mode;
8098  }
8099 
8100  @Override
8101  public void execute() throws SQLException {
8102  connection.setAutoCommit(mode);
8103  }
8104  }
8105 
8106  final class Commit implements DbCommand {
8107 
8108  private final Connection connection;
8109 
8110  Commit(Connection connection) {
8111  this.connection = connection;
8112  }
8113 
8114  @Override
8115  public void execute() throws SQLException {
8116  connection.commit();
8117  }
8118  }
8119 
8120  final class ExecuteQuery implements DbCommand {
8121 
8122  private final Statement statement;
8123  private final String query;
8124  private ResultSet resultSet;
8125 
8126  ExecuteQuery(Statement statement, String query) {
8127  this.statement = statement;
8128  this.query = query;
8129  }
8130 
8131  ResultSet getResultSet() {
8132  return resultSet;
8133  }
8134 
8135  @Override
8136  public void execute() throws SQLException {
8137  resultSet = statement.executeQuery(query);
8138  }
8139  }
8140 
8141  final class ExecutePreparedStatementQuery implements DbCommand {
8142 
8143  private final PreparedStatement preparedStatement;
8144  private ResultSet resultSet;
8145 
8146  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
8147  this.preparedStatement = preparedStatement;
8148  }
8149 
8150  ResultSet getResultSet() {
8151  return resultSet;
8152  }
8153 
8154  @Override
8155  public void execute() throws SQLException {
8156  resultSet = preparedStatement.executeQuery();
8157  }
8158  }
8159 
8160  final class ExecutePreparedStatementUpdate implements DbCommand {
8161 
8162  private final PreparedStatement preparedStatement;
8163 
8164  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
8165  this.preparedStatement = preparedStatement;
8166  }
8167 
8168  @Override
8169  public void execute() throws SQLException {
8170  preparedStatement.executeUpdate();
8171  }
8172  }
8173 
8174  final class ExecuteStatementUpdate implements DbCommand {
8175 
8176  private final Statement statement;
8177  private final String updateCommand;
8178 
8179  ExecuteStatementUpdate(Statement statement, String updateCommand) {
8180  this.statement = statement;
8181  this.updateCommand = updateCommand;
8182  }
8183 
8184  @Override
8185  public void execute() throws SQLException {
8186  statement.executeUpdate(updateCommand);
8187  }
8188  }
8189 
8190  final class ExecuteStatementUpdateGenerateKeys implements DbCommand {
8191 
8192  private final Statement statement;
8193  private final int generateKeys;
8194  private final String updateCommand;
8195 
8196  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
8197  this.statement = statement;
8198  this.generateKeys = generateKeys;
8199  this.updateCommand = updateCommand;
8200  }
8201 
8202  @Override
8203  public void execute() throws SQLException {
8204  statement.executeUpdate(updateCommand, generateKeys);
8205  }
8206  }
8207 
8208  final class PrepareStatement implements DbCommand {
8209 
8210  private final Connection connection;
8211  private final String input;
8212  private PreparedStatement preparedStatement = null;
8213 
8214  PrepareStatement(Connection connection, String input) {
8215  this.connection = connection;
8216  this.input = input;
8217  }
8218 
8219  PreparedStatement getPreparedStatement() {
8220  return preparedStatement;
8221  }
8222 
8223  @Override
8224  public void execute() throws SQLException {
8225  preparedStatement = connection.prepareStatement(input);
8226  }
8227  }
8228 
8229  final class PrepareStatementGenerateKeys implements DbCommand {
8230 
8231  private final Connection connection;
8232  private final String input;
8233  private final int generateKeys;
8234  private PreparedStatement preparedStatement = null;
8235 
8236  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
8237  this.connection = connection;
8238  this.input = input;
8239  this.generateKeys = generateKeysInput;
8240  }
8241 
8242  PreparedStatement getPreparedStatement() {
8243  return preparedStatement;
8244  }
8245 
8246  @Override
8247  public void execute() throws SQLException {
8248  preparedStatement = connection.prepareStatement(input, generateKeys);
8249  }
8250  }
8251 
8252  abstract void executeCommand(DbCommand command) throws SQLException;
8253 
8254  private final Connection connection;
8255  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
8256 
8257  CaseDbConnection(Connection connection) {
8258  this.connection = connection;
8259  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
8260  }
8261 
8262  boolean isOpen() {
8263  return this.connection != null;
8264  }
8265 
8266  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
8267  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
8268  }
8269 
8270  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
8271  // Lazy statement preparation.
8272  PreparedStatement statement;
8273  if (this.preparedStatements.containsKey(statementKey)) {
8274  statement = this.preparedStatements.get(statementKey);
8275  } else {
8276  statement = prepareStatement(statementKey.getSQL(), generateKeys);
8277  this.preparedStatements.put(statementKey, statement);
8278  }
8279  return statement;
8280  }
8281 
8282  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
8283  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
8284  executeCommand(prepareStatement);
8285  return prepareStatement.getPreparedStatement();
8286  }
8287 
8288  Statement createStatement() throws SQLException {
8289  CreateStatement createStatement = new CreateStatement(this.connection);
8290  executeCommand(createStatement);
8291  return createStatement.getStatement();
8292  }
8293 
8294  void beginTransaction() throws SQLException {
8295  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
8296  executeCommand(setAutoCommit);
8297  }
8298 
8299  void commitTransaction() throws SQLException {
8300  Commit commit = new Commit(connection);
8301  executeCommand(commit);
8302  // You must turn auto commit back on when done with the transaction.
8303  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
8304  executeCommand(setAutoCommit);
8305  }
8306 
8312  void rollbackTransaction() {
8313  try {
8314  connection.rollback();
8315  } catch (SQLException e) {
8316  logger.log(Level.SEVERE, "Error rolling back transaction", e);
8317  }
8318  try {
8319  connection.setAutoCommit(true);
8320  } catch (SQLException e) {
8321  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
8322  }
8323  }
8324 
8332  void rollbackTransactionWithThrow() throws SQLException {
8333  try {
8334  connection.rollback();
8335  } finally {
8336  connection.setAutoCommit(true);
8337  }
8338  }
8339 
8340  ResultSet executeQuery(Statement statement, String query) throws SQLException {
8341  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
8342  executeCommand(queryCommand);
8343  return queryCommand.getResultSet();
8344  }
8345 
8355  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
8356  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
8357  executeCommand(executePreparedStatementQuery);
8358  return executePreparedStatementQuery.getResultSet();
8359  }
8360 
8361  void executeUpdate(Statement statement, String update) throws SQLException {
8362  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
8363  }
8364 
8365  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
8366  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
8367  executeCommand(executeStatementUpdate);
8368  }
8369 
8370  void executeUpdate(PreparedStatement statement) throws SQLException {
8371  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
8372  executeCommand(executePreparedStatementUpdate);
8373  }
8374 
8378  void close() {
8379  try {
8380  connection.close();
8381  } catch (SQLException ex) {
8382  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
8383  }
8384  }
8385 
8386  Connection getConnection() {
8387  return this.connection;
8388  }
8389  }
8390 
8394  private final class SQLiteConnection extends CaseDbConnection {
8395 
8396  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
8397  private static final int SQLITE_BUSY_ERROR = 5;
8398 
8399  SQLiteConnection(Connection conn) {
8400  super(conn);
8401  }
8402 
8403  @Override
8404  void executeCommand(DbCommand command) throws SQLException {
8405  while (true) {
8406  try {
8407  command.execute(); // Perform the operation
8408  break;
8409  } catch (SQLException ex) {
8410  if (ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) {
8411  try {
8412  // We do not notify of error here, as this is not an
8413  // error condition. It is likely a temporary busy or
8414  // locked issue and we will retry.
8415  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
8416  } catch (InterruptedException exp) {
8417  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
8418  }
8419  } else {
8420  throw ex;
8421  }
8422  }
8423  }
8424  }
8425  }
8426 
8430  private final class PostgreSQLConnection extends CaseDbConnection {
8431 
8432  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
8433  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
8434  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
8435  private static final int MAX_RETRIES = 3;
8436 
8437  PostgreSQLConnection(Connection conn) {
8438  super(conn);
8439  }
8440 
8441  @Override
8442  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
8443  ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
8444  executeCommand(executeStatementUpdateGenerateKeys);
8445  }
8446 
8447  @Override
8448  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
8449  PrepareStatementGenerateKeys prepareStatementGenerateKeys = new PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
8450  executeCommand(prepareStatementGenerateKeys);
8451  return prepareStatementGenerateKeys.getPreparedStatement();
8452  }
8453 
8454  @Override
8455  void executeCommand(DbCommand command) throws SQLException {
8456  for (int retries = 0; retries < MAX_RETRIES; retries++) {
8457  try {
8458  command.execute();
8459  break;
8460  } catch (SQLException ex) {
8461  String sqlState = ((PSQLException) ex).getSQLState();
8462  if (sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
8463  try {
8464  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
8465  } catch (InterruptedException exp) {
8466  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
8467  }
8468  } else {
8469  throw ex;
8470  }
8471  }
8472  }
8473  }
8474  }
8475 
8484  public static final class CaseDbTransaction {
8485 
8487 
8488  private CaseDbTransaction(CaseDbConnection connection) throws TskCoreException {
8489  this.connection = connection;
8490  try {
8491  this.connection.beginTransaction();
8492  } catch (SQLException ex) {
8493  throw new TskCoreException("Failed to create transaction on case database", ex);
8494  }
8495  }
8496 
8505  return this.connection;
8506  }
8507 
8514  public void commit() throws TskCoreException {
8515  try {
8516  this.connection.commitTransaction();
8517  } catch (SQLException ex) {
8518  throw new TskCoreException("Failed to commit transaction on case database", ex);
8519  } finally {
8520  close();
8521  }
8522  }
8523 
8530  public void rollback() throws TskCoreException {
8531  try {
8532  this.connection.rollbackTransactionWithThrow();
8533  } catch (SQLException ex) {
8534  throw new TskCoreException("Case database transaction rollback failed", ex);
8535  } finally {
8536  close();
8537  }
8538  }
8539 
8544  void close() {
8545  this.connection.close();
8546  }
8547  }
8548 
8558  public final class CaseDbQuery implements AutoCloseable {
8559 
8560  private ResultSet resultSet;
8562 
8563  private CaseDbQuery(String query) throws TskCoreException {
8564  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
8565  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
8566  }
8567  try {
8568  connection = connections.getConnection();
8569  } catch (TskCoreException ex) {
8570  throw new TskCoreException("Error getting connection for query: ", ex);
8571  }
8572 
8573  try {
8575  resultSet = connection.executeQuery(connection.createStatement(), query);
8576  } catch (SQLException ex) {
8578  throw new TskCoreException("Error executing query: ", ex);
8579  }
8580  }
8581 
8587  public ResultSet getResultSet() {
8588  return resultSet;
8589  }
8590 
8591  @Override
8592  public void close() throws TskCoreException {
8593  try {
8594  if (resultSet != null) {
8595  final Statement statement = resultSet.getStatement();
8596  if (statement != null) {
8597  statement.close();
8598  }
8599  resultSet.close();
8600  }
8601  connection.close();
8602  } catch (SQLException ex) {
8603  throw new TskCoreException("Error closing query: ", ex);
8604  } finally {
8606  }
8607  }
8608  }
8609 
8617  @Deprecated
8618  public void addErrorObserver(ErrorObserver observer) {
8619  sleuthkitCaseErrorObservers.add(observer);
8620  }
8621 
8629  @Deprecated
8630  public void removeErrorObserver(ErrorObserver observer) {
8631  int i = sleuthkitCaseErrorObservers.indexOf(observer);
8632  if (i >= 0) {
8633  sleuthkitCaseErrorObservers.remove(i);
8634  }
8635  }
8636 
8645  @Deprecated
8646  public void submitError(String context, String errorMessage) {
8647  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
8648  if (observer != null) {
8649  try {
8650  observer.receiveError(context, errorMessage);
8651  } catch (Exception ex) {
8652  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
8653  }
8654  }
8655  }
8656  }
8657 
8663  @Deprecated
8664  public interface ErrorObserver {
8665 
8672  public enum Context {
8673 
8677  IMAGE_READ_ERROR("Image File Read Error"),
8681  DATABASE_READ_ERROR("Database Read Error");
8682 
8683  private final String contextString;
8684 
8685  private Context(String context) {
8686  this.contextString = context;
8687  }
8688 
8689  public String getContextString() {
8690  return contextString;
8691  }
8692  };
8693 
8694  void receiveError(String context, String errorMessage);
8695  }
8696 
8710  @Deprecated
8711  long getDataSourceObjectId(long objectId) {
8712  try {
8713  CaseDbConnection connection = connections.getConnection();
8714  try {
8715  return getDataSourceObjectId(connection, objectId);
8716  } finally {
8717  connection.close();
8718  }
8719  } catch (TskCoreException ex) {
8720  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
8721  return 0;
8722  }
8723  }
8724 
8734  @Deprecated
8735  public long getLastObjectId() throws TskCoreException {
8736  CaseDbConnection connection = connections.getConnection();
8738  ResultSet rs = null;
8739  try {
8740  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
8741  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
8742  rs = connection.executeQuery(statement);
8743  long id = -1;
8744  if (rs.next()) {
8745  id = rs.getLong("max_obj_id");
8746  }
8747  return id;
8748  } catch (SQLException e) {
8749  throw new TskCoreException("Error getting last object id", e);
8750  } finally {
8751  closeResultSet(rs);
8752  connection.close();
8754  }
8755  }
8756 
8770  @Deprecated
8771  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
8772  CaseDbConnection connection = connections.getConnection();
8774  Statement s = null;
8775  ResultSet rs = null;
8776  try {
8777  s = connection.createStatement();
8778  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8779  List<FsContent> results = new ArrayList<FsContent>();
8780  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
8781  for (AbstractFile f : temp) {
8782  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
8783  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
8784  results.add((FsContent) f);
8785  }
8786  }
8787  return results;
8788  } catch (SQLException e) {
8789  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
8790  } finally {
8791  closeResultSet(rs);
8792  closeStatement(s);
8793  connection.close();
8795  }
8796  }
8797 
8809  @Deprecated
8810  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
8811  CaseDbConnection connection = connections.getConnection();
8813  Statement s = null;
8814  ResultSet rs = null;
8815  try {
8816  s = connection.createStatement();
8817  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
8818  int typeId = -1;
8819  if (rs.next()) {
8820  typeId = rs.getInt("artifact_type_id");
8821  }
8822  return typeId;
8823  } catch (SQLException ex) {
8824  throw new TskCoreException("Error getting artifact type id", ex);
8825  } finally {
8826  closeResultSet(rs);
8827  closeStatement(s);
8828  connection.close();
8830  }
8831  }
8832 
8842  @Deprecated
8843  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
8844  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
8845  }
8846 
8860  @Deprecated
8861  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
8862  try {
8863  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
8864  } catch (TskDataException ex) {
8865  throw new TskCoreException("Failed to add artifact type.", ex);
8866  }
8867  }
8868 
8882  @Deprecated
8883  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
8884  try {
8885  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
8886  } catch (TskDataException ex) {
8887  throw new TskCoreException("Couldn't add new attribute type");
8888  }
8889  }
8890 
8901  @Deprecated
8902  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
8903  CaseDbConnection connection = connections.getConnection();
8905  Statement s = null;
8906  ResultSet rs = null;
8907  try {
8908  s = connection.createStatement();
8909  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
8910  int typeId = -1;
8911  if (rs.next()) {
8912  typeId = rs.getInt("attribute_type_id");
8913  }
8914  return typeId;
8915  } catch (SQLException ex) {
8916  throw new TskCoreException("Error getting attribute type id", ex);
8917  } finally {
8918  closeResultSet(rs);
8919  closeStatement(s);
8920  connection.close();
8922  }
8923  }
8924 
8937  @Deprecated
8938  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
8939  CaseDbConnection connection = connections.getConnection();
8941  Statement s = null;
8942  ResultSet rs = null;
8943  try {
8944  s = connection.createStatement();
8945  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
8946  if (rs.next()) {
8947  return rs.getString("type_name");
8948  } else {
8949  throw new TskCoreException("No type with that id");
8950  }
8951  } catch (SQLException ex) {
8952  throw new TskCoreException("Error getting or creating a attribute type name", ex);
8953  } finally {
8954  closeResultSet(rs);
8955  closeStatement(s);
8956  connection.close();
8958  }
8959  }
8960 
8973  @Deprecated
8974  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
8975  CaseDbConnection connection = connections.getConnection();
8977  Statement s = null;
8978  ResultSet rs = null;
8979  try {
8980  s = connection.createStatement();
8981  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
8982  if (rs.next()) {
8983  return rs.getString("display_name");
8984  } else {
8985  throw new TskCoreException("No type with that id");
8986  }
8987  } catch (SQLException ex) {
8988  throw new TskCoreException("Error getting or creating a attribute type name", ex);
8989  } finally {
8990  closeResultSet(rs);
8991  closeStatement(s);
8992  connection.close();
8994  }
8995  }
8996 
9006  @Deprecated
9007  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
9008  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
9009  }
9010 
9026  @Deprecated
9027  public ResultSet runQuery(String query) throws SQLException {
9028  CaseDbConnection connection;
9029  try {
9030  connection = connections.getConnection();
9031  } catch (TskCoreException ex) {
9032  throw new SQLException("Error getting connection for ad hoc query", ex);
9033  }
9035  try {
9036  return connection.executeQuery(connection.createStatement(), query);
9037  } finally {
9038  //TODO unlock should be done in closeRunQuery()
9039  //but currently not all code calls closeRunQuery - need to fix this
9040  connection.close();
9042  }
9043  }
9044 
9054  @Deprecated
9055  public void closeRunQuery(ResultSet resultSet) throws SQLException {
9056  final Statement statement = resultSet.getStatement();
9057  resultSet.close();
9058  if (statement != null) {
9059  statement.close();
9060  }
9061  }
9062 
9079  @Deprecated
9080  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
9081  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
9082  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
9083  files.add(carvedFile);
9084  CarvingResult carvingResult;
9085  Content parent = getContentById(containerId);
9086  if (parent instanceof FileSystem
9087  || parent instanceof Volume
9088  || parent instanceof Image) {
9089  carvingResult = new CarvingResult(parent, files);
9090  } else {
9091  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
9092  }
9093  return addCarvedFiles(carvingResult).get(0);
9094  }
9095 
9109  @Deprecated
9110  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
9111  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
9112  for (CarvedFileContainer container : filesToAdd) {
9113  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
9114  carvedFiles.add(carvedFile);
9115  }
9116  CarvingResult carvingResult;
9117  Content parent = getContentById(filesToAdd.get(0).getId());
9118  if (parent instanceof FileSystem
9119  || parent instanceof Volume
9120  || parent instanceof Image) {
9121  carvingResult = new CarvingResult(parent, carvedFiles);
9122  } else {
9123  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
9124  }
9125  return addCarvedFiles(carvingResult);
9126  }
9127 
9157  @Deprecated
9158  public DerivedFile addDerivedFile(String fileName, String localPath,
9159  long size, long ctime, long crtime, long atime, long mtime,
9160  boolean isFile, AbstractFile parentFile,
9161  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
9162  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
9163  isFile, parentFile, rederiveDetails, toolName, toolVersion,
9164  otherDetails, TskData.EncodingType.NONE);
9165  }
9166 
9191  @Deprecated
9192  public LocalFile addLocalFile(String fileName, String localPath,
9193  long size, long ctime, long crtime, long atime, long mtime,
9194  boolean isFile,
9195  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
9196  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
9197  TskData.EncodingType.NONE, parent, transaction);
9198  }
9199 
9219  @Deprecated
9220  public LocalFile addLocalFile(String fileName, String localPath,
9221  long size, long ctime, long crtime, long atime, long mtime,
9222  boolean isFile,
9223  AbstractFile parent) throws TskCoreException {
9224  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
9225  isFile, TskData.EncodingType.NONE, parent);
9226  }
9227 
9244  @Deprecated
9245  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
9246  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "");
9247  }
9248 
9249 }
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
CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans)
BlackboardArtifact getArtifactById(long id)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
final ArrayList< ErrorObserver > sleuthkitCaseErrorObservers
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)
ArrayList< BlackboardArtifact > getArtifactsHelper(String whereClause)
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)
CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
void setPooledDataSource(PooledDataSource pooledDataSource)
boolean isCompatible(CaseDbSchemaVersionNumber dbSchemaVersion)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent)
FileSystem getFileSystemByIdHelper(long id, Content parent)
final Map< Long, FileSystem > fileSystemIdMap
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)
static String createCaseDataBaseName(String candidateDbName)
void addErrorObserver(ErrorObserver observer)
LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
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)
final Map< Long, VirtualDirectory > rootIdsToCarvedFileDirs
static TSK_FS_META_TYPE_ENUM valueOf(short metaType)
Definition: TskData.java:138
static final String SQL_ERROR_RESOURCE_GROUP
long getFileSystemId(long fileId, CaseDbConnection connection)
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()
static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP
static TSK_FS_ATTR_TYPE_ENUM valueOf(int val)
Definition: TskData.java:316
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId)
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)
List< AbstractFile > resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection)
CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
BlackboardArtifact getBlackboardArtifact(long artifactID)
Map< Integer, BlackboardArtifact.Type > typeIdToArtifactTypeMap
static void closeResultSet(ResultSet resultSet)
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
static TSK_FS_NAME_FLAG_ENUM valueOf(int dirFlag)
Definition: TskData.java:188
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)
void initReviewStatuses(CaseDbConnection connection)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypesInUse()
CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
int getAttrTypeID(String attrTypeName)
List< Content > getChildren()
USED
Metadata structure has been allocated at least once.
Definition: TskData.java:208
static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
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)
static EncodingType valueOf(int type)
Definition: TskData.java:815
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static final String SQL_ERROR_PRIVILEGE_GROUP
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)
static TSK_FS_NAME_TYPE_ENUM valueOf(short dir_type)
Definition: TskData.java:86
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone)
long getArtifactsCountHelper(int artifactTypeID, long obj_id)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:70
final ReentrantReadWriteLock rwLock
static final String SQL_ERROR_CONNECTION_GROUP
List< AbstractFile > findFilesByMd5(String md5Hash)
BlackboardArtifact.Type getArtifactType(String artTypeName)
BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id)
Map< Integer, BlackboardAttribute.Type > typeIdToAttributeTypeMap
void initIngestModuleTypes(CaseDbConnection connection)
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)
void initEncodingTypes(CaseDbConnection connection)
static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath)
Report addReport(String localPath, String sourceModuleName, String reportName)
List< BlackboardArtifactTag > getAllBlackboardArtifactTags()
static final String SQL_ERROR_INTERNAL_GROUP
void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName, long obj_id)
void removeErrorObserver(ErrorObserver observer)
static TSK_DB_FILES_TYPE_ENUM valueOf(short fileType)
Definition: TskData.java:696
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)
void initIngestStatusTypes(CaseDbConnection connection)
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)
long getDataSourceObjectId(CaseDbConnection connection, long objectId)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:726
Map< String, BlackboardArtifact.Type > typeNameToArtifactTypeMap
List< AbstractFile > findAllFilesWhere(String sqlWhereClause)
boolean setKnown(AbstractFile file, FileKnown fileKnown)
static void closeStatement(Statement statement)
static final ResourceBundle bundle
BlackboardAttribute.Type getAttributeType(int typeID)
static void tryConnect(CaseDbConnectionInfo info)
void receiveError(String context, String errorMessage)
static SleuthkitCase openCase(String dbPath)
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
List< IngestModuleInfo > getIngestModules(int ingestJobId, CaseDbConnection connection)
static SleuthkitCase newCase(String dbPath)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType)
BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName)
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)
Map< String, BlackboardAttribute.Type > typeNameToAttributeTypeMap
CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection)
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)
final Map< PREPARED_STATEMENT, PreparedStatement > preparedStatements
List< FsContent > findFilesWhere(String sqlWhereClause)
void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection)
List< TskFileRange > getFileRanges(long id)
static final String SQL_ERROR_AUTHENTICATION_GROUP
BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName)
UNUSED_BLOCKS
Set of blocks that are unallocated AND not used by a carved or other file type. Parent should be UNAL...
Definition: TskData.java:675
List< BlackboardArtifact > resultSetToArtifacts(ResultSet rs)
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)
VS
Volume System - see tsk_vs_info for more details.
Definition: TskData.java:625
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:624
SleuthkitJNI.CaseDbHandle caseHandle
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:157
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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