Sleuth Kit Java Bindings (JNI)  4.2
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 2012-2014 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 java.io.BufferedInputStream;
22 import java.io.BufferedOutputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.nio.file.Paths;
30 import java.sql.Connection;
31 import java.sql.DriverManager;
32 import java.sql.PreparedStatement;
33 import java.sql.ResultSet;
34 import java.sql.SQLException;
35 import java.sql.Statement;
36 import java.text.MessageFormat;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.EnumMap;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.LinkedHashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.ResourceBundle;
47 import java.util.concurrent.locks.ReentrantReadWriteLock;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
60 import org.sqlite.SQLiteConfig;
61 import org.sqlite.SQLiteJDBCLoader;
62 
67 public class SleuthkitCase {
68 
69  private static final int SCHEMA_VERSION_NUMBER = 3; // This must be the same as TSK_SCHEMA_VER in tsk/auto/db_sqlite.cpp.
70  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
71  private static final int SQLITE_BUSY_ERROR = 5;
72  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
73  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
74  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
76  private final ResultSetHelper rsHelper = new ResultSetHelper(this);
77  private final Map<Long, Long> carvedFileContainersCache = new HashMap<Long, Long>(); // Caches the IDs of the root $CarvedFiles for each volume.
78  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<Long, FileSystem>(); // Cache for file system results.
79  private final ArrayList<ErrorObserver> errorObservers = new ArrayList<ErrorObserver>();
80  private final String dbPath;
81  private final String dbDirPath;
82  private SleuthkitJNI.CaseDbHandle caseHandle; // Not currently used.
83  private int versionNumber;
84  private String dbBackupPath;
85  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
86 
87  // This read/write lock is used to implement a layer of locking on top of
88  // the locking protocol provided by the underlying SQLite database. The Java
89  // locking protocol improves performance for reasons that are not currently
90  // understood. Note that the lock is contructed to use a fairness policy.
91  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
92 
102  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle) throws Exception {
103  Class.forName("org.sqlite.JDBC");
104  this.dbPath = dbPath;
105  this.dbDirPath = new java.io.File(dbPath).getParentFile().getAbsolutePath();
106  this.caseHandle = caseHandle;
112  }
113 
119  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
120  CaseDbConnection connection = connections.getConnection();
121  Statement statement = null;
122  ResultSet resultSet = null;
123  try {
124  statement = connection.createStatement();
125  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
126  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) from blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS
127  if (resultSet.getLong(1) == 0) {
128  connection.executeUpdate(statement, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
129  }
130  resultSet.close();
131  resultSet = null;
132  }
133  } finally {
134  closeResultSet(resultSet);
135  closeStatement(statement);
136  }
137  }
138 
145  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
146  CaseDbConnection connection = connections.getConnection();
147  Statement statement = null;
148  ResultSet resultSet = null;
149  try {
150  statement = connection.createStatement();
151  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
152  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) from blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS
153  if (resultSet.getLong(1) == 0) {
154  connection.executeUpdate(statement, "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
155  }
156  resultSet.close();
157  resultSet = null;
158  }
159  } finally {
160  closeResultSet(resultSet);
161  closeStatement(statement);
162  }
163  }
164 
174  private void initNextArtifactId() throws TskCoreException, SQLException {
175  CaseDbConnection connection = connections.getConnection();
176  Statement statement = null;
177  ResultSet resultSet = null;
178  try {
179  statement = connection.createStatement();
180  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) FROM blackboard_artifacts");
181  this.nextArtifactId = resultSet.getLong(1) + 1;
182  if (this.nextArtifactId == 1) {
183  this.nextArtifactId = BASE_ARTIFACT_ID;
184  }
185  } finally {
186  closeResultSet(resultSet);
187  closeStatement(statement);
188  }
189  }
190 
197  private void updateDatabaseSchema() throws Exception {
198  CaseDbConnection connection = connections.getConnection();
199  ResultSet resultSet = null;
200  Statement statement = null;
201  try {
202  connection.beginTransaction();
203 
204  // Get the schema version number of the case database from the tsk_db_info table.
205  int schemaVersionNumber = SCHEMA_VERSION_NUMBER;
206  statement = connection.createStatement();
207  resultSet = connection.executeQuery(statement, "SELECT schema_ver FROM tsk_db_info"); //NON-NLS
208  if (resultSet.next()) {
209  schemaVersionNumber = resultSet.getInt("schema_ver"); //NON-NLS
210  }
211  resultSet.close();
212  resultSet = null;
213 
214  // Do the schema update(s), if needed.
215  if (SCHEMA_VERSION_NUMBER != schemaVersionNumber) {
216  // Make a backup copy of the database. Client code can get the path of the backup
217  // using the getBackupDatabasePath() method.
218  String backupFilePath = dbPath + ".schemaVer" + schemaVersionNumber + ".backup"; //NON-NLS
219  copyCaseDB(backupFilePath);
220  dbBackupPath = backupFilePath;
221 
222  // ***CALL SCHEMA UPDATE METHODS HERE***
223  // Each method should examine the schema number passed to it and either:
224  // a. do nothing and return the schema version number unchanged, or
225  // b. upgrade the database and then increment and return the schema version number.
226  schemaVersionNumber = updateFromSchema2toSchema3(schemaVersionNumber);
227 
228  // Write the updated schema version number to the the tsk_db_info table.
229  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + schemaVersionNumber); //NON-NLS
230  }
231  versionNumber = schemaVersionNumber;
232 
233  connection.commitTransaction();
234  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
235  connection.rollbackTransaction();
236  throw ex;
237  } finally {
238  closeResultSet(resultSet);
239  closeStatement(statement);
240  }
241  }
242 
251  public void copyCaseDB(String newDBPath) throws IOException {
252  InputStream in = null;
253  OutputStream out = null;
255  try {
256  InputStream inFile = new FileInputStream(dbPath);
257  in = new BufferedInputStream(inFile);
258  OutputStream outFile = new FileOutputStream(newDBPath);
259  out = new BufferedOutputStream(outFile);
260  int bytesRead = 0;
261  while ((bytesRead = in.read()) != -1) {
262  out.write(bytesRead);
263  }
264  } finally {
265  try {
266  if (in != null) {
267  in.close();
268  }
269  if (out != null) {
270  out.flush();
271  out.close();
272  }
273  } catch (IOException e) {
274  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
275  }
277  }
278  }
279 
283  private void logSQLiteJDBCDriverInfo() {
284  try {
285  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
286  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
287  ? "native" : "pure-java")); //NON-NLS
288  } catch (Exception ex) {
289  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
290  }
291  }
292 
301  @SuppressWarnings("deprecation")
302  private int updateFromSchema2toSchema3(int schemaVersionNumber) throws SQLException, TskCoreException {
303  if (schemaVersionNumber != 2) {
304  return schemaVersionNumber;
305  }
306 
307  CaseDbConnection connection = connections.getConnection();
308  Statement statement = null;
309  Statement updateStatement = null;
310  ResultSet resultSet = null;
311  try {
312  statement = connection.createStatement();
313 
314  // Add new tables for tags.
315  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
316  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
317  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
318 
319  // Add a new table for reports.
320  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
321 
322  // Add new columns to the image info table.
323  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
324  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
325  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
326 
327  // Add a new column to the file system info table.
328  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
329 
330  // Add a new column to the file table.
331  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
332 
333  // Add new columns and indexes to the attributes table and populate the
334  // new column. Note that addition of the new column is a denormalization
335  // to optimize attribute queries.
336  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
337  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
338  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
339  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
340  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
341  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
342  resultSet = statement.executeQuery(
343  "SELECT attrs.artifact_id, arts.artifact_type_id " + //NON-NLS
344  "FROM blackboard_attributes AS attrs " + //NON-NLS
345  "INNER JOIN blackboard_artifacts AS arts " + //NON-NLS
346  "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
347  updateStatement = connection.createStatement();
348  while (resultSet.next()) {
349  long artifactId = resultSet.getLong(1);
350  int artifactTypeId = resultSet.getInt(2);
351  updateStatement.executeUpdate(
352  "UPDATE blackboard_attributes " + //NON-NLS
353  "SET artifact_type_id = " + artifactTypeId + " " + //NON-NLS
354  "WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
355  }
356  resultSet.close();
357  resultSet = null;
358 
359  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
360  // TODO: This code depends on prepared statements that could evolve with
361  // time, breaking this upgrade. The code that follows should be rewritten
362  // to do everything with SQL specific to case database schema version 2.
363  HashMap<String, TagName> tagNames = new HashMap<String, TagName>();
365  Content content = getContentById(artifact.getObjectID());
366  String name = ""; //NON-NLS
367  String comment = ""; //NON-NLS
368  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
369  for (BlackboardAttribute attribute : attributes) {
370  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
371  name = attribute.getValueString();
372  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
373  comment = attribute.getValueString();
374  }
375  }
376  if (!name.isEmpty()) {
377  TagName tagName;
378  if (tagNames.containsKey(name)) {
379  tagName = tagNames.get(name);
380  } else {
381  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
382  tagNames.put(name, tagName);
383  }
384  addContentTag(content, tagName, comment, 0, content.getSize() - 1);
385  }
386  }
388  long taggedArtifactId = -1;
389  String name = ""; //NON-NLS
390  String comment = ""; //NON-NLS
391  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
392  for (BlackboardAttribute attribute : attributes) {
393  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
394  name = attribute.getValueString();
395  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
396  comment = attribute.getValueString();
397  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
398  taggedArtifactId = attribute.getValueLong();
399  }
400  }
401  if (taggedArtifactId != -1 && !name.isEmpty()) {
402  TagName tagName;
403  if (tagNames.containsKey(name)) {
404  tagName = tagNames.get(name);
405  } else {
406  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
407  tagNames.put(name, tagName);
408  }
409  addBlackboardArtifactTag(getBlackboardArtifact(taggedArtifactId), tagName, comment);
410  }
411  }
412  statement.execute(
413  "DELETE FROM blackboard_attributes WHERE artifact_id IN " + //NON-NLS
414  "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + //NON-NLS
415  " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
416  statement.execute(
417  "DELETE FROM blackboard_artifacts WHERE " + //NON-NLS
418  "artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + //NON-NLS
419  " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
420 
421  return 3;
422  } finally {
423  closeStatement(updateStatement);
424  closeResultSet(resultSet);
425  closeStatement(statement);
426  }
427  }
428 
434  public int getSchemaVersion() {
435  return this.versionNumber;
436  }
437 
444  public String getBackupDatabasePath() {
445  return dbBackupPath;
446  }
447 
458  return new CaseDbTransaction(connections.getConnection());
459  }
460 
466  public String getDbDirPath() {
467  return dbDirPath;
468  }
469 
475  public void acquireExclusiveLock() {
476  rwLock.writeLock().lock();
477  }
478 
484  public void releaseExclusiveLock() {
485  rwLock.writeLock().unlock();
486  }
487 
493  public void acquireSharedLock() {
494  rwLock.readLock().lock();
495  }
496 
502  public void releaseSharedLock() {
503  rwLock.readLock().unlock();
504  }
505 
513  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
514  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
515  try {
516  return new SleuthkitCase(dbPath, caseHandle);
517  } catch (Exception ex) {
518  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
519  }
520  }
521 
529  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
530  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(dbPath);
531  try {
532  return new SleuthkitCase(dbPath, caseHandle);
533  } catch (Exception ex) {
534  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
535  }
536  }
537 
550  public AddImageProcess makeAddImageProcess(String timezone, boolean processUnallocSpace, boolean noFatFsOrphans) {
551  return this.caseHandle.initAddImageProcess(timezone, processUnallocSpace, noFatFsOrphans);
552  }
553 
561  public List<Content> getRootObjects() throws TskCoreException {
562  CaseDbConnection connection = connections.getConnection();
564  Statement s = null;
565  ResultSet rs = null;
566  try {
567  s = connection.createStatement();
568  rs = connection.executeQuery(s, "SELECT obj_id, type from tsk_objects " //NON-NLS
569  + "WHERE par_obj_id IS NULL"); //NON-NLS
570  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
571  while (rs.next()) {
572  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
573  }
574 
575  List<Content> rootObjs = new ArrayList<Content>();
576  for (ObjectInfo i : infos) {
577  if (i.type == ObjectType.IMG) {
578  rootObjs.add(getImageById(i.id));
579  } else if (i.type == ObjectType.ABSTRACTFILE) {
580  // Check if virtual dir for local files.
582  if (af instanceof VirtualDirectory) {
583  rootObjs.add(af);
584  } else {
585  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
586  }
587  } else {
588  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
589  }
590  }
591  return rootObjs;
592  } catch (SQLException ex) {
593  throw new TskCoreException("Error getting root objects", ex);
594  } finally {
595  closeResultSet(rs);
596  closeStatement(s);
598  }
599  }
600 
608  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
609  CaseDbConnection connection = connections.getConnection();
611  ResultSet rs = null;
612  try {
613  String artifactTypeName = getArtifactTypeString(artifactTypeID);
614  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACTS_BY_TYPE);
615  statement.clearParameters();
616  statement.setInt(1, artifactTypeID);
617  rs = connection.executeQuery(statement);
618  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
619  while (rs.next()) {
620  artifacts.add(new BlackboardArtifact(this, rs.getLong(1), rs.getLong(2),
621  artifactTypeID, artifactTypeName, ARTIFACT_TYPE.fromID(artifactTypeID).getDisplayName()));
622  }
623  return artifacts;
624  } catch (SQLException ex) {
625  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
626  } finally {
627  closeResultSet(rs);
629  }
630  }
631 
639  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
640  CaseDbConnection connection = connections.getConnection();
642  ResultSet rs = null;
643  try {
644  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
645  statement.clearParameters();
646  statement.setLong(1, objId);
647  rs = connection.executeQuery(statement);
648  long count = 0;
649  if (rs.next()) {
650  count = rs.getLong(1);
651  }
652  return count;
653  } catch (SQLException ex) {
654  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
655  } finally {
656  closeResultSet(rs);
658  }
659  }
660 
668  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
669  CaseDbConnection connection = connections.getConnection();
671  ResultSet rs = null;
672  try {
673  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
674  statement.clearParameters();
675  statement.setInt(1, artifactTypeID);
676  rs = connection.executeQuery(statement);
677  long count = 0;
678  if (rs.next()) {
679  count = rs.getLong(1);
680  }
681  return count;
682  } catch (SQLException ex) {
683  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
684  } finally {
685  closeResultSet(rs);
687  }
688  }
689 
699  private List<BlackboardArtifact> getArtifactsHelper(ResultSet rs) throws SQLException {
700  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
701  while (rs.next()) {
702  final int artifactTypeID = rs.getInt(3);
703  final ARTIFACT_TYPE artType = ARTIFACT_TYPE.fromID(artifactTypeID);
704  artifacts.add(new BlackboardArtifact(this, rs.getLong(1), rs.getLong(2),
705  artifactTypeID, artType.getLabel(), artType.getDisplayName()));
706  }
707  return artifacts;
708  }
709 
721  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
722  CaseDbConnection connection = connections.getConnection();
724  Statement s = null;
725  ResultSet rs = null;
726  try {
727  s = connection.createStatement();
728  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
729  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
730  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
731  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
732  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
733  + " AND blackboard_attributes.value_text IS '" + value + "'"); //NON-NLS
734  return getArtifactsHelper(rs);
735  } catch (SQLException ex) {
736  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
737  } finally {
738  closeResultSet(rs);
739  closeStatement(s);
741  }
742  }
743 
758  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
759  subString = "%" + subString; //NON-NLS
760  if (startsWith == false) {
761  subString = subString + "%"; //NON-NLS
762  }
763  CaseDbConnection connection = connections.getConnection();
765  Statement s = null;
766  ResultSet rs = null;
767  try {
768  s = connection.createStatement();
769  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
770  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
771  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
772  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
773  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
774  + " AND blackboard_attributes.value_text LIKE '" + subString + "'"); //NON-NLS
775  return getArtifactsHelper(rs);
776  } catch (SQLException ex) {
777  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
778  } finally {
779  closeResultSet(rs);
780  closeStatement(s);
782  }
783  }
784 
796  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
797  CaseDbConnection connection = connections.getConnection();
799  Statement s = null;
800  ResultSet rs = null;
801  try {
802  s = connection.createStatement();
803  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
804  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
805  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
806  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
807  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
808  + " AND blackboard_attributes.value_int32 IS " + value); //NON-NLS
809  return getArtifactsHelper(rs);
810  } catch (SQLException ex) {
811  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
812  } finally {
813  closeResultSet(rs);
814  closeStatement(s);
816  }
817  }
818 
830  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
831  CaseDbConnection connection = connections.getConnection();
833  Statement s = null;
834  ResultSet rs = null;
835  try {
836  s = connection.createStatement();
837  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
838  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
839  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
840  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
841  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
842  + " AND blackboard_attributes.value_int64 IS " + value); //NON-NLS
843  return getArtifactsHelper(rs);
844  } catch (SQLException ex) {
845  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
846  } finally {
847  closeResultSet(rs);
848  closeStatement(s);
850  }
851  }
852 
864  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
865  CaseDbConnection connection = connections.getConnection();
867  Statement s = null;
868  ResultSet rs = null;
869  try {
870  s = connection.createStatement();
871  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
872  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
873  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
874  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
875  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
876  + " AND blackboard_attributes.value_double IS " + value); //NON-NLS
877  return getArtifactsHelper(rs);
878  } catch (SQLException ex) {
879  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
880  } finally {
881  closeResultSet(rs);
882  closeStatement(s);
884  }
885  }
886 
898  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
899  CaseDbConnection connection = connections.getConnection();
901  Statement s = null;
902  ResultSet rs = null;
903  try {
904  s = connection.createStatement();
905  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
906  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
907  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
908  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
909  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
910  + " AND blackboard_attributes.value_byte IS " + value); //NON-NLS
911  return getArtifactsHelper(rs);
912  } catch (SQLException ex) {
913  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
914  } finally {
915  closeResultSet(rs);
916  closeStatement(s);
918  }
919  }
920 
930  CaseDbConnection connection = connections.getConnection();
932  Statement s = null;
933  ResultSet rs = null;
934  try {
935  s = connection.createStatement();
936  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types"); //NON-NLS
937  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> artifact_types = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
938  while (rs.next()) {
939  /*
940  * Only return ones in the enum because otherwise exceptions
941  * get thrown down the call stack. Need to remove use of enum
942  * for the attribute types */
944  if (artType.getTypeID() == rs.getInt(1)) {
945  artifact_types.add(artType);
946  }
947  }
948  }
949  return artifact_types;
950  } catch (SQLException ex) {
951  throw new TskCoreException("Error getting artifact types", ex);
952  } finally {
953  closeResultSet(rs);
954  closeStatement(s);
956  }
957  }
958 
967  // @@@ TODO: This should be rewritten as a single query.
969  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
970  for (BlackboardArtifact.ARTIFACT_TYPE art : allArts) {
971  if (getBlackboardArtifactsTypeCount(art.getTypeID()) > 0) {
972  usedArts.add(art);
973  }
974  }
975  return usedArts;
976  }
977 
989  CaseDbConnection connection = connections.getConnection();
991  Statement s = null;
992  ResultSet rs = null;
993  try {
994  s = connection.createStatement();
995  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types"); //NON-NLS
996  ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> attribute_types = new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>();
997  while (rs.next()) {
998  attribute_types.add(BlackboardAttribute.ATTRIBUTE_TYPE.fromLabel(rs.getString(1)));
999  }
1000  return attribute_types;
1001  } catch (SQLException ex) {
1002  throw new TskCoreException("Error getting attribute types", ex);
1003  } finally {
1004  closeResultSet(rs);
1005  closeStatement(s);
1007  }
1008  }
1009 
1021  CaseDbConnection connection = connections.getConnection();
1023  Statement s = null;
1024  ResultSet rs = null;
1025  try {
1026  s = connection.createStatement();
1027  rs = connection.executeQuery(s, "SELECT COUNT(*) FROM blackboard_attribute_types"); //NON-NLS
1028  int count = 0;
1029  if (rs.next()) {
1030  count = rs.getInt(1);
1031  }
1032  return count;
1033  } catch (SQLException ex) {
1034  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
1035  } finally {
1036  closeResultSet(rs);
1037  closeStatement(s);
1039  }
1040  }
1041 
1053  private ArrayList<BlackboardArtifact> getArtifactsHelper(int artifactTypeID, String artifactTypeName, long obj_id) throws TskCoreException {
1054  CaseDbConnection connection = connections.getConnection();
1056  ResultSet rs = null;
1057  try {
1058  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACTS_BY_SOURCE_AND_TYPE);
1059  statement.clearParameters();
1060  statement.setLong(1, obj_id);
1061  statement.setInt(2, artifactTypeID);
1062  rs = connection.executeQuery(statement);
1063  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1064  while (rs.next()) {
1065  artifacts.add(new BlackboardArtifact(this, rs.getLong(1), obj_id, artifactTypeID, artifactTypeName, this.getArtifactTypeDisplayName(artifactTypeID)));
1066  }
1067  return artifacts;
1068  } catch (SQLException ex) {
1069  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
1070  } finally {
1071  closeResultSet(rs);
1073  }
1074  }
1075 
1086  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
1087  CaseDbConnection connection = connections.getConnection();
1089  ResultSet rs = null;
1090  try {
1091  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
1092  statement.clearParameters();
1093  statement.setLong(1, obj_id);
1094  statement.setInt(2, artifactTypeID);
1095  rs = connection.executeQuery(statement);
1096  long count = 0;
1097  if (rs.next()) {
1098  count = rs.getLong(1);
1099  }
1100  return count;
1101  } catch (SQLException ex) {
1102  throw new TskCoreException("Error getting blackboard artifact count", ex);
1103  } finally {
1104  closeResultSet(rs);
1106  }
1107  }
1108 
1118  private ArrayList<BlackboardArtifact> getArtifactsHelper(int artifactTypeID, String artifactTypeName) throws TskCoreException {
1119  CaseDbConnection connection = connections.getConnection();
1121  ResultSet rs = null;
1122  try {
1123  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACTS_BY_TYPE);
1124  statement.clearParameters();
1125  statement.setInt(1, artifactTypeID);
1126  rs = connection.executeQuery(statement);
1127  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
1128  while (rs.next()) {
1129  artifacts.add(new BlackboardArtifact(this, rs.getLong(1), rs.getLong(2), artifactTypeID, artifactTypeName, this.getArtifactTypeDisplayName(artifactTypeID)));
1130  }
1131  return artifacts;
1132  } catch (SQLException ex) {
1133  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
1134  } finally {
1135  closeResultSet(rs);
1137  }
1138  }
1139 
1149  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
1150  int artifactTypeID = this.getArtifactTypeID(artifactTypeName);
1151  if (artifactTypeID == -1) {
1152  return new ArrayList<BlackboardArtifact>();
1153  }
1154  return getArtifactsHelper(artifactTypeID, artifactTypeName, obj_id);
1155  }
1156 
1166  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
1167  String artifactTypeName = this.getArtifactTypeString(artifactTypeID);
1168  return getArtifactsHelper(artifactTypeID, artifactTypeName, obj_id);
1169  }
1170 
1180  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
1181  return getArtifactsHelper(artifactType.getTypeID(), artifactType.getLabel(), obj_id);
1182  }
1183 
1194  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
1195  int artifactTypeID = this.getArtifactTypeID(artifactTypeName);
1196  if (artifactTypeID == -1) {
1197  return 0;
1198  }
1199  return getArtifactsCountHelper(artifactTypeID, obj_id);
1200  }
1201 
1212  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
1213  return getArtifactsCountHelper(artifactTypeID, obj_id);
1214  }
1215 
1226  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
1227  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
1228  }
1229 
1238  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
1239  int artifactTypeID = this.getArtifactTypeID(artifactTypeName);
1240  if (artifactTypeID == -1) {
1241  return new ArrayList<BlackboardArtifact>();
1242  }
1243  return getArtifactsHelper(artifactTypeID, artifactTypeName);
1244  }
1245 
1254  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
1255  return getArtifactsHelper(artifactType.getTypeID(), artifactType.getLabel());
1256  }
1257 
1269  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
1270  CaseDbConnection connection = connections.getConnection();
1272  Statement s = null;
1273  ResultSet rs = null;
1274  try {
1275  s = connection.createStatement();
1276  rs = connection.executeQuery(s, "SELECT DISTINCT blackboard_artifacts.artifact_id, " //NON-NLS
1277  + "blackboard_artifacts.obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS
1278  + "FROM blackboard_artifacts, blackboard_attributes " //NON-NLS
1279  + "WHERE blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
1280  + "AND blackboard_attributes.attribute_type_id IS " + attrType.getTypeID() //NON-NLS
1281  + " AND blackboard_artifacts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
1282  + " AND blackboard_attributes.value_text IS '" + value + "'"); //NON-NLS
1283  return getArtifactsHelper(rs);
1284  } catch (SQLException ex) {
1285  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
1286  } finally {
1287  closeResultSet(rs);
1288  closeStatement(s);
1290  }
1291  }
1292 
1302  CaseDbConnection connection = connections.getConnection();
1304  ResultSet rs = null;
1305  try {
1306  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ID);
1307  statement.clearParameters();
1308  statement.setLong(1, artifactID);
1309  rs = connection.executeQuery(statement);
1310  List<BlackboardArtifact> artifacts = getArtifactsHelper(rs);
1311  if (artifacts.size() > 0) {
1312  return artifacts.get(0);
1313  } else {
1314  /* I think this should actually return null (or Optional) when there
1315  * is no artifact with the given id, but it looks like existing code is
1316  * not expecting that. -jm */
1317  throw new TskCoreException("No blackboard artifact with id " + artifactID);
1318  }
1319  } catch (SQLException ex) {
1320  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
1321  } finally {
1322  closeResultSet(rs);
1324  }
1325  }
1326 
1334  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
1335  CaseDbConnection connection = connections.getConnection();
1337  try {
1338  addBlackBoardAttribute(attr, artifactTypeId, connection);
1339  } catch (SQLException ex) {
1340  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
1341  } finally {
1343  }
1344  }
1345 
1354  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
1355  CaseDbConnection connection = connections.getConnection();
1357  try {
1358  connection.beginTransaction();
1359  for (final BlackboardAttribute attr : attributes) {
1360  addBlackBoardAttribute(attr, artifactTypeId, connection);
1361  }
1362  connection.commitTransaction();
1363  } catch (SQLException ex) {
1364  connection.rollbackTransaction();
1365  throw new TskCoreException("Error adding blackboard attributes", ex);
1366  } finally {
1368  }
1369  }
1370 
1371  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
1372  PreparedStatement statement;
1373  switch (attr.getValueType()) {
1374  case STRING:
1375  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
1376  statement.clearParameters();
1377  statement.setString(7, escapeForBlackboard(attr.getValueString()));
1378  break;
1379  case BYTE:
1380  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
1381  statement.clearParameters();
1382  statement.setBytes(7, attr.getValueBytes());
1383  break;
1384  case INTEGER:
1385  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
1386  statement.clearParameters();
1387  statement.setInt(7, attr.getValueInt());
1388  break;
1389  case LONG:
1390  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
1391  statement.clearParameters();
1392  statement.setLong(7, attr.getValueLong());
1393  break;
1394  case DOUBLE:
1395  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
1396  statement.clearParameters();
1397  statement.setDouble(7, attr.getValueDouble());
1398  break;
1399  default:
1400  throw new TskCoreException("Unrecognized artifact attribute value type");
1401  }
1402  statement.setLong(1, attr.getArtifactID());
1403  statement.setInt(2, artifactTypeId);
1404  statement.setString(3, attr.getModuleName());
1405  statement.setString(4, attr.getContext());
1406  statement.setInt(5, attr.getAttributeTypeID());
1407  statement.setLong(6, attr.getValueType().getType());
1408  connection.executeUpdate(statement);
1409  }
1410 
1420  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
1421  CaseDbConnection connection = connections.getConnection();
1423  Statement s = null;
1424  ResultSet rs = null;
1425  try {
1426  connection.beginTransaction();
1427  s = connection.createStatement();
1428  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
1429  if (!rs.next()) {
1430  rs.close();
1431  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (type_name, display_name) VALUES ('" + attrTypeString + "', '" + displayName + "')"); //NON-NLS
1432  rs = s.getGeneratedKeys();
1433  }
1434  int type = rs.getInt(1);
1435  connection.commitTransaction();
1436  return type;
1437  } catch (SQLException ex) {
1438  connection.rollbackTransaction();
1439  throw new TskCoreException("Error adding attribute type", ex);
1440  } finally {
1441  closeResultSet(rs);
1442  closeStatement(s);
1444  }
1445  }
1446 
1455  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
1456  CaseDbConnection connection = connections.getConnection();
1458  Statement s = null;
1459  ResultSet rs = null;
1460  try {
1461  s = connection.createStatement();
1462  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
1463  int typeId = -1;
1464  if (rs.next()) {
1465  typeId = rs.getInt(1);
1466  }
1467  return typeId;
1468  } catch (SQLException ex) {
1469  throw new TskCoreException("Error getting attribute type id", ex);
1470  } finally {
1471  closeResultSet(rs);
1472  closeStatement(s);
1474  }
1475  }
1476 
1486  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
1487  CaseDbConnection connection = connections.getConnection();
1489  Statement s = null;
1490  ResultSet rs = null;
1491  try {
1492  s = connection.createStatement();
1493  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
1494  if (rs.next()) {
1495  return rs.getString(1);
1496  } else {
1497  throw new TskCoreException("No type with that id");
1498  }
1499  } catch (SQLException ex) {
1500  throw new TskCoreException("Error getting or creating a attribute type name", ex);
1501  } finally {
1502  closeResultSet(rs);
1503  closeStatement(s);
1505  }
1506  }
1507 
1517  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
1518  CaseDbConnection connection = connections.getConnection();
1520  Statement s = null;
1521  ResultSet rs = null;
1522  try {
1523  s = connection.createStatement();
1524  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
1525  if (rs.next()) {
1526  return rs.getString(1);
1527  } else {
1528  throw new TskCoreException("No type with that id");
1529  }
1530  } catch (SQLException ex) {
1531  throw new TskCoreException("Error getting or creating a attribute type name", ex);
1532  } finally {
1533  closeResultSet(rs);
1534  closeStatement(s);
1536  }
1537  }
1538 
1547  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
1548  CaseDbConnection connection = connections.getConnection();
1550  Statement s = null;
1551  ResultSet rs = null;
1552  try {
1553  s = connection.createStatement();
1554  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
1555  int typeId = -1;
1556  if (rs.next()) {
1557  typeId = rs.getInt(1);
1558  }
1559  return typeId;
1560  } catch (SQLException ex) {
1561  throw new TskCoreException("Error getting artifact type id", ex);
1562  } finally {
1563  closeResultSet(rs);
1564  closeStatement(s);
1566  }
1567  }
1568 
1578  String getArtifactTypeString(int artifactTypeID) throws TskCoreException {
1579  // TODO: This should return null, not throw an exception
1580  CaseDbConnection connection = connections.getConnection();
1582  Statement s = null;
1583  ResultSet rs = null;
1584  try {
1585  s = connection.createStatement();
1586  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artifactTypeID); //NON-NLS
1587  if (rs.next()) {
1588  return rs.getString(1);
1589  } else {
1590  throw new TskCoreException("Error getting artifact type name, artifact type id = " + artifactTypeID + " not found");
1591  }
1592  } catch (SQLException ex) {
1593  throw new TskCoreException("Error getting artifact type name, artifact type id = " + artifactTypeID, ex);
1594  } finally {
1595  closeResultSet(rs);
1596  closeStatement(s);
1598  }
1599  }
1600 
1611  String getArtifactTypeDisplayName(int artifactTypeID) throws TskCoreException {
1612  // TODO: This should return null, not throw an exception
1613  CaseDbConnection connection = connections.getConnection();
1615  Statement s = null;
1616  ResultSet rs = null;
1617  try {
1618  s = connection.createStatement();
1619  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artifactTypeID); //NON-NLS
1620  if (rs.next()) {
1621  return rs.getString(1);
1622  } else {
1623  throw new TskCoreException("Error getting artifact type display name, artifact type id = " + artifactTypeID + " not found");
1624  }
1625  } catch (SQLException ex) {
1626  throw new TskCoreException("Error getting artifact type display name, artifact type id = " + artifactTypeID, ex);
1627  } finally {
1628  closeResultSet(rs);
1629  closeStatement(s);
1631  }
1632  }
1633 
1644  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
1645  CaseDbConnection connection = connections.getConnection();
1647  Statement s = null;
1648  ResultSet rs = null;
1649  try {
1650  connection.beginTransaction();
1651  s = connection.createStatement();
1652  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
1653  if (!rs.next()) {
1654  rs.close();
1655  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (type_name, display_name) VALUES ('" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
1656  rs = s.getGeneratedKeys();
1657  }
1658  int id = rs.getInt(1);
1659  connection.commitTransaction();
1660  return id;
1661  } catch (SQLException ex) {
1662  connection.rollbackTransaction();
1663  throw new TskCoreException("Error adding artifact type", ex);
1664  } finally {
1665  closeResultSet(rs);
1666  closeStatement(s);
1668  }
1669  }
1670 
1671  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
1672  CaseDbConnection connection = connections.getConnection();
1674  ResultSet rs = null;
1675  try {
1676  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ATTRIBUTES_OF_ARTIFACT);
1677  statement.clearParameters();
1678  statement.setLong(1, artifact.getArtifactID());
1679  rs = connection.executeQuery(statement);
1680  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
1681  while (rs.next()) {
1682  final BlackboardAttribute attr = new BlackboardAttribute(
1683  rs.getLong(1),
1684  rs.getInt(4),
1685  rs.getString(2),
1686  rs.getString(3),
1688  rs.getInt(8),
1689  rs.getLong(9),
1690  rs.getDouble(10),
1691  rs.getString(7),
1692  rs.getBytes(6), this);
1693  attributes.add(attr);
1694  }
1695  return attributes;
1696  } catch (SQLException ex) {
1697  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
1698  } finally {
1699  closeResultSet(rs);
1701  }
1702  }
1703 
1714  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
1715  CaseDbConnection connection = connections.getConnection();
1717  Statement s = null;
1718  ResultSet rs = null;
1719  try {
1720  s = connection.createStatement();
1721  rs = connection.executeQuery(s, "Select artifact_id, source, context, attribute_type_id, value_type, " //NON-NLS
1722  + "value_byte, value_text, value_int32, value_int64, value_double FROM blackboard_attributes " + whereClause); //NON-NLS
1723  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
1724  while (rs.next()) {
1725  BlackboardAttribute attr = new BlackboardAttribute(rs.getLong("artifact_id"), rs.getInt("attribute_type_id"), rs.getString("source"), rs.getString("context"), //NON-NLS
1726  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getInt("value_type")), rs.getInt("value_int32"), rs.getLong("value_int64"), rs.getDouble("value_double"), //NON-NLS
1727  rs.getString("value_text"), rs.getBytes("value_byte"), this); //NON-NLS
1728  matches.add(attr);
1729  }
1730  return matches;
1731  } catch (SQLException ex) {
1732  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
1733  } finally {
1734  closeResultSet(rs);
1735  closeStatement(s);
1737  }
1738  }
1739 
1749  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
1750  CaseDbConnection connection = connections.getConnection();
1752  ResultSet rs = null;
1753  Statement s = null;
1754  try {
1755  s = connection.createStatement();
1756  rs = connection.executeQuery(s, "SELECT artifact_id, obj_id, artifact_type_id FROM blackboard_artifacts " + whereClause); //NON-NLS
1757  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
1758  while (rs.next()) {
1759  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong(1), rs.getLong(2), rs.getInt(3), this.getArtifactTypeString(rs.getInt(3)), this.getArtifactTypeDisplayName(rs.getInt(3)));
1760  matches.add(artifact);
1761  }
1762  return matches;
1763  } catch (SQLException ex) {
1764  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
1765  } finally {
1766  closeResultSet(rs);
1767  closeStatement(s);
1769  }
1770  }
1771 
1783  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
1784  return newBlackboardArtifact(artifactTypeID, obj_id, getArtifactTypeString(artifactTypeID), getArtifactTypeDisplayName(artifactTypeID));
1785  }
1786 
1796  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
1797  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
1798  }
1799 
1800  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
1801  CaseDbConnection connection = connections.getConnection();
1803  ResultSet rs = null;
1804  try {
1805  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_ARTIFACT);
1806  statement.clearParameters();
1807  statement.setLong(1, this.nextArtifactId++);
1808  statement.setLong(2, obj_id);
1809  statement.setInt(3, artifact_type_id);
1810  connection.executeUpdate(statement);
1811  rs = statement.getGeneratedKeys();
1812  return new BlackboardArtifact(this, rs.getLong(1), obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, true);
1813  } catch (SQLException ex) {
1814  throw new TskCoreException("Error creating a blackboard artifact", ex);
1815  } finally {
1816  closeResultSet(rs);
1818  }
1819  }
1820 
1831  boolean getContentHasChildren(Content content) throws TskCoreException {
1832  CaseDbConnection connection = connections.getConnection();
1834  ResultSet rs = null;
1835  try {
1836  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
1837  statement.clearParameters();
1838  statement.setLong(1, content.getId());
1839  rs = connection.executeQuery(statement);
1840  boolean hasChildren = false;
1841  if (rs.next()) {
1842  hasChildren = rs.getInt(1) > 0;
1843  }
1844  return hasChildren;
1845  } catch (SQLException e) {
1846  throw new TskCoreException("Error checking for children of parent " + content, e);
1847  } finally {
1848  closeResultSet(rs);
1850  }
1851  }
1852 
1863  int getContentChildrenCount(Content content) throws TskCoreException {
1864  CaseDbConnection connection = connections.getConnection();
1866  ResultSet rs = null;
1867  try {
1868  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
1869  statement.clearParameters();
1870  statement.setLong(1, content.getId());
1871  rs = connection.executeQuery(statement);
1872  int countChildren = -1;
1873  if (rs.next()) {
1874  countChildren = rs.getInt(1);
1875  }
1876  return countChildren;
1877  } catch (SQLException e) {
1878  throw new TskCoreException("Error checking for children of parent " + content, e);
1879  } finally {
1880  closeResultSet(rs);
1882  }
1883  }
1884 
1894  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
1895  CaseDbConnection connection = connections.getConnection();
1897  ResultSet rs = null;
1898  try {
1899  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
1900  statement.clearParameters();
1901  long parentId = parent.getId();
1902  statement.setLong(1, parentId);
1903  statement.setShort(2, type.getFileType());
1904  rs = connection.executeQuery(statement);
1905  return rsHelper.fileChildren(rs, parentId);
1906  } catch (SQLException ex) {
1907  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
1908  } finally {
1909  closeResultSet(rs);
1911  }
1912  }
1913 
1923  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
1924  CaseDbConnection connection = connections.getConnection();
1926  ResultSet rs = null;
1927  try {
1928  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
1929  statement.clearParameters();
1930  long parentId = parent.getId();
1931  statement.setLong(1, parentId);
1932  rs = connection.executeQuery(statement);
1933  return rsHelper.fileChildren(rs, parentId);
1934  } catch (SQLException ex) {
1935  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
1936  } finally {
1937  closeResultSet(rs);
1939  }
1940  }
1941 
1951  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
1952  CaseDbConnection connection = connections.getConnection();
1954  ResultSet rs = null;
1955  try {
1956  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
1957  statement.clearParameters();
1958  statement.setLong(1, parent.getId());
1959  statement.setShort(2, type.getFileType());
1960  rs = connection.executeQuery(statement);
1961  List<Long> children = new ArrayList<Long>();
1962  while (rs.next()) {
1963  children.add(rs.getLong(1));
1964  }
1965  return children;
1966  } catch (SQLException ex) {
1967  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
1968  } finally {
1969  closeResultSet(rs);
1971  }
1972  }
1973 
1981  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
1982  CaseDbConnection connection = connections.getConnection();
1984  ResultSet rs = null;
1985  try {
1986  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
1987  statement.clearParameters();
1988  statement.setLong(1, parent.getId());
1989  rs = connection.executeQuery(statement);
1990  List<Long> children = new ArrayList<Long>();
1991  while (rs.next()) {
1992  children.add(rs.getLong(1));
1993  }
1994  return children;
1995  } catch (SQLException ex) {
1996  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
1997  } finally {
1998  closeResultSet(rs);
2000  }
2001  }
2002 
2006  static class ObjectInfo {
2007 
2008  long id;
2009  TskData.ObjectType type;
2010 
2011  ObjectInfo(long id, ObjectType type) {
2012  this.id = id;
2013  this.type = type;
2014  }
2015  }
2016 
2025  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
2026  CaseDbConnection connection = connections.getConnection();
2028  Statement s = null;
2029  ResultSet rs = null;
2030  try {
2031  s = connection.createStatement();
2032  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id, tsk_objects.type " //NON-NLS
2033  + "FROM tsk_objects left join tsk_files " //NON-NLS
2034  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
2035  + "WHERE tsk_objects.par_obj_id = " + c.getId()); //NON-NLS
2036  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
2037  while (rs.next()) {
2038  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
2039  }
2040  return infos;
2041  } catch (SQLException ex) {
2042  throw new TskCoreException("Error getting Children Info for Content", ex);
2043  } finally {
2044  closeResultSet(rs);
2045  closeStatement(s);
2047  }
2048  }
2049 
2058  ObjectInfo getParentInfo(Content c) throws TskCoreException {
2059  // TODO: This should not throw an exception if Content has no parent,
2060  // return null instead.
2061  CaseDbConnection connection = connections.getConnection();
2063  Statement s = null;
2064  ResultSet rs = null;
2065  try {
2066  s = connection.createStatement();
2067  rs = connection.executeQuery(s, "SELECT parent.obj_id, parent.type " //NON-NLS
2068  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
2069  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
2070  + "WHERE child.obj_id = " + c.getId()); //NON-NLS
2071  if (rs.next()) {
2072  return new ObjectInfo(rs.getLong(1), ObjectType.valueOf(rs.getShort(2)));
2073  } else {
2074  throw new TskCoreException("Given content (id: " + c.getId() + ") has no parent");
2075  }
2076  } catch (SQLException ex) {
2077  throw new TskCoreException("Error getting Parent Info for Content", ex);
2078  } finally {
2079  closeResultSet(rs);
2080  closeStatement(s);
2082  }
2083  }
2084 
2093  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
2094  // TODO: This should not throw an exception if Content has no parent,
2095  // return null instead.
2096  CaseDbConnection connection = connections.getConnection();
2098  Statement s = null;
2099  ResultSet rs = null;
2100  try {
2101  s = connection.createStatement();
2102  rs = connection.executeQuery(s, "SELECT parent.obj_id, parent.type " //NON-NLS
2103  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
2104  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
2105  + "WHERE child.obj_id = " + contentId); //NON-NLS
2106  if (rs.next()) {
2107  return new ObjectInfo(rs.getLong(1), ObjectType.valueOf(rs.getShort(2)));
2108  } else {
2109  throw new TskCoreException("Given content (id: " + contentId + ") has no parent.");
2110  }
2111  } catch (SQLException ex) {
2112  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
2113  } finally {
2114  closeResultSet(rs);
2115  closeStatement(s);
2117  }
2118  }
2119 
2128  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
2129  // TODO: This should not throw an exception if Content has no parent,
2130  // return null instead.
2131  if (fsc.isRoot()) {
2132  throw new TskCoreException("Given FsContent (id: " + fsc.getId() + ") is a root object (can't have parent directory).");
2133  } else {
2134  ObjectInfo parentInfo = getParentInfo(fsc);
2135  Directory parent = null;
2136  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
2137  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
2138  } else {
2139  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
2140  }
2141  return parent;
2142  }
2143  }
2144 
2154  public Content getContentById(long id) throws TskCoreException {
2155  CaseDbConnection connection = connections.getConnection();
2157  Statement s = null;
2158  ResultSet rs = null;
2159  try {
2160  s = connection.createStatement();
2161  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
2162  if (!rs.next()) {
2163  return null;
2164  }
2165 
2166  AbstractContent content = null;
2167  long parentId = rs.getLong("par_obj_id"); //NON-NLS
2168  final TskData.ObjectType type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
2169  switch (type) {
2170  case IMG:
2171  content = getImageById(id);
2172  break;
2173  case VS:
2174  content = getVolumeSystemById(id, parentId);
2175  break;
2176  case VOL:
2177  content = getVolumeById(id, parentId);
2178  break;
2179  case FS:
2180  content = getFileSystemById(id, parentId);
2181  break;
2182  case ABSTRACTFILE:
2183  content = getAbstractFileById(id);
2184  break;
2185  default:
2186  throw new TskCoreException("Could not obtain Content object with ID: " + id);
2187  }
2188  return content;
2189  } catch (SQLException ex) {
2190  throw new TskCoreException("Error getting Content by ID.", ex);
2191  } finally {
2192  closeResultSet(rs);
2193  closeStatement(s);
2195  }
2196  }
2197 
2204  String getFilePath(long id) {
2205  CaseDbConnection connection;
2206  try {
2207  connection = connections.getConnection();
2208  } catch (TskCoreException ex) {
2209  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
2210  return null;
2211  }
2212  String filePath = null;
2214  ResultSet rs = null;
2215  try {
2216  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
2217  statement.clearParameters();
2218  statement.setLong(1, id);
2219  rs = connection.executeQuery(statement);
2220  if (rs.next()) {
2221  filePath = rs.getString(1);
2222  }
2223  } catch (SQLException ex) {
2224  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
2225  } finally {
2226  closeResultSet(rs);
2228  }
2229  return filePath;
2230  }
2231 
2238  String getFileParentPath(long id) {
2239  CaseDbConnection connection;
2240  try {
2241  connection = connections.getConnection();
2242  } catch (TskCoreException ex) {
2243  logger.log(Level.SEVERE, "Error getting parent file path for file " + id, ex); //NON-NLS
2244  return null;
2245  }
2246  String parentPath = null;
2248  ResultSet rs = null;
2249  try {
2250  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
2251  statement.clearParameters();
2252  statement.setLong(1, id);
2253  rs = connection.executeQuery(statement);
2254  if (rs.next()) {
2255  parentPath = rs.getString(1);
2256  }
2257  } catch (SQLException ex) {
2258  logger.log(Level.SEVERE, "Error getting file parent_path for file " + id, ex); //NON-NLS
2259  } finally {
2260  closeResultSet(rs);
2262  }
2263  return parentPath;
2264  }
2265 
2272  String getFileName(long id) {
2273  CaseDbConnection connection;
2274  try {
2275  connection = connections.getConnection();
2276  } catch (TskCoreException ex) {
2277  logger.log(Level.SEVERE, "Error getting file name for file " + id, ex); //NON-NLS
2278  return null;
2279  }
2280  String fileName = null;
2282  ResultSet rs = null;
2283  try {
2284  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_NAME);
2285  statement.clearParameters();
2286  statement.setLong(1, id);
2287  rs = connection.executeQuery(statement);
2288  if (rs.next()) {
2289  fileName = rs.getString(1);
2290  }
2291  } catch (SQLException ex) {
2292  logger.log(Level.SEVERE, "Error getting file parent_path for file " + id, ex); //NON-NLS
2293  } finally {
2294  closeResultSet(rs);
2296  }
2297  return fileName;
2298  }
2299 
2308  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
2309  CaseDbConnection connection = connections.getConnection();
2310  DerivedFile.DerivedMethod method = null;
2312  ResultSet rs1 = null;
2313  ResultSet rs2 = null;
2314  try {
2315  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_DERIVED_FILE);
2316  statement.clearParameters();
2317  statement.setLong(1, id);
2318  rs1 = connection.executeQuery(statement);
2319  if (rs1.next()) {
2320  int method_id = rs1.getInt(1);
2321  String rederive = rs1.getString(1);
2322  method = new DerivedFile.DerivedMethod(method_id, rederive);
2323  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
2324  statement.clearParameters();
2325  statement.setInt(1, method_id);
2326  rs2 = connection.executeQuery(statement);
2327  if (rs2.next()) {
2328  method.setToolName(rs2.getString(1));
2329  method.setToolVersion(rs2.getString(2));
2330  method.setOther(rs2.getString(3));
2331  }
2332  }
2333  } catch (SQLException e) {
2334  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
2335  } finally {
2336  closeResultSet(rs2);
2337  closeResultSet(rs1);
2339  }
2340  return method;
2341  }
2342 
2352  CaseDbConnection connection = connections.getConnection();
2354  ResultSet rs = null;
2355  try {
2356  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_BY_ID);
2357  statement.clearParameters();
2358  statement.setLong(1, id);
2359  rs = connection.executeQuery(statement);
2360  List<AbstractFile> results;
2361  if ((results = resultSetToAbstractFiles(rs)).size() > 0) {
2362  return results.get(0);
2363  } else {
2364  return null;
2365  }
2366  } catch (SQLException ex) {
2367  throw new TskCoreException("Error getting file by id, id = " + id, ex);
2368  } finally {
2369  closeResultSet(rs);
2371  }
2372  }
2373 
2384  private long getFileSystemId(long fileId) {
2385  CaseDbConnection connection;
2386  try {
2387  connection = connections.getConnection();
2388  } catch (TskCoreException ex) {
2389  logger.log(Level.SEVERE, "Error getting file system id for file " + fileId, ex); //NON-NLS
2390  return -1;
2391  }
2393  ResultSet rs = null;
2394  long ret = -1;
2395  try {
2396  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
2397  statement.clearParameters();
2398  statement.setLong(1, fileId);
2399  rs = connection.executeQuery(statement);
2400  if (rs.next()) {
2401  ret = rs.getLong(1);
2402  if (ret == 0) {
2403  ret = -1;
2404  }
2405  }
2406  } catch (SQLException e) {
2407  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
2408  } finally {
2409  closeResultSet(rs);
2411  }
2412  return ret;
2413  }
2414 
2424  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
2425  if (dataSource.getParent() != null) {
2426  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.isFileFromSource.exception.msg.text"), dataSource);
2427  logger.log(Level.SEVERE, msg);
2428  throw new IllegalArgumentException(msg);
2429  }
2430 
2431  //get fs_id for file id
2432  long fsId = getFileSystemId(fileId);
2433  if (fsId == -1) {
2434  return false;
2435  }
2436 
2437  //if image, check if one of fs in data source
2438  if (dataSource instanceof Image) {
2439  Collection<FileSystem> fss = getFileSystems((Image) dataSource);
2440  for (FileSystem fs : fss) {
2441  if (fs.getId() == fsId) {
2442  return true;
2443  }
2444  }
2445  return false;
2446  } //if VirtualDirectory, check if dataSource id is the fs_id
2447  else if (dataSource instanceof VirtualDirectory) {
2448  //fs_obj_id is not a real fs in this case
2449  //we are currently using this field internally to get to data source of non-fs files quicker
2450  //this will be fixed in 2.5 schema
2451  return dataSource.getId() == fsId;
2452  } else {
2453  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.isFileFromSource.exception.msg2.text"), dataSource);
2454  logger.log(Level.SEVERE, msg);
2455  throw new IllegalArgumentException(msg);
2456  }
2457  }
2458 
2468  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
2469  if (dataSource.getParent() != null) {
2470  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.isFileFromSource.exception.msg1.text"), dataSource);
2471  logger.log(Level.SEVERE, msg);
2472  throw new IllegalArgumentException(msg);
2473  }
2474 
2475  List<AbstractFile> files = new ArrayList<AbstractFile>();
2476  CaseDbConnection connection = connections.getConnection();
2478  ResultSet rs = null;
2479  try {
2480  if (dataSource instanceof Image) {
2481  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILES_BY_FILE_SYSTEM_AND_NAME);
2482 
2483  for (FileSystem fileSystem : getFileSystems((Image) dataSource)) {
2484  statement.clearParameters();
2485  statement.setString(1, fileName.toLowerCase());
2486  statement.setLong(2, fileSystem.getId());
2487  rs = connection.executeQuery(statement);
2488  files.addAll(resultSetToAbstractFiles(rs));
2489  }
2490  } else if (dataSource instanceof VirtualDirectory) {
2491  // A future database schema could probably make this cleaner.
2492  // fs_obj_id is set only for file system files.
2493  // We will match the VirtualDirectory's name in the parent path
2494  Statement s = connection.createStatement();
2495  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE LOWER(name) LIKE '" + fileName.toLowerCase() + "' and LOWER(name) NOT LIKE '%journal%' AND parent_path LIKE '/" + dataSource.getName() + "/%'"); //NON-NLS
2496  files = resultSetToAbstractFiles(rs);
2497  } else {
2498  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.findFiles.exception.msg2.text"), dataSource);
2499  logger.log(Level.SEVERE, msg);
2500  throw new IllegalArgumentException(msg);
2501  }
2502  } catch (SQLException e) {
2503  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
2504  } finally {
2505  closeResultSet(rs);
2507  }
2508  return files;
2509  }
2510 
2522  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirName) throws TskCoreException {
2523  if (dataSource.getParent() != null) {
2524  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.findFiles3.exception.msg1.text"), dataSource);
2525  logger.log(Level.SEVERE, msg);
2526  throw new IllegalArgumentException(msg);
2527  }
2528 
2529  List<AbstractFile> files = new ArrayList<AbstractFile>();
2530  CaseDbConnection connection = connections.getConnection();
2532  ResultSet rs = null;
2533  try {
2534  if (dataSource instanceof Image) {
2535  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_FILES_BY_FILE_SYSTEM_AND_PATH);
2536 
2537  for (FileSystem fileSystem : getFileSystems((Image) dataSource)) {
2538  statement.clearParameters();
2539  statement.setString(1, fileName.toLowerCase());
2540  statement.setString(2, "%" + dirName.toLowerCase() + "%"); //NON-NLS
2541  statement.setLong(3, fileSystem.getId());
2542  rs = connection.executeQuery(statement);
2543  files.addAll(resultSetToAbstractFiles(rs));
2544  }
2545  } else if (dataSource instanceof VirtualDirectory) {
2546  // A future database schema could probably make this cleaner.
2547  // fs_obj_id is set only for file system files.
2548  // We will match the VirtualDirectory's name in the parent path
2549  Statement s = connection.createStatement();
2550  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE LOWER(name) LIKE '" + fileName.toLowerCase() + "' and LOWER(name) NOT LIKE '%journal%' AND parent_path LIKE '/" + dataSource.getName() + "/%' AND lower(parent_path) LIKE '%" + dirName.toLowerCase() + "%'"); //NON-NLS
2551  files = resultSetToAbstractFiles(rs);
2552  } else {
2553  final String msg = MessageFormat.format(bundle.getString("SleuthkitCase.findFiles3.exception.msg2.text"), dataSource);
2554  logger.log(Level.SEVERE, msg);
2555  throw new IllegalArgumentException(msg);
2556  }
2557  } catch (SQLException e) {
2558  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
2559  } finally {
2560  if (rs != null) {
2561  try {
2562  rs.close();
2563  } catch (SQLException ex) {
2564  logger.log(Level.WARNING, "Error closing result set after finding files", ex); //NON-NLS
2565  }
2566  }
2568  }
2569  return files;
2570  }
2571 
2581  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
2583  CaseDbTransaction localTrans = beginTransaction();
2584  try {
2585  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
2586  localTrans.commit();
2587  return newVD;
2588  } catch (TskCoreException ex) {
2589  localTrans.rollback();
2590  throw ex;
2591  } finally {
2593  }
2594  }
2595 
2608  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction trans) throws TskCoreException {
2609  if (trans == null) {
2610  throw new TskCoreException("Passed null CaseDbTransaction");
2611  }
2612 
2614  ResultSet resultSet = null;
2615  try {
2616  // Get the parent path.
2617  String parentPath = getFileParentPath(parentId);
2618  if (parentPath == null) {
2619  parentPath = "/"; //NON-NLS
2620  }
2621  String parentName = getFileName(parentId);
2622  if (parentName != null) {
2623  parentPath = parentPath + parentName + "/"; //NON-NLS
2624  }
2625 
2626  // Insert a row for the virtual directory into the tsk_objects table.
2627  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
2628  CaseDbConnection connection = trans.getConnection();
2629  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_OBJECT);
2630  statement.clearParameters();
2631  if (parentId != 0) {
2632  statement.setLong(1, parentId);
2633  }
2634  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
2635  connection.executeUpdate(statement);
2636  resultSet = statement.getGeneratedKeys();
2637  long newObjId = resultSet.getLong(1);
2638 
2639  // Insert a row for the virtual directory into the tsk_files table.
2640  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
2641  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path)
2642  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2643  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_FILE);
2644  statement.clearParameters();
2645  statement.setLong(1, newObjId);
2646 
2647  // If the parent is part of a file system, grab its file system ID
2648  long parentFs = this.getFileSystemId(parentId);
2649  if (parentFs != -1) {
2650  statement.setLong(2, parentFs);
2651  }
2652  statement.setString(3, directoryName);
2653 
2654  //type, has_path
2655  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
2656  statement.setBoolean(5, true);
2657 
2658  //flags
2660  statement.setShort(6, dirType.getValue());
2662  statement.setShort(7, metaType.getValue());
2663 
2664  //note: using alloc under assumption that derived files derive from alloc files
2666  statement.setShort(8, dirFlag.getValue());
2667  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
2668  | TSK_FS_META_FLAG_ENUM.USED.getValue());
2669  statement.setShort(9, metaFlags);
2670 
2671  //size
2672  long size = 0;
2673  statement.setLong(10, size);
2674 
2675  //parent path, nulls for params 11-14
2676  statement.setString(15, parentPath);
2677 
2678  connection.executeUpdate(statement);
2679 
2680  return new VirtualDirectory(this, newObjId, directoryName, dirType,
2681  metaType, dirFlag, metaFlags, size, null, FileKnown.UNKNOWN,
2682  parentPath);
2683  } catch (SQLException e) {
2684  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
2685  } finally {
2686  closeResultSet(resultSet);
2688  }
2689  }
2690 
2698  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
2699  CaseDbConnection connection = connections.getConnection();
2701  Statement s = null;
2702  ResultSet rs = null;
2703  try {
2704  s = connection.createStatement();
2705  rs = connection.executeQuery(s, "SELECT tsk_files.* FROM tsk_objects, tsk_files WHERE " //NON-NLS
2706  + "tsk_objects.par_obj_id IS NULL AND " //NON-NLS
2707  + "tsk_objects.type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + " AND " //NON-NLS
2708  + "tsk_objects.obj_id = tsk_files.obj_id AND " //NON-NLS
2709  + "tsk_files.type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
2710  + " ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"); //NON-NLS
2711  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
2712  while (rs.next()) {
2713  virtDirRootIds.add(rsHelper.virtualDirectory(rs));
2714  }
2715  return virtDirRootIds;
2716  } catch (SQLException ex) {
2717  throw new TskCoreException("Error getting local files virtual folder id", ex);
2718  } finally {
2719  closeResultSet(rs);
2720  closeStatement(s);
2722  }
2723  }
2724 
2738  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
2739 
2740  List<CarvedFileContainer> carvedFileContainer = new ArrayList<CarvedFileContainer>();
2741  carvedFileContainer.add(new CarvedFileContainer(carvedFileName, carvedFileSize, containerId, data));
2742 
2743  List<LayoutFile> layoutCarvedFiles = addCarvedFiles(carvedFileContainer);
2744  if (layoutCarvedFiles != null) {
2745  return layoutCarvedFiles.get(0);
2746  } else {
2747  return null;
2748  }
2749  }
2750 
2762  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
2763  if (filesToAdd != null && filesToAdd.isEmpty() == false) {
2764  List<LayoutFile> addedFiles = new ArrayList<LayoutFile>();
2765  CaseDbTransaction localTrans = null;
2766  Statement s = null;
2767  ResultSet rs = null;
2769  try {
2770  localTrans = beginTransaction();
2771  CaseDbConnection connection = localTrans.getConnection();
2772 
2773  // get the ID of the appropriate '$CarvedFiles' directory
2774  long firstItemId = filesToAdd.get(0).getId();
2775  long id = 0;
2776  // first, check the cache
2777  Long carvedDirId = carvedFileContainersCache.get(firstItemId);
2778  if (carvedDirId != null) {
2779  id = carvedDirId;
2780  } else {
2781  // it's not in the cache. Go to the DB
2782  // determine if we've got a volume system or file system ID
2783  Content parent = getContentById(firstItemId);
2784  if (parent == null) {
2785  throw new TskCoreException("No Content object found with this ID (" + firstItemId + ").");
2786  }
2787 
2788  List<Content> children = Collections.<Content>emptyList();
2789  if (parent instanceof FileSystem) {
2790  FileSystem fs = (FileSystem) parent;
2791  children = fs.getRootDirectory().getChildren();
2792  } else if (parent instanceof Volume
2793  || parent instanceof Image) {
2794  children = parent.getChildren();
2795  } else {
2796  throw new TskCoreException("The given ID (" + firstItemId + ") was not an image, volume or file system.");
2797  }
2798 
2799  // see if any of the children are a '$CarvedFiles' directory
2800  Content carvedFilesDir = null;
2801  for (Content child : children) {
2802  if (child.getName().equals(VirtualDirectory.NAME_CARVED)) {
2803  carvedFilesDir = child;
2804  break;
2805  }
2806  }
2807 
2808  // if we found it, add it to the cache and grab its ID
2809  if (carvedFilesDir != null) {
2810  // add it to the cache
2811  carvedFileContainersCache.put(firstItemId, carvedFilesDir.getId());
2812  id = carvedFilesDir.getId();
2813  } else {
2814  // a carved files directory does not exist; create one
2815  VirtualDirectory vd = addVirtualDirectory(firstItemId, VirtualDirectory.NAME_CARVED, localTrans);
2816  id = vd.getId();
2817  // add it to the cache
2818  carvedFileContainersCache.put(firstItemId, id);
2819  }
2820  }
2821 
2822  // get the parent path for the $CarvedFiles directory
2823  String parentPath = getFileParentPath(id);
2824  if (parentPath == null) {
2825  parentPath = "/"; //NON-NLS
2826  }
2827  String parentName = getFileName(id);
2828  if (parentName != null) {
2829  parentPath = parentPath + parentName + "/"; //NON-NLS
2830  }
2831 
2832  // we should cache this when we start adding lots of carved files...
2833  boolean isContainerAFs = false;
2834  s = connection.createStatement();
2835  rs = connection.executeQuery(s, "select * from tsk_fs_info " //NON-NLS
2836  + "where obj_id = " + firstItemId); //NON-NLS
2837  if (rs.next()) {
2838  isContainerAFs = true;
2839  }
2840  rs.close();
2841  rs = null;
2842 
2843  for (CarvedFileContainer itemToAdd : filesToAdd) {
2844 
2845  // Insert a row for the carved file into the tsk_objects table.
2846  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
2847  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_OBJECT);
2848  statement.clearParameters();
2849  statement.setLong(1, id);
2850  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
2851  connection.executeUpdate(statement);
2852  rs = statement.getGeneratedKeys();
2853  long newObjId = rs.getLong(1);
2854 
2855  // Insert a row for the carved file into the tsk_files table.
2856  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
2857  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path)
2858  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2859  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_FILE);
2860  statement.clearParameters();
2861  statement.setLong(1, newObjId);
2862 
2863  // only insert into the fs_obj_id column if container is a FS
2864  if (isContainerAFs) {
2865  statement.setLong(2, itemToAdd.getId());
2866  }
2867  statement.setString(3, itemToAdd.getName());
2868 
2869  // type
2871  statement.setShort(4, type.getFileType());
2872 
2873  // has_path
2874  statement.setBoolean(5, true);
2875 
2876  // dirType
2878  statement.setShort(6, dirType.getValue());
2879 
2880  // metaType
2882  statement.setShort(7, metaType.getValue());
2883 
2884  // dirFlag
2886  statement.setShort(8, dirFlag.getValue());
2887 
2888  // metaFlags
2889  final short metaFlags = TSK_FS_META_FLAG_ENUM.UNALLOC.getValue();
2890  statement.setShort(9, metaFlags);
2891 
2892  // size
2893  statement.setLong(10, itemToAdd.getSize());
2894 
2895  //parent path, nulls for params 11-14
2896  statement.setString(15, parentPath);
2897 
2898  connection.executeUpdate(statement);
2899 
2900  // Add a row in the tsk_layout_file table for each TskFileRange.
2901  // INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence)
2902  // VALUES (?, ?, ?, ?)
2903  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
2904  for (TskFileRange tskFileRange : itemToAdd.getRanges()) {
2905  statement.clearParameters();
2906 
2907  // set the object ID
2908  statement.setLong(1, newObjId);
2909 
2910  // set byte_start
2911  statement.setLong(2, tskFileRange.getByteStart());
2912 
2913  // set byte_len
2914  statement.setLong(3, tskFileRange.getByteLen());
2915 
2916  // set the sequence number
2917  statement.setLong(4, tskFileRange.getSequence());
2918 
2919  // execute it
2920  connection.executeUpdate(statement);
2921  }
2922 
2923  addedFiles.add(new LayoutFile(this, newObjId, itemToAdd.getName(),
2924  type, dirType, metaType, dirFlag, metaFlags,
2925  itemToAdd.getSize(), null, FileKnown.UNKNOWN, parentPath));
2926  }
2927  localTrans.commit();
2928  return addedFiles;
2929  } catch (SQLException ex) {
2930  if (null != localTrans) {
2931  localTrans.rollback();
2932  }
2933  throw new TskCoreException("Failed to add carved file to case database", ex);
2934  } finally {
2935  closeResultSet(rs);
2936  closeStatement(s);
2938  }
2939  } else {
2940  return Collections.emptyList();
2941  }
2942  }
2943 
2968  public DerivedFile addDerivedFile(String fileName, String localPath,
2969  long size, long ctime, long crtime, long atime, long mtime,
2970  boolean isFile, AbstractFile parentFile,
2971  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
2972  CaseDbConnection connection = connections.getConnection();
2974  ResultSet rs = null;
2975  try {
2976  connection.beginTransaction();
2977 
2978  final long parentId = parentFile.getId();
2979  final String parentPath = parentFile.getParentPath() + parentFile.getName() + '/'; //NON-NLS
2980 
2981  // Insert a row for the derived file into the tsk_objects table.
2982  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
2983  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_OBJECT);
2984  statement.clearParameters();
2985  statement.setLong(1, parentId);
2986  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
2987  connection.executeUpdate(statement);
2988  rs = statement.getGeneratedKeys();
2989  long newObjId = rs.getLong(1);
2990  rs.close();
2991  rs = null;
2992 
2993  // Insert a row for the virtual directory into the tsk_files table.
2994  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
2995  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path)
2996  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2997  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_FILE);
2998  statement.clearParameters();
2999  statement.setLong(1, newObjId);
3000 
3001  // If the parentFile is part of a file system, use its file system object ID.
3002  long fsObjId = this.getFileSystemId(parentId);
3003  if (fsObjId != -1) {
3004  statement.setLong(2, fsObjId);
3005  }
3006  statement.setString(3, fileName);
3007 
3008  //type, has_path
3009  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
3010  statement.setBoolean(5, true);
3011 
3012  //flags
3014  statement.setShort(6, dirType.getValue());
3016  statement.setShort(7, metaType.getValue());
3017 
3018  //note: using alloc under assumption that derived files derive from alloc files
3020  statement.setShort(8, dirFlag.getValue());
3021  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3022  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3023  statement.setShort(9, metaFlags);
3024 
3025  //size
3026  statement.setLong(10, size);
3027 
3028  //mactimes
3029  //long ctime, long crtime, long atime, long mtime,
3030  statement.setLong(11, ctime);
3031  statement.setLong(12, crtime);
3032  statement.setLong(13, atime);
3033  statement.setLong(14, mtime);
3034 
3035  //parent path
3036  statement.setString(15, parentPath);
3037 
3038  connection.executeUpdate(statement);
3039 
3040  //add localPath
3041  addFilePath(connection, newObjId, localPath);
3042 
3043  connection.commitTransaction();
3044 
3045  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
3046  return new DerivedFile(this, newObjId, fileName, dirType, metaType, dirFlag, metaFlags,
3047  size, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId);
3048  } catch (SQLException ex) {
3049  connection.rollbackTransaction();
3050  throw new TskCoreException("Failed to add derived file to case database", ex);
3051  } finally {
3052  closeResultSet(rs);
3054  }
3055  }
3056 
3074  public LocalFile addLocalFile(String fileName, String localPath,
3075  long size, long ctime, long crtime, long atime, long mtime,
3076  boolean isFile, AbstractFile parent) throws TskCoreException {
3078  CaseDbTransaction localTrans = beginTransaction();
3079  try {
3080  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parent, localTrans);
3081  localTrans.commit();
3082  return created;
3083  } catch (TskCoreException ex) {
3084  localTrans.rollback();
3085  throw ex;
3086  } finally {
3088  }
3089  }
3090 
3116  public LocalFile addLocalFile(String fileName, String localPath,
3117  long size, long ctime, long crtime, long atime, long mtime,
3118  boolean isFile, AbstractFile parent, CaseDbTransaction trans) throws TskCoreException {
3119  if (trans == null) {
3120  throw new TskCoreException("Passed null CaseDbTransaction");
3121  }
3122 
3124  ResultSet resultSet = null;
3125  try {
3126  long parentId = -1;
3127  String parentPath;
3128  if (parent == null) {
3129  throw new TskCoreException(MessageFormat.format(bundle.getString("SleuthkitCase.addLocalFile.exception.msg1.text"), fileName));
3130  } else {
3131  parentId = parent.getId();
3132  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
3133  }
3134 
3135  // Insert a row for the local/logical file into the tsk_objects table.
3136  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
3137  CaseDbConnection connection = connections.getConnection();
3138  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_OBJECT);
3139  statement.clearParameters();
3140  statement.setLong(1, parentId);
3141  statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
3142  connection.executeUpdate(statement);
3143  resultSet = statement.getGeneratedKeys();
3144  long newObjId = resultSet.getLong(1);
3145  resultSet.close();
3146  resultSet = null;
3147 
3148  // Insert a row for the local/logical file into the tsk_files table.
3149  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
3150  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path)
3151  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3152  statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_FILE);
3153  statement.clearParameters();
3154  statement.setLong(1, newObjId);
3155 
3156  // nothing to set for parameter 2, fs_obj_id since local files aren't part of file systems
3157  statement.setString(3, fileName);
3158 
3159  //type, has_path
3160  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
3161  statement.setBoolean(5, true);
3162 
3163  //flags
3165  statement.setShort(6, dirType.getValue());
3167  statement.setShort(7, metaType.getValue());
3168 
3169  //note: using alloc under assumption that derived files derive from alloc files
3171  statement.setShort(8, dirFlag.getValue());
3172  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3173  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3174  statement.setShort(9, metaFlags);
3175 
3176  //size
3177  statement.setLong(10, size);
3178 
3179  //mactimes
3180  //long ctime, long crtime, long atime, long mtime,
3181  statement.setLong(11, ctime);
3182  statement.setLong(12, crtime);
3183  statement.setLong(13, atime);
3184  statement.setLong(14, mtime);
3185 
3186  //parent path
3187  statement.setString(15, parentPath);
3188 
3189  connection.executeUpdate(statement);
3190 
3191  //add localPath
3192  addFilePath(connection, newObjId, localPath);
3193 
3194  return new LocalFile(this, newObjId, fileName, dirType, metaType, dirFlag, metaFlags,
3195  size, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId);
3196  } catch (SQLException e) {
3197  throw new TskCoreException("Error adding local file directory " + fileName + " with local path " + localPath, e);
3198  } finally {
3199  closeResultSet(resultSet);
3201  }
3202  }
3203 
3212  private void addFilePath(CaseDbConnection connection, long objId, String path) throws SQLException {
3213  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_LOCAL_PATH);
3214  statement.clearParameters();
3215  statement.setLong(1, objId);
3216  statement.setString(2, path);
3217  connection.executeUpdate(statement);
3218  }
3219 
3231  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
3232  return findFiles(dataSource, fileName, parentFile.getName());
3233  }
3234 
3243  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
3244  CaseDbConnection connection = connections.getConnection();
3246  Statement s = null;
3247  ResultSet rs = null;
3248  try {
3249  s = connection.createStatement();
3250  rs = connection.executeQuery(s, "SELECT COUNT (*) FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
3251  return rs.getLong(1);
3252  } catch (SQLException e) {
3253  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
3254  } finally {
3255  closeResultSet(rs);
3256  closeStatement(s);
3258  }
3259  }
3260 
3272  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
3273  CaseDbConnection connection = connections.getConnection();
3275  Statement s = null;
3276  ResultSet rs = null;
3277  try {
3278  s = connection.createStatement();
3279  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
3280  return resultSetToAbstractFiles(rs);
3281  } catch (SQLException e) {
3282  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
3283  } finally {
3284  closeResultSet(rs);
3285  closeStatement(s);
3287  }
3288  }
3289 
3299  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
3300  CaseDbConnection connection = connections.getConnection();
3302  Statement s = null;
3303  ResultSet rs = null;
3304  try {
3305  s = connection.createStatement();
3306  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
3307  List<Long> ret = new ArrayList<Long>();
3308  while (rs.next()) {
3309  ret.add(rs.getLong(1));
3310  }
3311  return ret;
3312  } catch (SQLException e) {
3313  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
3314  } finally {
3315  closeResultSet(rs);
3316  closeStatement(s);
3318  }
3319  }
3320 
3331  @Deprecated
3332  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
3333  CaseDbConnection connection = connections.getConnection();
3335  Statement s = null;
3336  ResultSet rs = null;
3337  try {
3338  s = connection.createStatement();
3339  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
3340  return resultSetToFsContents(rs);
3341  } catch (SQLException e) {
3342  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
3343  } finally {
3344  closeResultSet(rs);
3345  closeStatement(s);
3347  }
3348  }
3349 
3358  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
3359 
3360  // get the non-unique path (strip of image and volume path segments, if
3361  // the exist.
3362  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
3363 
3364  // split the file name from the parent path
3365  int lastSlash = path.lastIndexOf("/"); //NON-NLS
3366 
3367  // if the last slash is at the end, strip it off
3368  if (lastSlash == path.length()) {
3369  path = path.substring(0, lastSlash - 1);
3370  lastSlash = path.lastIndexOf("/"); //NON-NLS
3371  }
3372 
3373  String parentPath = path.substring(0, lastSlash);
3374  String fileName = path.substring(lastSlash);
3375 
3376  return findFiles(dataSource, fileName, parentPath);
3377  }
3378 
3387  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
3388  CaseDbConnection connection = connections.getConnection();
3390  Statement s = null;
3391  ResultSet rs = null;
3392  try {
3393  s = connection.createStatement();
3394  rs = connection.executeQuery(s, "select * from tsk_file_layout where obj_id = " + id + " order by sequence");
3395  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
3396  while (rs.next()) {
3397  ranges.add(rsHelper.tskFileRange(rs));
3398  }
3399  return ranges;
3400  } catch (SQLException ex) {
3401  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
3402  } finally {
3403  closeResultSet(rs);
3404  closeStatement(s);
3406  }
3407  }
3408 
3417  public Image getImageById(long id) throws TskCoreException {
3418  CaseDbConnection connection = connections.getConnection();
3420  Statement s1 = null;
3421  ResultSet rs1 = null;
3422  Statement s2 = null;
3423  ResultSet rs2 = null;
3424  try {
3425  s1 = connection.createStatement();
3426  rs1 = connection.executeQuery(s1, "SELECT * FROM tsk_image_info WHERE obj_id = " + id); //NON-NLS
3427  if (rs1.next()) {
3428  s2 = connection.createStatement();
3429  rs2 = connection.executeQuery(s2, "select * from tsk_image_names where obj_id = " + rs1.getLong("obj_id")); //NON-NLS
3430  List<String> imagePaths = new ArrayList<String>();
3431  while (rs2.next()) {
3432  imagePaths.add(rsHelper.imagePath(rs2));
3433  }
3434  return rsHelper.image(rs1, imagePaths.toArray(new String[imagePaths.size()]));
3435  } else {
3436  throw new TskCoreException("No image found for id: " + id);
3437  }
3438  } catch (SQLException ex) {
3439  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
3440  } finally {
3441  closeResultSet(rs2);
3442  closeStatement(s2);
3443  closeResultSet(rs1);
3444  closeStatement(s1);
3446  }
3447  }
3448 
3458  VolumeSystem getVolumeSystemById(long id, Image parent) throws TskCoreException {
3459  CaseDbConnection connection = connections.getConnection();
3461  Statement s = null;
3462  ResultSet rs = null;
3463  try {
3464  s = connection.createStatement();
3465  rs = connection.executeQuery(s, "select * from tsk_vs_info " //NON-NLS
3466  + "where obj_id = " + id); //NON-NLS
3467  if (rs.next()) {
3468  return rsHelper.volumeSystem(rs, parent);
3469  } else {
3470  throw new TskCoreException("No volume system found for id:" + id);
3471  }
3472  } catch (SQLException ex) {
3473  throw new TskCoreException("Error getting Volume System by ID.", ex);
3474  } finally {
3475  closeResultSet(rs);
3476  closeStatement(s);
3478  }
3479  }
3480 
3487  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
3488  VolumeSystem vs = getVolumeSystemById(id, null);
3489  vs.setParentId(parentId);
3490  return vs;
3491  }
3492 
3502  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
3503  return getFileSystemByIdHelper(id, parent);
3504  }
3505 
3512  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
3513  Volume vol = null;
3514  FileSystem fs = getFileSystemById(id, vol);
3515  fs.setParentId(parentId);
3516  return fs;
3517  }
3518 
3528  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
3529  return getFileSystemByIdHelper(id, parent);
3530  }
3531 
3542  // see if we already have it
3543  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
3544  // but it should be the same...
3545  synchronized (fileSystemIdMap) {
3546  if (fileSystemIdMap.containsKey(id)) {
3547  return fileSystemIdMap.get(id);
3548  }
3549  }
3550  CaseDbConnection connection = connections.getConnection();
3552  Statement s = null;
3553  ResultSet rs = null;
3554  try {
3555  s = connection.createStatement();
3556  rs = connection.executeQuery(s, "select * from tsk_fs_info " //NON-NLS
3557  + "where obj_id = " + id); //NON-NLS
3558  if (rs.next()) {
3559  FileSystem fs = rsHelper.fileSystem(rs, parent);
3560  // save it for the next call
3561  synchronized (fileSystemIdMap) {
3562  fileSystemIdMap.put(id, fs);
3563  }
3564  return fs;
3565  } else {
3566  throw new TskCoreException("No file system found for id:" + id);
3567  }
3568  } catch (SQLException ex) {
3569  throw new TskCoreException("Error getting File System by ID", ex);
3570  } finally {
3571  closeResultSet(rs);
3572  closeStatement(s);
3574  }
3575  }
3576 
3586  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
3587  CaseDbConnection connection = connections.getConnection();
3589  Statement s = null;
3590  ResultSet rs = null;
3591  try {
3592  s = connection.createStatement();
3593  rs = connection.executeQuery(s, "select * from tsk_vs_parts " //NON-NLS
3594  + "where obj_id = " + id); //NON-NLS
3595  if (rs.next()) {
3596  return rsHelper.volume(rs, parent);
3597  } else {
3598  throw new TskCoreException("No volume found for id:" + id);
3599  }
3600  } catch (SQLException ex) {
3601  throw new TskCoreException("Error getting Volume by ID", ex);
3602  } finally {
3603  closeResultSet(rs);
3604  closeStatement(s);
3606  }
3607  }
3608 
3615  Volume getVolumeById(long id, long parentId) throws TskCoreException {
3616  Volume vol = getVolumeById(id, null);
3617  vol.setParentId(parentId);
3618  return vol;
3619  }
3620 
3630  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
3631  CaseDbConnection connection = connections.getConnection();
3633  Statement s = null;
3634  ResultSet rs = null;
3635  try {
3636  s = connection.createStatement();
3637  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
3638  + "WHERE obj_id = " + id);
3639  Directory temp = null; //NON-NLS
3640  if (rs.next()) {
3641  final short type = rs.getShort("type"); //NON-NLS
3642  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
3643  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
3644  temp = rsHelper.directory(rs, parentFs);
3645  }
3646  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
3647  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
3648  }
3649  } else {
3650  throw new TskCoreException("No Directory found for id:" + id);
3651  }
3652  return temp;
3653  } catch (SQLException ex) {
3654  throw new TskCoreException("Error getting Directory by ID", ex);
3655  } finally {
3656  closeResultSet(rs);
3657  closeStatement(s);
3659  }
3660  }
3661 
3668  public Collection<FileSystem> getFileSystems(Image image) {
3669  List<FileSystem> fileSystems = new ArrayList<FileSystem>();
3670  CaseDbConnection connection;
3671  try {
3672  connection = connections.getConnection();
3673  } catch (TskCoreException ex) {
3674  logger.log(Level.SEVERE, "Error getting file systems for image " + image.getId(), ex); //NON-NLS
3675  return fileSystems;
3676  }
3678  Statement s = null;
3679  ResultSet rs = null;
3680  try {
3681  s = connection.createStatement();
3682 
3683  // Get all the file systems.
3684  List<FileSystem> allFileSystems = new ArrayList<FileSystem>();
3685  try {
3686  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info"); //NON-NLS
3687  while (rs.next()) {
3688  allFileSystems.add(rsHelper.fileSystem(rs, null));
3689  }
3690  } catch (SQLException ex) {
3691  logger.log(Level.SEVERE, "There was a problem while trying to obtain all file systems", ex); //NON-NLS
3692  } finally {
3693  closeResultSet(rs);
3694  rs = null;
3695  }
3696 
3697  // For each file system, find the image to which it belongs by iteratively
3698  // climbing the tsk_ojbects hierarchy only taking those file systems
3699  // that belong to this image.
3700  for (FileSystem fs : allFileSystems) {
3701  Long imageID = null;
3702  Long currentObjID = fs.getId();
3703  while (imageID == null) {
3704  try {
3705  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS
3706  currentObjID = rs.getLong("par_obj_id"); //NON-NLS
3707  if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS
3708  imageID = rs.getLong("obj_id"); //NON-NLS
3709  }
3710  } catch (SQLException ex) {
3711  logger.log(Level.SEVERE, "There was a problem while trying to obtain this image's file systems", ex); //NON-NLS
3712  } finally {
3713  closeResultSet(rs);
3714  rs = null;
3715  }
3716  }
3717 
3718  // see if imageID is this image'statement ID
3719  if (imageID == image.getId()) {
3720  fileSystems.add(fs);
3721  }
3722  }
3723  } catch (SQLException ex) {
3724  logger.log(Level.SEVERE, "Error getting case database connection", ex); //NON-NLS
3725  } finally {
3726  closeResultSet(rs);
3727  closeStatement(s);
3729  }
3730  return fileSystems;
3731  }
3732 
3741  List<Content> getImageChildren(Image img) throws TskCoreException {
3742  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
3743  List<Content> children = new ArrayList<Content>();
3744  for (ObjectInfo info : childInfos) {
3745  if (info.type == ObjectType.VS) {
3746  children.add(getVolumeSystemById(info.id, img));
3747  } else if (info.type == ObjectType.FS) {
3748  children.add(getFileSystemById(info.id, img));
3749  } else if (info.type == ObjectType.ABSTRACTFILE) {
3750  AbstractFile f = getAbstractFileById(info.id);
3751  if (f != null) {
3752  children.add(f);
3753  }
3754  } else {
3755  throw new TskCoreException("Image has child of invalid type: " + info.type);
3756  }
3757  }
3758  return children;
3759  }
3760 
3769  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
3770  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
3771  List<Long> children = new ArrayList<Long>();
3772  for (ObjectInfo info : childInfos) {
3773  if (info.type == ObjectType.VS
3774  || info.type == ObjectType.FS
3775  || info.type == ObjectType.ABSTRACTFILE) {
3776  children.add(info.id);
3777  } else {
3778  throw new TskCoreException("Image has child of invalid type: " + info.type);
3779  }
3780  }
3781  return children;
3782  }
3783 
3792  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
3793  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
3794  List<Content> children = new ArrayList<Content>();
3795  for (ObjectInfo info : childInfos) {
3796  if (info.type == ObjectType.VOL) {
3797  children.add(getVolumeById(info.id, vs));
3798  } else if (info.type == ObjectType.ABSTRACTFILE) {
3799  AbstractFile f = getAbstractFileById(info.id);
3800  if (f != null) {
3801  children.add(f);
3802  }
3803  } else {
3804  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
3805  }
3806  }
3807  return children;
3808  }
3809 
3818  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
3819  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
3820  List<Long> children = new ArrayList<Long>();
3821  for (ObjectInfo info : childInfos) {
3822  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE) {
3823  children.add(info.id);
3824  } else {
3825  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
3826  }
3827  }
3828  return children;
3829  }
3830 
3839  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
3840  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
3841  List<Content> children = new ArrayList<Content>();
3842  for (ObjectInfo info : childInfos) {
3843  if (info.type == ObjectType.FS) {
3844  children.add(getFileSystemById(info.id, vol));
3845  } else if (info.type == ObjectType.ABSTRACTFILE) {
3846  AbstractFile f = getAbstractFileById(info.id);
3847  if (f != null) {
3848  children.add(f);
3849  }
3850  } else {
3851  throw new TskCoreException("Volume has child of invalid type: " + info.type);
3852  }
3853  }
3854  return children;
3855  }
3856 
3865  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
3866  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
3867  final List<Long> children = new ArrayList<Long>();
3868  for (ObjectInfo info : childInfos) {
3869  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE) {
3870  children.add(info.id);
3871  } else {
3872  throw new TskCoreException("Volume has child of invalid type: " + info.type);
3873  }
3874  }
3875  return children;
3876  }
3877 
3886  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
3887  CaseDbConnection connection = connections.getConnection();
3889  Statement s1 = null;
3890  Statement s2 = null;
3891  ResultSet rs1 = null;
3892  ResultSet rs2 = null;
3893  try {
3894  s1 = connection.createStatement();
3895  rs1 = connection.executeQuery(s1, "select obj_id from tsk_image_info"); //NON-NLS
3896  s2 = connection.createStatement();
3897  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
3898  while (rs1.next()) {
3899  long obj_id = rs1.getLong("obj_id"); //NON-NLS
3900  rs2 = connection.executeQuery(s2, "select * from tsk_image_names where obj_id = " + obj_id); //NON-NLS
3901  List<String> paths = new ArrayList<String>();
3902  while (rs2.next()) {
3903  paths.add(rsHelper.imagePath(rs2));
3904  }
3905  rs2.close();
3906  rs2 = null;
3907  imgPaths.put(obj_id, paths);
3908  }
3909  return imgPaths;
3910  } catch (SQLException ex) {
3911  throw new TskCoreException("Error getting image paths.", ex);
3912  } finally {
3913  closeResultSet(rs2);
3914  closeStatement(s2);
3915  closeResultSet(rs1);
3916  closeStatement(s1);
3918  }
3919  }
3920 
3926  public List<Image> getImages() throws TskCoreException {
3927  CaseDbConnection connection = connections.getConnection();
3929  Statement s = null;
3930  ResultSet rs = null;
3931  try {
3932  s = connection.createStatement();
3933  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
3934  Collection<Long> imageIDs = new ArrayList<Long>();
3935  while (rs.next()) {
3936  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
3937  }
3938  List<Image> images = new ArrayList<Image>();
3939  for (long id : imageIDs) {
3940  images.add(getImageById(id));
3941  }
3942  return images;
3943  } catch (SQLException ex) {
3944  throw new TskCoreException("Error retrieving images.", ex);
3945  } finally {
3946  closeResultSet(rs);
3947  closeStatement(s);
3949  }
3950  }
3951 
3959  public long getLastObjectId() throws TskCoreException {
3960  CaseDbConnection connection = connections.getConnection();
3962  ResultSet rs = null;
3963  try {
3964  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
3965  rs = connection.executeQuery(statement);
3966  long id = -1;
3967  if (rs.next()) {
3968  id = rs.getLong(1);
3969  }
3970  return id;
3971  } catch (SQLException e) {
3972  throw new TskCoreException("Error getting last object id", e);
3973  } finally {
3974  closeResultSet(rs);
3976  }
3977  }
3978 
3987  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
3988  CaseDbConnection connection = connections.getConnection();
3990  Statement statement = null;
3991  try {
3992  connection.beginTransaction();
3993  statement = connection.createStatement();
3994  connection.executeUpdate(statement, "DELETE FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
3995  for (int i = 0; i < paths.size(); i++) {
3996  connection.executeUpdate(statement, "INSERT INTO tsk_image_names VALUES (" + obj_id + ", \"" + paths.get(i) + "\", " + i + ")"); //NON-NLS
3997  }
3998  connection.commitTransaction();
3999  } catch (SQLException ex) {
4000  connection.rollbackTransaction();
4001  throw new TskCoreException("Error updating image paths.", ex);
4002  } finally {
4003  closeStatement(statement);
4005  }
4006  }
4007 
4018  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs) throws SQLException {
4019  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
4020  try {
4021  while (rs.next()) {
4022  final short type = rs.getShort("type"); //NON-NLS
4023  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
4024  FsContent result;
4025  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
4026  result = rsHelper.directory(rs, null);
4027  } else {
4028  result = rsHelper.file(rs, null);
4029  }
4030  results.add(result);
4031  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
4032  final VirtualDirectory virtDir = rsHelper.virtualDirectory(rs);
4033  results.add(virtDir);
4034  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
4035  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
4036  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()) {
4038  String parentPath = rs.getString("parent_path"); //NON-NLS
4039  if (parentPath == null) {
4040  parentPath = "/"; //NON-NLS
4041  }
4042  LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"), //NON-NLS
4043  rs.getString("name"), //NON-NLS
4044  atype,
4045  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
4046  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
4047  rs.getLong("size"), //NON-NLS
4048  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
4049  results.add(lf);
4050  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
4051  final DerivedFile df;
4052  df = rsHelper.derivedFile(rs, AbstractContent.UNKNOWN_ID);
4053  results.add(df);
4054  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
4055  final LocalFile lf;
4056  lf = rsHelper.localFile(rs, AbstractContent.UNKNOWN_ID);
4057  results.add(lf);
4058  }
4059 
4060  } //end for each resultSet
4061  } catch (SQLException e) {
4062  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
4063  }
4064 
4065  return results;
4066  }
4067 
4075  private List<FsContent> resultSetToFsContents(ResultSet rs) throws SQLException {
4076  List<FsContent> results = new ArrayList<FsContent>();
4077  List<AbstractFile> temp = resultSetToAbstractFiles(rs);
4078  for (AbstractFile f : temp) {
4079  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
4080  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
4081  results.add((FsContent) f);
4082  }
4083  }
4084  return results;
4085  }
4086 
4100  @Deprecated
4101  public ResultSet runQuery(String query) throws SQLException {
4102  CaseDbConnection connection;
4103  try {
4104  connection = connections.getConnection();
4105  } catch (TskCoreException ex) {
4106  throw new SQLException("Error getting connection for ad hoc query", ex);
4107  }
4109  try {
4110  return connection.executeQuery(connection.createStatement(), query);
4111  } finally {
4112  //TODO unlock should be done in closeRunQuery()
4113  //but currently not all code calls closeRunQuery - need to fix this
4115  }
4116  }
4117 
4125  @Deprecated
4126  public void closeRunQuery(ResultSet resultSet) throws SQLException {
4127  final Statement statement = resultSet.getStatement();
4128  resultSet.close();
4129  if (statement != null) {
4130  statement.close();
4131  }
4132  }
4133 
4146  public CaseDbQuery executeQuery(String query) throws TskCoreException {
4147  return new CaseDbQuery(query);
4148  }
4149 
4150  @Override
4151  public void finalize() throws Throwable {
4152  try {
4153  close();
4154  } finally {
4155  super.finalize();
4156  }
4157  }
4158 
4162  public void close() {
4163  System.err.println(this.hashCode() + " closed"); //NON-NLS
4164  System.err.flush();
4166  connections.close();
4167  fileSystemIdMap.clear();
4168 
4169  try {
4170  if (this.caseHandle != null) {
4171  this.caseHandle.free();
4172  this.caseHandle = null;
4173 
4174  }
4175  } catch (TskCoreException ex) {
4176  logger.log(Level.WARNING,
4177  "Error freeing case handle.", ex); //NON-NLS
4178  } finally {
4180  }
4181  }
4182 
4193  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
4194  long id = file.getId();
4195  FileKnown currentKnown = file.getKnown();
4196  if (currentKnown.compareTo(fileKnown) > 0) {
4197  return false;
4198  }
4199  CaseDbConnection connection = connections.getConnection();
4201  Statement statement = null;
4202  try {
4203  statement = connection.createStatement();
4204  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
4205  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
4206  + "WHERE obj_id=" + id); //NON-NLS
4207  file.setKnown(fileKnown);
4208  } catch (SQLException ex) {
4209  throw new TskCoreException("Error setting Known status.", ex);
4210  } finally {
4211  closeStatement(statement);
4213  }
4214  return true;
4215  }
4216 
4225  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
4226  if (md5Hash == null) {
4227  return;
4228  }
4229  long id = file.getId();
4230  CaseDbConnection connection = connections.getConnection();
4232  try {
4233  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.UPDATE_FILE_MD5);
4234  statement.clearParameters();
4235  statement.setString(1, md5Hash.toLowerCase());
4236  statement.setLong(2, id);
4237  connection.executeUpdate(statement);
4238  file.setMd5Hash(md5Hash.toLowerCase());
4239  } catch (SQLException ex) {
4240  throw new TskCoreException("Error setting MD5 hash", ex);
4241  } finally {
4243  }
4244  }
4245 
4255  CaseDbConnection connection = connections.getConnection();
4257  Statement s = null;
4258  ResultSet rs = null;
4259  try {
4260  s = connection.createStatement();
4261  Short contentShort = contentType.getValue();
4262  rs = connection.executeQuery(s, "SELECT COUNT(*) FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
4263  int count = 0;
4264  if (rs.next()) {
4265  count = rs.getInt(1);
4266  }
4267  return count;
4268  } catch (SQLException ex) {
4269  throw new TskCoreException("Error getting number of objects.", ex);
4270  } finally {
4271  closeResultSet(rs);
4272  closeStatement(s);
4274  }
4275  }
4276 
4284  private static String escapeForBlackboard(String text) {
4285  if (text != null) {
4286  text = text.replaceAll("'", "''");
4287  }
4288  return text;
4289  }
4290 
4297  public List<AbstractFile> findFilesByMd5(String md5Hash) {
4298  if (md5Hash == null) {
4299  return Collections.<AbstractFile>emptyList();
4300  }
4301  CaseDbConnection connection;
4302  try {
4303  connection = connections.getConnection();
4304  } catch (TskCoreException ex) {
4305  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
4306  return Collections.<AbstractFile>emptyList();
4307  }
4309  Statement s = null;
4310  ResultSet rs = null;
4311  try {
4312  s = connection.createStatement();
4313  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
4314  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
4315  + "AND size > 0"); //NON-NLS
4316  return resultSetToAbstractFiles(rs);
4317  } catch (SQLException ex) {
4318  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
4319  return Collections.<AbstractFile>emptyList();
4320  } finally {
4321  closeResultSet(rs);
4322  closeStatement(s);
4324  }
4325  }
4326 
4333  public boolean allFilesMd5Hashed() {
4334  CaseDbConnection connection;
4335  try {
4336  connection = connections.getConnection();
4337  } catch (TskCoreException ex) {
4338  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
4339  return false;
4340  }
4341  boolean allFilesAreHashed = false;
4343  Statement s = null;
4344  ResultSet rs = null;
4345  try {
4346  s = connection.createStatement();
4347  rs = connection.executeQuery(s, "SELECT COUNT(*) FROM tsk_files " //NON-NLS
4348  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
4349  + "AND md5 IS NULL " //NON-NLS
4350  + "AND size > '0'"); //NON-NLS
4351  if (rs.next() && rs.getInt(1) == 0) {
4352  allFilesAreHashed = true;
4353  }
4354  } catch (SQLException ex) {
4355  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
4356  } finally {
4357  closeResultSet(rs);
4358  closeStatement(s);
4360  }
4361  return allFilesAreHashed;
4362  }
4363 
4369  public int countFilesMd5Hashed() {
4370  CaseDbConnection connection;
4371  try {
4372  connection = connections.getConnection();
4373  } catch (TskCoreException ex) {
4374  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
4375  return 0;
4376  }
4377  int count = 0;
4379  Statement s = null;
4380  ResultSet rs = null;
4381  try {
4382  s = connection.createStatement();
4383  rs = connection.executeQuery(s, "SELECT COUNT(*) FROM tsk_files " //NON-NLS
4384  + "WHERE md5 IS NOT NULL " //NON-NLS
4385  + "AND size > '0'"); //NON-NLS
4386  if (rs.next()) {
4387  count = rs.getInt(1);
4388  }
4389  } catch (SQLException ex) {
4390  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
4391  } finally {
4392  closeResultSet(rs);
4393  closeStatement(s);
4395  }
4396  return count;
4397  }
4398 
4404  @Deprecated
4405  public interface ErrorObserver {
4406 
4407  void receiveError(String context, String errorMessage);
4408  }
4409 
4416  @Deprecated
4417  public void addErrorObserver(ErrorObserver observer) {
4418  errorObservers.add(observer);
4419  }
4420 
4427  @Deprecated
4428  public void removerErrorObserver(ErrorObserver observer) {
4429  int i = errorObservers.indexOf(observer);
4430  if (i >= 0) {
4431  errorObservers.remove(i);
4432  }
4433  }
4434 
4442  @Deprecated
4443  public void submitError(String context, String errorMessage) {
4444  for (ErrorObserver observer : errorObservers) {
4445  observer.receiveError(context, errorMessage);
4446  }
4447  }
4448 
4456  public List<TagName> getAllTagNames() throws TskCoreException {
4457  CaseDbConnection connection = connections.getConnection();
4459  ResultSet resultSet = null;
4460  try {
4461  // SELECT * FROM tag_names
4462  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_TAG_NAMES);
4463  resultSet = connection.executeQuery(statement);
4464  ArrayList<TagName> tagNames = new ArrayList<TagName>();
4465  while (resultSet.next()) {
4466  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
4467  }
4468  return tagNames;
4469  } catch (SQLException ex) {
4470  throw new TskCoreException("Error selecting rows from tag_names table", ex);
4471  } finally {
4472  closeResultSet(resultSet);
4474  }
4475  }
4476 
4486  public List<TagName> getTagNamesInUse() throws TskCoreException {
4487  CaseDbConnection connection = connections.getConnection();
4489  ResultSet resultSet = null;
4490  try {
4491  // 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)
4492  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
4493  resultSet = connection.executeQuery(statement);
4494  ArrayList<TagName> tagNames = new ArrayList<TagName>();
4495  while (resultSet.next()) {
4496  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
4497  }
4498  return tagNames;
4499  } catch (SQLException ex) {
4500  throw new TskCoreException("Error selecting rows from tag_names table", ex);
4501  } finally {
4502  closeResultSet(resultSet);
4504  }
4505  }
4506 
4516  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
4517  CaseDbConnection connection = connections.getConnection();
4519  ResultSet resultSet = null;
4520  try {
4521  // INSERT INTO tag_names (display_name, description, color) VALUES (?, ?, ?)
4522  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_TAG_NAME);
4523  statement.clearParameters();
4524  statement.setString(1, displayName);
4525  statement.setString(2, description);
4526  statement.setString(3, color.getName());
4527  connection.executeUpdate(statement);
4528  resultSet = statement.getGeneratedKeys();
4529  return new TagName(resultSet.getLong(1), displayName, description, color);
4530  } catch (SQLException ex) {
4531  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
4532  } finally {
4533  closeResultSet(resultSet);
4535  }
4536  }
4537 
4549  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
4550  CaseDbConnection connection = connections.getConnection();
4552  ResultSet resultSet = null;
4553  try {
4554  // INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
4555  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_CONTENT_TAG);
4556  statement.clearParameters();
4557  statement.setLong(1, content.getId());
4558  statement.setLong(2, tagName.getId());
4559  statement.setString(3, comment);
4560  statement.setLong(4, beginByteOffset);
4561  statement.setLong(5, endByteOffset);
4562  connection.executeUpdate(statement);
4563  resultSet = statement.getGeneratedKeys();
4564  return new ContentTag(resultSet.getLong(1), content, tagName, comment, beginByteOffset, endByteOffset);
4565  } catch (SQLException ex) {
4566  throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex);
4567  } finally {
4568  closeResultSet(resultSet);
4570  }
4571  }
4572 
4573  /*
4574  * Deletes a row from the content_tags table in the case database.
4575  * @param tag A ContentTag data transfer object (DTO) for the row to delete.
4576  * @throws TskCoreException
4577  */
4579  CaseDbConnection connection = connections.getConnection();
4581  try {
4582  // DELETE FROM content_tags WHERE tag_id = ?
4583  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.DELETE_CONTENT_TAG);
4584  statement.clearParameters();
4585  statement.setLong(1, tag.getId());
4586  connection.executeUpdate(statement);
4587  } catch (SQLException ex) {
4588  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
4589  } finally {
4591  }
4592  }
4593 
4601  public List<ContentTag> getAllContentTags() throws TskCoreException {
4602  CaseDbConnection connection = connections.getConnection();
4604  ResultSet resultSet = null;
4605  try {
4606  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
4607  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
4608  resultSet = connection.executeQuery(statement);
4609  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
4610  while (resultSet.next()) {
4611  TagName tagName = new TagName(resultSet.getLong(2), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
4612  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
4613  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"))); //NON-NLS
4614  }
4615  return tags;
4616  } catch (SQLException ex) {
4617  throw new TskCoreException("Error selecting rows from content_tags table", ex);
4618  } finally {
4619  closeResultSet(resultSet);
4621  }
4622  }
4623 
4633  if (tagName.getId() == Tag.ID_NOT_SET) {
4634  throw new TskCoreException("TagName object is invalid, id not set");
4635  }
4636  CaseDbConnection connection = connections.getConnection();
4638  ResultSet resultSet = null;
4639  try {
4640  // SELECT COUNT(*) FROM content_tags WHERE tag_name_id = ?
4641  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
4642  statement.clearParameters();
4643  statement.setLong(1, tagName.getId());
4644  resultSet = connection.executeQuery(statement);
4645  if (resultSet.next()) {
4646  return resultSet.getLong(1);
4647  } else {
4648  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
4649  }
4650  } catch (SQLException ex) {
4651  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
4652  } finally {
4653  closeResultSet(resultSet);
4655  }
4656  }
4657 
4667  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
4668  if (tagName.getId() == Tag.ID_NOT_SET) {
4669  throw new TskCoreException("TagName object is invalid, id not set");
4670  }
4671  CaseDbConnection connection = connections.getConnection();
4673  ResultSet resultSet = null;
4674  try {
4675  // SELECT * FROM content_tags WHERE tag_name_id = ?
4676  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
4677  statement.clearParameters();
4678  statement.setLong(1, tagName.getId());
4679  resultSet = connection.executeQuery(statement);
4680  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
4681  while (resultSet.next()) {
4682  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
4683  tags.add(tag);
4684  }
4685  resultSet.close();
4686  return tags;
4687  } catch (SQLException ex) {
4688  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
4689  } finally {
4690  closeResultSet(resultSet);
4692  }
4693  }
4694 
4704  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
4705  CaseDbConnection connection = connections.getConnection();
4707  ResultSet resultSet = null;
4708  try {
4709  // SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id WHERE content_tags.obj_id = ?
4710  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
4711  statement.clearParameters();
4712  statement.setLong(1, content.getId());
4713  resultSet = connection.executeQuery(statement);
4714  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
4715  while (resultSet.next()) {
4716  TagName tagName = new TagName(resultSet.getLong(3), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
4717  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS
4718  tags.add(tag);
4719  }
4720  return tags;
4721  } catch (SQLException ex) {
4722  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
4723  } finally {
4724  closeResultSet(resultSet);
4726  }
4727  }
4728 
4741  CaseDbConnection connection = connections.getConnection();
4743  ResultSet resultSet = null;
4744  try {
4745  // INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)
4746  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_ARTIFACT_TAG);
4747  statement.clearParameters();
4748  statement.setLong(1, artifact.getArtifactID());
4749  statement.setLong(2, tagName.getId());
4750  statement.setString(3, comment);
4751  connection.executeUpdate(statement);
4752  resultSet = statement.getGeneratedKeys();
4753  return new BlackboardArtifactTag(resultSet.getLong(1), artifact, getContentById(artifact.getObjectID()), tagName, comment);
4754  } catch (SQLException ex) {
4755  throw new TskCoreException("Error adding row to blackboard_artifact_tags table (obj_id = " + artifact.getArtifactID() + ", tag_name_id = " + tagName.getId() + ")", ex);
4756  } finally {
4757  closeResultSet(resultSet);
4759  }
4760  }
4761 
4762  /*
4763  * Deletes a row from the blackboard_artifact_tags table in the case database.
4764  * @param tag A BlackboardArtifactTag data transfer object (DTO) representing the row to delete.
4765  * @throws TskCoreException
4766  */
4768  CaseDbConnection connection = connections.getConnection();
4770  try {
4771  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
4772  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
4773  statement.clearParameters();
4774  statement.setLong(1, tag.getId());
4775  connection.executeUpdate(statement);
4776  } catch (SQLException ex) {
4777  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
4778  } finally {
4780  }
4781  }
4782 
4791  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
4792  CaseDbConnection connection = connections.getConnection();
4794  ResultSet resultSet = null;
4795  try {
4796  // SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
4797  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
4798  resultSet = connection.executeQuery(statement);
4799  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
4800  while (resultSet.next()) {
4801  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
4802  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
4803  Content content = getContentById(artifact.getObjectID());
4804  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"), artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
4805  tags.add(tag);
4806  }
4807  return tags;
4808  } catch (SQLException ex) {
4809  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
4810  } finally {
4811  closeResultSet(resultSet);
4813  }
4814  }
4815 
4825  if (tagName.getId() == Tag.ID_NOT_SET) {
4826  throw new TskCoreException("TagName object is invalid, id not set");
4827  }
4828  CaseDbConnection connection = connections.getConnection();
4830  ResultSet resultSet = null;
4831  try {
4832  // SELECT COUNT(*) FROM blackboard_artifact_tags WHERE tag_name_id = ?
4833  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
4834  statement.clearParameters();
4835  statement.setLong(1, tagName.getId());
4836  resultSet = connection.executeQuery(statement);
4837  if (resultSet.next()) {
4838  return resultSet.getLong(1);
4839  } else {
4840  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
4841  }
4842  } catch (SQLException ex) {
4843  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
4844  } finally {
4845  closeResultSet(resultSet);
4847  }
4848  }
4849 
4859  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
4860  if (tagName.getId() == Tag.ID_NOT_SET) {
4861  throw new TskCoreException("TagName object is invalid, id not set");
4862  }
4863  CaseDbConnection connection = connections.getConnection();
4865  ResultSet resultSet = null;
4866  try {
4867  // SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?
4868  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
4869  statement.clearParameters();
4870  statement.setLong(1, tagName.getId());
4871  resultSet = connection.executeQuery(statement);
4872  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
4873  while (resultSet.next()) {
4874  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
4875  Content content = getContentById(artifact.getObjectID());
4876  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"), artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
4877  tags.add(tag);
4878  }
4879  return tags;
4880  } catch (SQLException ex) {
4881  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
4882  } finally {
4883  closeResultSet(resultSet);
4885  }
4886  }
4887 
4898  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
4899  CaseDbConnection connection = connections.getConnection();
4901  ResultSet resultSet = null;
4902  try {
4903  // 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 = ?
4904  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
4905  statement.clearParameters();
4906  statement.setLong(1, artifact.getArtifactID());
4907  resultSet = connection.executeQuery(statement);
4908  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
4909  while (resultSet.next()) {
4910  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color"))); //NON-NLS
4911  Content content = getContentById(artifact.getObjectID());
4912  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"), artifact, content, tagName, resultSet.getString("comment")); //NON-NLS
4913  tags.add(tag);
4914  }
4915  return tags;
4916  } catch (SQLException ex) {
4917  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
4918  } finally {
4919  closeResultSet(resultSet);
4921  }
4922  }
4923 
4934  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
4935  // Make sure the local path of the report is in the database directory
4936  // or one of its subdirectories.
4937  String relativePath = ""; //NON-NLS
4938  try {
4939  relativePath = new File(getDbDirPath()).toURI().relativize(new File(localPath).toURI()).getPath();
4940  } catch (IllegalArgumentException ex) {
4941  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
4942  throw new TskCoreException(errorMessage, ex);
4943  }
4944 
4945  // Figure out the create time of the report.
4946  long createTime = 0;
4947  try {
4948  java.io.File tempFile = new java.io.File(localPath);
4949  // Convert to UNIX epoch (seconds, not milliseconds).
4950  createTime = tempFile.lastModified() / 1000;
4951  } catch (Exception ex) {
4952  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
4953  }
4954 
4955  // Write the report data to the database.
4956  CaseDbConnection connection = connections.getConnection();
4958  ResultSet resultSet = null;
4959  try {
4960  // INSERT INTO reports (path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?)
4961  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.INSERT_REPORT);
4962  statement.clearParameters();
4963  statement.setString(1, relativePath);
4964  statement.setLong(2, createTime);
4965  statement.setString(3, sourceModuleName);
4966  statement.setString(4, reportName);
4967  connection.executeUpdate(statement);
4968  resultSet = statement.getGeneratedKeys();
4969  return new Report(resultSet.getLong(1), localPath, createTime, sourceModuleName, reportName);
4970  } catch (SQLException ex) {
4971  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
4972  } finally {
4973  closeResultSet(resultSet);
4975  }
4976  }
4977 
4985  public List<Report> getAllReports() throws TskCoreException {
4986  CaseDbConnection connection = connections.getConnection();
4988  ResultSet resultSet = null;
4989  try {
4990  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.SELECT_REPORTS);
4991  resultSet = connection.executeQuery(statement);
4992  ArrayList<Report> reports = new ArrayList<Report>();
4993  while (resultSet.next()) {
4994  reports.add(new Report(resultSet.getLong("report_id"), //NON-NLS
4995  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
4996  resultSet.getLong("crtime"), //NON-NLS
4997  resultSet.getString("src_module_name"), //NON-NLS
4998  resultSet.getString("report_name"))); //NON-NLS
4999  }
5000  return reports;
5001  } catch (SQLException ex) {
5002  throw new TskCoreException("Error querying reports table", ex);
5003  } finally {
5004  closeResultSet(resultSet);
5006  }
5007  }
5008 
5015  public void deleteReport(Report report) throws TskCoreException {
5016  CaseDbConnection connection = connections.getConnection();
5018  try {
5019  PreparedStatement statement = connection.getPreparedStatement(CaseDbConnection.PREPARED_STATEMENT.DELETE_REPORT);
5020  statement.setString(1, String.valueOf(report.getId()));
5021  connection.executeUpdate(statement);
5022  } catch (SQLException ex) {
5023  throw new TskCoreException("Error querying reports table", ex);
5024  } finally {
5026  }
5027  }
5028 
5029  private static void closeResultSet(ResultSet resultSet) {
5030  if (resultSet != null) {
5031  try {
5032  resultSet.close();
5033  } catch (SQLException ex) {
5034  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
5035  }
5036  }
5037  }
5038 
5039  private static void closeStatement(Statement statement) {
5040  if (statement != null) {
5041  try {
5042  statement.close();
5043  } catch (SQLException ex) {
5044  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
5045  }
5046  }
5047  }
5048 
5049  private final class ConnectionPerThreadDispenser extends ThreadLocal<CaseDbConnection> {
5050 
5051  private final HashSet<CaseDbConnection> databaseConnections = new HashSet<CaseDbConnection>();
5052  private boolean isClosed = false;
5053 
5054  synchronized CaseDbConnection getConnection() throws TskCoreException {
5055  if (isClosed) {
5056  throw new TskCoreException("Error getting case database connection - case is closed");
5057  }
5058 
5059  CaseDbConnection connection = get();
5060  if (!connection.isOpen()) {
5061  throw new TskCoreException("Case database connection for current thread is not open");
5062  }
5063  databaseConnections.add(connection);
5064  return connection;
5065  }
5066 
5072  public synchronized void close() {
5073  for (CaseDbConnection entry : databaseConnections) {
5074  entry.close();
5075  }
5076  databaseConnections.clear();
5077  isClosed = true;
5078  }
5079 
5080  @Override
5082  return new CaseDbConnection(dbPath);
5083  }
5084  }
5085 
5090  private static final class CaseDbConnection {
5091 
5092  enum PREPARED_STATEMENT {
5093 
5094  SELECT_ATTRIBUTES_OF_ARTIFACT("SELECT artifact_id, source, context, attribute_type_id, value_type, " //NON-NLS
5095  + "value_byte, value_text, value_int32, value_int64, value_double " //NON-NLS
5096  + "FROM blackboard_attributes WHERE artifact_id = ?"), //NON-NLS
5097  SELECT_ARTIFACT_BY_ID("SELECT artifact_id ,obj_id, artifact_type_id FROM blackboard_artifacts WHERE artifact_id = ?"), //NON-NLS
5098  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
5099  + "WHERE artifact_type_id = ?"), //NON-NLS
5100  COUNT_ARTIFACTS_OF_TYPE("SELECT COUNT(*) FROM blackboard_artifacts WHERE artifact_type_id = ?"), //NON-NLS
5101  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) FROM blackboard_artifacts WHERE obj_id = ?"), //NON-NLS
5102  SELECT_ARTIFACTS_BY_SOURCE_AND_TYPE("SELECT artifact_id FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?"), //NON-NLS
5103  COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE("SELECT COUNT(*) FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?"), //NON-NLS
5104  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
5105  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
5106  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
5107  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
5108  + "ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"), //NON-NLS
5109  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
5110  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
5111  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
5112  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
5113  + "ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"), //NON-NLS
5114  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
5115  + "ON tsk_objects.obj_id=tsk_files.obj_id WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
5116  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id " //NON-NLS
5117  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
5118  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
5119  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
5120  + "AND tsk_files.type = ? )"), //NON-NLS
5121  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
5122  INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_type_id) " //NON-NLS
5123  + "VALUES (?, ?, ?)"), //NON-NLS
5124  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
5125  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
5126  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
5127  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
5128  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
5129  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
5130  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
5131  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
5132  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
5133  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
5134  SELECT_FILES_BY_FILE_SYSTEM_AND_NAME("SELECT * FROM tsk_files WHERE LOWER(name) LIKE ? and LOWER(name) NOT LIKE '%journal%' AND fs_obj_id = ?"), //NON-NLS
5135  SELECT_FILES_BY_FILE_SYSTEM_AND_PATH("SELECT * FROM tsk_files WHERE LOWER(name) LIKE ? AND LOWER(name) NOT LIKE '%journal%' AND LOWER(parent_path) LIKE ? AND fs_obj_id = ?"), //NON-NLS
5136  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
5137  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
5138  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
5139  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
5140  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
5141  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
5142  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) from tsk_objects"), //NON-NLS
5143  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
5144  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) " //NON-NLS
5145  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
5146  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
5147  + "VALUES (?, ?, ?, ?)"), //NON-NLS
5148  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path) VALUES (?, ?)"), //NON-NLS
5149  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
5150  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
5151  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
5152  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
5153  + "WHERE tag_name_id IN " //NON-NLS
5154  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
5155  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color) VALUES (?, ?, ?)"), //NON-NLS
5156  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
5157  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
5158  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
5159  SELECT_CONTENT_TAGS("SELECT * FROM content_tags INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id"), //NON-NLS
5160  SELECT_CONTENT_TAGS_BY_TAG_NAME("SELECT * FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
5161  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
5162  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) VALUES (?, ?, ?)"), //NON-NLS
5163  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
5164  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
5165  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
5166  SELECT_ARTIFACT_TAGS_BY_TAG_NAME("SELECT * FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
5167  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
5168  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
5169  INSERT_REPORT("INSERT INTO reports (path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?)"), //NON-NLS
5170  DELETE_REPORT("DELETE FROM reports WHERE reports.report_id = ?"); //NON-NLS
5171 
5172  private final String sql;
5173 
5174  private PREPARED_STATEMENT(String sql) {
5175  this.sql = sql;
5176  }
5177 
5178  String getSQL() {
5179  return sql;
5180  }
5181  }
5182  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
5183  private Connection connection;
5184 
5185  CaseDbConnection(String dbPath) {
5186  this.preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
5187  Statement statement = null;
5188  try {
5189  SQLiteConfig config = new SQLiteConfig();
5190 
5191  // Reduce I/O operations, we have no OS crash recovery anyway.
5192  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF);
5193 
5194  // The original comment for "read_uncommited" indicating that it
5195  // was being set to "allow query while in transaction". I don't fully
5196  // understand why this is needed since all it does it expose dirty writes
5197  // within one transaction to other queries. There was also the suggestion
5198  // that it may have helped to increase performance.
5199  config.setReadUncommited(true);
5200 
5201  // Enforce foreign key constraints.
5202  config.enforceForeignKeys(true);
5203 
5204  this.connection = DriverManager.getConnection("jdbc:sqlite:" + dbPath, config.toProperties()); //NON-NLS
5205  } catch (SQLException ex) {
5206  // The exception is caught and logged here because this
5207  // constructor will be called by an override of
5208  // ThreadLocal<T>.initialValue() which cannot throw. Calls to
5209  // ConnectionPerThreadDispenser.getConnection() will detect
5210  // the error state via isOpen() and throw an appropriate
5211  // exception.
5212  SleuthkitCase.logger.log(Level.SEVERE, "Error setting up case database connection for thread", ex); //NON-NLS
5213  if (this.connection != null) {
5214  try {
5215  this.connection.close();
5216  } catch (SQLException e) {
5217  SleuthkitCase.logger.log(Level.SEVERE, "Failed to close connection", e);
5218  }
5219  this.connection = null;
5220  }
5221  }
5222  }
5223 
5224  boolean isOpen() {
5225  return this.connection != null;
5226  }
5227 
5228  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
5229  // Lazy statement preparation.
5230  PreparedStatement statement;
5231  if (this.preparedStatements.containsKey(statementKey)) {
5232  statement = this.preparedStatements.get(statementKey);
5233  } else {
5234  statement = prepareStatement(statementKey.getSQL());
5235  this.preparedStatements.put(statementKey, statement);
5236  }
5237  return statement;
5238  }
5239 
5240  private PreparedStatement prepareStatement(String sqlStatement) throws SQLException {
5241  PreparedStatement statement = null;
5242  boolean locked = true;
5243  while (locked) {
5244  try {
5245  statement = this.connection.prepareStatement(sqlStatement);
5246  locked = false;
5247  } catch (SQLException ex) {
5248  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5249  throw ex;
5250  }
5251  }
5252  }
5253  return statement;
5254  }
5255 
5256  Statement createStatement() throws SQLException {
5257  Statement statement = null;
5258  boolean locked = true;
5259  while (locked) {
5260  try {
5261  statement = this.connection.createStatement();
5262  locked = false;
5263  } catch (SQLException ex) {
5264  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5265  throw ex;
5266  }
5267  }
5268  }
5269  return statement;
5270  }
5271 
5272  void beginTransaction() throws SQLException {
5273  boolean locked = true;
5274  while (locked) {
5275  try {
5276  connection.setAutoCommit(false);
5277  locked = false;
5278  } catch (SQLException ex) {
5279  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5280  throw ex;
5281  }
5282  }
5283  }
5284  }
5285 
5286  void commitTransaction() throws SQLException {
5287  boolean locked = true;
5288 
5289  // Exceptions can be thrown on a call to commit so we will retry
5290  // until it succeeds.
5291  while (locked) {
5292  try {
5293  connection.commit();
5294  locked = false;
5295  } catch (SQLException ex) {
5296  logger.log(Level.SEVERE, String.format("Exception commiting transaction: Error code: %d SQLState: %s", ex.getErrorCode(), ex.getSQLState()), ex);
5297  }
5298  }
5299 
5300  // You must turn auto commit back on when done with the transaction.
5301  try {
5302  connection.setAutoCommit(true);
5303  } catch (SQLException ex) {
5304  logger.log(Level.SEVERE, String.format("Exception resetting auto commit: Error code: %d SQLState: %s", ex.getErrorCode(), ex.getSQLState()), ex);
5305  }
5306  }
5307 
5313  void rollbackTransaction() {
5314  try {
5315  connection.rollback();
5316  } catch (SQLException e) {
5317  logger.log(Level.SEVERE, "Error rolling back transaction", e);
5318  }
5319  try {
5320  connection.setAutoCommit(true);
5321  } catch (SQLException e) {
5322  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
5323  }
5324  }
5325 
5333  void rollbackTransactionWithThrow() throws SQLException {
5334  try {
5335  connection.rollback();
5336  } finally {
5337  connection.setAutoCommit(true);
5338  }
5339  }
5340 
5341  private ResultSet executeQuery(Statement statement, String query) throws SQLException {
5342  ResultSet resultSet = null;
5343  boolean locked = true;
5344  while (locked) {
5345  try {
5346  resultSet = statement.executeQuery(query);
5347  locked = false;
5348  } catch (SQLException ex) {
5349  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5350  throw ex;
5351  }
5352  }
5353  }
5354  return resultSet;
5355  }
5356 
5357  private ResultSet executeQuery(PreparedStatement statement) throws SQLException {
5358  ResultSet resultSet = null;
5359  boolean locked = true;
5360  while (locked) {
5361  try {
5362  resultSet = statement.executeQuery();
5363  locked = false;
5364  } catch (SQLException ex) {
5365  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5366  throw ex;
5367  }
5368  }
5369  }
5370  return resultSet;
5371  }
5372 
5373  void executeUpdate(Statement statement, String update) throws SQLException {
5374  boolean locked = true;
5375  while (locked) {
5376  try {
5377  statement.executeUpdate(update);
5378  locked = false;
5379  } catch (SQLException ex) {
5380  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5381  throw ex;
5382  }
5383  }
5384  }
5385  }
5386 
5387  void executeUpdate(PreparedStatement statement) throws SQLException {
5388  boolean locked = true;
5389  while (locked) {
5390  try {
5391  statement.executeUpdate();
5392  locked = false;
5393  } catch (SQLException ex) {
5394  if (ex.getErrorCode() != SQLITE_BUSY_ERROR && ex.getErrorCode() != DATABASE_LOCKED_ERROR) {
5395  throw ex;
5396  }
5397  }
5398  }
5399  }
5400 
5406  private void close() {
5407  try { // close all file handles to the autopsy.db database.
5408  connection.close();
5409  } catch (SQLException ex) {
5410  logger.log(Level.SEVERE, "Unable to close handle to autopsy.db", ex);
5411  }
5412  }
5413  }
5414 
5423  public static final class CaseDbTransaction {
5424 
5426 
5428  this.connection = connection;
5429  try {
5430  this.connection.beginTransaction();
5431  } catch (SQLException ex) {
5432  throw new TskCoreException("Failed to create transaction on case database", ex);
5433  }
5434  }
5435 
5444  return this.connection;
5445  }
5446 
5453  public void commit() throws TskCoreException {
5454  try {
5455  this.connection.commitTransaction();
5456  } catch (SQLException ex) {
5457  throw new TskCoreException("Failed to commit transaction on case database", ex);
5458  }
5459  }
5460 
5467  public void rollback() throws TskCoreException {
5468  try {
5469  this.connection.rollbackTransactionWithThrow();
5470  } catch (SQLException ex) {
5471  throw new TskCoreException("Case database transaction rollback failed", ex);
5472  }
5473  }
5474  }
5475 
5486  public final class CaseDbQuery implements AutoCloseable {
5487 
5488  private ResultSet resultSet;
5489 
5490  private CaseDbQuery(String query) throws TskCoreException {
5491  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
5492  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
5493  }
5494 
5495  CaseDbConnection connection;
5496 
5497  try {
5498  connection = connections.getConnection();
5499  } catch (TskCoreException ex) {
5500  throw new TskCoreException("Error getting connection for query: ", ex);
5501  }
5502 
5503  try {
5505  resultSet = connection.executeQuery(connection.createStatement(), query);
5506  } catch (SQLException ex) {
5508  throw new TskCoreException("Error executing query: ", ex);
5509  }
5510  }
5511 
5517  public ResultSet getResultSet() {
5518  return resultSet;
5519  }
5520 
5521  @Override
5522  public void close() throws TskCoreException {
5523  try {
5524  if (resultSet != null) {
5525  final Statement statement = resultSet.getStatement();
5526  if (statement != null) {
5527  statement.close();
5528  }
5529  resultSet.close();
5530  }
5531 
5533  } catch (SQLException ex) {
5534  throw new TskCoreException("Error closing query: ", ex);
5535  }
5536  }
5537  }
5538 }
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value)
FS
File that can be found in file system tree.
Definition: TskData.java:644
static FileKnown valueOf(byte known)
Definition: TskData.java:715
ArrayList< BlackboardArtifact > getArtifactsHelper(int artifactTypeID, String artifactTypeName)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value)
void addBlackboardAttributes(Collection< BlackboardAttribute > attributes, int artifactTypeId)
final ConnectionPerThreadDispenser connections
AddImageProcess makeAddImageProcess(String timezone, boolean processUnallocSpace, boolean noFatFsOrphans)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails)
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:200
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
void addErrorObserver(ErrorObserver observer)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction trans)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:201
void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId)
int addArtifactType(String artifactTypeName, String displayName)
ResultSet executeQuery(Statement statement, String query)
static TSK_FS_META_TYPE_ENUM valueOf(short metaType)
Definition: TskData.java:135
int updateFromSchema2toSchema3(int schemaVersionNumber)
List< FsContent > resultSetToFsContents(ResultSet rs)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value)
List< AbstractFile > openFiles(Content dataSource, String filePath)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)
long getBlackboardArtifactsCount(String artifactTypeName, long obj_id)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value)
List< VirtualDirectory > getVirtualDirectoryRoots()
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:647
Map< Long, List< String > > getImagePaths()
List< Long > findAllFileIdsWhere(String sqlWhereClause)
BlackboardArtifact getBlackboardArtifact(long artifactID)
static void closeResultSet(ResultSet resultSet)
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:645
static TSK_FS_NAME_FLAG_ENUM valueOf(int dirFlag)
Definition: TskData.java:183
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)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypesInUse()
List< AbstractFile > resultSetToAbstractFiles(ResultSet rs)
int getAttrTypeID(String attrTypeName)
List< Content > getChildren()
USED
Metadata structure has been allocated at least once.
Definition: TskData.java:202
final Map< Long, Long > carvedFileContainersCache
final ArrayList< ErrorObserver > errorObservers
void closeRunQuery(ResultSet resultSet)
int addAttrType(String attrTypeString, String displayName)
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag)
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
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:84
long getArtifactsCountHelper(int artifactTypeID, long obj_id)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:67
final ReentrantReadWriteLock rwLock
List< AbstractFile > findFilesByMd5(String md5Hash)
BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id)
List< BlackboardArtifact > getArtifactsHelper(ResultSet rs)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent, CaseDbTransaction trans)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:646
List< LayoutFile > addCarvedFiles(List< CarvedFileContainer > filesToAdd)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName)
Report addReport(String localPath, String sourceModuleName, String reportName)
List< BlackboardArtifactTag > getAllBlackboardArtifactTags()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName, long obj_id)
static TSK_DB_FILES_TYPE_ENUM valueOf(short fileType)
Definition: TskData.java:667
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:648
ArrayList< BlackboardAttribute > getMatchingAttributes(String whereClause)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
long getBlackboardArtifactsTypeCount(int artifactTypeID)
ArrayList< BlackboardArtifact > getArtifactsHelper(int artifactTypeID, String artifactTypeName, long obj_id)
static ObjectType valueOf(short objectType)
Definition: TskData.java:628
long getContentTagsCountByTagName(TagName tagName)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:697
List< AbstractFile > findAllFilesWhere(String sqlWhereClause)
boolean setKnown(AbstractFile file, FileKnown fileKnown)
static void closeStatement(Statement statement)
static final ResourceBundle bundle
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)
ResultSet executeQuery(PreparedStatement statement)
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:650
static SleuthkitCase newCase(String dbPath)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
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:605
ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith)
void addFilePath(CaseDbConnection connection, long objId, String path)
void removerErrorObserver(ErrorObserver observer)
final Map< PREPARED_STATEMENT, PreparedStatement > preparedStatements
List< FsContent > findFilesWhere(String sqlWhereClause)
PreparedStatement prepareStatement(String sqlStatement)
void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection)
List< TskFileRange > getFileRanges(long id)
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:649
static String escapeForBlackboard(String text)
CaseDbQuery executeQuery(String query)
void setImagePaths(long obj_id, List< String > paths)
VS
Volume System - see tsk_vs_info for more details.
Definition: TskData.java:602
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:601
SleuthkitJNI.CaseDbHandle caseHandle
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:153
Collection< FileSystem > getFileSystems(Image image)

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.