Sleuth Kit Java Bindings (JNI)  4.6
Java bindings for using The Sleuth Kit
SleuthkitCase.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
21 import com.google.common.collect.ImmutableSet;
22 import com.google.common.eventbus.EventBus;
23 import com.mchange.v2.c3p0.ComboPooledDataSource;
24 import com.mchange.v2.c3p0.DataSources;
25 import com.mchange.v2.c3p0.PooledDataSource;
26 import com.zaxxer.sparsebits.SparseBitSet;
27 import java.beans.PropertyVetoException;
28 import java.io.BufferedInputStream;
29 import java.io.BufferedOutputStream;
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.io.UnsupportedEncodingException;
37 import java.net.InetAddress;
38 import java.net.URLEncoder;
39 import java.nio.charset.StandardCharsets;
40 import java.nio.file.Paths;
41 import java.sql.Connection;
42 import java.sql.DriverManager;
43 import java.sql.PreparedStatement;
44 import java.sql.ResultSet;
45 import java.sql.SQLException;
46 import java.sql.Statement;
47 import java.text.SimpleDateFormat;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.Date;
53 import java.util.EnumMap;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.MissingResourceException;
60 import java.util.ResourceBundle;
61 import java.util.Set;
62 import java.util.UUID;
63 import java.util.concurrent.ConcurrentHashMap;
64 import java.util.concurrent.locks.ReentrantReadWriteLock;
65 import java.util.logging.Level;
66 import java.util.logging.Logger;
67 import org.postgresql.util.PSQLState;
83 import org.sqlite.SQLiteConfig;
84 import org.sqlite.SQLiteDataSource;
85 import org.sqlite.SQLiteJDBCLoader;
86 
91 public class SleuthkitCase {
92 
93  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
94 
99  private static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
100  = new CaseDbSchemaVersionNumber(8, 4);
101 
102  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
103  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
104  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
105  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
106  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
107  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
108  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
109  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
110  private static final String SQL_ERROR_LIMIT_GROUP = "54";
111  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
112  private static final int MIN_USER_DEFINED_TYPE_ID = 10000;
113 
114  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
115  "tsk_events",
116  "tsk_event_descriptions",
117  "tsk_event_types",
118  "tsk_db_info",
119  "tsk_objects",
120  "tsk_image_info",
121  "tsk_image_names",
122  "tsk_vs_info",
123  "tsk_vs_parts",
124  "tsk_fs_info",
125  "tsk_file_layout",
126  "tsk_files",
127  "tsk_files_path",
128  "tsk_files_derived",
129  "tsk_files_derived_method",
130  "tag_names",
131  "content_tags",
132  "blackboard_artifact_tags",
133  "blackboard_artifacts",
134  "blackboard_attributes",
135  "blackboard_artifact_types",
136  "blackboard_attribute_types",
137  "data_source_info",
138  "file_encoding_types",
139  "ingest_module_types",
140  "ingest_job_status_types",
141  "ingest_modules",
142  "ingest_jobs",
143  "ingest_job_modules",
144  "account_types",
145  "accounts",
146  "account_relationships",
147  "review_statuses",
148  "reports,");
149 
150  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
151  "parObjId",
152  "layout_objID",
153  "artifact_objID",
154  "artifact_artifact_objID",
155  "artifact_typeID",
156  "attrsArtifactID",
157  "mime_type",
158  "file_extension",
159  "relationships_account1",
160  "relationships_account2",
161  "relationships_relationship_source_obj_id",
162  "relationships_date_time",
163  "relationships_relationship_type",
164  "relationships_data_source_obj_id",
165  "events_time",
166  "events_type",
167  "events_data_source_obj_id",
168  "events_file_obj_id",
169  "events_artifact_id");
170 
171  private static final String TSK_VERSION_KEY = "TSK_VER";
172  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
173  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
174  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
175  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
176 
177  private final ConnectionPool connections;
178  private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<>();
179  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
180  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
181  private final String databaseName;
182  private final String dbPath;
183  private final DbType dbType;
184  private final String caseDirPath;
185  private SleuthkitJNI.CaseDbHandle caseHandle;
186  private String dbBackupPath;
187  private Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap;
188  private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
189  private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
190  private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
191  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
192 
193  /*
194  * First parameter is used to specify the SparseBitSet to use, as object IDs
195  * can be larger than the max size of a SparseBitSet
196  */
197  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
198 
199  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
200  // This read/write lock is used to implement a layer of locking on top of
201  // the locking protocol provided by the underlying SQLite database. The Java
202  // locking protocol improves performance for reasons that are not currently
203  // understood. Note that the lock is contructed to use a fairness policy.
204  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
205 
206  private CommunicationsManager communicationsMgr;
207  private TimelineManager timelineMgr;
208  private Blackboard blackboard;
209  private CaseDbAccessManager dbAccessManager;
210 
211  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
212 
213  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
214 
215  public void registerForEvents(Object listener) {
216  eventBus.register(listener);
217  }
218 
219  public void unregisterForEvents(Object listener) {
220  eventBus.unregister(listener);
221  }
222 
223  void fireTSKEvent(Object event) {
224  eventBus.post(event);
225  }
226 
227  // Cache of frequently used content objects (e.g. data source, file system).
228  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
229 
230  private Examiner cachedCurrentExaminer = null;
231 
246  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
247  // Check if we can talk to the database.
248  if (info.getHost() == null || info.getHost().isEmpty()) {
249  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
250  } else if (info.getPort() == null || info.getPort().isEmpty()) {
251  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
252  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
253  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
254  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
255  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
256  }
257 
258  try {
259  Class.forName("org.postgresql.Driver"); //NON-NLS
260  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
261  if (conn != null) {
262  conn.close();
263  }
264  } catch (SQLException ex) {
265  String result;
266  String sqlState = ex.getSQLState().toLowerCase();
267  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
268  try {
269  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
270  // if we can reach the host, then it's probably port problem
271  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
272  } else {
273  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
274  }
275  } catch (IOException | MissingResourceException any) {
276  // it may be anything
277  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
278  }
279  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
280  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
281  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
282  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
283  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
284  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
285  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
286  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
287  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
288  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
289  } else {
290  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
291  }
292  throw new TskCoreException(result);
293  } catch (ClassNotFoundException ex) {
294  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
295  }
296  }
297 
309  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
310  Class.forName("org.sqlite.JDBC");
311  this.dbPath = dbPath;
312  this.dbType = dbType;
313  File dbFile = new File(dbPath);
314  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
315  this.databaseName = dbFile.getName();
316  this.connections = new SQLiteConnections(dbPath);
317  this.caseHandle = caseHandle;
318  init();
319  logSQLiteJDBCDriverInfo();
320  }
321 
339  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
340  this.dbPath = "";
341  this.databaseName = dbName;
342  this.dbType = dbType;
343  this.caseDirPath = caseDirPath;
344  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
345  this.caseHandle = caseHandle;
346  init();
347  }
348 
349  private void init() throws Exception {
350  typeIdToArtifactTypeMap = new ConcurrentHashMap<>();
351  typeIdToAttributeTypeMap = new ConcurrentHashMap<>();
352  typeNameToArtifactTypeMap = new ConcurrentHashMap<>();
353  typeNameToAttributeTypeMap = new ConcurrentHashMap<>();
354 
355  /*
356  * The following methods need to be called before updateDatabaseSchema
357  * due to the way that updateFromSchema2toSchema3 was implemented.
358  */
359  initBlackboardArtifactTypes();
360  initBlackboardAttributeTypes();
361  initNextArtifactId();
362  updateDatabaseSchema(null);
363 
364  try (CaseDbConnection connection = connections.getConnection()) {
365  initIngestModuleTypes(connection);
366  initIngestStatusTypes(connection);
367  initReviewStatuses(connection);
368  initEncodingTypes(connection);
369  populateHasChildrenMap(connection);
370  updateExaminers(connection);
371  initDBSchemaCreationVersion(connection);
372  }
373 
374  blackboard = new Blackboard(this);
375  communicationsMgr = new CommunicationsManager(this);
376  timelineMgr = new TimelineManager(this);
377  dbAccessManager = new CaseDbAccessManager(this);
378  }
379 
385  static Set<String> getCoreTableNames() {
386  return CORE_TABLE_NAMES;
387  }
388 
394  static Set<String> getCoreIndexNames() {
395  return CORE_INDEX_NAMES;
396  }
397 
406  boolean getHasChildren(Content content) {
407  long objId = content.getId();
408  long mapIndex = objId / Integer.MAX_VALUE;
409  int mapValue = (int) (objId % Integer.MAX_VALUE);
410 
411  synchronized (hasChildrenBitSetMap) {
412  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
413  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
414  }
415  return false;
416  }
417  }
418 
424  private void setHasChildren(Long objId) {
425  long mapIndex = objId / Integer.MAX_VALUE;
426  int mapValue = (int) (objId % Integer.MAX_VALUE);
427 
428  synchronized (hasChildrenBitSetMap) {
429  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
430  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
431  } else {
432  SparseBitSet bitSet = new SparseBitSet();
433  bitSet.set(mapValue);
434  hasChildrenBitSetMap.put(mapIndex, bitSet);
435  }
436  }
437  }
438 
447  return communicationsMgr;
448  }
449 
456  return blackboard;
457  }
458 
467  return timelineMgr;
468  }
469 
470  /*
471  * Gets the case database access manager for this case.
472  *
473  * @return The per case CaseDbAccessManager object.
474  *
475  * @throws org.sleuthkit.datamodel.TskCoreException
476  */
478  return dbAccessManager;
479  }
480 
487  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
488  CaseDbConnection connection = connections.getConnection();
489  Statement statement = null;
490  ResultSet resultSet = null;
492  try {
493  statement = connection.createStatement();
494  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
495  try {
496  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
497  } catch (SQLException ex) {
498  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS
499  resultSet.next();
500  if (resultSet.getLong("count") == 0) {
501  throw ex;
502  }
503  resultSet.close();
504  resultSet = null;
505  }
506  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
507  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
508  }
509  if (dbType == DbType.POSTGRESQL) {
510  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
511  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
512  }
513  } finally {
514  closeResultSet(resultSet);
515  closeStatement(statement);
516  connection.close();
518  }
519  }
520 
528  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
529  CaseDbConnection connection = connections.getConnection();
530  Statement statement = null;
531  ResultSet resultSet = null;
533  try {
534  statement = connection.createStatement();
535  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
536  try {
537  statement.execute("INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "', '" + type.getValueType().getType() + "')"); //NON-NLS
538  } catch (SQLException ex) {
539  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS
540  resultSet.next();
541  if (resultSet.getLong("count") == 0) {
542  throw ex;
543  }
544  resultSet.close();
545  resultSet = null;
546  }
547  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
548  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
549  }
550  if (this.dbType == DbType.POSTGRESQL) {
551  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
552  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
553  }
554  } finally {
555  closeResultSet(resultSet);
556  closeStatement(statement);
557  connection.close();
559  }
560  }
561 
571  private void initNextArtifactId() throws SQLException, TskCoreException {
572  CaseDbConnection connection = connections.getConnection();
573  Statement statement = null;
574  ResultSet resultSet = null;
576  try {
577  statement = connection.createStatement();
578  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
579  resultSet.next();
580  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
581  if (this.nextArtifactId == 1) {
582  this.nextArtifactId = BASE_ARTIFACT_ID;
583  }
584  } finally {
585  closeResultSet(resultSet);
586  closeStatement(statement);
587  connection.close();
589  }
590  }
591 
599  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
600  Statement statement = null;
601  ResultSet resultSet = null;
603  try {
604  statement = connection.createStatement();
605  for (IngestModuleType type : IngestModuleType.values()) {
606  try {
607  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
608  } catch (SQLException ex) {
609  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
610  resultSet.next();
611  if (resultSet.getLong("count") == 0) {
612  throw ex;
613  }
614  resultSet.close();
615  resultSet = null;
616  }
617  }
618  } finally {
619  closeResultSet(resultSet);
620  closeStatement(statement);
622  }
623  }
624 
632  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
633  Statement statement = null;
634  ResultSet resultSet = null;
636  try {
637  statement = connection.createStatement();
638  for (IngestJobStatusType type : IngestJobStatusType.values()) {
639  try {
640  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
641  } catch (SQLException ex) {
642  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
643  resultSet.next();
644  if (resultSet.getLong("count") == 0) {
645  throw ex;
646  }
647  resultSet.close();
648  resultSet = null;
649  }
650  }
651  } finally {
652  closeResultSet(resultSet);
653  closeStatement(statement);
655  }
656  }
657 
664  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
665  Statement statement = null;
666  ResultSet resultSet = null;
668  try {
669  statement = connection.createStatement();
670  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
671  try {
672  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
673  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
674  } catch (SQLException ex) {
675  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
676  resultSet.next();
677  if (resultSet.getLong("count") == 0) {
678  throw ex;
679  }
680  resultSet.close();
681  resultSet = null;
682  }
683  }
684  } finally {
685  closeResultSet(resultSet);
686  closeStatement(statement);
688  }
689  }
690 
698  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
699  Statement statement = null;
700  ResultSet resultSet = null;
702  try {
703  statement = connection.createStatement();
704  for (TskData.EncodingType type : TskData.EncodingType.values()) {
705  try {
706  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
707  } catch (SQLException ex) {
708  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
709  resultSet.next();
710  if (resultSet.getLong("count") == 0) {
711  throw ex;
712  }
713  resultSet.close();
714  resultSet = null;
715  }
716  }
717  } finally {
718  closeResultSet(resultSet);
719  closeStatement(statement);
721  }
722  }
723 
732  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
733 
734  String loginName = System.getProperty("user.name");
735  if (loginName.isEmpty()) {
736  logger.log(Level.SEVERE, "Cannot determine logged in user name");
737  return;
738  }
739 
741  Statement statement = connection.createStatement();
742  try {
743  String query = "INTO tsk_examiners (login_name) VALUES ('" + loginName + "')";
744  switch (getDatabaseType()) {
745  case POSTGRESQL:
746  query = "INSERT " + query + " ON CONFLICT DO NOTHING"; //NON-NLS
747  break;
748  case SQLITE:
749  query = "INSERT OR IGNORE " + query;
750  break;
751  default:
752  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
753  }
754 
755  statement.execute(query); //NON-NLS
756  } catch (SQLException ex) {
757  throw new TskCoreException("Error inserting row in tsk_examiners", ex);
758  } finally {
759  closeStatement(statement);
761  }
762  }
763 
771  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
772  long timestamp = System.currentTimeMillis();
773 
774  Statement statement = null;
775  ResultSet resultSet = null;
777  try {
778  statement = connection.createStatement();
779  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
780 
781  synchronized (hasChildrenBitSetMap) {
782  while (resultSet.next()) {
783  setHasChildren(resultSet.getLong("par_obj_id"));
784  }
785  }
786  long delay = System.currentTimeMillis() - timestamp;
787  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
788  } catch (SQLException ex) {
789  throw new TskCoreException("Error populating parent node cache", ex);
790  } finally {
791  closeResultSet(resultSet);
792  closeStatement(statement);
794  }
795  }
796 
803  void addDataSourceToHasChildrenMap() throws TskCoreException {
804 
805  CaseDbConnection connection = connections.getConnection();
806  try {
807  populateHasChildrenMap(connection);
808  } finally {
809  if (connection != null) {
810  connection.close();
811  }
812  }
813  }
814 
824  private void updateDatabaseSchema(String dbPath) throws Exception {
825  CaseDbConnection connection = connections.getConnection();
826  ResultSet resultSet = null;
827  Statement statement = null;
829  try {
830  connection.beginTransaction();
831 
832  boolean hasMinorVersion = false;
833  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
834  while (columns.next()) {
835  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
836  hasMinorVersion = true;
837  }
838  }
839 
840  // Get the schema version number of the case database from the tsk_db_info table.
841  int dbSchemaMajorVersion;
842  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
843 
844  statement = connection.createStatement();
845  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
846  + (hasMinorVersion ? ", schema_minor_ver" : "")
847  + " FROM tsk_db_info"); //NON-NLS
848  if (resultSet.next()) {
849  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
850  if (hasMinorVersion) {
851  //if there is a minor version column, use it, else default to zero.
852  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
853  }
854  } else {
855  throw new TskCoreException();
856  }
857  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
858 
859  resultSet.close();
860  resultSet = null;
861  statement.close();
862  statement = null;
863  //check schema compatibility
864  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
865  //we cannot open a db with a major schema version higher than the current one.
866  throw new TskUnsupportedSchemaVersionException(
867  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
868  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
869  //The schema version is compatible,possibly after upgrades.
870 
871  if (null != dbPath) {
872  // Make a backup copy of the database. Client code can get the path of the backup
873  // using the getBackupDatabasePath() method.
874  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
875  copyCaseDB(backupFilePath);
876  dbBackupPath = backupFilePath;
877  }
878 
879  // ***CALL SCHEMA UPDATE METHODS HERE***
880  // Each method should examine the schema version passed to it and either:
881  // a. do nothing and return the schema version unchanged, or
882  // b. upgrade the database and return the schema version that the db was upgraded to.
883  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
884  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
885  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
886  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
887  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
888  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
889  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
890  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
891  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
892  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
893  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
894  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
895  statement = connection.createStatement();
896  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
897  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
898  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
899  statement.close();
900  statement = null;
901  }
902 
903  connection.commitTransaction();
904  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
905  connection.rollbackTransaction();
906  throw ex;
907  } finally {
908  closeResultSet(resultSet);
909  closeStatement(statement);
910  connection.close();
912  }
913  }
914 
922  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
923 
924  Statement statement = null;
925  ResultSet resultSet = null;
926  String createdSchemaMajorVersion = "0";
927  String createdSchemaMinorVersion = "0";
929  try {
930  statement = connection.createStatement();
931  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
932  while (resultSet.next()) {
933  String name = resultSet.getString("name");
934  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
935  createdSchemaMajorVersion = resultSet.getString("value");
936  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
937  createdSchemaMinorVersion = resultSet.getString("value");
938  }
939  }
940 
941  } finally {
942  closeResultSet(resultSet);
943  closeStatement(statement);
945  }
946 
947  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
948  }
949 
959  public void copyCaseDB(String newDBPath) throws IOException {
960  if (dbPath.isEmpty()) {
961  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
962  }
963  InputStream in = null;
964  OutputStream out = null;
966  try {
967  InputStream inFile = new FileInputStream(dbPath);
968  in = new BufferedInputStream(inFile);
969  OutputStream outFile = new FileOutputStream(newDBPath);
970  out = new BufferedOutputStream(outFile);
971  int bytesRead = in.read();
972  while (bytesRead != -1) {
973  out.write(bytesRead);
974  bytesRead = in.read();
975  }
976  } finally {
977  try {
978  if (in != null) {
979  in.close();
980  }
981  if (out != null) {
982  out.flush();
983  out.close();
984  }
985  } catch (IOException e) {
986  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
987  }
989  }
990  }
991 
995  private void logSQLiteJDBCDriverInfo() {
996  try {
997  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
998  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
999  ? "native" : "pure-java")); //NON-NLS
1000  } catch (Exception ex) {
1001  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1002  }
1003  }
1004 
1018  @SuppressWarnings("deprecation")
1019  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1020  if (schemaVersion.getMajor() != 2) {
1021  return schemaVersion;
1022  }
1023  Statement statement = null;
1024  Statement updateStatement = null;
1025  ResultSet resultSet = null;
1027  try {
1028  statement = connection.createStatement();
1029 
1030  // Add new tables for tags.
1031  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
1032  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
1033  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
1034 
1035  // Add a new table for reports.
1036  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
1037 
1038  // Add new columns to the image info table.
1039  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1040  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1041  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1042 
1043  // Add a new column to the file system info table.
1044  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1045 
1046  // Add a new column to the file table.
1047  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1048 
1049  // Add new columns and indexes to the attributes table and populate the
1050  // new column. Note that addition of the new column is a denormalization
1051  // to optimize attribute queries.
1052  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1053  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1054  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1055  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1056  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1057  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1058  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1059  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1060  + "FROM blackboard_attributes AS attrs " //NON-NLS
1061  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1062  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1063  updateStatement = connection.createStatement();
1064  while (resultSet.next()) {
1065  long artifactId = resultSet.getLong("artifact_id");
1066  int artifactTypeId = resultSet.getInt("artifact_type_id");
1067  updateStatement.executeUpdate(
1068  "UPDATE blackboard_attributes " //NON-NLS
1069  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1070  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1071  }
1072  resultSet.close();
1073  resultSet = null;
1074 
1075  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1076  // TODO: This code depends on prepared statements that could evolve with
1077  // time, breaking this upgrade. The code that follows should be rewritten
1078  // to do everything with SQL specific to case database schema version 2.
1079  HashMap<String, TagName> tagNames = new HashMap<String, TagName>();
1080  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_FILE)) {
1081  Content content = getContentById(artifact.getObjectID());
1082  String name = ""; //NON-NLS
1083  String comment = ""; //NON-NLS
1084  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
1085  for (BlackboardAttribute attribute : attributes) {
1086  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
1087  name = attribute.getValueString();
1088  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
1089  comment = attribute.getValueString();
1090  }
1091  }
1092  if (!name.isEmpty()) {
1093  TagName tagName;
1094  if (tagNames.containsKey(name)) {
1095  tagName = tagNames.get(name);
1096  } else {
1097  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
1098  tagNames.put(name, tagName);
1099  }
1100  addContentTag(content, tagName, comment, 0, content.getSize() - 1);
1101  }
1102  }
1103  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
1104  long taggedArtifactId = -1;
1105  String name = ""; //NON-NLS
1106  String comment = ""; //NON-NLS
1107  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
1108  for (BlackboardAttribute attribute : attributes) {
1109  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
1110  name = attribute.getValueString();
1111  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
1112  comment = attribute.getValueString();
1113  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
1114  taggedArtifactId = attribute.getValueLong();
1115  }
1116  }
1117  if (taggedArtifactId != -1 && !name.isEmpty()) {
1118  TagName tagName;
1119  if (tagNames.containsKey(name)) {
1120  tagName = tagNames.get(name);
1121  } else {
1122  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
1123  tagNames.put(name, tagName);
1124  }
1125  addBlackboardArtifactTag(getBlackboardArtifact(taggedArtifactId), tagName, comment);
1126  }
1127  }
1128  statement.execute(
1129  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1130  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1131  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1132  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1133  statement.execute(
1134  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1135  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1136  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1137 
1138  return new CaseDbSchemaVersionNumber(3, 0);
1139  } finally {
1140  closeStatement(updateStatement);
1141  closeResultSet(resultSet);
1142  closeStatement(statement);
1143  connection.close();
1145  }
1146  }
1147 
1161  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1162  if (schemaVersion.getMajor() != 3) {
1163  return schemaVersion;
1164  }
1165 
1166  Statement statement = null;
1167  ResultSet resultSet = null;
1168  Statement queryStatement = null;
1169  ResultSet queryResultSet = null;
1170  Statement updateStatement = null;
1172  try {
1173  // Add mime_type column to tsk_files table. Populate with general
1174  // info artifact file signature data.
1175  statement = connection.createStatement();
1176  updateStatement = connection.createStatement();
1177  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1178  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1179  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1180  + "WHERE files.obj_id = arts.obj_id AND "
1181  + "arts.artifact_id = attrs.artifact_id AND "
1182  + "arts.artifact_type_id = 1 AND "
1183  + "attrs.attribute_type_id = 62");
1184  while (resultSet.next()) {
1185  updateStatement.executeUpdate(
1186  "UPDATE tsk_files " //NON-NLS
1187  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1188  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1189  }
1190  resultSet.close();
1191 
1192  // Add value_type column to blackboard_attribute_types table.
1193  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1194  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1195  while (resultSet.next()) {
1196  int attributeTypeId = resultSet.getInt("attribute_type_id");
1197  String attributeLabel = resultSet.getString("type_name");
1198  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
1199  updateStatement.executeUpdate(
1200  "UPDATE blackboard_attribute_types " //NON-NLS
1201  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1202  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1203  }
1204  }
1205  resultSet.close();
1206 
1207  // Add a data_sources_info table.
1208  queryStatement = connection.createStatement();
1209  statement.execute("CREATE TABLE data_source_info (obj_id INTEGER PRIMARY KEY, device_id TEXT NOT NULL, time_zone TEXT NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id));");
1210  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1211  while (resultSet.next()) {
1212  long objectId = resultSet.getLong("obj_id");
1213  String timeZone = "";
1214  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1215  if (queryResultSet.next()) {
1216  timeZone = queryResultSet.getString("tzone");
1217  }
1218  queryResultSet.close();
1219  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1220  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1221  }
1222  resultSet.close();
1223 
1224  // Add data_source_obj_id column to the tsk_files table.
1225  //
1226  // NOTE: A new case database will have the following FK constraint:
1227  //
1228  // REFERENCES data_source_info (obj_id)
1229  //
1230  // The constraint is sacrificed here to avoid having to create and
1231  // populate a new tsk_files table.
1232  //
1233  // TODO: Do this right.
1234  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1235  resultSet = statement.executeQuery("SELECT tsk_files.obj_id AS obj_id, par_obj_id FROM tsk_files, tsk_objects WHERE tsk_files.obj_id = tsk_objects.obj_id");
1236  while (resultSet.next()) {
1237  long fileId = resultSet.getLong("obj_id");
1238  long dataSourceId = getDataSourceObjectId(connection, fileId);
1239  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1240  }
1241  resultSet.close();
1242  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1243  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1244  if (this.dbType.equals(DbType.SQLITE)) {
1245  statement.execute("CREATE TABLE ingest_modules (ingest_module_id INTEGER PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS
1246  statement.execute("CREATE TABLE ingest_jobs (ingest_job_id INTEGER PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS
1247  } else {
1248  statement.execute("CREATE TABLE ingest_modules (ingest_module_id BIGSERIAL PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS
1249  statement.execute("CREATE TABLE ingest_jobs (ingest_job_id BIGSERIAL PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS
1250  }
1251 
1252  statement.execute("CREATE TABLE ingest_job_modules (ingest_job_id INTEGER, ingest_module_id INTEGER, pipeline_position INTEGER, PRIMARY KEY(ingest_job_id, ingest_module_id), FOREIGN KEY(ingest_job_id) REFERENCES ingest_jobs(ingest_job_id), FOREIGN KEY(ingest_module_id) REFERENCES ingest_modules(ingest_module_id));"); //NON-NLS
1253  initIngestModuleTypes(connection);
1254  initIngestStatusTypes(connection);
1255 
1256  return new CaseDbSchemaVersionNumber(4, 0);
1257 
1258  } finally {
1259  closeResultSet(queryResultSet);
1260  closeStatement(queryStatement);
1261  closeStatement(updateStatement);
1262  closeResultSet(resultSet);
1263  closeStatement(statement);
1265  }
1266  }
1267 
1281  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1282  if (schemaVersion.getMajor() != 4) {
1283  return schemaVersion;
1284  }
1285 
1286  Statement statement = null;
1288  try {
1289  // Add the review_statuses lookup table.
1290  statement = connection.createStatement();
1291  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1292 
1293  /*
1294  * Add review_status_id column to artifacts table.
1295  *
1296  * NOTE: For DBs created with schema 5 we define a foreign key
1297  * constraint on the review_status_column. We don't bother with this
1298  * for DBs updated to schema 5 because of limitations of the SQLite
1299  * ALTER TABLE command.
1300  */
1301  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1302 
1303  // Add the encoding table
1304  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1305  initEncodingTypes(connection);
1306 
1307  /*
1308  * This needs to be done due to a Autopsy/TSK out of synch problem.
1309  * Without this, it is possible to upgrade from version 4 to 5 and
1310  * then 5 to 6, but not from 4 to 6.
1311  */
1312  initReviewStatuses(connection);
1313 
1314  // Add encoding type column to tsk_files_path
1315  // This should really have the FOREIGN KEY constraint but there are problems
1316  // getting that to work, so we don't add it on this upgrade path.
1317  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1318 
1319  return new CaseDbSchemaVersionNumber(5, 0);
1320 
1321  } finally {
1322  closeStatement(statement);
1324  }
1325  }
1326 
1340  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1341  if (schemaVersion.getMajor() != 5) {
1342  return schemaVersion;
1343  }
1344 
1345  /*
1346  * This upgrade fixes a bug where some releases had artifact review
1347  * status support in the case database and others did not.
1348  */
1349  Statement statement = null;
1350  ResultSet resultSet = null;
1352  try {
1353  /*
1354  * Add the review_statuses lookup table, if missing.
1355  */
1356  statement = connection.createStatement();
1357  statement.execute("CREATE TABLE IF NOT EXISTS review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1358 
1359  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1360  resultSet.next();
1361  if (resultSet.getLong("count") == 0) {
1362  /*
1363  * Add review_status_id column to artifacts table.
1364  *
1365  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1366  * key constraint on the review_status_column. We don't bother
1367  * with this for DBs updated to schema 5 or 6 because of
1368  * limitations of the SQLite ALTER TABLE command.
1369  */
1370  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1371  }
1372 
1373  return new CaseDbSchemaVersionNumber(6, 0);
1374 
1375  } finally {
1376  closeResultSet(resultSet);
1377  closeStatement(statement);
1379  }
1380  }
1381 
1395  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1396  if (schemaVersion.getMajor() != 6) {
1397  return schemaVersion;
1398  }
1399 
1400  /*
1401  * This upgrade adds an indexed extension column to the tsk_files table.
1402  */
1403  Statement statement = null;
1404  Statement updstatement = null;
1405  ResultSet resultSet = null;
1407  try {
1408  statement = connection.createStatement();
1409  updstatement = connection.createStatement();
1410  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1411 
1412  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1413  while (resultSet.next()) {
1414  long objID = resultSet.getLong("obj_id");
1415  String name = resultSet.getString("name");
1416  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1417  + "WHERE obj_id = " + objID);
1418  }
1419 
1420  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1421 
1422  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1423  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1424 
1425  return new CaseDbSchemaVersionNumber(7, 0);
1426 
1427  } finally {
1428  closeResultSet(resultSet);
1429  closeStatement(statement);
1430  closeStatement(updstatement);
1432  }
1433  }
1434 
1448  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1449  if (schemaVersion.getMajor() != 7) {
1450  return schemaVersion;
1451  }
1452 
1453  if (schemaVersion.getMinor() != 0) {
1454  return schemaVersion;
1455  }
1456 
1457  /*
1458  * This upgrade adds a minor version number column.
1459  */
1460  Statement statement = null;
1461  ResultSet resultSet = null;
1463  try {
1464  statement = connection.createStatement();
1465 
1466  //add the schema minor version number column.
1467  if (schemaVersion.getMinor() == 0) {
1468  //add the schema minor version number column.
1469  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1470  }
1471  return new CaseDbSchemaVersionNumber(7, 1);
1472 
1473  } finally {
1474  closeResultSet(resultSet);
1475  closeStatement(statement);
1477  }
1478  }
1479 
1493  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1494  if (schemaVersion.getMajor() != 7) {
1495  return schemaVersion;
1496  }
1497 
1498  if (schemaVersion.getMinor() != 1) {
1499  return schemaVersion;
1500  }
1501 
1502  Statement statement = null;
1503  Statement updstatement = null;
1504  ResultSet resultSet = null;
1506  try {
1507  //add the data_source_obj_id column to blackboard_artifacts.
1508  statement = connection.createStatement();
1509  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1510 
1511  // populate data_source_obj_id for each artifact
1512  updstatement = connection.createStatement();
1513  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1514  while (resultSet.next()) {
1515  long artifact_id = resultSet.getLong("artifact_id");
1516  long obj_id = resultSet.getLong("obj_id");
1517  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1518  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1519  + "WHERE artifact_id = " + artifact_id);
1520  }
1521  closeResultSet(resultSet);
1522  closeStatement(statement);
1523  closeStatement(updstatement);
1524 
1525  /*
1526  * Add a knownStatus column to the tag_names table.
1527  */
1528  statement = connection.createStatement();
1529  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1530 
1531  // Create account_types, accounts, and account_relationships table
1532  if (this.dbType.equals(DbType.SQLITE)) {
1533  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1534  statement.execute("CREATE TABLE accounts (account_id INTEGER PRIMARY KEY, account_type_id INTEGER NOT NULL, account_unique_identifier TEXT NOT NULL, UNIQUE(account_type_id, account_unique_identifier) , FOREIGN KEY(account_type_id) REFERENCES account_types(account_type_id))");
1535  statement.execute("CREATE TABLE account_relationships (relationship_id INTEGER PRIMARY KEY, account1_id INTEGER NOT NULL, account2_id INTEGER NOT NULL, relationship_source_obj_id INTEGER NOT NULL, date_time INTEGER, relationship_type INTEGER NOT NULL, data_source_obj_id INTEGER NOT NULL, UNIQUE(account1_id, account2_id, relationship_source_obj_id), FOREIGN KEY(account1_id) REFERENCES accounts(account_id), FOREIGN KEY(account2_id) REFERENCES accounts(account_id), FOREIGN KEY(relationship_source_obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id))");
1536  } else {
1537  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1538  statement.execute("CREATE TABLE accounts (account_id BIGSERIAL PRIMARY KEY, account_type_id INTEGER NOT NULL, account_unique_identifier TEXT NOT NULL, UNIQUE(account_type_id, account_unique_identifier) , FOREIGN KEY(account_type_id) REFERENCES account_types(account_type_id))");
1539  statement.execute("CREATE TABLE account_relationships (relationship_id BIGSERIAL PRIMARY KEY, account1_id INTEGER NOT NULL, account2_id INTEGER NOT NULL, relationship_source_obj_id INTEGER NOT NULL, date_time BIGINT, relationship_type INTEGER NOT NULL, data_source_obj_id INTEGER NOT NULL, UNIQUE(account1_id, account2_id, relationship_source_obj_id), FOREIGN KEY(account1_id) REFERENCES accounts(account_id), FOREIGN KEY(account2_id) REFERENCES accounts(account_id), FOREIGN KEY(relationship_source_obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id))");
1540  }
1541 
1542  // Create indexes
1543  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1544  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1545  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1546  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1547  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1548  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1549  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1550 
1551  return new CaseDbSchemaVersionNumber(7, 2);
1552  } finally {
1553  closeResultSet(resultSet);
1554  closeStatement(statement);
1555  closeStatement(updstatement);
1557  }
1558  }
1559 
1573  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1574  if (schemaVersion.getMajor() != 7) {
1575  return schemaVersion;
1576  }
1577 
1578  if (schemaVersion.getMinor() != 2) {
1579  return schemaVersion;
1580  }
1581 
1582  Statement updateSchemaStatement = connection.createStatement();
1583  Statement getExistingReportsStatement = connection.createStatement();
1584  ResultSet resultSet = null;
1585  ResultSet existingReports = null;
1586 
1588  try {
1589  // Update the schema to turn report_id into an object id.
1590 
1591  // Unfortunately, SQLite doesn't support adding a constraint
1592  // to an existing table so we have to rename the old...
1593  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1594 
1595  // ...create the new...
1596  updateSchemaStatement.execute("CREATE TABLE reports (obj_id BIGSERIAL PRIMARY KEY, path TEXT NOT NULL, crtime INTEGER NOT NULL, src_module_name TEXT NOT NULL, report_name TEXT NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id))");
1597 
1598  // ...add the existing report records back...
1599  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1600  while (existingReports.next()) {
1601  String path = existingReports.getString(2);
1602  long crtime = existingReports.getInt(3);
1603  String sourceModule = existingReports.getString(4);
1604  String reportName = existingReports.getString(5);
1605 
1606  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1607  insertObjectStatement.clearParameters();
1608  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1609  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1610  connection.executeUpdate(insertObjectStatement);
1611  resultSet = insertObjectStatement.getGeneratedKeys();
1612  if (!resultSet.next()) {
1613  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1614  }
1615  long objectId = resultSet.getLong(1); //last_insert_rowid()
1616 
1617  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1618  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1619  insertReportStatement.clearParameters();
1620  insertReportStatement.setLong(1, objectId);
1621  insertReportStatement.setString(2, path);
1622  insertReportStatement.setLong(3, crtime);
1623  insertReportStatement.setString(4, sourceModule);
1624  insertReportStatement.setString(5, reportName);
1625  connection.executeUpdate(insertReportStatement);
1626  }
1627 
1628  // ...and drop the old table.
1629  updateSchemaStatement.execute("DROP TABLE old_reports");
1630 
1631  return new CaseDbSchemaVersionNumber(8, 0);
1632  } finally {
1633  closeResultSet(resultSet);
1634  closeResultSet(existingReports);
1635  closeStatement(updateSchemaStatement);
1636  closeStatement(getExistingReportsStatement);
1638  }
1639  }
1640 
1654  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1655  if (schemaVersion.getMajor() != 8) {
1656  return schemaVersion;
1657  }
1658 
1659  if (schemaVersion.getMinor() != 0) {
1660  return schemaVersion;
1661  }
1662 
1664 
1665  try (Statement statement = connection.createStatement();) {
1666  // create examiners table
1667  if (this.dbType.equals(DbType.SQLITE)) {
1668  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1669  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1670  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1671  } else {
1672  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1673  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1674  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1675  }
1676 
1677  return new CaseDbSchemaVersionNumber(8, 1);
1678  } finally {
1680  }
1681  }
1682 
1696  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1697  if (schemaVersion.getMajor() != 8) {
1698  return schemaVersion;
1699  }
1700 
1701  if (schemaVersion.getMinor() != 1) {
1702  return schemaVersion;
1703  }
1704 
1706 
1707  try (Statement statement = connection.createStatement();) {
1708  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1709  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1710 
1711  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1712 
1713  /*
1714  * Add new tsk_db_extended_info table with TSK version, creation
1715  * time schema and schema version numbers as the initial data. The
1716  * creation time schema version is set to 0, 0 to indicate that it
1717  * is not known.
1718  */
1719  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1720  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1721  result.next();
1722  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1723  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1724  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1725  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1726  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1727 
1728  String primaryKeyType;
1729  switch (getDatabaseType()) {
1730  case POSTGRESQL:
1731  primaryKeyType = "BIGSERIAL";
1732  break;
1733  case SQLITE:
1734  primaryKeyType = "INTEGER";
1735  break;
1736  default:
1737  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1738  }
1739 
1740  //create and initialize tsk_event_types tables
1741  statement.execute("CREATE TABLE tsk_event_types ("
1742  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1743  + " display_name TEXT UNIQUE NOT NULL, "
1744  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1745  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1746  + " values( 0, 'Event Types', null)");
1747  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1748  + " values(1, 'File System', 0)");
1749  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1750  + " values(2, 'Web Activity', 0)");
1751  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1752  + " values(3, 'Misc Types', 0)");
1753  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1754  + " values(4, 'Modified', 1)");
1755  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1756  + " values(5, 'Accessed', 1)");
1757  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1758  + " values(6, 'Created', 1)");
1759  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1760  + " values(7, 'Changed', 1)");
1761 
1762  //create tsk_events tables
1763  statement.execute("CREATE TABLE tsk_event_descriptions ("
1764  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1765  + " full_description TEXT NOT NULL, "
1766  + " med_description TEXT, "
1767  + " short_description TEXT,"
1768  + " data_source_obj_id BIGINT NOT NULL, "
1769  + " file_obj_id BIGINT NOT NULL, "
1770  + " artifact_id BIGINT, "
1771  + " hash_hit INTEGER NOT NULL, " //boolean
1772  + " tagged INTEGER NOT NULL, " //boolean
1773  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1774  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1775  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1776  );
1777 
1778  statement.execute("CREATE TABLE tsk_events ( "
1779  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1780  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1781  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1782  + " time INTEGER NOT NULL) "
1783  );
1784 
1785  //create tsk_events indices
1786  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1787  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1788  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1789  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1790  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1791  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1792  return new CaseDbSchemaVersionNumber(8, 2);
1793 
1794  } finally {
1796  }
1797  }
1798 
1812  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1813  if (schemaVersion.getMajor() != 8) {
1814  return schemaVersion;
1815  }
1816 
1817  if (schemaVersion.getMinor() != 2) {
1818  return schemaVersion;
1819  }
1820 
1822 
1823  ResultSet resultSet = null;
1824 
1825  try (Statement statement = connection.createStatement();) {
1826 
1827  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1828  // Unfortunately, SQLite doesn't support adding a constraint
1829  // to an existing table so we have to rename the old...
1830  String primaryKeyType;
1831  switch (getDatabaseType()) {
1832  case POSTGRESQL:
1833  primaryKeyType = "BIGSERIAL";
1834  break;
1835  case SQLITE:
1836  primaryKeyType = "INTEGER";
1837  break;
1838  default:
1839  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1840  }
1841 
1842  //create and initialize tsk_event_types tables which may or may not exist
1843  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
1844  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1845  + " display_name TEXT UNIQUE NOT NULL, "
1846  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1847 
1848  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
1849 
1850  // If there is something in resultSet then the table must have previously
1851  // existing therefore there is not need to populate
1852  if (!resultSet.next()) {
1853 
1854  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1855  + " values( 0, 'Event Types', null)");
1856  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1857  + " values(1, 'File System', 0)");
1858  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1859  + " values(2, 'Web Activity', 0)");
1860  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1861  + " values(3, 'Misc Types', 0)");
1862  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1863  + " values(4, 'Modified', 1)");
1864  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1865  + " values(5, 'Accessed', 1)");
1866  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1867  + " values(6, 'Created', 1)");
1868  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1869  + " values(7, 'Changed', 1)");
1870  }
1871 
1872  // Delete the old table that may have been created with the upgrade
1873  // from 8.1 to 8.2.
1874  statement.execute("DROP TABLE IF EXISTS tsk_events");
1875 
1876  // Delete the old table that may have been created with the upgrade
1877  // from 8.1 to 8.2
1878  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
1879 
1880  //create new tsk_event_description table
1881  statement.execute("CREATE TABLE tsk_event_descriptions ("
1882  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1883  + " full_description TEXT NOT NULL, "
1884  + " med_description TEXT, "
1885  + " short_description TEXT,"
1886  + " data_source_obj_id BIGINT NOT NULL, "
1887  + " file_obj_id BIGINT NOT NULL, "
1888  + " artifact_id BIGINT, "
1889  + " hash_hit INTEGER NOT NULL, " //boolean
1890  + " tagged INTEGER NOT NULL, " //boolean
1891  + " UNIQUE(full_description, file_obj_id, artifact_id), "
1892  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1893  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1894  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1895  );
1896 
1897  // create a new table
1898  statement.execute("CREATE TABLE tsk_events ( "
1899  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1900  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1901  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1902  + " time INTEGER NOT NULL, "
1903  + " UNIQUE (event_type_id, event_description_id, time))"
1904  );
1905 
1906  // Fix mistakenly set names in tsk_db_info_extended
1907  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
1908  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
1909 
1910 
1911 
1912  return new CaseDbSchemaVersionNumber(8, 3);
1913  } finally {
1914  closeResultSet(resultSet);
1916  }
1917  }
1918 
1939  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1940  if (schemaVersion.getMajor() != 8) {
1941  return schemaVersion;
1942  }
1943 
1944  if (schemaVersion.getMinor() != 3) {
1945  return schemaVersion;
1946  }
1947 
1948  Statement statement = connection.createStatement();
1949  ResultSet results = null;
1950 
1952  try {
1953  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
1954  // the previous update code.
1955  if (null == getDatabaseType()) {
1956  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1957  }
1958 
1959  switch (getDatabaseType()) {
1960  case POSTGRESQL:
1961  // Check if the misnamed column is present
1962  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
1963  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
1964  if (results.next()) {
1965  // In PostgreSQL we can rename the column if it exists
1966  statement.execute("ALTER TABLE tsk_event_descriptions "
1967  + "RENAME COLUMN file_obj_id TO content_obj_id");
1968 
1969  // In 8.2 to 8.3 upgrade, the event_id & time column in tsk_events table was erroneously created as type INTEGER, instead of BIGINT
1970  // Fix the schema, preserving any data if exists.
1971  statement.execute("CREATE TABLE temp_tsk_events ( "
1972  + " event_id BIGSERIAL PRIMARY KEY, "
1973  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1974  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
1975  + " time BIGINT NOT NULL, "
1976  + " UNIQUE (event_type_id, event_description_id, time))"
1977  );
1978 
1979  // Copy the data
1980  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
1981  + "event_description_id, time) SELECT * FROM tsk_events");
1982 
1983  // Drop the old table
1984  statement.execute("DROP TABLE tsk_events");
1985 
1986  // Rename the new table
1987  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
1988 
1989  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
1990  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1991  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
1992  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1993  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1994  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
1995  }
1996  break;
1997  case SQLITE:
1998  boolean hasMisnamedColumn = false;
1999  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2000  while (results.next()) {
2001  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2002  hasMisnamedColumn = true;
2003  break;
2004  }
2005  }
2006 
2007  if (hasMisnamedColumn) {
2008  // Since we can't rename the column we'll need to make new tables and copy the data
2009  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2010  + " event_description_id INTEGER PRIMARY KEY, "
2011  + " full_description TEXT NOT NULL, "
2012  + " med_description TEXT, "
2013  + " short_description TEXT,"
2014  + " data_source_obj_id BIGINT NOT NULL, "
2015  + " content_obj_id BIGINT NOT NULL, "
2016  + " artifact_id BIGINT, "
2017  + " hash_hit INTEGER NOT NULL, " //boolean
2018  + " tagged INTEGER NOT NULL, " //boolean
2019  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2020  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2021  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2022  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2023  );
2024 
2025  statement.execute("CREATE TABLE temp_tsk_events ( "
2026  + " event_id INTEGER PRIMARY KEY, "
2027  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2028  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2029  + " time INTEGER NOT NULL, "
2030  + " UNIQUE (event_type_id, event_description_id, time))"
2031  );
2032 
2033  // Copy the data
2034  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2035  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2036  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2037 
2038  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2039  + "event_description_id, time) SELECT * FROM tsk_events");
2040 
2041  // Drop the old tables
2042  statement.execute("DROP TABLE tsk_events");
2043  statement.execute("DROP TABLE tsk_event_descriptions");
2044 
2045  // Rename the new tables
2046  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2047  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2048 
2049  //create tsk_events indices
2050  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2051  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2052  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2053  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2054  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2055  }
2056  break;
2057  default:
2058  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2059  }
2060 
2061  // create pool info table
2062  if (this.dbType.equals(DbType.SQLITE)) {
2063  statement.execute("CREATE TABLE tsk_pool_info (obj_id INTEGER PRIMARY KEY, pool_type INTEGER NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE)");
2064  } else {
2065  statement.execute("CREATE TABLE tsk_pool_info (obj_id BIGSERIAL PRIMARY KEY, pool_type INTEGER NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE)");
2066  }
2067 
2068  // Add new account types for newly supported messaging applications, if they dont exists already.
2069  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2070  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2071  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2072  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2073  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2074  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2075  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2076  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2077  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2078  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2079 
2080  return new CaseDbSchemaVersionNumber(8, 4);
2081  } finally {
2082  closeResultSet(results);
2083  closeStatement(statement);
2085  }
2086  }
2087 
2099  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2100 
2101  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2102  switch (getDatabaseType()) {
2103  case POSTGRESQL:
2104  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2105  break;
2106  case SQLITE:
2107  insertSQL = "INSERT OR IGNORE " + insertSQL;
2108  break;
2109  default:
2110  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2111  }
2112  statement.execute(insertSQL); //NON-NLS
2113  }
2121  static String extractExtension(final String fileName) {
2122  String ext;
2123  int i = fileName.lastIndexOf(".");
2124  // > 0 because we assume it's not an extension if period is the first character
2125  if ((i > 0) && ((i + 1) < fileName.length())) {
2126  ext = fileName.substring(i + 1);
2127  } else {
2128  return "";
2129  }
2130  // we added this at one point to deal with files that had crazy names based on URLs
2131  // it's too hard though to clean those up and not mess up basic extensions though.
2132  // We need to add '-' to the below if we use it again
2133  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2134  // if (findNonAlphanumeric.length > 1) {
2135  // ext = findNonAlphanumeric[0];
2136  // }
2137  return ext.toLowerCase();
2138  }
2139 
2150  @Deprecated
2151  public int getSchemaVersion() {
2152  return getDBSchemaVersion().getMajor();
2153  }
2154 
2161  return CURRENT_DB_SCHEMA_VERSION;
2162  }
2163 
2171  return caseDBSchemaCreationVersion;
2172  }
2173 
2180  return this.dbType;
2181  }
2182 
2189  public String getBackupDatabasePath() {
2190  return dbBackupPath;
2191  }
2192 
2203  public CaseDbTransaction beginTransaction() throws TskCoreException {
2204  return new CaseDbTransaction(this, connections.getConnection());
2205  }
2206 
2212  public String getDatabaseName() {
2213  return databaseName;
2214  }
2215 
2222  public String getDbDirPath() {
2223  return caseDirPath;
2224  }
2225 
2232  if (dbType == DbType.SQLITE) {
2233  rwLock.writeLock().lock();
2234  }
2235  }
2236 
2243  if (dbType == DbType.SQLITE) {
2244  rwLock.writeLock().unlock();
2245  }
2246  }
2247 
2254  if (dbType == DbType.SQLITE) {
2255  rwLock.readLock().lock();
2256  }
2257  }
2258 
2265  if (dbType == DbType.SQLITE) {
2266  rwLock.readLock().unlock();
2267  }
2268  }
2269 
2279  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2280  try {
2281  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2282  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2284  //don't wrap in new TskCoreException
2285  throw ex;
2286  } catch (Exception ex) {
2287  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
2288  }
2289  }
2290 
2302  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
2303  try {
2304  /*
2305  * The flow of this method involves trying to open case and if
2306  * successful, return that case. If unsuccessful, an exception is
2307  * thrown. We catch any exceptions, and use tryConnect() to attempt
2308  * to obtain further information about the error. If tryConnect() is
2309  * unable to successfully connect, tryConnect() will throw a
2310  * TskCoreException with a message containing user-level error
2311  * reporting. If tryConnect() is able to connect, flow continues and
2312  * we rethrow the original exception obtained from trying to create
2313  * the case. In this way, we obtain more detailed information if we
2314  * are able, but do not lose any information if unable.
2315  */
2316  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2317  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
2318  } catch (PropertyVetoException exp) {
2319  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2320  throw new TskCoreException(exp.getMessage(), exp);
2322  //don't wrap in new TskCoreException
2323  throw ex;
2324  } catch (Exception exp) {
2325  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2326  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2327  }
2328  }
2329 
2339  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
2340  try {
2341  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(dbPath);
2342  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2343  } catch (Exception ex) {
2344  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
2345  }
2346  }
2347 
2363  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
2364  String databaseName = createCaseDataBaseName(caseName);
2365  try {
2378  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(databaseName, info);
2379  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
2380  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
2381  } catch (PropertyVetoException exp) {
2382  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2383  throw new TskCoreException(exp.getMessage(), exp);
2384  } catch (Exception exp) {
2385  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2386  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2387  }
2388  }
2389 
2399  private static String createCaseDataBaseName(String candidateDbName) {
2400  String dbName;
2401  if (!candidateDbName.isEmpty()) {
2402  /*
2403  * Replace all non-ASCII characters.
2404  */
2405  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
2406 
2407  /*
2408  * Replace all control characters.
2409  */
2410  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
2411 
2412  /*
2413  * Replace /, \, :, ?, space, ' ".
2414  */
2415  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
2416 
2417  /*
2418  * Make it all lowercase.
2419  */
2420  dbName = dbName.toLowerCase();
2421 
2422  /*
2423  * Must start with letter or underscore. If not, prepend an
2424  * underscore.
2425  */
2426  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
2427  dbName = "_" + dbName;
2428  }
2429 
2430  /*
2431  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
2432  * uniqueness.
2433  */
2434  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
2435  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
2436  }
2437 
2438  } else {
2439  /*
2440  * Must start with letter or underscore.
2441  */
2442  dbName = "_";
2443  }
2444  /*
2445  * Add the time stmap.
2446  */
2447  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
2448  Date date = new Date();
2449  dbName = dbName + "_" + dateFormat.format(date);
2450 
2451  return dbName;
2452  }
2453 
2461  public Examiner getCurrentExaminer() throws TskCoreException {
2462 
2463  // return cached value if there's one
2464  if (cachedCurrentExaminer != null) {
2465  return cachedCurrentExaminer;
2466  }
2467  String loginName = System.getProperty("user.name");
2468  if (loginName == null || loginName.isEmpty()) {
2469  throw new TskCoreException("Failed to determine logged in user name.");
2470  }
2471 
2472  CaseDbConnection connection = connections.getConnection();
2474  ResultSet resultSet = null;
2475  try {
2476  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
2477  statement.clearParameters();
2478  statement.setString(1, loginName);
2479  resultSet = connection.executeQuery(statement);
2480  if (resultSet.next()) {
2481  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
2482  return cachedCurrentExaminer;
2483  } else {
2484  throw new TskCoreException("Error getting examaminer for name = " + loginName);
2485  }
2486 
2487  } catch (SQLException ex) {
2488  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
2489  } finally {
2490  closeResultSet(resultSet);
2491  connection.close();
2493  }
2494 
2495  }
2496 
2506  Examiner getExaminerById(long id) throws TskCoreException {
2507 
2508  CaseDbConnection connection = connections.getConnection();
2510  ResultSet resultSet = null;
2511  try {
2512  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
2513  statement.clearParameters();
2514  statement.setLong(1, id);
2515  resultSet = connection.executeQuery(statement);
2516  if (resultSet.next()) {
2517  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
2518  } else {
2519  throw new TskCoreException("Error getting examaminer for id = " + id);
2520  }
2521  } catch (SQLException ex) {
2522  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
2523  } finally {
2524  closeResultSet(resultSet);
2525  connection.close();
2527  }
2528  }
2529 
2547  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
2548  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
2549  }
2550 
2559  public List<Content> getRootObjects() throws TskCoreException {
2560  CaseDbConnection connection = connections.getConnection();
2562  Statement s = null;
2563  ResultSet rs = null;
2564  try {
2565  s = connection.createStatement();
2566  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
2567  + "WHERE par_obj_id IS NULL"); //NON-NLS
2568  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
2569  while (rs.next()) {
2570  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
2571  }
2572 
2573  List<Content> rootObjs = new ArrayList<Content>();
2574  for (ObjectInfo i : infos) {
2575  if (null != i.type) {
2576  switch (i.type) {
2577  case IMG:
2578  rootObjs.add(getImageById(i.id));
2579  break;
2580  case ABSTRACTFILE:
2581  // Check if virtual dir for local files.
2582  AbstractFile af = getAbstractFileById(i.id);
2583  if (af instanceof VirtualDirectory) {
2584  rootObjs.add(af);
2585  } else {
2586  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
2587  }
2588  break;
2589  case REPORT:
2590  break;
2591  default:
2592  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
2593  }
2594  }
2595  }
2596  return rootObjs;
2597  } catch (SQLException ex) {
2598  throw new TskCoreException("Error getting root objects", ex);
2599  } finally {
2600  closeResultSet(rs);
2601  closeStatement(s);
2602  connection.close();
2604  }
2605  }
2606 
2618  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
2619 
2620  // check cached map first
2621  synchronized (deviceIdToDatasourceObjIdMap) {
2622  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
2623  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
2624  }
2625 
2626  CaseDbConnection connection = connections.getConnection();
2628  Statement s = null;
2629  ResultSet rs = null;
2630  try {
2631  s = connection.createStatement();
2632  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
2633  List<Long> dataSourceObjIds = new ArrayList<Long>();
2634  while (rs.next()) {
2635  dataSourceObjIds.add(rs.getLong("obj_id"));
2636 
2637  // Add to map of deviceID to data_source_obj_id.
2638  long ds_obj_id = rs.getLong("obj_id");
2639  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
2640  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
2641  } else {
2642  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
2643  }
2644  }
2645  return dataSourceObjIds;
2646  } catch (SQLException ex) {
2647  throw new TskCoreException("Error getting data sources", ex);
2648  } finally {
2649  closeResultSet(rs);
2650  closeStatement(s);
2651  connection.close();
2653  }
2654  }
2655  }
2656 
2673  public List<DataSource> getDataSources() throws TskCoreException {
2674  CaseDbConnection connection = connections.getConnection();
2676  Statement statement = null;
2677  ResultSet resultSet = null;
2678  Statement statement2 = null;
2679  ResultSet resultSet2 = null;
2680  try {
2681  statement = connection.createStatement();
2682  statement2 = connection.createStatement();
2683  resultSet = connection.executeQuery(statement,
2684  "SELECT ds.obj_id, ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
2685  + "FROM data_source_info AS ds "
2686  + "LEFT JOIN tsk_image_info AS img "
2687  + "ON ds.obj_id = img.obj_id"); //NON-NLS
2688 
2689  List<DataSource> dataSourceList = new ArrayList<DataSource>();
2690  Map<Long, List<String>> imagePathsMap = getImagePaths();
2691 
2692  while (resultSet.next()) {
2693  DataSource dataSource;
2694  Long objectId = resultSet.getLong("obj_id");
2695  String deviceId = resultSet.getString("device_id");
2696  String timezone = resultSet.getString("time_zone");
2697  String type = resultSet.getString("type");
2698 
2699  if (type == null) {
2700  /*
2701  * No data found in 'tsk_image_info', so we build a
2702  * LocalFilesDataSource.
2703  */
2704 
2705  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
2706  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
2707  resultSet2.close();
2708 
2712  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
2713  | TSK_FS_META_FLAG_ENUM.USED.getValue());
2714  String parentPath = "/"; //NON-NLS
2715  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
2716  } else {
2717  /*
2718  * Data found in 'tsk_image_info', so we build an Image.
2719  */
2720  Long ssize = resultSet.getLong("ssize");
2721  Long size = resultSet.getLong("size");
2722  String md5 = resultSet.getString("md5");
2723  String sha1 = resultSet.getString("sha1");
2724  String sha256 = resultSet.getString("sha256");
2725  String name = resultSet.getString("display_name");
2726 
2727  List<String> imagePaths = imagePathsMap.get(objectId);
2728  if (name == null) {
2729  if (imagePaths.size() > 0) {
2730  String path = imagePaths.get(0);
2731  name = (new java.io.File(path)).getName();
2732  } else {
2733  name = "";
2734  }
2735  }
2736 
2737  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
2738  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
2739  }
2740 
2741  dataSourceList.add(dataSource);
2742  }
2743 
2744  return dataSourceList;
2745 
2746  } catch (SQLException ex) {
2747  throw new TskCoreException("Error getting data sources", ex);
2748  } finally {
2749  closeResultSet(resultSet);
2750  closeStatement(statement);
2751  closeResultSet(resultSet2);
2752  closeStatement(statement2);
2753  connection.close();
2755  }
2756  }
2757 
2777  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
2778  DataSource dataSource = null;
2779  CaseDbConnection connection = connections.getConnection();
2781  Statement statement = null;
2782  ResultSet resultSet = null;
2783  Statement statement2 = null;
2784  ResultSet resultSet2 = null;
2785  try {
2786  statement = connection.createStatement();
2787  statement2 = connection.createStatement();
2788  resultSet = connection.executeQuery(statement,
2789  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
2790  + "FROM data_source_info AS ds "
2791  + "LEFT JOIN tsk_image_info AS img "
2792  + "ON ds.obj_id = img.obj_id "
2793  + "WHERE ds.obj_id = " + objectId); //NON-NLS
2794  if (resultSet.next()) {
2795  String deviceId = resultSet.getString("device_id");
2796  String timezone = resultSet.getString("time_zone");
2797  String type = resultSet.getString("type");
2798 
2799  if (type == null) {
2800  /*
2801  * No data found in 'tsk_image_info', so we build an
2802  * LocalFilesDataSource.
2803  */
2804 
2805  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
2806  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
2807 
2811  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
2812  | TSK_FS_META_FLAG_ENUM.USED.getValue());
2813  String parentPath = "/"; //NON-NLS
2814  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
2815  } else {
2816  /*
2817  * Data found in 'tsk_image_info', so we build an Image.
2818  */
2819  Long ssize = resultSet.getLong("ssize");
2820  Long size = resultSet.getLong("size");
2821  String md5 = resultSet.getString("md5");
2822  String sha1 = resultSet.getString("sha1");
2823  String sha256 = resultSet.getString("sha256");
2824  String name = resultSet.getString("display_name");
2825 
2826  List<String> imagePaths = getImagePathsById(objectId);
2827  if (name == null) {
2828  if (imagePaths.size() > 0) {
2829  String path = imagePaths.get(0);
2830  name = (new java.io.File(path)).getName();
2831  } else {
2832  name = "";
2833  }
2834  }
2835 
2836  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
2837  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
2838  }
2839  } else {
2840  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
2841  }
2842  } catch (SQLException ex) {
2843  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
2844  } finally {
2845  closeResultSet(resultSet);
2846  closeStatement(statement);
2847  closeResultSet(resultSet2);
2848  closeStatement(statement2);
2849  connection.close();
2851  }
2852 
2853  return dataSource;
2854  }
2855 
2866  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
2867  return getArtifactsHelper("blackboard_artifacts.artifact_type_id = " + artifactTypeID);
2868  }
2869 
2880  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
2881  CaseDbConnection connection = connections.getConnection();
2883  ResultSet rs = null;
2884  try {
2885  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
2886  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
2887  statement.clearParameters();
2888  statement.setLong(1, objId);
2889  rs = connection.executeQuery(statement);
2890  long count = 0;
2891  if (rs.next()) {
2892  count = rs.getLong("count");
2893  }
2894  return count;
2895  } catch (SQLException ex) {
2896  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
2897  } finally {
2898  closeResultSet(rs);
2899  connection.close();
2901  }
2902  }
2903 
2914  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
2915  CaseDbConnection connection = connections.getConnection();
2917  ResultSet rs = null;
2918  try {
2919  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
2920  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
2921  statement.clearParameters();
2922  statement.setInt(1, artifactTypeID);
2923  rs = connection.executeQuery(statement);
2924  long count = 0;
2925  if (rs.next()) {
2926  count = rs.getLong("count");
2927  }
2928  return count;
2929  } catch (SQLException ex) {
2930  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
2931  } finally {
2932  closeResultSet(rs);
2933  connection.close();
2935  }
2936  }
2937 
2952  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
2953  CaseDbConnection connection = connections.getConnection();
2955  Statement s = null;
2956  ResultSet rs = null;
2957  try {
2958  s = connection.createStatement();
2959  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2960  + "arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
2961  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
2962  + " arts.review_status_id AS review_status_id " //NON-NLS
2963  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
2964  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
2965  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
2966  + " AND attrs.value_text = '" + value + "'"
2967  + " AND types.artifact_type_id=arts.artifact_type_id"
2968  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
2969  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
2970  while (rs.next()) {
2971  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
2972  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
2973  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
2974  }
2975  return artifacts;
2976  } catch (SQLException ex) {
2977  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
2978  } finally {
2979  closeResultSet(rs);
2980  closeStatement(s);
2981  connection.close();
2983  }
2984  }
2985 
3003  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3004  String valSubStr = "%" + subString; //NON-NLS
3005  if (startsWith == false) {
3006  valSubStr += "%"; //NON-NLS
3007  }
3008  CaseDbConnection connection = connections.getConnection();
3010  Statement s = null;
3011  ResultSet rs = null;
3012  try {
3013  s = connection.createStatement();
3014  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3015  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, " //NON-NLS
3016  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3017  + " arts.review_status_id AS review_status_id " //NON-NLS
3018  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3019  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3020  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3021  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3022  + " AND types.artifact_type_id=arts.artifact_type_id "
3023  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3024  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3025  while (rs.next()) {
3026  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3027  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3028  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3029  }
3030  return artifacts;
3031  } catch (SQLException ex) {
3032  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3033  } finally {
3034  closeResultSet(rs);
3035  closeStatement(s);
3036  connection.close();
3038  }
3039  }
3040 
3055  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3056  CaseDbConnection connection = connections.getConnection();
3058  Statement s = null;
3059  ResultSet rs = null;
3060  try {
3061  s = connection.createStatement();
3062  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3063  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3064  + " types.type_name AS type_name, types.display_name AS display_name, "
3065  + " arts.review_status_id AS review_status_id "//NON-NLS
3066  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3067  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3068  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3069  + " AND attrs.value_int32 = " + value //NON-NLS
3070  + " AND types.artifact_type_id=arts.artifact_type_id "
3071  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3072  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3073  while (rs.next()) {
3074  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3075  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3076  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3077  }
3078  return artifacts;
3079  } catch (SQLException ex) {
3080  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3081  } finally {
3082  closeResultSet(rs);
3083  closeStatement(s);
3084  connection.close();
3086  }
3087  }
3088 
3103  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3104  CaseDbConnection connection = connections.getConnection();
3106  Statement s = null;
3107  ResultSet rs = null;
3108  try {
3109  s = connection.createStatement();
3110  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3111  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3112  + " types.type_name AS type_name, types.display_name AS display_name, "
3113  + " arts.review_status_id AS review_status_id "//NON-NLS
3114  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3115  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3116  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3117  + " AND attrs.value_int64 = " + value //NON-NLS
3118  + " AND types.artifact_type_id=arts.artifact_type_id "
3119  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3120  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3121  while (rs.next()) {
3122  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3123  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3124  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3125  }
3126  return artifacts;
3127  } catch (SQLException ex) {
3128  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3129  } finally {
3130  closeResultSet(rs);
3131  closeStatement(s);
3132  connection.close();
3134  }
3135  }
3136 
3151  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3152  CaseDbConnection connection = connections.getConnection();
3154  Statement s = null;
3155  ResultSet rs = null;
3156  try {
3157  s = connection.createStatement();
3158  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3159  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3160  + " types.type_name AS type_name, types.display_name AS display_name, "
3161  + " arts.review_status_id AS review_status_id "//NON-NLS
3162  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3163  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3164  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3165  + " AND attrs.value_double = " + value //NON-NLS
3166  + " AND types.artifact_type_id=arts.artifact_type_id "
3167  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3168  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3169  while (rs.next()) {
3170  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3171  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3172  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3173  }
3174  return artifacts;
3175  } catch (SQLException ex) {
3176  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3177  } finally {
3178  closeResultSet(rs);
3179  closeStatement(s);
3180  connection.close();
3182  }
3183  }
3184 
3199  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3200  CaseDbConnection connection = connections.getConnection();
3202  Statement s = null;
3203  ResultSet rs = null;
3204  try {
3205  s = connection.createStatement();
3206  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3207  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3208  + " types.type_name AS type_name, types.display_name AS display_name, "
3209  + " arts.review_status_id AS review_status_id "//NON-NLS
3210  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3211  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3212  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3213  + " AND attrs.value_byte = " + value //NON-NLS
3214  + " AND types.artifact_type_id=arts.artifact_type_id "
3215  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3216  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3217  while (rs.next()) {
3218  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3219  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3220  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3221  }
3222  return artifacts;
3223  } catch (SQLException ex) {
3224  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3225  } finally {
3226  closeResultSet(rs);
3227  closeStatement(s);
3228  connection.close();
3230  }
3231  }
3232 
3240  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3241  CaseDbConnection connection = connections.getConnection();
3243  Statement s = null;
3244  ResultSet rs = null;
3245  try {
3246  s = connection.createStatement();
3247  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types"); //NON-NLS
3248  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
3249  while (rs.next()) {
3250  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3251  rs.getString("type_name"), rs.getString("display_name")));
3252  }
3253  return artifactTypes;
3254  } catch (SQLException ex) {
3255  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
3256  } finally {
3257  closeResultSet(rs);
3258  closeStatement(s);
3259  connection.close();
3261  }
3262  }
3263 
3272  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
3273  String typeIdList = "";
3274  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
3275  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
3276  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
3277  typeIdList += ", ";
3278  }
3279  }
3280  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
3281  + "WHERE artifact_type_id IN (" + typeIdList + ")";
3282  CaseDbConnection connection = connections.getConnection();
3284  Statement s = null;
3285  ResultSet rs = null;
3286  try {
3287  s = connection.createStatement();
3288  rs = connection.executeQuery(s, query);
3289  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
3290  while (rs.next()) {
3291  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
3292  }
3293  return usedArts;
3294  } catch (SQLException ex) {
3295  throw new TskCoreException("Error getting artifact types in use", ex);
3296  } finally {
3297  closeResultSet(rs);
3298  closeStatement(s);
3299  connection.close();
3301  }
3302  }
3303 
3314  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
3315  CaseDbConnection connection = connections.getConnection();
3317  Statement s = null;
3318  ResultSet rs = null;
3319  try {
3320  s = connection.createStatement();
3321  rs = connection.executeQuery(s,
3322  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
3323  + "types.type_name AS type_name, types.display_name AS display_name "
3324  + "FROM blackboard_artifact_types AS types "
3325  + "INNER JOIN blackboard_artifacts AS arts "
3326  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
3327  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
3328  while (rs.next()) {
3329  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3330  rs.getString("type_name"), rs.getString("display_name")));
3331  }
3332  return uniqueArtifactTypes;
3333  } catch (SQLException ex) {
3334  throw new TskCoreException("Error getting attribute types", ex);
3335  } finally {
3336  closeResultSet(rs);
3337  closeStatement(s);
3338  connection.close();
3340  }
3341  }
3342 
3350  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
3351  CaseDbConnection connection = connections.getConnection();
3353  Statement s = null;
3354  ResultSet rs = null;
3355  try {
3356  s = connection.createStatement();
3357  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
3358  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
3359  while (rs.next()) {
3360  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3361  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
3362  }
3363  return attribute_types;
3364  } catch (SQLException ex) {
3365  throw new TskCoreException("Error getting attribute types", ex);
3366  } finally {
3367  closeResultSet(rs);
3368  closeStatement(s);
3369  connection.close();
3371  }
3372  }
3373 
3385  public int getBlackboardAttributeTypesCount() throws TskCoreException {
3386  CaseDbConnection connection = connections.getConnection();
3388  Statement s = null;
3389  ResultSet rs = null;
3390  try {
3391  s = connection.createStatement();
3392  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
3393  int count = 0;
3394  if (rs.next()) {
3395  count = rs.getInt("count");
3396  }
3397  return count;
3398  } catch (SQLException ex) {
3399  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3400  } finally {
3401  closeResultSet(rs);
3402  closeStatement(s);
3403  connection.close();
3405  }
3406  }
3407 
3420  ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
3421  CaseDbConnection connection = connections.getConnection();
3423  ResultSet rs = null;
3424  try {
3425  Statement statement = connection.createStatement();
3426  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
3427  + "blackboard_artifacts.obj_id AS obj_id, "
3428  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
3429  + "blackboard_artifacts.data_source_obj_id AS data_source_obj_id, "
3430  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
3431  + "blackboard_artifact_types.type_name AS type_name, "
3432  + "blackboard_artifact_types.display_name AS display_name, "
3433  + "blackboard_artifacts.review_status_id AS review_status_id "
3434  + "FROM blackboard_artifacts, blackboard_artifact_types "
3435  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
3436  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
3437  + " AND " + whereClause;
3438  rs = connection.executeQuery(statement, query);
3439  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3440  while (rs.next()) {
3441  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3442  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3443  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3444  }
3445  return artifacts;
3446  } catch (SQLException ex) {
3447  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
3448  } finally {
3449  closeResultSet(rs);
3450  connection.close();
3452  }
3453  }
3454 
3467  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
3468  CaseDbConnection connection = connections.getConnection();
3470  ResultSet rs = null;
3471  try {
3472  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
3473  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
3474  statement.clearParameters();
3475  statement.setLong(1, obj_id);
3476  statement.setInt(2, artifactTypeID);
3477  rs = connection.executeQuery(statement);
3478  long count = 0;
3479  if (rs.next()) {
3480  count = rs.getLong("count");
3481  }
3482  return count;
3483  } catch (SQLException ex) {
3484  throw new TskCoreException("Error getting blackboard artifact count", ex);
3485  } finally {
3486  closeResultSet(rs);
3487  connection.close();
3489  }
3490  }
3491 
3504  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
3505  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3506  }
3507 
3520  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
3521  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
3522  }
3523 
3536  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3537  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
3538  }
3539 
3552  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
3553  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
3554  if (artifactTypeID == -1) {
3555  return 0;
3556  }
3557  return getArtifactsCountHelper(artifactTypeID, obj_id);
3558  }
3559 
3572  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
3573  return getArtifactsCountHelper(artifactTypeID, obj_id);
3574  }
3575 
3588  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3589  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
3590  }
3591 
3603  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
3604  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3605  }
3606 
3618  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
3619  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
3620  }
3621 
3635  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3636  CaseDbConnection connection = connections.getConnection();
3638  Statement s = null;
3639  ResultSet rs = null;
3640  try {
3641  s = connection.createStatement();
3642  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3643  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3644  + "types.type_name AS type_name, types.display_name AS display_name,"
3645  + "arts.review_status_id AS review_status_id "//NON-NLS
3646  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3647  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3648  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3649  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
3650  + " AND attrs.value_text = '" + value + "'" //NON-NLS
3651  + " AND types.artifact_type_id=arts.artifact_type_id"
3652  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3653  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3654  while (rs.next()) {
3655  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3656  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3657  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3658  }
3659  return artifacts;
3660  } catch (SQLException ex) {
3661  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
3662  } finally {
3663  closeResultSet(rs);
3664  closeStatement(s);
3665  connection.close();
3667  }
3668  }
3669 
3680  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
3681  CaseDbConnection connection = connections.getConnection();
3683  ResultSet rs = null;
3684  Statement s;
3685  try {
3686  s = connection.createStatement();
3687  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
3688  + "arts.obj_id AS obj_id, arts.artifact_obj_id as artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, "
3689  + "types.type_name AS type_name, types.display_name AS display_name,"
3690  + "arts.review_status_id AS review_status_id "//NON-NLS
3691  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
3692  + "WHERE arts.artifact_id = " + artifactID
3693  + " AND arts.artifact_type_id = types.artifact_type_id");
3694  if (rs.next()) {
3695  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3696  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3697  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
3698  } else {
3699  /*
3700  * I think this should actually return null (or Optional) when
3701  * there is no artifact with the given id, but it looks like
3702  * existing code is not expecting that. -jm
3703  */
3704  throw new TskCoreException("No blackboard artifact with id " + artifactID);
3705  }
3706  } catch (SQLException ex) {
3707  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
3708  } finally {
3709  closeResultSet(rs);
3710  connection.close();
3712  }
3713  }
3714 
3723  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
3724  CaseDbConnection connection = connections.getConnection();
3726  try {
3727  addBlackBoardAttribute(attr, artifactTypeId, connection);
3728  } catch (SQLException ex) {
3729  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
3730  } finally {
3731  connection.close();
3733  }
3734  }
3735 
3745  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
3746  CaseDbConnection connection = connections.getConnection();
3748  try {
3749  connection.beginTransaction();
3750  for (final BlackboardAttribute attr : attributes) {
3751  addBlackBoardAttribute(attr, artifactTypeId, connection);
3752  }
3753  connection.commitTransaction();
3754  } catch (SQLException ex) {
3755  connection.rollbackTransaction();
3756  throw new TskCoreException("Error adding blackboard attributes", ex);
3757  } finally {
3758  connection.close();
3760  }
3761  }
3762 
3763  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
3764  PreparedStatement statement;
3765  switch (attr.getAttributeType().getValueType()) {
3766  case STRING:
3767  case JSON:
3768  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
3769  statement.clearParameters();
3770  statement.setString(7, attr.getValueString());
3771  break;
3772  case BYTE:
3773  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
3774  statement.clearParameters();
3775  statement.setBytes(7, attr.getValueBytes());
3776  break;
3777  case INTEGER:
3778  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
3779  statement.clearParameters();
3780  statement.setInt(7, attr.getValueInt());
3781  break;
3782  case LONG:
3783  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3784  statement.clearParameters();
3785  statement.setLong(7, attr.getValueLong());
3786  break;
3787  case DOUBLE:
3788  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
3789  statement.clearParameters();
3790  statement.setDouble(7, attr.getValueDouble());
3791  break;
3792  case DATETIME:
3793  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3794  statement.clearParameters();
3795  statement.setLong(7, attr.getValueLong());
3796  break;
3797  default:
3798  throw new TskCoreException("Unrecognized artifact attribute value type");
3799  }
3800  statement.setLong(1, attr.getArtifactID());
3801  statement.setInt(2, artifactTypeId);
3802  statement.setString(3, attr.getSourcesCSV());
3803  statement.setString(4, "");
3804  statement.setInt(5, attr.getAttributeType().getTypeID());
3805  statement.setLong(6, attr.getAttributeType().getValueType().getType());
3806  connection.executeUpdate(statement);
3807  }
3808 
3819  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
3820  /*
3821  * WARNING: This is a temporary implementation that is not safe and
3822  * denormalizes the case datbase.
3823  *
3824  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
3825  * the sources of artifact attributes.
3826  */
3827  if (null == source || source.isEmpty()) {
3828  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
3829  }
3830  CaseDbConnection connection = connections.getConnection();
3832  Statement queryStmt = null;
3833  Statement updateStmt = null;
3834  ResultSet result = null;
3835  String newSources = "";
3836  try {
3837  connection.beginTransaction();
3838  String valueClause = "";
3839  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
3840  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
3841  switch (valueType) {
3842  case STRING:
3843  case JSON:
3844  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
3845  break;
3846  case INTEGER:
3847  valueClause = " value_int32 = " + attr.getValueInt();
3848  break;
3849  case LONG:
3850  case DATETIME:
3851  valueClause = " value_int64 = " + attr.getValueLong();
3852  break;
3853  case DOUBLE:
3854  valueClause = " value_double = " + attr.getValueDouble();
3855  break;
3856  default:
3857  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
3858  }
3859  String query = "SELECT source FROM blackboard_attributes WHERE"
3860  + " artifact_id = " + attr.getArtifactID()
3861  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
3862  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
3863  + " AND " + valueClause + ";";
3864  queryStmt = connection.createStatement();
3865  updateStmt = connection.createStatement();
3866  result = connection.executeQuery(queryStmt, query);
3867  } else {
3868  /*
3869  * SELECT source FROM blackboard_attributes WHERE artifact_id =
3870  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
3871  * = ?
3872  */
3873  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
3874  statement.clearParameters();
3875  statement.setLong(1, attr.getArtifactID());
3876  statement.setLong(2, attr.getAttributeType().getTypeID());
3877  statement.setBytes(3, attr.getValueBytes());
3878  result = connection.executeQuery(statement);
3879  }
3880  while (result.next()) {
3881  String oldSources = result.getString("source");
3882  if (null != oldSources && !oldSources.isEmpty()) {
3883  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
3884  if (!uniqueSources.contains(source)) {
3885  newSources = oldSources + "," + source;
3886  } else {
3887  newSources = oldSources;
3888  }
3889  } else {
3890  newSources = source;
3891  }
3892  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
3893  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
3894  + " artifact_id = " + attr.getArtifactID()
3895  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
3896  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
3897  + " AND " + valueClause + ";";
3898  connection.executeUpdate(updateStmt, update);
3899  } else {
3900  /*
3901  * UPDATE blackboard_attributes SET source = ? WHERE
3902  * artifact_id = ? AND attribute_type_id = ? AND value_type
3903  * = 4 AND value_byte = ?
3904  */
3905  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
3906  statement.clearParameters();
3907  statement.setString(1, newSources);
3908  statement.setLong(2, attr.getArtifactID());
3909  statement.setLong(3, attr.getAttributeType().getTypeID());
3910  statement.setBytes(4, attr.getValueBytes());
3911  connection.executeUpdate(statement);
3912  }
3913  }
3914  connection.commitTransaction();
3915  return newSources;
3916  } catch (SQLException ex) {
3917  connection.rollbackTransaction();
3918  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
3919  } finally {
3920  closeResultSet(result);
3921  closeStatement(updateStmt);
3922  closeStatement(queryStmt);
3923  connection.close();
3925  }
3926  }
3927 
3942  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
3943  CaseDbConnection connection = connections.getConnection();
3945  Statement s = null;
3946  ResultSet rs = null;
3947  try {
3948  connection.beginTransaction();
3949  s = connection.createStatement();
3950  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
3951  if (!rs.next()) {
3952  rs.close();
3953  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
3954  int maxID = 0;
3955  if (rs.next()) {
3956  maxID = rs.getInt("highest_id");
3957  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
3958  maxID = MIN_USER_DEFINED_TYPE_ID;
3959  } else {
3960  maxID++;
3961  }
3962  }
3963  connection.executeUpdate(s, "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES ('" + maxID + "', '" + attrTypeString + "', '" + displayName + "', '" + valueType.getType() + "')"); //NON-NLS
3964  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
3965  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
3966  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
3967  connection.commitTransaction();
3968  return type;
3969  } else {
3970  throw new TskDataException("The attribute type that was added was already within the system.");
3971  }
3972 
3973  } catch (SQLException ex) {
3974  connection.rollbackTransaction();
3975  throw new TskCoreException("Error adding attribute type", ex);
3976  } finally {
3977  closeResultSet(rs);
3978  closeStatement(s);
3979  connection.close();
3981  }
3982  }
3983 
3994  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
3995  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
3996  return this.typeNameToAttributeTypeMap.get(attrTypeName);
3997  }
3998  CaseDbConnection connection = connections.getConnection();
4000  Statement s = null;
4001  ResultSet rs = null;
4002  try {
4003  s = connection.createStatement();
4004  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
4005  BlackboardAttribute.Type type = null;
4006  if (rs.next()) {
4007  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4008  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4009  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4010  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
4011  }
4012  return type;
4013  } catch (SQLException ex) {
4014  throw new TskCoreException("Error getting attribute type id", ex);
4015  } finally {
4016  closeResultSet(rs);
4017  closeStatement(s);
4018  connection.close();
4020  }
4021  }
4022 
4033  private BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
4034  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
4035  return this.typeIdToAttributeTypeMap.get(typeID);
4036  }
4037  CaseDbConnection connection = connections.getConnection();
4039  Statement s = null;
4040  ResultSet rs = null;
4041  try {
4042  s = connection.createStatement();
4043  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE attribute_type_id = " + typeID + ""); //NON-NLS
4044  BlackboardAttribute.Type type = null;
4045  if (rs.next()) {
4046  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4047  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4048  this.typeIdToAttributeTypeMap.put(typeID, type);
4049  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4050  }
4051  return type;
4052  } catch (SQLException ex) {
4053  throw new TskCoreException("Error getting attribute type id", ex);
4054  } finally {
4055  closeResultSet(rs);
4056  closeStatement(s);
4057  connection.close();
4059  }
4060  }
4061 
4072  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4073  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
4074  return this.typeNameToArtifactTypeMap.get(artTypeName);
4075  }
4076  CaseDbConnection connection = connections.getConnection();
4078  Statement s = null;
4079  ResultSet rs = null;
4080  try {
4081  s = connection.createStatement();
4082  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
4083  BlackboardArtifact.Type type = null;
4084  if (rs.next()) {
4085  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4086  rs.getString("type_name"), rs.getString("display_name"));
4087  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4088  this.typeNameToArtifactTypeMap.put(artTypeName, type);
4089  }
4090  return type;
4091  } catch (SQLException ex) {
4092  throw new TskCoreException("Error getting artifact type from the database", ex);
4093  } finally {
4094  closeResultSet(rs);
4095  closeStatement(s);
4096  connection.close();
4098  }
4099  }
4100 
4111  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
4112  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
4113  return typeIdToArtifactTypeMap.get(artTypeId);
4114  }
4115  CaseDbConnection connection = connections.getConnection();
4117  Statement s = null;
4118  ResultSet rs = null;
4119  try {
4120  s = connection.createStatement();
4121  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
4122  BlackboardArtifact.Type type = null;
4123  if (rs.next()) {
4124  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4125  rs.getString("type_name"), rs.getString("display_name"));
4126  this.typeIdToArtifactTypeMap.put(artTypeId, type);
4127  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4128  }
4129  return type;
4130  } catch (SQLException ex) {
4131  throw new TskCoreException("Error getting artifact type from the database", ex);
4132  } finally {
4133  closeResultSet(rs);
4134  closeStatement(s);
4135  connection.close();
4137  }
4138  }
4139 
4152  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4153  CaseDbConnection connection = connections.getConnection();
4155  Statement s = null;
4156  ResultSet rs = null;
4157  try {
4158  connection.beginTransaction();
4159  s = connection.createStatement();
4160  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
4161  if (!rs.next()) {
4162  rs.close();
4163  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
4164  int maxID = 0;
4165  if (rs.next()) {
4166  maxID = rs.getInt("highest_id");
4167  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4168  maxID = MIN_USER_DEFINED_TYPE_ID;
4169  } else {
4170  maxID++;
4171  }
4172  }
4173  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
4174  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName);
4175  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4176  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4177  connection.commitTransaction();
4178  return type;
4179  } else {
4180  throw new TskDataException("The attribute type that was added was already within the system.");
4181  }
4182  } catch (SQLException ex) {
4183  connection.rollbackTransaction();
4184  throw new TskCoreException("Error adding artifact type", ex);
4185  } finally {
4186  closeResultSet(rs);
4187  closeStatement(s);
4188  connection.close();
4190  }
4191  }
4192 
4193  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4194  CaseDbConnection connection = connections.getConnection();
4196  ResultSet rs = null;
4197  try {
4198  Statement statement = connection.createStatement();
4199  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
4200  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
4201  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4202  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4203  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
4204  + "types.type_name AS type_name, types.display_name AS display_name "
4205  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
4206  + " AND attrs.attribute_type_id = types.attribute_type_id");
4207  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
4208  while (rs.next()) {
4209  int attributeTypeId = rs.getInt("attribute_type_id");
4210  String attributeTypeName = rs.getString("type_name");
4211  BlackboardAttribute.Type attributeType;
4212  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
4213  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
4214  } else {
4215  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
4216  rs.getString("display_name"),
4218  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
4219  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
4220  }
4221 
4222  final BlackboardAttribute attr = new BlackboardAttribute(
4223  rs.getLong("artifact_id"),
4224  attributeType,
4225  rs.getString("source"),
4226  rs.getString("context"),
4227  rs.getInt("value_int32"),
4228  rs.getLong("value_int64"),
4229  rs.getDouble("value_double"),
4230  rs.getString("value_text"),
4231  rs.getBytes("value_byte"), this
4232  );
4233  attributes.add(attr);
4234  }
4235  return attributes;
4236  } catch (SQLException ex) {
4237  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
4238  } finally {
4239  closeResultSet(rs);
4240  connection.close();
4242  }
4243  }
4244 
4257  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
4258  CaseDbConnection connection = connections.getConnection();
4260  Statement s = null;
4261  ResultSet rs = null;
4262  try {
4263  s = connection.createStatement();
4264  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
4265  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
4266  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
4267  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
4268  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
4269  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
4270  + "FROM blackboard_attributes " + whereClause); //NON-NLS
4271  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
4272  while (rs.next()) {
4274  // attribute type is cached, so this does not necessarily call to the db
4275  type = this.getAttributeType(rs.getInt("attribute_type_id"));
4277  rs.getLong("artifact_id"),
4278  type,
4279  rs.getString("source"),
4280  rs.getString("context"),
4281  rs.getInt("value_int32"),
4282  rs.getLong("value_int64"),
4283  rs.getDouble("value_double"),
4284  rs.getString("value_text"),
4285  rs.getBytes("value_byte"), this
4286  );
4287  matches.add(attr);
4288  }
4289  return matches;
4290  } catch (SQLException ex) {
4291  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4292  } finally {
4293  closeResultSet(rs);
4294  closeStatement(s);
4295  connection.close();
4297  }
4298  }
4299 
4311  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
4312  CaseDbConnection connection = connections.getConnection();
4314  ResultSet rs = null;
4315  Statement s = null;
4316  try {
4317  s = connection.createStatement();
4318  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
4319  + "blackboard_artifacts.obj_id AS obj_id, blackboard_artifacts.artifact_obj_id AS artifact_obj_id, blackboard_artifacts.data_source_obj_id AS data_source_obj_id, blackboard_artifacts.artifact_type_id AS artifact_type_id, "
4320  + "blackboard_artifacts.review_status_id AS review_status_id "
4321  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
4322  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
4323  while (rs.next()) {
4324  BlackboardArtifact.Type type;
4325  // artifact type is cached, so this does not necessarily call to the db
4326  type = this.getArtifactType(rs.getInt("artifact_type_id"));
4327  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
4328  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
4329  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
4330  matches.add(artifact);
4331  }
4332  return matches;
4333  } catch (SQLException ex) {
4334  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4335  } finally {
4336  closeResultSet(rs);
4337  closeStatement(s);
4338  connection.close();
4340  }
4341  }
4342 
4356  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
4357  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
4358  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName());
4359  }
4360 
4372  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4373  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
4374  }
4375 
4376  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
4377  CaseDbConnection connection = connections.getConnection();
4379  ResultSet resultSet = null;
4380  try {
4381  long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
4382  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
4383 
4384  PreparedStatement statement = null;
4385  if (dbType == DbType.POSTGRESQL) {
4386  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4387  statement.clearParameters();
4388  statement.setLong(1, obj_id);
4389  statement.setLong(2, artifact_obj_id);
4390  statement.setLong(3, data_source_obj_id);
4391  statement.setInt(4, artifact_type_id);
4392 
4393  } else {
4394  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4395  statement.clearParameters();
4396  this.nextArtifactId++;
4397  statement.setLong(1, this.nextArtifactId);
4398  statement.setLong(2, obj_id);
4399  statement.setLong(3, artifact_obj_id);
4400  statement.setLong(4, data_source_obj_id);
4401  statement.setInt(5, artifact_type_id);
4402 
4403  }
4404  connection.executeUpdate(statement);
4405  resultSet = statement.getGeneratedKeys();
4406  resultSet.next();
4407  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
4408  obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
4409  } catch (SQLException ex) {
4410  throw new TskCoreException("Error creating a blackboard artifact", ex);
4411  } finally {
4412  closeResultSet(resultSet);
4413  connection.close();
4415  }
4416  }
4417 
4430  boolean getContentHasChildren(Content content) throws TskCoreException {
4431  CaseDbConnection connection = connections.getConnection();
4433  ResultSet rs = null;
4434  try {
4435  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4436  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4437  statement.clearParameters();
4438  statement.setLong(1, content.getId());
4439  rs = connection.executeQuery(statement);
4440  boolean hasChildren = false;
4441  if (rs.next()) {
4442  hasChildren = rs.getInt("count") > 0;
4443  }
4444  return hasChildren;
4445  } catch (SQLException e) {
4446  throw new TskCoreException("Error checking for children of parent " + content, e);
4447  } finally {
4448  closeResultSet(rs);
4449  connection.close();
4451  }
4452  }
4453 
4466  int getContentChildrenCount(Content content) throws TskCoreException {
4467 
4468  if (!this.getHasChildren(content)) {
4469  return 0;
4470  }
4471 
4472  CaseDbConnection connection = connections.getConnection();
4474  ResultSet rs = null;
4475  try {
4476  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4477  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4478  statement.clearParameters();
4479  statement.setLong(1, content.getId());
4480  rs = connection.executeQuery(statement);
4481  int countChildren = -1;
4482  if (rs.next()) {
4483  countChildren = rs.getInt("count");
4484  }
4485  return countChildren;
4486  } catch (SQLException e) {
4487  throw new TskCoreException("Error checking for children of parent " + content, e);
4488  } finally {
4489  closeResultSet(rs);
4490  connection.close();
4492  }
4493  }
4494 
4506  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4507  CaseDbConnection connection = connections.getConnection();
4509  ResultSet rs = null;
4510  try {
4511  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
4512  statement.clearParameters();
4513  long parentId = parent.getId();
4514  statement.setLong(1, parentId);
4515  statement.setShort(2, type.getFileType());
4516  rs = connection.executeQuery(statement);
4517  return fileChildren(rs, connection, parentId);
4518  } catch (SQLException ex) {
4519  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4520  } finally {
4521  closeResultSet(rs);
4522  connection.close();
4524  }
4525  }
4526 
4536  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
4537  CaseDbConnection connection = connections.getConnection();
4539  ResultSet rs = null;
4540  try {
4541  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
4542  statement.clearParameters();
4543  long parentId = parent.getId();
4544  statement.setLong(1, parentId);
4545  rs = connection.executeQuery(statement);
4546  return fileChildren(rs, connection, parentId);
4547  } catch (SQLException ex) {
4548  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4549  } finally {
4550  closeResultSet(rs);
4551  connection.close();
4553  }
4554  }
4555 
4567  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4568  CaseDbConnection connection = connections.getConnection();
4570  ResultSet rs = null;
4571  try {
4572  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
4573  statement.clearParameters();
4574  statement.setLong(1, parent.getId());
4575  statement.setShort(2, type.getFileType());
4576  rs = connection.executeQuery(statement);
4577  List<Long> children = new ArrayList<Long>();
4578  while (rs.next()) {
4579  children.add(rs.getLong("obj_id"));
4580  }
4581  return children;
4582  } catch (SQLException ex) {
4583  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4584  } finally {
4585  closeResultSet(rs);
4586  connection.close();
4588  }
4589  }
4590 
4600  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
4601  CaseDbConnection connection = connections.getConnection();
4603  ResultSet rs = null;
4604  try {
4605  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
4606  statement.clearParameters();
4607  statement.setLong(1, parent.getId());
4608  rs = connection.executeQuery(statement);
4609  List<Long> children = new ArrayList<Long>();
4610  while (rs.next()) {
4611  children.add(rs.getLong("obj_id"));
4612  }
4613  return children;
4614  } catch (SQLException ex) {
4615  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4616  } finally {
4617  closeResultSet(rs);
4618  connection.close();
4620  }
4621  }
4622 
4633  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
4634  CaseDbConnection connection = connections.getConnection();
4636  ResultSet rs = null;
4637  try {
4638  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
4639  statement.clearParameters();
4640  statement.setLong(1, parent.getId());
4641  rs = connection.executeQuery(statement);
4642  List<Long> children = new ArrayList<Long>();
4643  while (rs.next()) {
4644  children.add(rs.getLong("obj_id"));
4645  }
4646  return children;
4647  } catch (SQLException ex) {
4648  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
4649  } finally {
4650  closeResultSet(rs);
4651  connection.close();
4653  }
4654  }
4655 
4665  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
4666 
4667  long parentId = parent.getId();
4668  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
4669 
4670  List<Content> lc = new ArrayList<Content>();
4671  lc.addAll(artsArray);
4672  return lc;
4673  }
4674 
4683  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
4684  CaseDbConnection connection = connections.getConnection();
4686  Statement s = null;
4687  ResultSet rs = null;
4688  try {
4689  s = connection.createStatement();
4690  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
4691  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
4692  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
4693  + "WHERE tsk_objects.par_obj_id = " + c.getId()
4694  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
4695  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
4696  while (rs.next()) {
4697  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
4698  }
4699  return infos;
4700  } catch (SQLException ex) {
4701  throw new TskCoreException("Error getting Children Info for Content", ex);
4702  } finally {
4703  closeResultSet(rs);
4704  closeStatement(s);
4705  connection.close();
4707  }
4708  }
4709 
4720  ObjectInfo getParentInfo(Content c) throws TskCoreException {
4721  return getParentInfo(c.getId());
4722  }
4723 
4734  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
4735  CaseDbConnection connection = connections.getConnection();
4737  Statement s = null;
4738  ResultSet rs = null;
4739  try {
4740  s = connection.createStatement();
4741  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
4742  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
4743  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
4744  + "WHERE child.obj_id = " + contentId); //NON-NLS
4745  if (rs.next()) {
4746  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
4747  } else {
4748  return null;
4749  }
4750  } catch (SQLException ex) {
4751  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
4752  } finally {
4753  closeResultSet(rs);
4754  closeStatement(s);
4755  connection.close();
4757  }
4758  }
4759 
4770  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
4771  if (fsc.isRoot()) {
4772  // Given FsContent is a root object and can't have parent directory
4773  return null;
4774  } else {
4775  ObjectInfo parentInfo = getParentInfo(fsc);
4776  if (parentInfo == null) {
4777  return null;
4778  }
4779  Directory parent = null;
4780  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
4781  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
4782  } else {
4783  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
4784  }
4785  return parent;
4786  }
4787  }
4788 
4800  public Content getContentById(long id) throws TskCoreException {
4801  // First check to see if this exists in our frequently used content cache.
4802  Content content = frequentlyUsedContentMap.get(id);
4803  if (null != content) {
4804  return content;
4805  }
4806 
4807  CaseDbConnection connection = connections.getConnection();
4809  Statement s = null;
4810  ResultSet rs = null;
4811  long parentId;
4812  TskData.ObjectType type;
4813 
4814  try {
4815  s = connection.createStatement();
4816  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
4817  if (!rs.next()) {
4818  return null;
4819  }
4820  parentId = rs.getLong("par_obj_id"); //NON-NLS
4821  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
4822  } catch (SQLException ex) {
4823  throw new TskCoreException("Error getting Content by ID.", ex);
4824  } finally {
4825  closeResultSet(rs);
4826  closeStatement(s);
4827  connection.close();
4829  }
4830 
4831  // Construct the object
4832  switch (type) {
4833  case IMG:
4834  content = getImageById(id);
4835  frequentlyUsedContentMap.put(id, content);
4836  break;
4837  case VS:
4838  content = getVolumeSystemById(id, parentId);
4839  break;
4840  case VOL:
4841  content = getVolumeById(id, parentId);
4842  frequentlyUsedContentMap.put(id, content);
4843  break;
4844  case POOL:
4845  content = getPoolById(id, parentId);
4846  break;
4847  case FS:
4848  content = getFileSystemById(id, parentId);
4849  frequentlyUsedContentMap.put(id, content);
4850  break;
4851  case ABSTRACTFILE:
4852  content = getAbstractFileById(id);
4853 
4854  // Add virtual and root directories to frequently used map.
4855  // Calling isRoot() on local directories goes up the entire directory structure
4856  // and they can only be the root of portable cases, so skip trying to add
4857  // them to the cache.
4858  if (((AbstractFile) content).isVirtual()
4859  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
4860  frequentlyUsedContentMap.put(id, content);
4861  }
4862  break;
4863  case ARTIFACT:
4864  content = getArtifactById(id);
4865  break;
4866  case REPORT:
4867  content = getReportById(id);
4868  break;
4869  default:
4870  throw new TskCoreException("Could not obtain Content object with ID: " + id);
4871  }
4872 
4873  return content;
4874  }
4875 
4883  String getFilePath(long id) {
4884  CaseDbConnection connection;
4885  try {
4886  connection = connections.getConnection();
4887  } catch (TskCoreException ex) {
4888  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
4889  return null;
4890  }
4891  String filePath = null;
4893  ResultSet rs = null;
4894  try {
4895  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
4896  statement.clearParameters();
4897  statement.setLong(1, id);
4898  rs = connection.executeQuery(statement);
4899  if (rs.next()) {
4900  filePath = rs.getString("path");
4901  }
4902  } catch (SQLException ex) {
4903  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
4904  } finally {
4905  closeResultSet(rs);
4906  connection.close();
4908  }
4909  return filePath;
4910  }
4911 
4919  TskData.EncodingType getEncodingType(long id) {
4920  CaseDbConnection connection;
4921  try {
4922  connection = connections.getConnection();
4923  } catch (TskCoreException ex) {
4924  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
4925  return null;
4926  }
4927  TskData.EncodingType type = TskData.EncodingType.NONE;
4929  ResultSet rs = null;
4930  try {
4931  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
4932  statement.clearParameters();
4933  statement.setLong(1, id);
4934  rs = connection.executeQuery(statement);
4935  if (rs.next()) {
4936  type = TskData.EncodingType.valueOf(rs.getInt(1));
4937  }
4938  } catch (SQLException ex) {
4939  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
4940  } finally {
4941  closeResultSet(rs);
4942  connection.close();
4944  }
4945  return type;
4946  }
4947 
4956  String getFileParentPath(long objectId, CaseDbConnection connection) {
4957  String parentPath = null;
4959  ResultSet rs = null;
4960  try {
4961  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
4962  statement.clearParameters();
4963  statement.setLong(1, objectId);
4964  rs = connection.executeQuery(statement);
4965  if (rs.next()) {
4966  parentPath = rs.getString("parent_path");
4967  }
4968  } catch (SQLException ex) {
4969  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
4970  } finally {
4971  closeResultSet(rs);
4973  }
4974  return parentPath;
4975  }
4976 
4985  String getFileName(long objectId, CaseDbConnection connection) {
4986  String fileName = null;
4988  ResultSet rs = null;
4989  try {
4990  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
4991  statement.clearParameters();
4992  statement.setLong(1, objectId);
4993  rs = connection.executeQuery(statement);
4994  if (rs.next()) {
4995  fileName = rs.getString("name");
4996  }
4997  } catch (SQLException ex) {
4998  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
4999  } finally {
5000  closeResultSet(rs);
5002  }
5003  return fileName;
5004  }
5005 
5016  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5017  CaseDbConnection connection = connections.getConnection();
5018  DerivedFile.DerivedMethod method = null;
5020  ResultSet rs1 = null;
5021  ResultSet rs2 = null;
5022  try {
5023  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5024  statement.clearParameters();
5025  statement.setLong(1, id);
5026  rs1 = connection.executeQuery(statement);
5027  if (rs1.next()) {
5028  int method_id = rs1.getInt("derived_id");
5029  String rederive = rs1.getString("rederive");
5030  method = new DerivedFile.DerivedMethod(method_id, rederive);
5031  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5032  statement.clearParameters();
5033  statement.setInt(1, method_id);
5034  rs2 = connection.executeQuery(statement);
5035  if (rs2.next()) {
5036  method.setToolName(rs2.getString("tool_name"));
5037  method.setToolVersion(rs2.getString("tool_version"));
5038  method.setOther(rs2.getString("other"));
5039  }
5040  }
5041  } catch (SQLException e) {
5042  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5043  } finally {
5044  closeResultSet(rs2);
5045  closeResultSet(rs1);
5046  connection.close();
5048  }
5049  return method;
5050  }
5051 
5062  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5063  CaseDbConnection connection = connections.getConnection();
5064  try {
5065  return getAbstractFileById(id, connection);
5066  } finally {
5067  connection.close();
5068  }
5069  }
5070 
5083  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
5085  ResultSet rs = null;
5086  try {
5087  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
5088  statement.clearParameters();
5089  statement.setLong(1, objectId);
5090  rs = connection.executeQuery(statement);
5091  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
5092  if (files.size() > 0) {
5093  return files.get(0);
5094  } else {
5095  return null;
5096  }
5097  } catch (SQLException ex) {
5098  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
5099  } finally {
5100  closeResultSet(rs);
5102  }
5103  }
5104 
5115  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
5116  CaseDbConnection connection = connections.getConnection();
5118  ResultSet rs = null;
5119  try {
5120  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID);
5121  statement.clearParameters();
5122  statement.setLong(1, id);
5123  rs = connection.executeQuery(statement);
5124  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5125  if (artifacts.size() > 0) {
5126  return artifacts.get(0);
5127  } else {
5128  return null;
5129  }
5130  } catch (SQLException ex) {
5131  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
5132  } finally {
5133  closeResultSet(rs);
5134  connection.close();
5136  }
5137  }
5138 
5149  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
5150  CaseDbConnection connection = connections.getConnection();
5152  ResultSet rs = null;
5153  try {
5154  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_ID);
5155  statement.clearParameters();
5156  statement.setLong(1, id);
5157  rs = connection.executeQuery(statement);
5158  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5159  if (artifacts.size() > 0) {
5160  return artifacts.get(0);
5161  } else {
5162  return null;
5163  }
5164  } catch (SQLException ex) {
5165  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
5166  } finally {
5167  closeResultSet(rs);
5168  connection.close();
5170  }
5171  }
5172 
5185  private long getFileSystemId(long fileId, CaseDbConnection connection) {
5187  ResultSet rs = null;
5188  long ret = -1;
5189  try {
5190  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
5191  statement.clearParameters();
5192  statement.setLong(1, fileId);
5193  rs = connection.executeQuery(statement);
5194  if (rs.next()) {
5195  ret = rs.getLong("fs_obj_id");
5196  if (ret == 0) {
5197  ret = -1;
5198  }
5199  }
5200  } catch (SQLException e) {
5201  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
5202  } finally {
5203  closeResultSet(rs);
5205  }
5206  return ret;
5207  }
5208 
5220  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
5221  String query = String.format("SELECT COUNT(*) AS count FROM tsk_files WHERE obj_id = %d AND data_source_obj_id = %d", fileId, dataSource.getId()); //NON-NLS
5222  CaseDbConnection connection = connections.getConnection();
5224  Statement statement = null;
5225  ResultSet resultSet = null;
5226  try {
5227  statement = connection.createStatement();
5228  resultSet = connection.executeQuery(statement, query);
5229  resultSet.next();
5230  return (resultSet.getLong("count") > 0L);
5231  } catch (SQLException ex) {
5232  throw new TskCoreException(String.format("Error executing query %s", query), ex);
5233  } finally {
5234  closeResultSet(resultSet);
5235  closeStatement(statement);
5236  connection.close();
5238  }
5239  }
5240 
5252  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
5253  List<AbstractFile> files = new ArrayList<AbstractFile>();
5254  CaseDbConnection connection = connections.getConnection();
5256  ResultSet resultSet = null;
5257  try {
5258  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
5259  statement.clearParameters();
5260  statement.setString(1, fileName.toLowerCase());
5261  statement.setLong(2, dataSource.getId());
5262  resultSet = connection.executeQuery(statement);
5263  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5264  } catch (SQLException e) {
5265  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
5266  } finally {
5267  closeResultSet(resultSet);
5268  connection.close();
5270  }
5271  return files;
5272  }
5273 
5287  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
5288  List<AbstractFile> files = new ArrayList<AbstractFile>();
5289  CaseDbConnection connection = connections.getConnection();
5291  ResultSet resultSet = null;
5292  try {
5293  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
5294  statement.clearParameters();
5295  statement.setString(1, fileName.toLowerCase());
5296  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
5297  statement.setLong(3, dataSource.getId());
5298  resultSet = connection.executeQuery(statement);
5299  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5300  } catch (SQLException e) {
5301  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
5302  } finally {
5303  closeResultSet(resultSet);
5304  connection.close();
5306  }
5307  return files;
5308  }
5309 
5321  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
5322  CaseDbTransaction localTrans = beginTransaction();
5323  localTrans.acquireSingleUserCaseWriteLock();
5324  try {
5325  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
5326  localTrans.commit();
5327  localTrans = null;
5328  return newVD;
5329  } finally {
5330  // NOTE: write lock will be released by transaction
5331  if (null != localTrans) {
5332  try {
5333  localTrans.rollback();
5334  } catch (TskCoreException ex2) {
5335  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
5336  }
5337  }
5338  }
5339  }
5340 
5353  private long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
5354  ResultSet resultSet = null;
5356  try {
5357  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5358  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5359  statement.clearParameters();
5360  if (parentId != 0) {
5361  statement.setLong(1, parentId);
5362  } else {
5363  statement.setNull(1, java.sql.Types.BIGINT);
5364  }
5365  statement.setInt(2, objectType);
5366  connection.executeUpdate(statement);
5367  resultSet = statement.getGeneratedKeys();
5368 
5369  if (resultSet.next()) {
5370  if (parentId != 0) {
5371  setHasChildren(parentId);
5372  }
5373  return resultSet.getLong(1); //last_insert_rowid()
5374  } else {
5375  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
5376  }
5377  } finally {
5378  closeResultSet(resultSet);
5380  }
5381  }
5382 
5400  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5401  if (transaction == null) {
5402  throw new TskCoreException("Passed null CaseDbTransaction");
5403  }
5404 
5405  transaction.acquireSingleUserCaseWriteLock();
5406  ResultSet resultSet = null;
5407  try {
5408  // Get the parent path.
5409  CaseDbConnection connection = transaction.getConnection();
5410 
5411  String parentPath;
5412  Content parent = this.getAbstractFileById(parentId, connection);
5413  if (parent instanceof AbstractFile) {
5414  if (isRootDirectory((AbstractFile) parent, transaction)) {
5415  parentPath = "/";
5416  } else {
5417  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
5418  }
5419  } else {
5420  // The parent was either null or not an abstract file
5421  parentPath = "/";
5422  }
5423 
5424  // Insert a row for the virtual directory into the tsk_objects table.
5425  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5426 
5427  // Insert a row for the virtual directory into the tsk_files table.
5428  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5429  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension)
5430  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5431  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5432  statement.clearParameters();
5433  statement.setLong(1, newObjId);
5434 
5435  // If the parent is part of a file system, grab its file system ID
5436  if (0 != parentId) {
5437  long parentFs = this.getFileSystemId(parentId, connection);
5438  if (parentFs != -1) {
5439  statement.setLong(2, parentFs);
5440  } else {
5441  statement.setNull(2, java.sql.Types.BIGINT);
5442  }
5443  } else {
5444  statement.setNull(2, java.sql.Types.BIGINT);
5445  }
5446 
5447  // name
5448  statement.setString(3, directoryName);
5449 
5450  //type
5451  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5452  statement.setShort(5, (short) 1);
5453 
5454  //flags
5456  statement.setShort(6, dirType.getValue());
5458  statement.setShort(7, metaType.getValue());
5459 
5460  //allocated
5462  statement.setShort(8, dirFlag.getValue());
5463  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5464  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5465  statement.setShort(9, metaFlags);
5466 
5467  //size
5468  statement.setLong(10, 0);
5469 
5470  // nulls for params 11-14
5471  statement.setNull(11, java.sql.Types.BIGINT);
5472  statement.setNull(12, java.sql.Types.BIGINT);
5473  statement.setNull(13, java.sql.Types.BIGINT);
5474  statement.setNull(14, java.sql.Types.BIGINT);
5475 
5476  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5477  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5478  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5479 
5480  // parent path
5481  statement.setString(18, parentPath);
5482 
5483  // data source object id (same as object id if this is a data source)
5484  long dataSourceObjectId;
5485  if (0 == parentId) {
5486  dataSourceObjectId = newObjId;
5487  } else {
5488  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5489  }
5490  statement.setLong(19, dataSourceObjectId);
5491 
5492  //extension, since this is not really file we just set it to null
5493  statement.setString(20, null);
5494  connection.executeUpdate(statement);
5495 
5496  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5497  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5498  parentPath);
5499  } catch (SQLException e) {
5500  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
5501  } finally {
5502  closeResultSet(resultSet);
5503  // NOTE: write lock will be released by transaction
5504  }
5505  }
5506 
5519  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
5521  CaseDbTransaction localTrans = beginTransaction();
5522  try {
5523  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
5524  localTrans.commit();
5525  return newLD;
5526  } catch (TskCoreException ex) {
5527  try {
5528  localTrans.rollback();
5529  } catch (TskCoreException ex2) {
5530  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5531  }
5532  throw ex;
5533  } finally {
5535  }
5536  }
5537 
5555  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5556  if (transaction == null) {
5557  throw new TskCoreException("Passed null CaseDbTransaction");
5558  }
5559 
5560  transaction.acquireSingleUserCaseWriteLock();
5561  ResultSet resultSet = null;
5562  try {
5563  // Get the parent path.
5564  CaseDbConnection connection = transaction.getConnection();
5565  AbstractFile parent = getAbstractFileById(parentId, connection);
5566  String parentPath;
5567  if ((parent == null) || isRootDirectory(parent, transaction)) {
5568  parentPath = "/";
5569  } else {
5570  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
5571  }
5572 
5573  // Insert a row for the local directory into the tsk_objects table.
5574  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5575 
5576  // Insert a row for the local directory into the tsk_files table.
5577  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5578  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id)
5579  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5580  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5581  statement.clearParameters();
5582  statement.setLong(1, newObjId);
5583 
5584  // The parent of a local directory will never be a file system
5585  statement.setNull(2, java.sql.Types.BIGINT);
5586 
5587  // name
5588  statement.setString(3, directoryName);
5589 
5590  //type
5591  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
5592  statement.setShort(5, (short) 1);
5593 
5594  //flags
5596  statement.setShort(6, dirType.getValue());
5598  statement.setShort(7, metaType.getValue());
5599 
5600  //allocated
5602  statement.setShort(8, dirFlag.getValue());
5603  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5604  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5605  statement.setShort(9, metaFlags);
5606 
5607  //size
5608  statement.setLong(10, 0);
5609 
5610  // nulls for params 11-14
5611  statement.setNull(11, java.sql.Types.BIGINT);
5612  statement.setNull(12, java.sql.Types.BIGINT);
5613  statement.setNull(13, java.sql.Types.BIGINT);
5614  statement.setNull(14, java.sql.Types.BIGINT);
5615 
5616  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5617  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5618  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5619 
5620  // parent path
5621  statement.setString(18, parentPath);
5622 
5623  // data source object id
5624  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5625  statement.setLong(19, dataSourceObjectId);
5626 
5627  //extension, since this is a directory we just set it to null
5628  statement.setString(20, null);
5629 
5630  connection.executeUpdate(statement);
5631 
5632  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5633  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5634  parentPath);
5635  } catch (SQLException e) {
5636  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
5637  } finally {
5638  closeResultSet(resultSet);
5639  // NOTE: write lock will be released by transaction
5640  }
5641  }
5642 
5662  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
5664  Statement statement = null;
5665  try {
5666  // Insert a row for the root virtual directory of the data source
5667  // into the tsk_objects table.
5668  CaseDbConnection connection = transaction.getConnection();
5669  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5670 
5671  // Insert a row for the virtual directory of the data source into
5672  // the data_source_info table.
5673  statement = connection.createStatement();
5674  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
5675  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');");
5676 
5677  // Insert a row for the root virtual directory of the data source
5678  // into the tsk_files table. Note that its data source object id is
5679  // its own object id.
5680  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
5681  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
5682  // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension)
5683  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5684  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5685  preparedStatement.clearParameters();
5686  preparedStatement.setLong(1, newObjId);
5687  preparedStatement.setNull(2, java.sql.Types.BIGINT);
5688  preparedStatement.setString(3, rootDirectoryName);
5689  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5690  preparedStatement.setShort(5, (short) 1);
5692  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
5694  preparedStatement.setShort(7, metaType.getValue());
5696  preparedStatement.setShort(8, dirFlag.getValue());
5697  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5698  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5699  preparedStatement.setShort(9, metaFlags);
5700  preparedStatement.setLong(10, 0);
5701  preparedStatement.setNull(11, java.sql.Types.BIGINT);
5702  preparedStatement.setNull(12, java.sql.Types.BIGINT);
5703  preparedStatement.setNull(13, java.sql.Types.BIGINT);
5704  preparedStatement.setNull(14, java.sql.Types.BIGINT);
5705  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
5706  preparedStatement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5707  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5708  String parentPath = "/"; //NON-NLS
5709  preparedStatement.setString(18, parentPath);
5710  preparedStatement.setLong(19, newObjId);
5711  preparedStatement.setString(20, null); //extension, just set it to null
5712  connection.executeUpdate(preparedStatement);
5713 
5714  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, FileKnown.UNKNOWN, parentPath);
5715 
5716  } catch (SQLException ex) {
5717  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
5718  } finally {
5719  closeStatement(statement);
5721  }
5722  }
5723 
5743  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
5744  String timezone, String md5, String sha1, String sha256,
5745  String deviceId,
5746  CaseDbTransaction transaction) throws TskCoreException {
5748  Statement statement = null;
5749  try {
5750  // Insert a row for the Image into the tsk_objects table.
5751  CaseDbConnection connection = transaction.getConnection();
5752  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
5753 
5754  // Add a row to tsk_image_info
5755  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
5756  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
5757  preparedStatement.clearParameters();
5758  preparedStatement.setLong(1, newObjId);
5759  preparedStatement.setShort(2, (short) type.getValue());
5760  preparedStatement.setLong(3, sectorSize);
5761  preparedStatement.setString(4, timezone);
5762  //prevent negative size
5763  long savedSize = size < 0 ? 0 : size;
5764  preparedStatement.setLong(5, savedSize);
5765  preparedStatement.setString(6, md5);
5766  preparedStatement.setString(7, sha1);
5767  preparedStatement.setString(8, sha256);
5768  preparedStatement.setString(9, displayName);
5769  connection.executeUpdate(preparedStatement);
5770 
5771  // If there are paths, add them to tsk_image_names
5772  for (int i = 0; i < imagePaths.size(); i++) {
5773  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
5774  preparedStatement.clearParameters();
5775  preparedStatement.setLong(1, newObjId);
5776  preparedStatement.setString(2, imagePaths.get(i));
5777  preparedStatement.setLong(3, i);
5778  connection.executeUpdate(preparedStatement);
5779  }
5780 
5781  // Add a row to data_source_info
5782  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
5783  statement = connection.createStatement();
5784  preparedStatement.setLong(1, newObjId);
5785  preparedStatement.setString(2, deviceId);
5786  preparedStatement.setString(3, timezone);
5787  connection.executeUpdate(preparedStatement);
5788 
5789  // Create the new Image object
5790  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, displayName,
5791  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
5792  } catch (SQLException ex) {
5793  if (!imagePaths.isEmpty()) {
5794  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
5795  } else {
5796  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
5797  }
5798  } finally {
5799  closeStatement(statement);
5801  }
5802  }
5803 
5817  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
5818  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
5820  try {
5821  // Insert a row for the VolumeSystem into the tsk_objects table.
5822  CaseDbConnection connection = transaction.getConnection();
5823  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
5824 
5825  // Add a row to tsk_vs_info
5826  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
5827  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
5828  preparedStatement.clearParameters();
5829  preparedStatement.setLong(1, newObjId);
5830  preparedStatement.setShort(2, (short) type.getVsType());
5831  preparedStatement.setLong(3, imgOffset);
5832  preparedStatement.setLong(4, blockSize);
5833  connection.executeUpdate(preparedStatement);
5834 
5835  // Create the new VolumeSystem object
5836  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
5837  } catch (SQLException ex) {
5838  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
5839  parentObjId, imgOffset), ex);
5840  } finally {
5842  }
5843  }
5844 
5860  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
5861  long flags, CaseDbTransaction transaction) throws TskCoreException {
5863  Statement statement = null;
5864  try {
5865  // Insert a row for the Volume into the tsk_objects table.
5866  CaseDbConnection connection = transaction.getConnection();
5867  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
5868 
5869  // Add a row to tsk_vs_parts
5870  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
5871  PreparedStatement preparedStatement;
5872  if (this.dbType == DbType.POSTGRESQL) {
5873  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
5874  } else {
5875  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
5876  }
5877  preparedStatement.clearParameters();
5878  preparedStatement.setLong(1, newObjId);
5879  preparedStatement.setLong(2, addr);
5880  preparedStatement.setLong(3, start);
5881  preparedStatement.setLong(4, length);
5882  preparedStatement.setString(5, desc);
5883  preparedStatement.setShort(6, (short) flags);
5884  connection.executeUpdate(preparedStatement);
5885 
5886  // Create the new Volume object
5887  return new Volume(this, newObjId, addr, start, length, flags, desc);
5888  } catch (SQLException ex) {
5889  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
5890  } finally {
5891  closeStatement(statement);
5893  }
5894  }
5895 
5907  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
5909  Statement statement = null;
5910  try {
5911  // Insert a row for the Pool into the tsk_objects table.
5912  CaseDbConnection connection = transaction.getConnection();
5913  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
5914 
5915  // Add a row to tsk_pool_info
5916  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
5917  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
5918  preparedStatement.clearParameters();
5919  preparedStatement.setLong(1, newObjId);
5920  preparedStatement.setShort(2, type.getValue());
5921  connection.executeUpdate(preparedStatement);
5922 
5923  // Create the new Pool object
5924  return new Pool(this, newObjId, type.getName(), type.getValue());
5925  } catch (SQLException ex) {
5926  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
5927  } finally {
5928  closeStatement(statement);
5930  }
5931  }
5932 
5951  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
5952  long rootInum, long firstInum, long lastInum, String displayName,
5953  CaseDbTransaction transaction) throws TskCoreException {
5955  Statement statement = null;
5956  try {
5957  // Insert a row for the FileSystem into the tsk_objects table.
5958  CaseDbConnection connection = transaction.getConnection();
5959  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
5960 
5961  // Add a row to tsk_fs_info
5962  // INSERT INTO tsk_fs_info (obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)
5963  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
5964  preparedStatement.clearParameters();
5965  preparedStatement.setLong(1, newObjId);
5966  preparedStatement.setLong(2, imgOffset);
5967  preparedStatement.setShort(3, (short) type.getValue());
5968  preparedStatement.setLong(4, blockSize);
5969  preparedStatement.setLong(5, blockCount);
5970  preparedStatement.setLong(6, rootInum);
5971  preparedStatement.setLong(7, firstInum);
5972  preparedStatement.setLong(8, lastInum);
5973  preparedStatement.setString(9, displayName);
5974  connection.executeUpdate(preparedStatement);
5975 
5976  // Create the new FileSystem object
5977  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
5978  firstInum, lastInum);
5979  } catch (SQLException ex) {
5980  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
5981  imgOffset, parentObjId), ex);
5982  } finally {
5983  closeStatement(statement);
5985  }
5986  }
5987 
6013  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
6014  String fileName,
6015  long metaAddr, int metaSeq,
6016  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
6017  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
6018  long ctime, long crtime, long atime, long mtime,
6019  boolean isFile, Content parent) throws TskCoreException {
6020 
6021  CaseDbTransaction transaction = beginTransaction();
6022  Statement queryStatement = null;
6023  try {
6024  CaseDbConnection connection = transaction.getConnection();
6025  transaction.acquireSingleUserCaseWriteLock();
6026 
6027  // Insert a row for the local/logical file into the tsk_objects table.
6028  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6029  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6030 
6031  String parentPath;
6032 
6033  if (parent instanceof AbstractFile) {
6034  AbstractFile parentFile = (AbstractFile) parent;
6035  if (isRootDirectory(parentFile, transaction)) {
6036  parentPath = "/";
6037  } else {
6038  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
6039  }
6040  } else {
6041  parentPath = "/";
6042  }
6043 
6044  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
6045  statement.clearParameters();
6046  statement.setLong(1, objectId); // obj_is
6047  statement.setLong(2, fsObjId); // fs_obj_id
6048  statement.setLong(3, dataSourceObjId); // data_source_obj_id
6049  statement.setShort(4, (short) attrType.getValue()); // attr_type
6050  statement.setInt(5, attrId); // attr_id
6051  statement.setString(6, fileName); // name
6052  statement.setLong(7, metaAddr); // meta_addr
6053  statement.setInt(8, metaSeq); // meta_addr
6054  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
6055  statement.setShort(10, (short) 1); // has_path
6057  statement.setShort(11, dirType.getValue()); // dir_type
6059  statement.setShort(12, metaType.getValue()); // meta_type
6060  statement.setShort(13, dirFlag.getValue()); // dir_flags
6061  statement.setShort(14, metaFlags); // meta_flags
6062  statement.setLong(15, size < 0 ? 0 : size);
6063  statement.setLong(16, ctime);
6064  statement.setLong(17, crtime);
6065  statement.setLong(18, atime);
6066  statement.setLong(19, mtime);
6067  statement.setString(20, parentPath);
6068  final String extension = extractExtension(fileName);
6069  statement.setString(21, extension);
6070 
6071  connection.executeUpdate(statement);
6072 
6073  transaction.commit();
6074  transaction = null;
6075 
6076  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
6077  attrType, attrId, fileName, metaAddr, metaSeq,
6078  dirType, metaType, dirFlag, metaFlags,
6079  size, ctime, crtime, atime, mtime,
6080  (short) 0, 0, 0, null, null, parentPath, null,
6081  extension);
6082 
6083  } catch (SQLException ex) {
6084  logger.log(Level.WARNING, "Failed to add file system file", ex);
6085  } finally {
6086  closeStatement(queryStatement);
6087  if (null != transaction) {
6088  try {
6089  transaction.rollback();
6090  } catch (TskCoreException ex2) {
6091  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6092  }
6093  }
6094  }
6095  return null;
6096  }
6097 
6106  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
6107  CaseDbConnection connection = connections.getConnection();
6109  Statement s = null;
6110  ResultSet rs = null;
6111  try {
6112  s = connection.createStatement();
6113  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
6114  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
6115  + " AND obj_id = data_source_obj_id"
6116  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
6117  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
6118  while (rs.next()) {
6119  virtDirRootIds.add(virtualDirectory(rs, connection));
6120  }
6121  return virtDirRootIds;
6122  } catch (SQLException ex) {
6123  throw new TskCoreException("Error getting local files virtual folder id", ex);
6124  } finally {
6125  closeResultSet(rs);
6126  closeStatement(s);
6127  connection.close();
6129  }
6130  }
6131 
6144  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
6145  assert (null != fileRanges);
6146  if (null == fileRanges) {
6147  throw new TskCoreException("TskFileRange object is null");
6148  }
6149 
6150  assert (null != parent);
6151  if (null == parent) {
6152  throw new TskCoreException("Conent is null");
6153  }
6154 
6155  CaseDbTransaction transaction = null;
6156  Statement statement = null;
6157  ResultSet resultSet = null;
6158 
6159  try {
6160  transaction = beginTransaction();
6161  transaction.acquireSingleUserCaseWriteLock();
6162  CaseDbConnection connection = transaction.getConnection();
6163 
6164  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
6165  for (TskFileRange fileRange : fileRanges) {
6166  /*
6167  * Insert a row for the Tsk file range into the tsk_objects
6168  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
6169  * ?)
6170  */
6171  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6172  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
6173  /*
6174  * Insert a row for the Tsk file range into the tsk_files table:
6175  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6176  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6177  * ctime, crtime, atime, mtime, md5, known, mime_type,
6178  * parent_path, data_source_obj_id,extension) VALUES (?, ?, ?,
6179  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6180  */
6181  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6182  prepStmt.clearParameters();
6183  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
6184  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6185  prepStmt.setString(3, "Unalloc_" + parent.getId() + "_" + fileRange.getByteStart() + "_" + end_byte_in_parent); // name of form Unalloc_[image obj_id]_[start byte in parent]_[end byte in parent]
6186  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
6187  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
6188  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6189  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6190  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6191  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6192  prepStmt.setLong(10, fileRange.getByteLen()); // size
6193  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6194  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6195  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6196  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6197  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6198  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6199  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6200  prepStmt.setNull(18, java.sql.Types.VARCHAR); // parent path
6201  prepStmt.setLong(19, parent.getId()); // data_source_obj_id
6202 
6203  //extension, since this is not a FS file we just set it to null
6204  prepStmt.setString(20, null);
6205  connection.executeUpdate(prepStmt);
6206 
6207  /*
6208  * Insert a row in the tsk_layout_file table for each chunk of
6209  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6210  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6211  */
6212  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6213  prepStmt.clearParameters();
6214  prepStmt.setLong(1, fileRangeId); // obj_id
6215  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
6216  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
6217  prepStmt.setLong(4, fileRange.getSequence()); // sequence
6218  connection.executeUpdate(prepStmt);
6219 
6220  /*
6221  * Create a layout file representation of the carved file.
6222  */
6223  fileRangeLayoutFiles.add(new LayoutFile(this,
6224  fileRangeId,
6225  parent.getId(),
6226  Long.toString(fileRange.getSequence()),
6231  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6232  fileRange.getByteLen(),
6233  0L, 0L, 0L, 0L,
6234  null,
6236  parent.getUniquePath(),
6237  null));
6238  }
6239 
6240  transaction.commit();
6241  transaction = null;
6242  return fileRangeLayoutFiles;
6243 
6244  } catch (SQLException ex) {
6245  throw new TskCoreException("Failed to add layout files to case database", ex);
6246  } finally {
6247  closeResultSet(resultSet);
6248  closeStatement(statement);
6249 
6250  // NOTE: write lock will be released by transaction
6251  if (null != transaction) {
6252  try {
6253  transaction.rollback();
6254  } catch (TskCoreException ex2) {
6255  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6256  }
6257  }
6258  }
6259  }
6260 
6272  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
6273  assert (null != carvingResult);
6274  if (null == carvingResult) {
6275  throw new TskCoreException("Carving is null");
6276  }
6277  assert (null != carvingResult.getParent());
6278  if (null == carvingResult.getParent()) {
6279  throw new TskCoreException("Carving result has null parent");
6280  }
6281  assert (null != carvingResult.getCarvedFiles());
6282  if (null == carvingResult.getCarvedFiles()) {
6283  throw new TskCoreException("Carving result has null carved files");
6284  }
6285  CaseDbTransaction transaction = null;
6286  Statement statement = null;
6287  ResultSet resultSet = null;
6288  long newCacheKey = 0; // Used to roll back cache if transaction is rolled back.
6289  try {
6290  transaction = beginTransaction();
6291  transaction.acquireSingleUserCaseWriteLock();
6292  CaseDbConnection connection = transaction.getConnection();
6293 
6294  /*
6295  * Carved files are "re-parented" as children of the $CarvedFiles
6296  * virtual directory of the root file system, volume, or image
6297  * ancestor of the carved files parent, but if no such ancestor is
6298  * found, then the parent specified in the carving result is used.
6299  */
6300  Content root = carvingResult.getParent();
6301  while (null != root) {
6302  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
6303  break;
6304  }
6305  root = root.getParent();
6306  }
6307  if (null == root) {
6308  root = carvingResult.getParent();
6309  }
6310 
6311  /*
6312  * Get or create the $CarvedFiles virtual directory for the root
6313  * ancestor.
6314  */
6315  VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
6316  if (null == carvedFilesDir) {
6317  List<Content> rootChildren;
6318  if (root instanceof FileSystem) {
6319  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
6320  } else {
6321  rootChildren = root.getChildren();
6322  }
6323  for (Content child : rootChildren) {
6324  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
6325  carvedFilesDir = (VirtualDirectory) child;
6326  break;
6327  }
6328  }
6329  if (null == carvedFilesDir) {
6330  long parId = root.getId();
6331  // $CarvedFiles should be a child of the root directory, not the file system
6332  if (root instanceof FileSystem) {
6333  Content rootDir = ((FileSystem) root).getRootDirectory();
6334  parId = rootDir.getId();
6335  }
6336  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED, transaction);
6337  }
6338  newCacheKey = root.getId();
6339  rootIdsToCarvedFileDirs.put(newCacheKey, carvedFilesDir);
6340  }
6341 
6342  /*
6343  * Add the carved files to the database as children of the
6344  * $CarvedFile directory of the root ancestor.
6345  */
6346  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
6347  List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>();
6348  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
6349  /*
6350  * Insert a row for the carved file into the tsk_objects table:
6351  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6352  */
6353  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6354 
6355  /*
6356  * Insert a row for the carved file into the tsk_files table:
6357  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6358  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6359  * ctime, crtime, atime, mtime, md5, known, mime_type,
6360  * parent_path, data_source_obj_id,extenion) VALUES (?, ?, ?, ?,
6361  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6362  */
6363  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6364  prepStmt.clearParameters();
6365  prepStmt.setLong(1, carvedFileId); // obj_id
6366  if (root instanceof FileSystem) {
6367  prepStmt.setLong(2, root.getId()); // fs_obj_id
6368  } else {
6369  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6370  }
6371  prepStmt.setString(3, carvedFile.getName()); // name
6372  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
6373  prepStmt.setShort(5, (short) 1); // has_path
6374  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6375  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6376  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6377  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6378  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
6379  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6380  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6381  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6382  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6383  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6384  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6385  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6386  prepStmt.setString(18, parentPath); // parent path
6387  prepStmt.setLong(19, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
6388  prepStmt.setString(20, extractExtension(carvedFile.getName())); //extension
6389  connection.executeUpdate(prepStmt);
6390 
6391  /*
6392  * Insert a row in the tsk_layout_file table for each chunk of
6393  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6394  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6395  */
6396  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6397  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
6398  prepStmt.clearParameters();
6399  prepStmt.setLong(1, carvedFileId); // obj_id
6400  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
6401  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
6402  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
6403  connection.executeUpdate(prepStmt);
6404  }
6405 
6406  /*
6407  * Create a layout file representation of the carved file.
6408  */
6409  carvedFiles.add(new LayoutFile(this,
6410  carvedFileId,
6411  carvedFilesDir.getDataSourceObjectId(),
6412  carvedFile.getName(),
6417  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6418  carvedFile.getSizeInBytes(),
6419  0L, 0L, 0L, 0L,
6420  null,
6422  parentPath,
6423  null));
6424  }
6425 
6426  transaction.commit();
6427  transaction = null;
6428  return carvedFiles;
6429 
6430  } catch (SQLException ex) {
6431  throw new TskCoreException("Failed to add carved files to case database", ex);
6432  } finally {
6433  closeResultSet(resultSet);
6434  closeStatement(statement);
6435 
6436  // NOTE: write lock will be released by transaction
6437  if (null != transaction) {
6438  try {
6439  transaction.rollback();
6440  } catch (TskCoreException ex2) {
6441  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6442  }
6443  if (0 != newCacheKey) {
6444  rootIdsToCarvedFileDirs.remove(newCacheKey);
6445  }
6446  }
6447  }
6448  }
6449 
6480  public DerivedFile addDerivedFile(String fileName, String localPath,
6481  long size, long ctime, long crtime, long atime, long mtime,
6482  boolean isFile, Content parentObj,
6483  String rederiveDetails, String toolName, String toolVersion,
6484  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6485  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6486  localPath = localPath.replaceAll("^[/\\\\]+", "");
6487 
6489  TimelineManager timelineManager = getTimelineManager();
6490 
6491  CaseDbTransaction transaction = beginTransaction();
6492  CaseDbConnection connection = transaction.getConnection();
6493  try {
6494  final long parentId = parentObj.getId();
6495  String parentPath = "";
6496  if (parentObj instanceof BlackboardArtifact) {
6497  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6498  } else if (parentObj instanceof AbstractFile) {
6499  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6500  }
6501 
6502  // Insert a row for the derived file into the tsk_objects table.
6503  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6504  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6505 
6506  // Insert a row for the virtual directory into the tsk_files table.
6507  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6508  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6509  // parent_path, data_source_obj_id, extension)
6510  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6511  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6512  statement.clearParameters();
6513  statement.setLong(1, newObjId);
6514 
6515  // If the parentFile is part of a file system, use its file system object ID.
6516  long fsObjId = this.getFileSystemId(parentId, connection);
6517  if (fsObjId != -1) {
6518  statement.setLong(2, fsObjId);
6519  } else {
6520  statement.setNull(2, java.sql.Types.BIGINT);
6521  }
6522  statement.setString(3, fileName);
6523 
6524  //type, has_path
6525  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6526  statement.setShort(5, (short) 1);
6527 
6528  //flags
6530  statement.setShort(6, dirType.getValue());
6532  statement.setShort(7, metaType.getValue());
6533 
6534  //note: using alloc under assumption that derived files derive from alloc files
6536  statement.setShort(8, dirFlag.getValue());
6537  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6538  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6539  statement.setShort(9, metaFlags);
6540 
6541  //size
6542  //prevent negative size
6543  long savedSize = size < 0 ? 0 : size;
6544  statement.setLong(10, savedSize);
6545 
6546  //mactimes
6547  //long ctime, long crtime, long atime, long mtime,
6548  statement.setLong(11, ctime);
6549  statement.setLong(12, crtime);
6550  statement.setLong(13, atime);
6551  statement.setLong(14, mtime);
6552 
6553  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6554  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6555  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
6556 
6557  //parent path
6558  statement.setString(18, parentPath);
6559 
6560  // root data source object id
6561  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6562  statement.setLong(19, dataSourceObjId);
6563  final String extension = extractExtension(fileName);
6564  //extension
6565  statement.setString(20, extension);
6566 
6567  connection.executeUpdate(statement);
6568 
6569  //add localPath
6570  addFilePath(connection, newObjId, localPath, encodingType);
6571 
6572  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
6573  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6574 
6575  timelineManager.addEventsForNewFile(derivedFile, connection);
6576  transaction.commit();
6577  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
6578  return derivedFile;
6579  } catch (SQLException ex) {
6580  connection.rollbackTransaction();
6581  throw new TskCoreException("Failed to add derived file to case database", ex);
6582  } finally {
6583  connection.close();
6585  }
6586  }
6587 
6618  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
6619  long size, long ctime, long crtime, long atime, long mtime,
6620  boolean isFile, String mimeType,
6621  String rederiveDetails, String toolName, String toolVersion,
6622  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6623 
6624  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6625  localPath = localPath.replaceAll("^[/\\\\]+", "");
6626 
6627  CaseDbConnection connection = connections.getConnection();
6629  ResultSet rs = null;
6630  try {
6631  Content parentObj = derivedFile.getParent();
6632  connection.beginTransaction();
6633  final long parentId = parentObj.getId();
6634  String parentPath = "";
6635  if (parentObj instanceof BlackboardArtifact) {
6636  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6637  } else if (parentObj instanceof AbstractFile) {
6638  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6639  }
6640  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
6641  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
6642  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
6643  statement.clearParameters();
6644 
6645  //type
6646  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6647 
6648  //flags
6650  statement.setShort(2, dirType.getValue());
6652  statement.setShort(3, metaType.getValue());
6653 
6654  //note: using alloc under assumption that derived files derive from alloc files
6656  statement.setShort(4, dirFlag.getValue());
6657  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6658  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6659  statement.setShort(5, metaFlags);
6660 
6661  //size
6662  //prevent negative size
6663  long savedSize = size < 0 ? 0 : size;
6664  statement.setLong(6, savedSize);
6665 
6666  //mactimes
6667  //long ctime, long crtime, long atime, long mtime,
6668  statement.setLong(7, ctime);
6669  statement.setLong(8, crtime);
6670  statement.setLong(9, atime);
6671  statement.setLong(10, mtime);
6672  statement.setString(11, mimeType);
6673  statement.setString(12, String.valueOf(derivedFile.getId()));
6674  connection.executeUpdate(statement);
6675 
6676  //add localPath
6677  updateFilePath(connection, derivedFile.getId(), localPath, encodingType);
6678 
6679  connection.commitTransaction();
6680 
6681  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6682  final String extension = extractExtension(derivedFile.getName());
6683  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
6684  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6685  } catch (SQLException ex) {
6686  connection.rollbackTransaction();
6687  throw new TskCoreException("Failed to add derived file to case database", ex);
6688  } finally {
6689  closeResultSet(rs);
6690  connection.close();
6692  }
6693  }
6694 
6714  public LocalFile addLocalFile(String fileName, String localPath,
6715  long size, long ctime, long crtime, long atime, long mtime,
6716  boolean isFile, TskData.EncodingType encodingType,
6717  AbstractFile parent) throws TskCoreException {
6718 
6719  CaseDbTransaction localTrans = beginTransaction();
6720  try {
6721  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
6722  localTrans.commit();
6723  localTrans = null;
6724  return created;
6725  } finally {
6726  if (null != localTrans) {
6727  try {
6728  localTrans.rollback();
6729  } catch (TskCoreException ex2) {
6730  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6731  }
6732  }
6733  }
6734  }
6735 
6760  public LocalFile addLocalFile(String fileName, String localPath,
6761  long size, long ctime, long crtime, long atime, long mtime,
6762  boolean isFile, TskData.EncodingType encodingType,
6763  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6764 
6765  return addLocalFile(fileName, localPath,
6766  size, ctime, crtime, atime, mtime,
6767  null, null, null,
6768  isFile, encodingType,
6769  parent, transaction);
6770  }
6771 
6799  public LocalFile addLocalFile(String fileName, String localPath,
6800  long size, long ctime, long crtime, long atime, long mtime,
6801  String md5, FileKnown known, String mimeType,
6802  boolean isFile, TskData.EncodingType encodingType,
6803  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6804  CaseDbConnection connection = transaction.getConnection();
6805  transaction.acquireSingleUserCaseWriteLock();
6806  Statement queryStatement = null;
6807  try {
6808 
6809  // Insert a row for the local/logical file into the tsk_objects table.
6810  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6811  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6812 
6813  // Insert a row for the local/logical file into the tsk_files table.
6814  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6815  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6816  // parent_path, data_source_obj_id,extension)
6817  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6818  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6819  statement.clearParameters();
6820  statement.setLong(1, objectId);
6821  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
6822  statement.setString(3, fileName);
6823  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
6824  statement.setShort(5, (short) 1);
6826  statement.setShort(6, dirType.getValue());
6828  statement.setShort(7, metaType.getValue());
6830  statement.setShort(8, dirFlag.getValue());
6831  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
6832  statement.setShort(9, metaFlags);
6833  //prevent negative size
6834  long savedSize = size < 0 ? 0 : size;
6835  statement.setLong(10, savedSize);
6836  statement.setLong(11, ctime);
6837  statement.setLong(12, crtime);
6838  statement.setLong(13, atime);
6839  statement.setLong(14, mtime);
6840  statement.setString(15, md5);
6841  if (known != null) {
6842  statement.setByte(16, known.getFileKnownValue());
6843  } else {
6844  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue());
6845  }
6846  statement.setString(17, mimeType);
6847  String parentPath;
6848  long dataSourceObjId;
6849 
6850  if (parent instanceof AbstractFile) {
6851  AbstractFile parentFile = (AbstractFile) parent;
6852  if (isRootDirectory(parentFile, transaction)) {
6853  parentPath = "/";
6854  } else {
6855  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
6856  }
6857  dataSourceObjId = parentFile.getDataSourceObjectId();
6858  } else {
6859  parentPath = "/";
6860  dataSourceObjId = getDataSourceObjectId(connection, parent.getId());
6861  }
6862  statement.setString(18, parentPath);
6863  statement.setLong(19, dataSourceObjId);
6864  final String extension = extractExtension(fileName);
6865  statement.setString(20, extension);
6866 
6867  connection.executeUpdate(statement);
6868  addFilePath(connection, objectId, localPath, encodingType);
6869  LocalFile localFile = new LocalFile(this,
6870  objectId,
6871  fileName,
6873  dirType,
6874  metaType,
6875  dirFlag,
6876  metaFlags,
6877  savedSize,
6878  ctime, crtime, atime, mtime,
6879  mimeType, md5, known,
6880  parent.getId(), parentPath,
6881  dataSourceObjId,
6882  localPath,
6883  encodingType, extension);
6884  getTimelineManager().addEventsForNewFile(localFile, connection);
6885  return localFile;
6886 
6887  } catch (SQLException ex) {
6888  throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_files table", fileName, localPath, parent.getId()), ex);
6889  } finally {
6890  closeStatement(queryStatement);
6891  // NOTE: write lock will be released by transaction
6892  }
6893  }
6894 
6907  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
6908  CaseDbConnection connection = transaction.getConnection();
6909  transaction.acquireSingleUserCaseWriteLock();
6910  Statement statement = null;
6911  ResultSet resultSet = null;
6912 
6913  try {
6914  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
6915  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
6916  + "WHERE ChildRow.obj_id = %s;", file.getId());
6917 
6918  statement = connection.createStatement();
6919  resultSet = statement.executeQuery(query);
6920  if (resultSet.next()) {
6921  long parentId = resultSet.getLong("parent_object_id");
6922  if (parentId == 0) {
6923  return true;
6924  }
6925  int type = resultSet.getInt("parent_type");
6926  return (type == TskData.ObjectType.IMG.getObjectType()
6927  || type == TskData.ObjectType.VS.getObjectType()
6928  || type == TskData.ObjectType.VOL.getObjectType()
6929  || type == TskData.ObjectType.FS.getObjectType());
6930 
6931  } else {
6932  return true; // The file has no parent
6933  }
6934  } catch (SQLException ex) {
6935  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
6936  } finally {
6937  closeResultSet(resultSet);
6938  closeStatement(statement);
6939  // NOTE: write lock will be released by transaction
6940  }
6941  }
6942 
6962  public LayoutFile addLayoutFile(String fileName,
6963  long size,
6964  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
6965  long ctime, long crtime, long atime, long mtime,
6966  List<TskFileRange> fileRanges,
6967  Content parent) throws TskCoreException {
6968 
6969  if (null == parent) {
6970  throw new TskCoreException("Parent can not be null");
6971  }
6972 
6973  String parentPath;
6974  if (parent instanceof AbstractFile) {
6975  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
6976  } else {
6977  parentPath = "/";
6978  }
6979 
6980  CaseDbTransaction transaction = null;
6981  Statement statement = null;
6982  ResultSet resultSet = null;
6983  try {
6984  transaction = beginTransaction();
6985  transaction.acquireSingleUserCaseWriteLock();
6986  CaseDbConnection connection = transaction.getConnection();
6987 
6988  /*
6989  * Insert a row for the layout file into the tsk_objects table:
6990  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6991  */
6992  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6993 
6994  /*
6995  * Insert a row for the file into the tsk_files table: INSERT INTO
6996  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
6997  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
6998  * mtime, md5, known, mime_type, parent_path,
6999  * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,
7000  * ?, ?, ?, ?, ?, ?, ?,?)
7001  */
7002  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7003  prepStmt.clearParameters();
7004  prepStmt.setLong(1, newFileId); // obj_id
7005 
7006  // If the parent is part of a file system, grab its file system ID
7007  if (0 != parent.getId()) {
7008  long parentFs = this.getFileSystemId(parent.getId(), connection);
7009  if (parentFs != -1) {
7010  prepStmt.setLong(2, parentFs);
7011  } else {
7012  prepStmt.setNull(2, java.sql.Types.BIGINT);
7013  }
7014  } else {
7015  prepStmt.setNull(2, java.sql.Types.BIGINT);
7016  }
7017  prepStmt.setString(3, fileName); // name
7018  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
7019  prepStmt.setShort(5, (short) 0); // has_path
7020  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7021  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7022  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
7023  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
7024  //prevent negative size
7025  long savedSize = size < 0 ? 0 : size;
7026  prepStmt.setLong(10, savedSize); // size
7027  prepStmt.setLong(11, ctime); // ctime
7028  prepStmt.setLong(12, crtime); // crtime
7029  prepStmt.setLong(13, atime); // atime
7030  prepStmt.setLong(14, mtime); // mtime
7031  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7032  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7033  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
7034  prepStmt.setString(18, parentPath); // parent path
7035  prepStmt.setLong(19, parent.getDataSource().getId()); // data_source_obj_id
7036 
7037  prepStmt.setString(20, extractExtension(fileName)); //extension
7038  connection.executeUpdate(prepStmt);
7039 
7040  /*
7041  * Insert a row in the tsk_layout_file table for each chunk of the
7042  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
7043  * byte_len, sequence) VALUES (?, ?, ?, ?)
7044  */
7045  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7046  for (TskFileRange tskFileRange : fileRanges) {
7047  prepStmt.clearParameters();
7048  prepStmt.setLong(1, newFileId); // obj_id
7049  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7050  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7051  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7052  connection.executeUpdate(prepStmt);
7053  }
7054 
7055  /*
7056  * Create a layout file representation of the carved file.
7057  */
7058  LayoutFile layoutFile = new LayoutFile(this,
7059  newFileId,
7060  parent.getDataSource().getId(),
7061  fileName,
7065  dirFlag,
7066  metaFlag.getValue(),
7067  savedSize,
7068  ctime, crtime, atime, mtime,
7069  null,
7071  parentPath,
7072  null);
7073 
7074  transaction.commit();
7075  transaction = null;
7076  return layoutFile;
7077 
7078  } catch (SQLException ex) {
7079  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
7080  } finally {
7081  closeResultSet(resultSet);
7082  closeStatement(statement);
7083 
7084  // NOTE: write lock will be released by transaction
7085  if (null != transaction) {
7086  try {
7087  transaction.rollback();
7088  } catch (TskCoreException ex2) {
7089  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7090  }
7091  }
7092  }
7093  }
7094 
7107  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
7109  Statement statement = null;
7110  ResultSet resultSet = null;
7111  try {
7112  statement = connection.createStatement();
7113  long dataSourceObjId;
7114  long ancestorId = objectId;
7115  do {
7116  dataSourceObjId = ancestorId;
7117  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
7118  resultSet = statement.executeQuery(query);
7119  if (resultSet.next()) {
7120  ancestorId = resultSet.getLong("par_obj_id");
7121  } else {
7122  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
7123  }
7124  resultSet.close();
7125  resultSet = null;
7126  } while (0 != ancestorId); // Not NULL
7127  return dataSourceObjId;
7128  } catch (SQLException ex) {
7129  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
7130  } finally {
7131  closeResultSet(resultSet);
7132  closeStatement(statement);
7134  }
7135  }
7136 
7148  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7149  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
7150  statement.clearParameters();
7151  statement.setLong(1, objId);
7152  statement.setString(2, path);
7153  statement.setInt(3, type.getType());
7154  connection.executeUpdate(statement);
7155  }
7156 
7168  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7169  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
7170  statement.clearParameters();
7171  statement.setString(1, path);
7172  statement.setInt(2, type.getType());
7173  statement.setLong(3, objId);
7174  connection.executeUpdate(statement);
7175  }
7176 
7192  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
7193  return findFiles(dataSource, fileName, parentFile.getName());
7194  }
7195 
7207  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
7208  CaseDbConnection connection = connections.getConnection();
7210  Statement s = null;
7211  ResultSet rs = null;
7212  try {
7213  s = connection.createStatement();
7214  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7215  rs.next();
7216  return rs.getLong("count");
7217  } catch (SQLException e) {
7218  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
7219  } finally {
7220  closeResultSet(rs);
7221  closeStatement(s);
7222  connection.close();
7224  }
7225  }
7226 
7244  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
7245  CaseDbConnection connection = connections.getConnection();
7247  Statement s = null;
7248  ResultSet rs = null;
7249  try {
7250  s = connection.createStatement();
7251  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7252  return resultSetToAbstractFiles(rs, connection);
7253  } catch (SQLException e) {
7254  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
7255  } finally {
7256  closeResultSet(rs);
7257  closeStatement(s);
7258  connection.close();
7260  }
7261  }
7262 
7275  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
7276  CaseDbConnection connection = connections.getConnection();
7278  Statement s = null;
7279  ResultSet rs = null;
7280  try {
7281  s = connection.createStatement();
7282  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7283  List<Long> ret = new ArrayList<Long>();
7284  while (rs.next()) {
7285  ret.add(rs.getLong("obj_id"));
7286  }
7287  return ret;
7288  } catch (SQLException e) {
7289  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
7290  } finally {
7291  closeResultSet(rs);
7292  closeStatement(s);
7293  connection.close();
7295  }
7296  }
7297 
7309  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
7310 
7311  // get the non-unique path (strip of image and volume path segments, if
7312  // the exist.
7313  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
7314 
7315  // split the file name from the parent path
7316  int lastSlash = path.lastIndexOf('/'); //NON-NLS
7317 
7318  // if the last slash is at the end, strip it off
7319  if (lastSlash == path.length()) {
7320  path = path.substring(0, lastSlash - 1);
7321  lastSlash = path.lastIndexOf('/'); //NON-NLS
7322  }
7323 
7324  String parentPath = path.substring(0, lastSlash);
7325  String fileName = path.substring(lastSlash);
7326 
7327  return findFiles(dataSource, fileName, parentPath);
7328  }
7329 
7340  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
7341  CaseDbConnection connection = connections.getConnection();
7343  Statement s = null;
7344  ResultSet rs = null;
7345  try {
7346  s = connection.createStatement();
7347  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
7348  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
7349  while (rs.next()) {
7350  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
7351  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
7352  ranges.add(range);
7353  }
7354  return ranges;
7355  } catch (SQLException ex) {
7356  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
7357  } finally {
7358  closeResultSet(rs);
7359  closeStatement(s);
7360  connection.close();
7362  }
7363  }
7364 
7375  public Image getImageById(long id) throws TskCoreException {
7376  CaseDbConnection connection = connections.getConnection();
7378  Statement s1 = null;
7379  ResultSet rs1 = null;
7380  Statement s2 = null;
7381  ResultSet rs2 = null;
7382  try {
7383  s1 = connection.createStatement();
7384  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.type, tsk_image_info.ssize, tsk_image_info.tzone, tsk_image_info.size, tsk_image_info.md5, tsk_image_info.sha1, tsk_image_info.sha256, tsk_image_info.display_name, data_source_info.device_id "
7385  + "FROM tsk_image_info "
7386  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
7387  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
7388  if (rs1.next()) {
7389  s2 = connection.createStatement();
7390  rs2 = connection.executeQuery(s2, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + id); //NON-NLS
7391  List<String> imagePaths = new ArrayList<String>();
7392  while (rs2.next()) {
7393  imagePaths.add(rs2.getString("name"));
7394  }
7395  long type = rs1.getLong("type"); //NON-NLS
7396  long ssize = rs1.getLong("ssize"); //NON-NLS
7397  String tzone = rs1.getString("tzone"); //NON-NLS
7398  long size = rs1.getLong("size"); //NON-NLS
7399  String md5 = rs1.getString("md5"); //NON-NLS
7400  String sha1 = rs1.getString("sha1"); //NON-NLS
7401  String sha256 = rs1.getString("sha256"); //NON-NLS
7402  String name = rs1.getString("display_name");
7403  if (name == null) {
7404  if (imagePaths.size() > 0) {
7405  String path = imagePaths.get(0);
7406  name = (new java.io.File(path)).getName();
7407  } else {
7408  name = "";
7409  }
7410  }
7411  String device_id = rs1.getString("device_id");
7412 
7413  return new Image(this, id, type, device_id, ssize, name,
7414  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
7415  } else {
7416  throw new TskCoreException("No image found for id: " + id);
7417  }
7418  } catch (SQLException ex) {
7419  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
7420  } finally {
7421  closeResultSet(rs2);
7422  closeStatement(s2);
7423  closeResultSet(rs1);
7424  closeStatement(s1);
7425  connection.close();
7427  }
7428  }
7429 
7441  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
7442  CaseDbConnection connection = connections.getConnection();
7444  Statement s = null;
7445  ResultSet rs = null;
7446  try {
7447  s = connection.createStatement();
7448  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
7449  + "where obj_id = " + id); //NON-NLS
7450  if (rs.next()) {
7451  long type = rs.getLong("vs_type"); //NON-NLS
7452  long imgOffset = rs.getLong("img_offset"); //NON-NLS
7453  long blockSize = rs.getLong("block_size"); //NON-NLS
7454  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
7455  vs.setParent(parent);
7456  return vs;
7457  } else {
7458  throw new TskCoreException("No volume system found for id:" + id);
7459  }
7460  } catch (SQLException ex) {
7461  throw new TskCoreException("Error getting Volume System by ID.", ex);
7462  } finally {
7463  closeResultSet(rs);
7464  closeStatement(s);
7465  connection.close();
7467  }
7468  }
7469 
7478  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
7479  VolumeSystem vs = getVolumeSystemById(id, null);
7480  vs.setParentId(parentId);
7481  return vs;
7482  }
7483 
7495  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
7496  return getFileSystemByIdHelper(id, parent);
7497  }
7498 
7507  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
7508  Volume vol = null;
7509  FileSystem fs = getFileSystemById(id, vol);
7510  fs.setParentId(parentId);
7511  return fs;
7512  }
7513 
7525  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
7526  return getFileSystemByIdHelper(id, parent);
7527  }
7528 
7540  Pool getPoolById(long id, Content parent) throws TskCoreException {
7541  return getPoolByIdHelper(id, parent);
7542  }
7543 
7552  Pool getPoolById(long id, long parentId) throws TskCoreException {
7553  Pool pool = getPoolById(id, null);
7554  pool.setParentId(parentId);
7555  return pool;
7556  }
7557 
7569  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
7570 
7572  try (CaseDbConnection connection = connections.getConnection();
7573  Statement s = connection.createStatement();
7574  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
7575  + "where obj_id = " + id);) { //NON-NLS
7576  if (rs.next()) {
7577  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
7578  pool.setParent(parent);
7579 
7580  return pool;
7581  } else {
7582  throw new TskCoreException("No pool found for ID:" + id);
7583  }
7584  } catch (SQLException ex) {
7585  throw new TskCoreException("Error getting Pool by ID", ex);
7586  } finally {
7588  }
7589  }
7590 
7602  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
7603  // see if we already have it
7604  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
7605  // but it should be the same...
7606  synchronized (fileSystemIdMap) {
7607  if (fileSystemIdMap.containsKey(id)) {
7608  return fileSystemIdMap.get(id);
7609  }
7610  }
7611  CaseDbConnection connection = connections.getConnection();
7613  Statement s = null;
7614  ResultSet rs = null;
7615  try {
7616  s = connection.createStatement();
7617  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
7618  + "where obj_id = " + id); //NON-NLS
7619  if (rs.next()) {
7620  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7621  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7622  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7623  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7624  fs.setParent(parent);
7625  // save it for the next call
7626  synchronized (fileSystemIdMap) {
7627  fileSystemIdMap.put(id, fs);
7628  }
7629  return fs;
7630  } else {
7631  throw new TskCoreException("No file system found for id:" + id);
7632  }
7633  } catch (SQLException ex) {
7634  throw new TskCoreException("Error getting File System by ID", ex);
7635  } finally {
7636  closeResultSet(rs);
7637  closeStatement(s);
7638  connection.close();
7640  }
7641  }
7642 
7654  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
7655  CaseDbConnection connection = connections.getConnection();
7657  Statement s = null;
7658  ResultSet rs = null;
7659  try {
7660  s = connection.createStatement();
7661  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
7662  + "where obj_id = " + id); //NON-NLS
7663  if (rs.next()) {
7671  String description;
7672  try {
7673  description = rs.getString("desc");
7674  } catch (Exception ex) {
7675  description = rs.getString("descr");
7676  }
7677  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
7678  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
7679  description);
7680  vol.setParent(parent);
7681  return vol;
7682  } else {
7683  throw new TskCoreException("No volume found for id:" + id);
7684  }
7685  } catch (SQLException ex) {
7686  throw new TskCoreException("Error getting Volume by ID", ex);
7687  } finally {
7688  closeResultSet(rs);
7689  closeStatement(s);
7690  connection.close();
7692  }
7693  }
7694 
7703  Volume getVolumeById(long id, long parentId) throws TskCoreException {
7704  Volume vol = getVolumeById(id, null);
7705  vol.setParentId(parentId);
7706  return vol;
7707  }
7708 
7720  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
7721  CaseDbConnection connection = connections.getConnection();
7723  Statement s = null;
7724  ResultSet rs = null;
7725  try {
7726  s = connection.createStatement();
7727  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
7728  + "WHERE obj_id = " + id);
7729  Directory temp = null; //NON-NLS
7730  if (rs.next()) {
7731  final short type = rs.getShort("type"); //NON-NLS
7732  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
7733  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
7734  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
7735  temp = directory(rs, parentFs);
7736  }
7737  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
7738  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
7739  }
7740  } else {
7741  throw new TskCoreException("No Directory found for id:" + id);
7742  }
7743  return temp;
7744  } catch (SQLException ex) {
7745  throw new TskCoreException("Error getting Directory by ID", ex);
7746  } finally {
7747  closeResultSet(rs);
7748  closeStatement(s);
7749  connection.close();
7751  }
7752  }
7753 
7761  public Collection<FileSystem> getFileSystems(Image image) {
7762  List<FileSystem> fileSystems = new ArrayList<FileSystem>();
7763  CaseDbConnection connection;
7764  try {
7765  connection = connections.getConnection();
7766  } catch (TskCoreException ex) {
7767  logger.log(Level.SEVERE, "Error getting file systems for image " + image.getId(), ex); //NON-NLS
7768  return fileSystems;
7769  }
7771  Statement s = null;
7772  ResultSet rs = null;
7773  try {
7774  s = connection.createStatement();
7775 
7776  // Get all the file systems.
7777  List<FileSystem> allFileSystems = new ArrayList<FileSystem>();
7778  try {
7779  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info"); //NON-NLS
7780  while (rs.next()) {
7781  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7782  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7783  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7784  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7785  fs.setParent(null);
7786  allFileSystems.add(fs);
7787  }
7788  } catch (SQLException ex) {
7789  logger.log(Level.SEVERE, "There was a problem while trying to obtain all file systems", ex); //NON-NLS
7790  } finally {
7791  closeResultSet(rs);
7792  rs = null;
7793  }
7794 
7795  // For each file system, find the image to which it belongs by iteratively
7796  // climbing the tsk_ojbects hierarchy only taking those file systems
7797  // that belong to this image.
7798  for (FileSystem fs : allFileSystems) {
7799  Long imageID = null;
7800  Long currentObjID = fs.getId();
7801  while (imageID == null) {
7802  try {
7803  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS
7804  rs.next();
7805  currentObjID = rs.getLong("par_obj_id"); //NON-NLS
7806  if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS
7807  imageID = rs.getLong("obj_id"); //NON-NLS
7808  }
7809  } catch (SQLException ex) {
7810  logger.log(Level.SEVERE, "There was a problem while trying to obtain this image's file systems", ex); //NON-NLS
7811  } finally {
7812  closeResultSet(rs);
7813  rs = null;
7814  }
7815  }
7816 
7817  // see if imageID is this image's ID
7818  if (imageID == image.getId()) {
7819  fileSystems.add(fs);
7820  }
7821  }
7822  } catch (SQLException ex) {
7823  logger.log(Level.SEVERE, "Error getting case database connection", ex); //NON-NLS
7824  } finally {
7825  closeResultSet(rs);
7826  closeStatement(s);
7827  connection.close();
7829  }
7830  return fileSystems;
7831  }
7832 
7843  List<Content> getImageChildren(Image img) throws TskCoreException {
7844  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
7845  List<Content> children = new ArrayList<Content>();
7846  for (ObjectInfo info : childInfos) {
7847  if (null != info.type) {
7848  switch (info.type) {
7849  case VS:
7850  children.add(getVolumeSystemById(info.id, img));
7851  break;
7852  case POOL:
7853  children.add(getPoolById(info.id, img));
7854  break;
7855  case FS:
7856  children.add(getFileSystemById(info.id, img));
7857  break;
7858  case ABSTRACTFILE:
7859  AbstractFile f = getAbstractFileById(info.id);
7860  if (f != null) {
7861  children.add(f);
7862  }
7863  break;
7864  case ARTIFACT:
7865  BlackboardArtifact art = getArtifactById(info.id);
7866  if (art != null) {
7867  children.add(art);
7868  }
7869  break;
7870  case REPORT:
7871  // Do nothing for now - see JIRA-3673
7872  break;
7873  default:
7874  throw new TskCoreException("Image has child of invalid type: " + info.type);
7875  }
7876  }
7877  }
7878  return children;
7879  }
7880 
7891  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
7892  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
7893  List<Long> children = new ArrayList<Long>();
7894  for (ObjectInfo info : childInfos) {
7895  if (info.type == ObjectType.VS
7896  || info.type == ObjectType.POOL
7897  || info.type == ObjectType.FS
7898  || info.type == ObjectType.ABSTRACTFILE
7899  || info.type == ObjectType.ARTIFACT) {
7900  children.add(info.id);
7901  } else if (info.type == ObjectType.REPORT) {
7902  // Do nothing for now - see JIRA-3673
7903  } else {
7904  throw new TskCoreException("Image has child of invalid type: " + info.type);
7905  }
7906  }
7907  return children;
7908  }
7909 
7920  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
7921  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
7922  List<Content> children = new ArrayList<Content>();
7923  for (ObjectInfo info : childInfos) {
7924  if (null != info.type) {
7925  switch (info.type) {
7926  case VS:
7927  children.add(getVolumeSystemById(info.id, pool));
7928  break;
7929  case ABSTRACTFILE:
7930  AbstractFile f = getAbstractFileById(info.id);
7931  if (f != null) {
7932  children.add(f);
7933  }
7934  break;
7935  case ARTIFACT:
7936  BlackboardArtifact art = getArtifactById(info.id);
7937  if (art != null) {
7938  children.add(art);
7939  }
7940  break;
7941  default:
7942  throw new TskCoreException("Pool has child of invalid type: " + info.type);
7943  }
7944  }
7945  }
7946  return children;
7947  }
7948 
7959  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
7960  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
7961  List<Long> children = new ArrayList<Long>();
7962  for (ObjectInfo info : childInfos) {
7963  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
7964  children.add(info.id);
7965  } else {
7966  throw new TskCoreException("Pool has child of invalid type: " + info.type);
7967  }
7968  }
7969  return children;
7970  }
7971 
7982  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
7983  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
7984  List<Content> children = new ArrayList<Content>();
7985  for (ObjectInfo info : childInfos) {
7986  if (null != info.type) {
7987  switch (info.type) {
7988  case VOL:
7989  children.add(getVolumeById(info.id, vs));
7990  break;
7991  case ABSTRACTFILE:
7992  AbstractFile f = getAbstractFileById(info.id);
7993  if (f != null) {
7994  children.add(f);
7995  }
7996  break;
7997  case ARTIFACT:
7998  BlackboardArtifact art = getArtifactById(info.id);
7999  if (art != null) {
8000  children.add(art);
8001  }
8002  break;
8003  default:
8004  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8005  }
8006  }
8007  }
8008  return children;
8009  }
8010 
8021  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
8022  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
8023  List<Long> children = new ArrayList<Long>();
8024  for (ObjectInfo info : childInfos) {
8025  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8026  children.add(info.id);
8027  } else {
8028  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8029  }
8030  }
8031  return children;
8032  }
8033 
8044  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
8045  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8046  List<Content> children = new ArrayList<Content>();
8047  for (ObjectInfo info : childInfos) {
8048  if (null != info.type) {
8049  switch (info.type) {
8050  case POOL:
8051  children.add(getPoolById(info.id, vol));
8052  break;
8053  case FS:
8054  children.add(getFileSystemById(info.id, vol));
8055  break;
8056  case ABSTRACTFILE:
8057  AbstractFile f = getAbstractFileById(info.id);
8058  if (f != null) {
8059  children.add(f);
8060  }
8061  break;
8062  case ARTIFACT:
8063  BlackboardArtifact art = getArtifactById(info.id);
8064  if (art != null) {
8065  children.add(art);
8066  }
8067  break;
8068  default:
8069  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8070  }
8071  }
8072  }
8073  return children;
8074  }
8075 
8086  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
8087  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8088  final List<Long> children = new ArrayList<Long>();
8089  for (ObjectInfo info : childInfos) {
8090  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8091  children.add(info.id);
8092  } else {
8093  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8094  }
8095  }
8096  return children;
8097  }
8098 
8112  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
8113  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, this);
8114  return getImageById(imageId);
8115  }
8116 
8126  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
8127  CaseDbConnection connection = connections.getConnection();
8129  Statement s1 = null;
8130  Statement s2 = null;
8131  ResultSet rs1 = null;
8132  ResultSet rs2 = null;
8133  try {
8134  s1 = connection.createStatement();
8135  rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8136  s2 = connection.createStatement();
8137  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
8138  while (rs1.next()) {
8139  long obj_id = rs1.getLong("obj_id"); //NON-NLS
8140  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
8141  List<String> paths = new ArrayList<String>();
8142  while (rs2.next()) {
8143  paths.add(rs2.getString("name"));
8144  }
8145  rs2.close();
8146  rs2 = null;
8147  imgPaths.put(obj_id, paths);
8148  }
8149  return imgPaths;
8150  } catch (SQLException ex) {
8151  throw new TskCoreException("Error getting image paths.", ex);
8152  } finally {
8153  closeResultSet(rs2);
8154  closeStatement(s2);
8155  closeResultSet(rs1);
8156  closeStatement(s1);
8157  connection.close();
8159  }
8160  }
8161 
8172  private List<String> getImagePathsById(long objectId) throws TskCoreException {
8173  List<String> imagePaths = new ArrayList<String>();
8174  CaseDbConnection connection = connections.getConnection();
8176  Statement statement = null;
8177  ResultSet resultSet = null;
8178  try {
8179  statement = connection.createStatement();
8180  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
8181  while (resultSet.next()) {
8182  imagePaths.add(resultSet.getString("name"));
8183  }
8184  } catch (SQLException ex) {
8185  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
8186  } finally {
8187  closeResultSet(resultSet);
8188  closeStatement(statement);
8189  connection.close();
8191  }
8192 
8193  return imagePaths;
8194  }
8195 
8202  public List<Image> getImages() throws TskCoreException {
8203  CaseDbConnection connection = connections.getConnection();
8205  Statement s = null;
8206  ResultSet rs = null;
8207  try {
8208  s = connection.createStatement();
8209  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8210  Collection<Long> imageIDs = new ArrayList<Long>();
8211  while (rs.next()) {
8212  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
8213  }
8214  List<Image> images = new ArrayList<Image>();
8215  for (long id : imageIDs) {
8216  images.add(getImageById(id));
8217  }
8218  return images;
8219  } catch (SQLException ex) {
8220  throw new TskCoreException("Error retrieving images.", ex);
8221  } finally {
8222  closeResultSet(rs);
8223  closeStatement(s);
8224  connection.close();
8226  }
8227  }
8228 
8239  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
8240  CaseDbConnection connection = connections.getConnection();
8242  PreparedStatement statement = null;
8243  try {
8244  connection.beginTransaction();
8245  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
8246  statement.clearParameters();
8247  statement.setLong(1, obj_id);
8248  connection.executeUpdate(statement);
8249  for (int i = 0; i < paths.size(); i++) {
8250  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
8251  statement.clearParameters();
8252  statement.setLong(1, obj_id);
8253  statement.setString(2, paths.get(i));
8254  statement.setLong(3, i);
8255  connection.executeUpdate(statement);
8256  }
8257  connection.commitTransaction();
8258  } catch (SQLException ex) {
8259  connection.rollbackTransaction();
8260  throw new TskCoreException("Error updating image paths.", ex);
8261  } finally {
8262  connection.close();
8264  }
8265  }
8266 
8278  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
8279  CaseDbConnection connection = connections.getConnection();
8280  Statement statement = null;
8282  try {
8283  statement = connection.createStatement();
8284  connection.beginTransaction();
8285  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
8286  // all associated rows from tsk_object and its children. For large data sources this may take some time.
8287  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
8288  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
8289  // associated rows from accounts table and its children.
8290  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
8291  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
8292  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
8293  statement.execute(accountSql);
8294  connection.commitTransaction();
8295  } catch (SQLException ex) {
8296  connection.rollbackTransaction();
8297  throw new TskCoreException("Error deleting data source.", ex);
8298  } finally {
8299  connection.close();
8301  }
8302  }
8303 
8329  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
8330  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
8331  try {
8332  while (rs.next()) {
8333  final short type = rs.getShort("type"); //NON-NLS
8334  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
8335  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
8336  FsContent result;
8337  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
8338  result = directory(rs, null);
8339  } else {
8340  result = file(rs, null);
8341  }
8342  results.add(result);
8343  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
8344  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
8345  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
8346  results.add(virtDir);
8347  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
8348  final LocalDirectory localDir = localDirectory(rs);
8349  results.add(localDir);
8350  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
8351  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
8352  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
8353  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
8354  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
8355  String parentPath = rs.getString("parent_path"); //NON-NLS
8356  if (parentPath == null) {
8357  parentPath = "/"; //NON-NLS
8358  }
8359  LayoutFile lf = new LayoutFile(this,
8360  rs.getLong("obj_id"), //NON-NLS
8361  rs.getLong("data_source_obj_id"),
8362  rs.getString("name"), //NON-NLS
8363  atype,
8364  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8365  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8366  rs.getLong("size"), //NON-NLS
8367  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8368  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS
8369  results.add(lf);
8370  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
8371  final DerivedFile df;
8372  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
8373  results.add(df);
8374  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
8375  final LocalFile lf;
8376  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
8377  results.add(lf);
8378  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
8379  final SlackFile sf = slackFile(rs, null);
8380  results.add(sf);
8381  }
8382  } //end for each resultSet
8383  } catch (SQLException e) {
8384  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
8385  }
8386 
8387  return results;
8388  }
8389 
8390  // This following methods generate AbstractFile objects from a ResultSet
8402  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
8403  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
8404  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8405  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8406  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8407  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8408  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8409  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8410  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8411  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8412  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8413  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8414  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8415  f.setFileSystem(fs);
8416  return f;
8417  }
8418 
8430  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
8431  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8432  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8433  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8434  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8435  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8436  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8437  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8438  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8439  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8440  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8441  rs.getString("parent_path")); //NON-NLS
8442  dir.setFileSystem(fs);
8443  return dir;
8444  }
8445 
8456  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
8457  String parentPath = rs.getString("parent_path"); //NON-NLS
8458  if (parentPath == null) {
8459  parentPath = "";
8460  }
8461 
8462  long objId = rs.getLong("obj_id");
8463  long dsObjId = rs.getLong("data_source_obj_id");
8464  if (objId == dsObjId) { // virtual directory is a data source
8465 
8466  String deviceId = "";
8467  String timeZone = "";
8468  Statement s = null;
8469  ResultSet rsDataSourceInfo = null;
8470 
8472  try {
8473  s = connection.createStatement();
8474  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
8475  if (rsDataSourceInfo.next()) {
8476  deviceId = rsDataSourceInfo.getString("device_id");
8477  timeZone = rsDataSourceInfo.getString("time_zone");
8478  }
8479  } catch (SQLException ex) {
8480  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
8481  } finally {
8482  closeResultSet(rsDataSourceInfo);
8483  closeStatement(s);
8485  }
8486 
8487  return new LocalFilesDataSource(this,
8488  objId, dsObjId,
8489  deviceId,
8490  rs.getString("name"),
8491  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8492  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8493  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
8494  rs.getShort("meta_flags"),
8495  timeZone,
8496  rs.getString("md5"),
8497  FileKnown.valueOf(rs.getByte("known")),
8498  parentPath);
8499  } else {
8500  final VirtualDirectory vd = new VirtualDirectory(this,
8501  objId, dsObjId,
8502  rs.getString("name"), //NON-NLS
8503  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8504  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8505  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8506  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8507  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8508  return vd;
8509  }
8510  }
8511 
8521  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
8522  String parentPath = rs.getString("parent_path"); //NON-NLS
8523  if (parentPath == null) {
8524  parentPath = "";
8525  }
8526  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
8527  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
8528  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8529  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8530  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8531  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8532  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8533  return ld;
8534  }
8535 
8549  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8550  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
8551  long objId = rs.getLong("obj_id"); //NON-NLS
8552  String localPath = null;
8553  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8554  if (hasLocalPath) {
8555  ResultSet rsFilePath = null;
8557  try {
8558  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8559  statement.clearParameters();
8560  statement.setLong(1, objId);
8561  rsFilePath = connection.executeQuery(statement);
8562  if (rsFilePath.next()) {
8563  localPath = rsFilePath.getString("path");
8564  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8565  }
8566  } catch (SQLException ex) {
8567  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8568  } finally {
8569  closeResultSet(rsFilePath);
8571  }
8572  }
8573  String parentPath = rs.getString("parent_path"); //NON-NLS
8574  if (parentPath == null) {
8575  parentPath = "";
8576  }
8577  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
8578  rs.getString("name"), //NON-NLS
8579  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8580  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8581  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8582  rs.getLong("size"), //NON-NLS
8583  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8584  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8585  parentPath, localPath, parentId, rs.getString("mime_type"),
8586  encodingType, rs.getString("extension"));
8587  return df;
8588  }
8589 
8603  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8604  long objId = rs.getLong("obj_id"); //NON-NLS
8605  String localPath = null;
8606  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8607  if (rs.getBoolean("has_path")) {
8608  ResultSet rsFilePath = null;
8610  try {
8611  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8612  statement.clearParameters();
8613  statement.setLong(1, objId);
8614  rsFilePath = connection.executeQuery(statement);
8615  if (rsFilePath.next()) {
8616  localPath = rsFilePath.getString("path");
8617  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8618  }
8619  } catch (SQLException ex) {
8620  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8621  } finally {
8622  closeResultSet(rsFilePath);
8624  }
8625  }
8626  String parentPath = rs.getString("parent_path"); //NON-NLS
8627  if (null == parentPath) {
8628  parentPath = "";
8629  }
8630  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
8631  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
8632  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8633  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8634  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8635  rs.getLong("size"), //NON-NLS
8636  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8637  rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8638  parentId, parentPath, rs.getLong("data_source_obj_id"),
8639  localPath, encodingType, rs.getString("extension"));
8640  return file;
8641  }
8642 
8654  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
8655  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
8656  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8657  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8658  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8659  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8660  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8661  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8662  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8663  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8664  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8665  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8666  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8667  f.setFileSystem(fs);
8668  return f;
8669  }
8670 
8682  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8683  List<Content> children = new ArrayList<Content>();
8684 
8685  while (rs.next()) {
8686  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
8687 
8688  if (null != type) {
8689  switch (type) {
8690  case FS:
8691  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
8692  FsContent result;
8693  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
8694  result = directory(rs, null);
8695  } else {
8696  result = file(rs, null);
8697  }
8698  children.add(result);
8699  } else {
8700  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8701  children.add(virtDir);
8702  }
8703  break;
8704  case VIRTUAL_DIR:
8705  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8706  children.add(virtDir);
8707  break;
8708  case LOCAL_DIR:
8709  LocalDirectory localDir = localDirectory(rs);
8710  children.add(localDir);
8711  break;
8712  case UNALLOC_BLOCKS:
8713  case UNUSED_BLOCKS:
8714  case CARVED:
8715  case LAYOUT_FILE: {
8716  String parentPath = rs.getString("parent_path");
8717  if (parentPath == null) {
8718  parentPath = "";
8719  }
8720  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
8721  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
8722  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
8723  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
8724  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
8725  rs.getLong("size"),
8726  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
8727  rs.getString("md5"),
8728  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"));
8729  children.add(lf);
8730  break;
8731  }
8732  case DERIVED:
8733  final DerivedFile df = derivedFile(rs, connection, parentId);
8734  children.add(df);
8735  break;
8736  case LOCAL: {
8737  final LocalFile lf = localFile(rs, connection, parentId);
8738  children.add(lf);
8739  break;
8740  }
8741  case SLACK: {
8742  final SlackFile sf = slackFile(rs, null);
8743  children.add(sf);
8744  break;
8745  }
8746  default:
8747  break;
8748  }
8749  }
8750  }
8751  return children;
8752  }
8753 
8769  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException, TskCoreException {
8770  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
8771  try {
8772  while (rs.next()) {
8773  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
8774  if (artifactType != null) {
8775  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
8776  rs.getInt("artifact_type_id"), artifactType.getTypeName(), artifactType.getDisplayName(),
8777  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
8778  } else {
8779  throw new TskCoreException("Error looking up artifact type ID " + rs.getInt("artifact_type_id") + " from artifact " + rs.getLong("artifact_id"));
8780  }
8781  } //end for each resultSet
8782  } catch (SQLException e) {
8783  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
8784  }
8785 
8786  return artifacts;
8787  }
8788 
8810  public CaseDbQuery executeQuery(String query) throws TskCoreException {
8811  return new CaseDbQuery(query);
8812  }
8813 
8835  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
8836  return new CaseDbQuery(query, true);
8837  }
8838 
8846  CaseDbConnection getConnection() throws TskCoreException {
8847  return connections.getConnection();
8848  }
8849 
8850  synchronized long getCaseDbPointer() throws TskCoreException {
8851  if (caseHandle != null) {
8852  return caseHandle.getCaseDbPointer();
8853  }
8854  throw new TskCoreException("Case has been closed");
8855  }
8856 
8857  @Override
8858  protected void finalize() throws Throwable {
8859  try {
8860  close();
8861  } finally {
8862  super.finalize();
8863  }
8864  }
8865 
8869  public synchronized void close() {
8871 
8872  try {
8873  connections.close();
8874  } catch (TskCoreException ex) {
8875  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
8876  }
8877 
8878  fileSystemIdMap.clear();
8879 
8880  try {
8881  if (this.caseHandle != null) {
8882  this.caseHandle.free();
8883  this.caseHandle = null;
8884  }
8885  } catch (TskCoreException ex) {
8886  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
8887  } finally {
8889  }
8890  }
8891 
8904  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
8905  long id = file.getId();
8906  FileKnown currentKnown = file.getKnown();
8907  if (currentKnown.compareTo(fileKnown) > 0) {
8908  return false;
8909  }
8910  CaseDbConnection connection = connections.getConnection();
8912  Statement statement = null;
8913  try {
8914  statement = connection.createStatement();
8915  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
8916  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
8917  + "WHERE obj_id=" + id); //NON-NLS
8918 
8919  file.setKnown(fileKnown);
8920  } catch (SQLException ex) {
8921  throw new TskCoreException("Error setting Known status.", ex);
8922  } finally {
8923  closeStatement(statement);
8924  connection.close();
8926  }
8927  return true;
8928  }
8929 
8938  void setFileName(String name, long objId) throws TskCoreException {
8939 
8940  CaseDbConnection connection = connections.getConnection();
8942  try {
8943  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
8944  preparedStatement.clearParameters();
8945  preparedStatement.setString(1, name);
8946  preparedStatement.setLong(2, objId);
8947  connection.executeUpdate(preparedStatement);
8948  } catch (SQLException ex) {
8949  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
8950  } finally {
8951  connection.close();
8953  }
8954  }
8955 
8964  void setImageName(String name, long objId) throws TskCoreException {
8965 
8966  CaseDbConnection connection = connections.getConnection();
8968  try {
8969  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
8970  preparedStatement.clearParameters();
8971  preparedStatement.setString(1, name);
8972  preparedStatement.setLong(2, objId);
8973  connection.executeUpdate(preparedStatement);
8974  } catch (SQLException ex) {
8975  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
8976  } finally {
8977  connection.close();
8979  }
8980  }
8981 
8991  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
8992  CaseDbConnection connection = connections.getConnection();
8993  Statement statement = null;
8994  ResultSet rs = null;
8996  try {
8997  statement = connection.createStatement();
8998  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
8999  file.setMIMEType(mimeType);
9000  } catch (SQLException ex) {
9001  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
9002  } finally {
9003  closeResultSet(rs);
9004  closeStatement(statement);
9005  connection.close();
9007  }
9008  }
9009 
9019  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
9020  if (md5Hash == null) {
9021  return;
9022  }
9023  long id = file.getId();
9024  CaseDbConnection connection = connections.getConnection();
9026  try {
9027  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
9028  statement.clearParameters();
9029  statement.setString(1, md5Hash.toLowerCase());
9030  statement.setLong(2, id);
9031  connection.executeUpdate(statement);
9032  file.setMd5Hash(md5Hash.toLowerCase());
9033  } catch (SQLException ex) {
9034  throw new TskCoreException("Error setting MD5 hash", ex);
9035  } finally {
9036  connection.close();
9038  }
9039  }
9040 
9050  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
9051  if (md5Hash == null) {
9052  return;
9053  }
9054  long id = img.getId();
9055  CaseDbConnection connection = connections.getConnection();
9057  try {
9058  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
9059  statement.clearParameters();
9060  statement.setString(1, md5Hash.toLowerCase());
9061  statement.setLong(2, id);
9062  connection.executeUpdate(statement);
9063  } catch (SQLException ex) {
9064  throw new TskCoreException("Error setting MD5 hash", ex);
9065  } finally {
9066  connection.close();
9068  }
9069  }
9070 
9081  String getMd5ImageHash(Image img) throws TskCoreException {
9082  long id = img.getId();
9083  CaseDbConnection connection = connections.getConnection();
9085  ResultSet rs = null;
9086  String hash = "";
9087  try {
9088  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
9089  statement.clearParameters();
9090  statement.setLong(1, id);
9091  rs = connection.executeQuery(statement);
9092  if (rs.next()) {
9093  hash = rs.getString("md5");
9094  }
9095  return hash;
9096  } catch (SQLException ex) {
9097  throw new TskCoreException("Error getting MD5 hash", ex);
9098  } finally {
9099  closeResultSet(rs);
9100  connection.close();
9102  }
9103  }
9104 
9114  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
9115  if (sha1Hash == null) {
9116  return;
9117  }
9118  long id = img.getId();
9119  CaseDbConnection connection = connections.getConnection();
9121  try {
9122  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
9123  statement.clearParameters();
9124  statement.setString(1, sha1Hash.toLowerCase());
9125  statement.setLong(2, id);
9126  connection.executeUpdate(statement);
9127  } catch (SQLException ex) {
9128  throw new TskCoreException("Error setting SHA1 hash", ex);
9129  } finally {
9130  connection.close();
9132  }
9133  }
9134 
9145  String getSha1ImageHash(Image img) throws TskCoreException {
9146  long id = img.getId();
9147  CaseDbConnection connection = connections.getConnection();
9149  ResultSet rs = null;
9150  String hash = "";
9151  try {
9152  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
9153  statement.clearParameters();
9154  statement.setLong(1, id);
9155  rs = connection.executeQuery(statement);
9156  if (rs.next()) {
9157  hash = rs.getString("sha1");
9158  }
9159  return hash;
9160  } catch (SQLException ex) {
9161  throw new TskCoreException("Error getting SHA1 hash", ex);
9162  } finally {
9163  closeResultSet(rs);
9164  connection.close();
9166  }
9167  }
9168 
9178  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
9179  if (sha256Hash == null) {
9180  return;
9181  }
9182  long id = img.getId();
9183  CaseDbConnection connection = connections.getConnection();
9185  try {
9186  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
9187  statement.clearParameters();
9188  statement.setString(1, sha256Hash.toLowerCase());
9189  statement.setLong(2, id);
9190  connection.executeUpdate(statement);
9191  } catch (SQLException ex) {
9192  throw new TskCoreException("Error setting SHA256 hash", ex);
9193  } finally {
9194  connection.close();
9196  }
9197  }
9198 
9209  String getSha256ImageHash(Image img) throws TskCoreException {
9210  long id = img.getId();
9211  CaseDbConnection connection = connections.getConnection();
9213  ResultSet rs = null;
9214  String hash = "";
9215  try {
9216  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
9217  statement.clearParameters();
9218  statement.setLong(1, id);
9219  rs = connection.executeQuery(statement);
9220  if (rs.next()) {
9221  hash = rs.getString("sha256");
9222  }
9223  return hash;
9224  } catch (SQLException ex) {
9225  throw new TskCoreException("Error setting SHA256 hash", ex);
9226  } finally {
9227  closeResultSet(rs);
9228  connection.close();
9230  }
9231  }
9232 
9241  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
9242 
9243  long id = datasource.getId();
9244  CaseDbConnection connection = connections.getConnection();
9246  try {
9247  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
9248  statement.clearParameters();
9249  statement.setString(1, details);
9250  statement.setLong(2, id);
9251  connection.executeUpdate(statement);
9252  } catch (SQLException ex) {
9253  throw new TskCoreException("Error setting acquisition details", ex);
9254  } finally {
9255  connection.close();
9257  }
9258  }
9259 
9269  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
9270  long id = datasource.getId();
9271  CaseDbConnection connection = connections.getConnection();
9273  ResultSet rs = null;
9274  String hash = "";
9275  try {
9276  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
9277  statement.clearParameters();
9278  statement.setLong(1, id);
9279  rs = connection.executeQuery(statement);
9280  if (rs.next()) {
9281  hash = rs.getString("acquisition_details");
9282  }
9283  return hash;
9284  } catch (SQLException ex) {
9285  throw new TskCoreException("Error setting acquisition details", ex);
9286  } finally {
9287  closeResultSet(rs);
9288  connection.close();
9290  }
9291  }
9292 
9303  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
9304  if (newStatus == null) {
9305  return;
9306  }
9307  CaseDbConnection connection = connections.getConnection();
9309  Statement statement = null;
9310  try {
9311  statement = connection.createStatement();
9312  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
9313  + " SET review_status_id=" + newStatus.getID()
9314  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
9315  } catch (SQLException ex) {
9316  throw new TskCoreException("Error setting review status", ex);
9317  } finally {
9318  closeStatement(statement);
9319  connection.close();
9321  }
9322  }
9323 
9334  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
9335  CaseDbConnection connection = connections.getConnection();
9337  Statement s = null;
9338  ResultSet rs = null;
9339  try {
9340  s = connection.createStatement();
9341  Short contentShort = contentType.getValue();
9342  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
9343  int count = 0;
9344  if (rs.next()) {
9345  count = rs.getInt("count");
9346  }
9347  return count;
9348  } catch (SQLException ex) {
9349  throw new TskCoreException("Error getting number of objects.", ex);
9350  } finally {
9351  closeResultSet(rs);
9352  closeStatement(s);
9353  connection.close();
9355  }
9356  }
9357 
9366  public static String escapeSingleQuotes(String text) {
9367  String escapedText = null;
9368  if (text != null) {
9369  escapedText = text.replaceAll("'", "''");
9370  }
9371  return escapedText;
9372  }
9373 
9381  public List<AbstractFile> findFilesByMd5(String md5Hash) {
9382  if (md5Hash == null) {
9383  return Collections.<AbstractFile>emptyList();
9384  }
9385  CaseDbConnection connection;
9386  try {
9387  connection = connections.getConnection();
9388  } catch (TskCoreException ex) {
9389  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
9390  return Collections.<AbstractFile>emptyList();
9391  }
9393  Statement s = null;
9394  ResultSet rs = null;
9395  try {
9396  s = connection.createStatement();
9397  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
9398  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
9399  + "AND size > 0"); //NON-NLS
9400  return resultSetToAbstractFiles(rs, connection);
9401  } catch (SQLException ex) {
9402  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
9403  return Collections.<AbstractFile>emptyList();
9404  } finally {
9405  closeResultSet(rs);
9406  closeStatement(s);
9407  connection.close();
9409  }
9410  }
9411 
9418  public boolean allFilesMd5Hashed() {
9419  CaseDbConnection connection;
9420  try {
9421  connection = connections.getConnection();
9422  } catch (TskCoreException ex) {
9423  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
9424  return false;
9425  }
9426  boolean allFilesAreHashed = false;
9428  Statement s = null;
9429  ResultSet rs = null;
9430  try {
9431  s = connection.createStatement();
9432  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9433  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
9434  + "AND md5 IS NULL " //NON-NLS
9435  + "AND size > '0'"); //NON-NLS
9436  if (rs.next() && rs.getInt("count") == 0) {
9437  allFilesAreHashed = true;
9438  }
9439  } catch (SQLException ex) {
9440  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
9441  } finally {
9442  closeResultSet(rs);
9443  closeStatement(s);
9444  connection.close();
9446  }
9447  return allFilesAreHashed;
9448  }
9449 
9455  public int countFilesMd5Hashed() {
9456  CaseDbConnection connection;
9457  try {
9458  connection = connections.getConnection();
9459  } catch (TskCoreException ex) {
9460  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
9461  return 0;
9462  }
9463  int count = 0;
9465  Statement s = null;
9466  ResultSet rs = null;
9467  try {
9468  s = connection.createStatement();
9469  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9470  + "WHERE md5 IS NOT NULL " //NON-NLS
9471  + "AND size > '0'"); //NON-NLS
9472  if (rs.next()) {
9473  count = rs.getInt("count");
9474  }
9475  } catch (SQLException ex) {
9476  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
9477  } finally {
9478  closeResultSet(rs);
9479  closeStatement(s);
9480  connection.close();
9482  }
9483  return count;
9484 
9485  }
9486 
9495  public List<TagName> getAllTagNames() throws TskCoreException {
9496  CaseDbConnection connection = connections.getConnection();
9498  ResultSet resultSet = null;
9499  try {
9500  // SELECT * FROM tag_names
9501  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
9502  resultSet = connection.executeQuery(statement);
9503  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9504  while (resultSet.next()) {
9505  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9506  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9507  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9508  }
9509  return tagNames;
9510  } catch (SQLException ex) {
9511  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9512  } finally {
9513  closeResultSet(resultSet);
9514  connection.close();
9516  }
9517  }
9518 
9529  public List<TagName> getTagNamesInUse() throws TskCoreException {
9530  CaseDbConnection connection = connections.getConnection();
9532  ResultSet resultSet = null;
9533  try {
9534  // 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)
9535  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
9536  resultSet = connection.executeQuery(statement);
9537  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9538  while (resultSet.next()) {
9539  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9540  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9541  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9542  }
9543  return tagNames;
9544  } catch (SQLException ex) {
9545  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9546  } finally {
9547  closeResultSet(resultSet);
9548  connection.close();
9550  }
9551  }
9552 
9565  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
9566 
9567  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9568  // SELECT * FROM tag_names WHERE tag_name_id IN
9569  // ( SELECT content_tags.tag_name_id as tag_name_id FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id AND tsk_files.data_source_obj_id = ? "
9570  // UNION
9571  // SELECT artifact_tags.tag_name_id as tag_name_id FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id AND arts.data_source_obj_id = ? )
9572  // )
9573  CaseDbConnection connection = connections.getConnection();
9575  ResultSet resultSet = null;
9576 
9577  try {
9578  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
9579  statement.setLong(1, dsObjId);
9580  statement.setLong(2, dsObjId);
9581  resultSet = connection.executeQuery(statement); //NON-NLS
9582  while (resultSet.next()) {
9583  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9584  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9585  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9586  }
9587  return tagNames;
9588  } catch (SQLException ex) {
9589  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
9590  } finally {
9591  closeResultSet(resultSet);
9592  connection.close();
9594  }
9595  }
9596 
9610  @Deprecated
9611  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
9612  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
9613  }
9614 
9629  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
9630  CaseDbConnection connection = connections.getConnection();
9632  ResultSet resultSet = null;
9633  try {
9634  PreparedStatement statement;
9635  // INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?
9636  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME, Statement.RETURN_GENERATED_KEYS);
9637  statement.clearParameters();
9638  statement.setString(5, description);
9639  statement.setString(6, color.getName());
9640  statement.setByte(7, knownStatus.getFileKnownValue());
9641  statement.setString(1, displayName);
9642  statement.setString(2, description);
9643  statement.setString(3, color.getName());
9644  statement.setByte(4, knownStatus.getFileKnownValue());
9645  connection.executeUpdate(statement);
9646  resultSet = statement.getGeneratedKeys();
9647  resultSet.next();
9648  return new TagName(resultSet.getLong(1), //last_insert_rowid()
9649  displayName, description, color, knownStatus);
9650  } catch (SQLException ex) {
9651  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
9652  } finally {
9653  closeResultSet(resultSet);
9654  connection.close();
9656  }
9657  }
9658 
9672  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
9673  CaseDbConnection connection = connections.getConnection();
9675  ResultSet resultSet = null;
9676  try {
9677  Examiner currentExaminer = getCurrentExaminer();
9678  // INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)
9679  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_CONTENT_TAG, Statement.RETURN_GENERATED_KEYS);
9680  statement.clearParameters();
9681  statement.setLong(1, content.getId());
9682  statement.setLong(2, tagName.getId());
9683  statement.setString(3, comment);
9684  statement.setLong(4, beginByteOffset);
9685  statement.setLong(5, endByteOffset);
9686  statement.setLong(6, currentExaminer.getId());
9687  connection.executeUpdate(statement);
9688  resultSet = statement.getGeneratedKeys();
9689  resultSet.next();
9690  return new ContentTag(resultSet.getLong(1), //last_insert_rowid()
9691  content, tagName, comment, beginByteOffset, endByteOffset, currentExaminer.getLoginName());
9692  } catch (SQLException ex) {
9693  throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex);
9694  } finally {
9695  closeResultSet(resultSet);
9696  connection.close();
9698  }
9699  }
9700 
9701  /*
9702  * Deletes a row from the content_tags table in the case database. @param
9703  * tag A ContentTag data transfer object (DTO) for the row to delete.
9704  * @throws TskCoreException
9705  */
9706  public void deleteContentTag(ContentTag tag) throws TskCoreException {
9707  CaseDbConnection connection = connections.getConnection();
9709  try {
9710  // DELETE FROM content_tags WHERE tag_id = ?
9711  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
9712  statement.clearParameters();
9713  statement.setLong(1, tag.getId());
9714  connection.executeUpdate(statement);
9715  } catch (SQLException ex) {
9716  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
9717  } finally {
9718  connection.close();
9720  }
9721  }
9722 
9731  public List<ContentTag> getAllContentTags() throws TskCoreException {
9732  CaseDbConnection connection = connections.getConnection();
9734  ResultSet resultSet = null;
9735  try {
9736  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
9737  // FROM content_tags
9738  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
9739  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9740  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
9741  resultSet = connection.executeQuery(statement);
9742  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9743  while (resultSet.next()) {
9744  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9745  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9746  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
9747  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
9748  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
9749  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
9750  }
9751  return tags;
9752  } catch (SQLException ex) {
9753  throw new TskCoreException("Error selecting rows from content_tags table", ex);
9754  } finally {
9755  closeResultSet(resultSet);
9756  connection.close();
9758  }
9759  }
9760 
9771  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
9772  if (tagName.getId() == Tag.ID_NOT_SET) {
9773  throw new TskCoreException("TagName object is invalid, id not set");
9774  }
9775  CaseDbConnection connection = connections.getConnection();
9777  ResultSet resultSet = null;
9778  try {
9779  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
9780  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
9781  statement.clearParameters();
9782  statement.setLong(1, tagName.getId());
9783  resultSet = connection.executeQuery(statement);
9784  if (resultSet.next()) {
9785  return resultSet.getLong("count");
9786  } else {
9787  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
9788  }
9789  } catch (SQLException ex) {
9790  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
9791  } finally {
9792  closeResultSet(resultSet);
9793  connection.close();
9795  }
9796  }
9797 
9813  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
9814 
9815  if (tagName.getId() == Tag.ID_NOT_SET) {
9816  throw new TskCoreException("TagName object is invalid, id not set");
9817  }
9818 
9819  CaseDbConnection connection = connections.getConnection();
9821  ResultSet resultSet = null;
9822  try {
9823  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
9824  // + " AND content_tags.tag_name_id = ? "
9825  // + " AND tsk_files.data_source_obj_id = ? "
9826  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
9827  statement.clearParameters();
9828  statement.setLong(1, tagName.getId());
9829  statement.setLong(2, dsObjId);
9830 
9831  resultSet = connection.executeQuery(statement);
9832  if (resultSet.next()) {
9833  return resultSet.getLong("count");
9834  } else {
9835  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
9836  }
9837  } catch (SQLException ex) {
9838  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
9839  } finally {
9840  closeResultSet(resultSet);
9841  connection.close();
9843  }
9844  }
9845 
9856  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
9857 
9858  CaseDbConnection connection = connections.getConnection();
9860  ResultSet resultSet = null;
9861  ContentTag tag = null;
9862  try {
9863  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
9864  // FROM content_tags
9865  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
9866  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9867  // WHERE tag_id = ?
9868  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
9869  statement.clearParameters();
9870  statement.setLong(1, contentTagID);
9871  resultSet = connection.executeQuery(statement);
9872 
9873  while (resultSet.next()) {
9874  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9875  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9876  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
9877  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
9878  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
9879  }
9880  resultSet.close();
9881 
9882  } catch (SQLException ex) {
9883  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
9884  } finally {
9885  closeResultSet(resultSet);
9886  connection.close();
9888  }
9889  return tag;
9890  }
9891 
9903  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
9904  if (tagName.getId() == Tag.ID_NOT_SET) {
9905  throw new TskCoreException("TagName object is invalid, id not set");
9906  }
9907  CaseDbConnection connection = connections.getConnection();
9909  ResultSet resultSet = null;
9910  try {
9911  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tsk_examiners.login_name
9912  // FROM content_tags
9913  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9914  // WHERE tag_name_id = ?
9915  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
9916  statement.clearParameters();
9917  statement.setLong(1, tagName.getId());
9918  resultSet = connection.executeQuery(statement);
9919  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9920  while (resultSet.next()) {
9921  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
9922  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
9923  tags.add(tag);
9924  }
9925  resultSet.close();
9926  return tags;
9927  } catch (SQLException ex) {
9928  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
9929  } finally {
9930  closeResultSet(resultSet);
9931  connection.close();
9933  }
9934  }
9935 
9948  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
9949 
9950  CaseDbConnection connection = connections.getConnection();
9952  ResultSet resultSet = null;
9953  try {
9954 
9955  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
9956  // FROM content_tags as content_tags, tsk_files as tsk_files
9957  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9958  // WHERE content_tags.obj_id = tsk_files.obj_id
9959  // AND content_tags.tag_name_id = ?
9960  // AND tsk_files.data_source_obj_id = ?
9961  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
9962  statement.clearParameters();
9963  statement.setLong(1, tagName.getId());
9964  statement.setLong(2, dsObjId);
9965  resultSet = connection.executeQuery(statement);
9966  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9967  while (resultSet.next()) {
9968  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
9969  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
9970  tags.add(tag);
9971  }
9972  resultSet.close();
9973  return tags;
9974  } catch (SQLException ex) {
9975  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
9976  } finally {
9977  closeResultSet(resultSet);
9978  connection.close();
9980  }
9981  }
9982 
9994  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
9995  CaseDbConnection connection = connections.getConnection();
9997  ResultSet resultSet = null;
9998  try {
9999  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
10000  // FROM content_tags
10001  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
10002  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10003  // WHERE content_tags.obj_id = ?
10004  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
10005  statement.clearParameters();
10006  statement.setLong(1, content.getId());
10007  resultSet = connection.executeQuery(statement);
10008  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10009  while (resultSet.next()) {
10010  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10011  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10012  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10013  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
10014  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10015  tags.add(tag);
10016  }
10017  return tags;
10018  } catch (SQLException ex) {
10019  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
10020  } finally {
10021  closeResultSet(resultSet);
10022  connection.close();
10024  }
10025  }
10026 
10040  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
10041  CaseDbConnection connection = connections.getConnection();
10043  ResultSet resultSet = null;
10044  try {
10045  Examiner currentExaminer = getCurrentExaminer();
10046  // "INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) VALUES (?, ?, ?, ?)"), //NON-NLS
10047  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT_TAG, Statement.RETURN_GENERATED_KEYS);
10048  statement.clearParameters();
10049  statement.setLong(1, artifact.getArtifactID());
10050  statement.setLong(2, tagName.getId());
10051  statement.setString(3, comment);
10052  statement.setLong(4, currentExaminer.getId());
10053  connection.executeUpdate(statement);
10054  resultSet = statement.getGeneratedKeys();
10055  resultSet.next();
10056  return new BlackboardArtifactTag(resultSet.getLong(1), //last_insert_rowid()
10057  artifact, getContentById(artifact.getObjectID()), tagName, comment, currentExaminer.getLoginName());
10058  } catch (SQLException ex) {
10059  throw new TskCoreException("Error adding row to blackboard_artifact_tags table (obj_id = " + artifact.getArtifactID() + ", tag_name_id = " + tagName.getId() + ")", ex);
10060  } finally {
10061  closeResultSet(resultSet);
10062  connection.close();
10064  }
10065  }
10066 
10067  /*
10068  * Deletes a row from the blackboard_artifact_tags table in the case
10069  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
10070  * representing the row to delete. @throws TskCoreException
10071  */
10072  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
10073  CaseDbConnection connection = connections.getConnection();
10075  try {
10076  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
10077  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
10078  statement.clearParameters();
10079  statement.setLong(1, tag.getId());
10080  connection.executeUpdate(statement);
10081  } catch (SQLException ex) {
10082  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
10083  } finally {
10084  connection.close();
10086  }
10087  }
10088 
10098  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
10099  CaseDbConnection connection = connections.getConnection();
10101  ResultSet resultSet = null;
10102  try {
10103  // SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
10104  // FROM blackboard_artifact_tags
10105  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10106  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10107  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
10108  resultSet = connection.executeQuery(statement);
10109  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10110  while (resultSet.next()) {
10111  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10112  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10113  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10114  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10115  Content content = getContentById(artifact.getObjectID());
10116  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10117  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10118  tags.add(tag);
10119  }
10120  return tags;
10121  } catch (SQLException ex) {
10122  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
10123  } finally {
10124  closeResultSet(resultSet);
10125  connection.close();
10127  }
10128  }
10129 
10140  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
10141  if (tagName.getId() == Tag.ID_NOT_SET) {
10142  throw new TskCoreException("TagName object is invalid, id not set");
10143  }
10144  CaseDbConnection connection = connections.getConnection();
10146  ResultSet resultSet = null;
10147  try {
10148  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
10149  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
10150  statement.clearParameters();
10151  statement.setLong(1, tagName.getId());
10152  resultSet = connection.executeQuery(statement);
10153  if (resultSet.next()) {
10154  return resultSet.getLong("count");
10155  } else {
10156  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
10157  }
10158  } catch (SQLException ex) {
10159  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
10160  } finally {
10161  closeResultSet(resultSet);
10162  connection.close();
10164  }
10165  }
10166 
10181  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10182 
10183  if (tagName.getId() == Tag.ID_NOT_SET) {
10184  throw new TskCoreException("TagName object is invalid, id not set");
10185  }
10186 
10187  CaseDbConnection connection = connections.getConnection();
10189  ResultSet resultSet = null;
10190  try {
10191  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
10192  // + " AND artifact_tags.tag_name_id = ?"
10193  // + " AND arts.data_source_obj_id = ? "
10194  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
10195  statement.clearParameters();
10196  statement.setLong(1, tagName.getId());
10197  statement.setLong(2, dsObjId);
10198  resultSet = connection.executeQuery(statement);
10199  if (resultSet.next()) {
10200  return resultSet.getLong("count");
10201  } else {
10202  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
10203  }
10204  } catch (SQLException ex) {
10205  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10206  } finally {
10207  closeResultSet(resultSet);
10208  connection.close();
10210  }
10211  }
10212 
10224  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
10225  if (tagName.getId() == Tag.ID_NOT_SET) {
10226  throw new TskCoreException("TagName object is invalid, id not set");
10227  }
10228  CaseDbConnection connection = connections.getConnection();
10230  ResultSet resultSet = null;
10231  try {
10232  // SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tsk_examiners.login_name
10233  // FROM blackboard_artifact_tags
10234  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10235  // WHERE tag_name_id = ?
10236  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
10237  statement.clearParameters();
10238  statement.setLong(1, tagName.getId());
10239  resultSet = connection.executeQuery(statement);
10240  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10241  while (resultSet.next()) {
10242  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10243  Content content = getContentById(artifact.getObjectID());
10244  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10245  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10246  tags.add(tag);
10247  }
10248  return tags;
10249  } catch (SQLException ex) {
10250  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
10251  } finally {
10252  closeResultSet(resultSet);
10253  connection.close();
10255  }
10256  }
10257 
10272  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10273 
10274  if (tagName.getId() == Tag.ID_NOT_SET) {
10275  throw new TskCoreException("TagName object is invalid, id not set");
10276  }
10277 
10278  CaseDbConnection connection = connections.getConnection();
10280  ResultSet resultSet = null;
10281  try {
10282  // SELECT artifact_tags.tag_id, artifact_tags.artifact_id, artifact_tags.tag_name_id, artifact_tags.comment, arts.obj_id, arts.artifact_obj_id, arts.data_source_obj_id, arts.artifact_type_id, arts.review_status_id, tsk_examiners.login_name
10283  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
10284  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
10285  // WHERE artifact_tags.artifact_id = arts.artifact_id
10286  // AND artifact_tags.tag_name_id = ?
10287  // AND arts.data_source_obj_id = ?
10288  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10289  statement.clearParameters();
10290  statement.setLong(1, tagName.getId());
10291  statement.setLong(2, dsObjId);
10292  resultSet = connection.executeQuery(statement);
10293  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10294  while (resultSet.next()) {
10295  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10296  Content content = getContentById(artifact.getObjectID());
10297  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10298  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10299  tags.add(tag);
10300  }
10301  return tags;
10302  } catch (SQLException ex) {
10303  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10304  } finally {
10305  closeResultSet(resultSet);
10306  connection.close();
10308  }
10309 
10310  }
10311 
10323  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
10324 
10325  CaseDbConnection connection = connections.getConnection();
10327  ResultSet resultSet = null;
10328  BlackboardArtifactTag tag = null;
10329  try {
10330  //SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
10331  // FROM blackboard_artifact_tags
10332  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10333  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10334  // WHERE blackboard_artifact_tags.tag_id = ?
10335  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
10336  statement.clearParameters();
10337  statement.setLong(1, artifactTagID);
10338  resultSet = connection.executeQuery(statement);
10339 
10340  while (resultSet.next()) {
10341  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10342  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10343  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
10344  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10345  Content content = getContentById(artifact.getObjectID());
10346  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10347  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
10348  }
10349  resultSet.close();
10350 
10351  } catch (SQLException ex) {
10352  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
10353  } finally {
10354  closeResultSet(resultSet);
10355  connection.close();
10357  }
10358  return tag;
10359  }
10360 
10373  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
10374  CaseDbConnection connection = connections.getConnection();
10376  ResultSet resultSet = null;
10377  try {
10378  // SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
10379  // FROM blackboard_artifact_tags
10380  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10381  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10382  // WHERE blackboard_artifact_tags.artifact_id = ?
10383  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
10384  statement.clearParameters();
10385  statement.setLong(1, artifact.getArtifactID());
10386  resultSet = connection.executeQuery(statement);
10387  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10388  while (resultSet.next()) {
10389  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10390  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10391  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10392  Content content = getContentById(artifact.getObjectID());
10393  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10394  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10395  tags.add(tag);
10396  }
10397  return tags;
10398  } catch (SQLException ex) {
10399  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
10400  } finally {
10401  closeResultSet(resultSet);
10402  connection.close();
10404  }
10405  }
10406 
10415  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
10416  CaseDbConnection connection = connections.getConnection();
10418  try {
10419  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
10420  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
10421  statement.clearParameters();
10422  statement.setString(1, newPath);
10423  statement.setLong(2, objectId);
10424  connection.executeUpdate(statement);
10425  } catch (SQLException ex) {
10426  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
10427  } finally {
10428  connection.close();
10430  }
10431  }
10432 
10446  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
10447  return addReport(localPath, sourceModuleName, reportName, null);
10448  }
10449 
10465  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
10466  // Make sure the local path of the report is in the database directory
10467  // or one of its subdirectories.
10468  String relativePath = ""; //NON-NLS
10469  long createTime = 0;
10470  String localPathLower = localPath.toLowerCase();
10471 
10472  if (localPathLower.startsWith("http")) {
10473  relativePath = localPathLower;
10474  createTime = System.currentTimeMillis() / 1000;
10475  } else {
10476  /*
10477  * Note: The following call to .relativize() may be dangerous in
10478  * case-sensitive operating systems and should be looked at. For
10479  * now, we are simply relativizing the paths as all lower case, then
10480  * using the length of the result to pull out the appropriate number
10481  * of characters from the localPath String.
10482  */
10483  try {
10484  String casePathLower = getDbDirPath().toLowerCase();
10485  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
10486  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
10487  } catch (IllegalArgumentException ex) {
10488  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
10489  throw new TskCoreException(errorMessage, ex);
10490  }
10491  try {
10492  // get its file time
10493  java.io.File tempFile = new java.io.File(localPath);
10494  // Convert to UNIX epoch (seconds, not milliseconds).
10495  createTime = tempFile.lastModified() / 1000;
10496  } catch (Exception ex) {
10497  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
10498  }
10499  }
10500 
10501  // Write the report data to the database.
10502  CaseDbConnection connection = connections.getConnection();
10504  ResultSet resultSet = null;
10505  try {
10506  // Insert a row for the report into the tsk_objects table.
10507  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
10508  long parentObjId = 0;
10509  if (parent != null) {
10510  parentObjId = parent.getId();
10511  }
10512  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
10513 
10514  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
10515  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
10516  statement.clearParameters();
10517  statement.setLong(1, objectId);
10518  statement.setString(2, relativePath);
10519  statement.setLong(3, createTime);
10520  statement.setString(4, sourceModuleName);
10521  statement.setString(5, reportName);
10522  connection.executeUpdate(statement);
10523  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
10524  } catch (SQLException ex) {
10525  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
10526  } finally {
10527  closeResultSet(resultSet);
10528  connection.close();
10530  }
10531  }
10532 
10541  public List<Report> getAllReports() throws TskCoreException {
10542  CaseDbConnection connection = connections.getConnection();
10544  ResultSet resultSet = null;
10545  ResultSet parentResultSet = null;
10546  PreparedStatement statement = null;
10547  Statement parentStatement = null;
10548  try {
10549  // SELECT * FROM reports
10550  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
10551  parentStatement = connection.createStatement();
10552  resultSet = connection.executeQuery(statement);
10553  ArrayList<Report> reports = new ArrayList<Report>();
10554  while (resultSet.next()) {
10555  String localpath = resultSet.getString("path");
10556  if (localpath.toLowerCase().startsWith("http") == false) {
10557  // make path absolute
10558  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
10559  }
10560 
10561  // get the report parent
10562  Content parent = null;
10563  long reportId = resultSet.getLong("obj_id"); // NON-NLS
10564  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
10565  parentResultSet = parentStatement.executeQuery(parentQuery);
10566  if (parentResultSet.next()) {
10567  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10568  parent = this.getContentById(parentId);
10569  }
10570  parentResultSet.close();
10571 
10572  reports.add(new Report(this,
10573  reportId,
10574  localpath,
10575  resultSet.getLong("crtime"), //NON-NLS
10576  resultSet.getString("src_module_name"), //NON-NLS
10577  resultSet.getString("report_name"),
10578  parent)); //NON-NLS
10579  }
10580  return reports;
10581  } catch (SQLException ex) {
10582  throw new TskCoreException("Error querying reports table", ex);
10583  } finally {
10584  closeResultSet(resultSet);
10585  closeResultSet(parentResultSet);
10586  closeStatement(statement);
10587  closeStatement(parentStatement);
10588 
10589  connection.close();
10591  }
10592  }
10593 
10603  public Report getReportById(long id) throws TskCoreException {
10604  CaseDbConnection connection = connections.getConnection();
10606  PreparedStatement statement = null;
10607  Statement parentStatement = null;
10608  ResultSet resultSet = null;
10609  ResultSet parentResultSet = null;
10610  Report report = null;
10611  try {
10612  // SELECT * FROM reports WHERE obj_id = ?
10613  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
10614  parentStatement = connection.createStatement();
10615  statement.clearParameters();
10616  statement.setLong(1, id);
10617  resultSet = connection.executeQuery(statement);
10618 
10619  if (resultSet.next()) {
10620  // get the report parent
10621  Content parent = null;
10622  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
10623  parentResultSet = parentStatement.executeQuery(parentQuery);
10624  if (parentResultSet.next()) {
10625  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10626  parent = this.getContentById(parentId);
10627  }
10628 
10629  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
10630  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
10631  resultSet.getLong("crtime"), //NON-NLS
10632  resultSet.getString("src_module_name"), //NON-NLS
10633  resultSet.getString("report_name"),
10634  parent); //NON-NLS
10635  } else {
10636  throw new TskCoreException("No report found for id: " + id);
10637  }
10638  } catch (SQLException ex) {
10639  throw new TskCoreException("Error querying reports table for id: " + id, ex);
10640  } finally {
10641  closeResultSet(resultSet);
10642  closeResultSet(parentResultSet);
10643  closeStatement(statement);
10644  closeStatement(parentStatement);
10645  connection.close();
10647  }
10648 
10649  return report;
10650  }
10651 
10659  public void deleteReport(Report report) throws TskCoreException {
10660  CaseDbConnection connection = connections.getConnection();
10662  try {
10663  // DELETE FROM reports WHERE reports.obj_id = ?
10664  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
10665  statement.setLong(1, report.getId());
10666  connection.executeUpdate(statement);
10667  } catch (SQLException ex) {
10668  throw new TskCoreException("Error querying reports table", ex);
10669  } finally {
10671  }
10672  }
10673 
10674  static void closeResultSet(ResultSet resultSet) {
10675  if (resultSet != null) {
10676  try {
10677  resultSet.close();
10678  } catch (SQLException ex) {
10679  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
10680  }
10681  }
10682  }
10683 
10684  static void closeStatement(Statement statement) {
10685  if (statement != null) {
10686  try {
10687  statement.close();
10688  } catch (SQLException ex) {
10689  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
10690 
10691  }
10692  }
10693  }
10694 
10703  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
10704  CaseDbConnection connection = connections.getConnection();
10706  try {
10707  Statement statement = connection.createStatement();
10708  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
10709  } catch (SQLException ex) {
10710  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
10711  } finally {
10712  connection.close();
10714  }
10715  }
10716 
10717  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
10718  CaseDbConnection connection = connections.getConnection();
10720  try {
10721  Statement statement = connection.createStatement();
10722  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
10723  } catch (SQLException ex) {
10724  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
10725  } finally {
10726  connection.close();
10728  }
10729  }
10730 
10747  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
10748  CaseDbConnection connection = connections.getConnection();
10750  ResultSet resultSet = null;
10751  Statement statement;
10752  try {
10753  connection.beginTransaction();
10754  statement = connection.createStatement();
10755  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
10756  insertStatement.setLong(1, dataSource.getId());
10757  insertStatement.setString(2, hostName);
10758  insertStatement.setLong(3, jobStart.getTime());
10759  insertStatement.setLong(4, jobEnd.getTime());
10760  insertStatement.setInt(5, status.ordinal());
10761  insertStatement.setString(6, settingsDir);
10762  connection.executeUpdate(insertStatement);
10763  resultSet = insertStatement.getGeneratedKeys();
10764  resultSet.next();
10765  long id = resultSet.getLong(1); //last_insert_rowid()
10766  for (int i = 0; i < ingestModules.size(); i++) {
10767  IngestModuleInfo ingestModule = ingestModules.get(i);
10768  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
10769  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
10770  }
10771  resultSet.close();
10772  resultSet = null;
10773  connection.commitTransaction();
10774  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
10775  } catch (SQLException ex) {
10776  connection.rollbackTransaction();
10777  throw new TskCoreException("Error adding the ingest job.", ex);
10778  } finally {
10779  closeResultSet(resultSet);
10780  connection.close();
10782  }
10783  }
10784 
10798  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
10799  CaseDbConnection connection = connections.getConnection();
10800  ResultSet resultSet = null;
10801  Statement statement = null;
10802  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
10804  try {
10805  statement = connection.createStatement();
10806  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10807  if (!resultSet.next()) {
10808  resultSet.close();
10809  resultSet = null;
10810  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
10811  insertStatement.setString(1, displayName);
10812  insertStatement.setString(2, uniqueName);
10813  insertStatement.setInt(3, type.ordinal());
10814  insertStatement.setString(4, version);
10815  connection.executeUpdate(insertStatement);
10816  resultSet = statement.getGeneratedKeys();
10817  resultSet.next();
10818  long id = resultSet.getLong(1); //last_insert_rowid()
10819  resultSet.close();
10820  resultSet = null;
10821  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
10822  } else {
10823  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10824  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10825  }
10826  } catch (SQLException ex) {
10827  try {
10828  closeStatement(statement);
10829  statement = connection.createStatement();
10830  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10831  if (resultSet.next()) {
10832  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10833  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10834  } else {
10835  throw new TskCoreException("Couldn't add new module to database.", ex);
10836  }
10837  } catch (SQLException ex1) {
10838  throw new TskCoreException("Couldn't add new module to database.", ex1);
10839  }
10840  } finally {
10841  closeResultSet(resultSet);
10842  closeStatement(statement);
10843  connection.close();
10845  }
10846  }
10847 
10855  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
10856  CaseDbConnection connection = connections.getConnection();
10857  ResultSet resultSet = null;
10858  Statement statement = null;
10859  List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>();
10861  try {
10862  statement = connection.createStatement();
10863  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
10864  while (resultSet.next()) {
10865  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
10866  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
10867  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
10868  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
10869  }
10870  return ingestJobs;
10871  } catch (SQLException ex) {
10872  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
10873  } finally {
10874  closeResultSet(resultSet);
10875  closeStatement(statement);
10876  connection.close();
10878  }
10879  }
10880 
10891  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
10892  ResultSet resultSet = null;
10893  Statement statement = null;
10894  List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>();
10896  try {
10897  statement = connection.createStatement();
10898  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
10899  + "ingest_job_modules.pipeline_position AS pipeline_position, "
10900  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
10901  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
10902  + "FROM ingest_job_modules, ingest_modules "
10903  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
10904  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
10905  + "ORDER BY (ingest_job_modules.pipeline_position);");
10906  while (resultSet.next()) {
10907  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10908  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
10909  }
10910  return ingestModules;
10911  } finally {
10912  closeResultSet(resultSet);
10913  closeStatement(statement);
10915 
10916  }
10917  }
10918 
10922  static class ObjectInfo {
10923 
10924  private long id;
10925  private TskData.ObjectType type;
10926 
10927  ObjectInfo(long id, ObjectType type) {
10928  this.id = id;
10929  this.type = type;
10930  }
10931 
10932  long getId() {
10933  return id;
10934  }
10935 
10936  TskData.ObjectType getType() {
10937  return type;
10938  }
10939  }
10940 
10941  private interface DbCommand {
10942 
10943  void execute() throws SQLException;
10944  }
10945 
10946  private enum PREPARED_STATEMENT {
10947 
10948  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
10949  + "WHERE artifact_type_id = ?"), //NON-NLS
10950  COUNT_ARTIFACTS_OF_TYPE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
10951  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
10952  COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
10953  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
10954  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
10955  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
10956  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
10957  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
10958  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
10959  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
10960  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
10961  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
10962  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
10963  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
10964  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
10965  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
10966  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
10967  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
10968  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
10969  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
10970  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
10971  + "AND tsk_files.type = ? )"), //NON-NLS
10972  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
10973  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
10974  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
10975  INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, review_status_id) " //NON-NLS
10976  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
10977  POSTGRESQL_INSERT_ARTIFACT("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, review_status_id) " //NON-NLS
10978  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
10979  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
10980  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
10981  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
10982  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
10983  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
10984  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
10985  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
10986  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
10987  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
10988  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
10989  SELECT_FILES_BY_DATA_SOURCE_AND_NAME("SELECT * FROM tsk_files WHERE LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND data_source_obj_id = ?"), //NON-NLS
10990  SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME("SELECT * FROM tsk_files WHERE LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND LOWER(parent_path) LIKE LOWER(?) AND data_source_obj_id = ?"), //NON-NLS
10991  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
10992  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
10993  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
10994  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
10995  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
10996  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
10997  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
10998  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
10999  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
11000  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
11001  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
11002  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
11003  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11004  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11005  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
11006  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
11007  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
11008  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
11009  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, md5, known, mime_type, parent_path, data_source_obj_id,extension) " //NON-NLS
11010  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
11011  INSERT_FILE_SYSTEM_FILE("INSERT INTO tsk_files(obj_id, fs_obj_id, data_source_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, extension)"
11012  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
11013  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
11014  + "WHERE obj_id = ?"), //NON-NLS
11015  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
11016  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11017  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
11018  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
11019  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
11020  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
11021  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
11022  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
11023  + "WHERE tag_name_id IN " //NON-NLS
11024  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
11025  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
11026  + "WHERE tag_name_id IN "
11027  + "( SELECT content_tags.tag_name_id as tag_name_id "
11028  + "FROM content_tags as content_tags, tsk_files as tsk_files"
11029  + " WHERE content_tags.obj_id = tsk_files.obj_id"
11030  + " AND tsk_files.data_source_obj_id = ?"
11031  + " UNION "
11032  + "SELECT artifact_tags.tag_name_id as tag_name_id "
11033  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
11034  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
11035  + " AND arts.data_source_obj_id = ?"
11036  + " )"),
11037  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
11038  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11039  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
11040  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
11041  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
11042  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11043  + " AND content_tags.tag_name_id = ? "
11044  + " AND tsk_files.data_source_obj_id = ? "
11045  ),
11046  SELECT_CONTENT_TAGS("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11047  + "FROM content_tags "
11048  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11049  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11050  SELECT_CONTENT_TAGS_BY_TAG_NAME("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tsk_examiners.login_name "
11051  + "FROM content_tags "
11052  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11053  + "WHERE tag_name_id = ?"), //NON-NLS
11054  SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11055  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
11056  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
11057  + " AND content_tags.obj_id = tsk_files.obj_id"
11058  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
11059  + " AND content_tags.tag_name_id = ?"
11060  + " AND tsk_files.data_source_obj_id = ? "),
11061  SELECT_CONTENT_TAG_BY_ID("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11062  + "FROM content_tags "
11063  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11064  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11065  + "WHERE tag_id = ?"), //NON-NLS
11066  SELECT_CONTENT_TAGS_BY_CONTENT("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11067  + "FROM content_tags "
11068  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11069  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11070  + "WHERE content_tags.obj_id = ?"), //NON-NLS
11071  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
11072  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11073  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
11074  SELECT_ARTIFACT_TAGS("SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11075  + "FROM blackboard_artifact_tags "
11076  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11077  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11078  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
11079  COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE("SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
11080  + " AND artifact_tags.tag_name_id = ?"
11081  + " AND arts.data_source_obj_id = ? "),
11082  SELECT_ARTIFACT_TAGS_BY_TAG_NAME("SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tsk_examiners.login_name "
11083  + "FROM blackboard_artifact_tags "
11084  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11085  + "WHERE tag_name_id = ?"), //NON-NLS
11086  SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE("SELECT artifact_tags.tag_id, artifact_tags.artifact_id, artifact_tags.tag_name_id, artifact_tags.comment, arts.obj_id, arts.artifact_obj_id, arts.data_source_obj_id, arts.artifact_type_id, arts.review_status_id, tsk_examiners.login_name "
11087  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
11088  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
11089  + " AND artifact_tags.artifact_id = arts.artifact_id"
11090  + " AND artifact_tags.tag_name_id = ? "
11091  + " AND arts.data_source_obj_id = ? "),
11092  SELECT_ARTIFACT_TAG_BY_ID("SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11093  + "FROM blackboard_artifact_tags "
11094  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11095  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11096  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
11097  SELECT_ARTIFACT_TAGS_BY_ARTIFACT("SELECT blackboard_artifact_tags.tag_id, blackboard_artifact_tags.artifact_id, blackboard_artifact_tags.tag_name_id, blackboard_artifact_tags.comment, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name "
11098  + "FROM blackboard_artifact_tags "
11099  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11100  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11101  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
11102  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
11103  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
11104  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
11105  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
11106  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11107  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
11108  SELECT_ATTR_BY_VALUE_BYTE("SELECT source FROM blackboard_attributes WHERE artifact_id = ? AND attribute_type_id = ? AND value_type = 4 AND value_byte = ?"), //NON-NLS
11109  UPDATE_ATTR_BY_VALUE_BYTE("UPDATE blackboard_attributes SET source = ? WHERE artifact_id = ? AND attribute_type_id = ? AND value_type = 4 AND value_byte = ?"), //NON-NLS
11110  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
11111  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
11112  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
11113  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
11114  + "WHERE (tsk_objects.par_obj_id = ?)"),
11115  INSERT_OR_UPDATE_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?"),
11116  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
11117  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
11118  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
11119  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
11120  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
11121  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
11122  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
11123  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
11124  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone) VALUES (?, ?, ?)"),
11125  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
11126  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11127  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11128  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
11129  INSERT_FS_INFO("INSERT INTO tsk_fs_info (obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)"
11130  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
11131 
11132  private final String sql;
11133 
11134  private PREPARED_STATEMENT(String sql) {
11135  this.sql = sql;
11136  }
11137 
11138  String getSQL() {
11139  return sql;
11140  }
11141  }
11142 
11148  abstract private class ConnectionPool {
11149 
11150  private PooledDataSource pooledDataSource;
11151 
11152  public ConnectionPool() {
11153  pooledDataSource = null;
11154  }
11155 
11156  CaseDbConnection getConnection() throws TskCoreException {
11157  if (pooledDataSource == null) {
11158  throw new TskCoreException("Error getting case database connection - case is closed");
11159  }
11160  try {
11161  return getPooledConnection();
11162  } catch (SQLException exp) {
11163  throw new TskCoreException(exp.getMessage());
11164  }
11165  }
11166 
11167  void close() throws TskCoreException {
11168  if (pooledDataSource != null) {
11169  try {
11170  pooledDataSource.close();
11171  } catch (SQLException exp) {
11172  throw new TskCoreException(exp.getMessage());
11173  } finally {
11174  pooledDataSource = null;
11175  }
11176  }
11177  }
11178 
11179  abstract CaseDbConnection getPooledConnection() throws SQLException;
11180 
11181  public PooledDataSource getPooledDataSource() {
11182  return pooledDataSource;
11183  }
11184 
11185  public void setPooledDataSource(PooledDataSource pooledDataSource) {
11186  this.pooledDataSource = pooledDataSource;
11187  }
11188  }
11189 
11194  private final class SQLiteConnections extends ConnectionPool {
11195 
11196  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
11197 
11198  SQLiteConnections(String dbPath) throws SQLException {
11199  configurationOverrides.put("acquireIncrement", "2");
11200  configurationOverrides.put("initialPoolSize", "5");
11201  configurationOverrides.put("minPoolSize", "5");
11202  /*
11203  * NOTE: max pool size and max statements are related. If you
11204  * increase max pool size, then also increase statements.
11205  */
11206  configurationOverrides.put("maxPoolSize", "20");
11207  configurationOverrides.put("maxStatements", "200");
11208  configurationOverrides.put("maxStatementsPerConnection", "20");
11209 
11210  SQLiteConfig config = new SQLiteConfig();
11211  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
11212  config.setReadUncommited(true);
11213  config.enforceForeignKeys(true); // Enforce foreign key constraints.
11214  SQLiteDataSource unpooled = new SQLiteDataSource(config);
11215  unpooled.setUrl("jdbc:sqlite:" + dbPath);
11216  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
11217  }
11218 
11219  @Override
11220  public CaseDbConnection getPooledConnection() throws SQLException {
11221  return new SQLiteConnection(getPooledDataSource().getConnection());
11222  }
11223  }
11224 
11229  private final class PostgreSQLConnections extends ConnectionPool {
11230 
11231  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
11232  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
11233  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
11234  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
11235  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
11236  comboPooledDataSource.setUser(userName);
11237  comboPooledDataSource.setPassword(password);
11238  comboPooledDataSource.setAcquireIncrement(2);
11239  comboPooledDataSource.setInitialPoolSize(5);
11240  comboPooledDataSource.setMinPoolSize(5);
11241  /*
11242  * NOTE: max pool size and max statements are related. If you
11243  * increase max pool size, then also increase statements.
11244  */
11245  comboPooledDataSource.setMaxPoolSize(20);
11246  comboPooledDataSource.setMaxStatements(200);
11247  comboPooledDataSource.setMaxStatementsPerConnection(20);
11248  setPooledDataSource(comboPooledDataSource);
11249  }
11250 
11251  @Override
11252  public CaseDbConnection getPooledConnection() throws SQLException {
11253  return new PostgreSQLConnection(getPooledDataSource().getConnection());
11254  }
11255  }
11256 
11260  abstract class CaseDbConnection implements AutoCloseable {
11261 
11262  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
11263  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
11264 
11265  private class CreateStatement implements DbCommand {
11266 
11267  private final Connection connection;
11268  private Statement statement = null;
11269 
11270  CreateStatement(Connection connection) {
11271  this.connection = connection;
11272  }
11273 
11274  Statement getStatement() {
11275  return statement;
11276  }
11277 
11278  @Override
11279  public void execute() throws SQLException {
11280  statement = connection.createStatement();
11281  }
11282  }
11283 
11284  private class SetAutoCommit implements DbCommand {
11285 
11286  private final Connection connection;
11287  private final boolean mode;
11288 
11289  SetAutoCommit(Connection connection, boolean mode) {
11290  this.connection = connection;
11291  this.mode = mode;
11292  }
11293 
11294  @Override
11295  public void execute() throws SQLException {
11296  connection.setAutoCommit(mode);
11297  }
11298  }
11299 
11300  private class Commit implements DbCommand {
11301 
11302  private final Connection connection;
11303 
11304  Commit(Connection connection) {
11305  this.connection = connection;
11306  }
11307 
11308  @Override
11309  public void execute() throws SQLException {
11310  connection.commit();
11311  }
11312  }
11313 
11314  private class ExecuteQuery implements DbCommand {
11315 
11316  private final Statement statement;
11317  private final String query;
11318  private ResultSet resultSet;
11319 
11320  ExecuteQuery(Statement statement, String query) {
11321  this.statement = statement;
11322  this.query = query;
11323  }
11324 
11325  ResultSet getResultSet() {
11326  return resultSet;
11327  }
11328 
11329  @Override
11330  public void execute() throws SQLException {
11331  resultSet = statement.executeQuery(query);
11332  }
11333  }
11334 
11335  private class ExecutePreparedStatementQuery implements DbCommand {
11336 
11337  private final PreparedStatement preparedStatement;
11338  private ResultSet resultSet;
11339 
11340  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
11341  this.preparedStatement = preparedStatement;
11342  }
11343 
11344  ResultSet getResultSet() {
11345  return resultSet;
11346  }
11347 
11348  @Override
11349  public void execute() throws SQLException {
11350  resultSet = preparedStatement.executeQuery();
11351  }
11352  }
11353 
11354  private class ExecutePreparedStatementUpdate implements DbCommand {
11355 
11356  private final PreparedStatement preparedStatement;
11357 
11358  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
11359  this.preparedStatement = preparedStatement;
11360  }
11361 
11362  @Override
11363  public void execute() throws SQLException {
11364  preparedStatement.executeUpdate();
11365  }
11366  }
11367 
11368  private class ExecuteStatementUpdate implements DbCommand {
11369 
11370  private final Statement statement;
11371  private final String updateCommand;
11372 
11373  ExecuteStatementUpdate(Statement statement, String updateCommand) {
11374  this.statement = statement;
11375  this.updateCommand = updateCommand;
11376  }
11377 
11378  @Override
11379  public void execute() throws SQLException {
11380  statement.executeUpdate(updateCommand);
11381  }
11382  }
11383 
11384  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
11385 
11386  private final Statement statement;
11387  private final int generateKeys;
11388  private final String updateCommand;
11389 
11390  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
11391  this.statement = statement;
11392  this.generateKeys = generateKeys;
11393  this.updateCommand = updateCommand;
11394  }
11395 
11396  @Override
11397  public void execute() throws SQLException {
11398  statement.executeUpdate(updateCommand, generateKeys);
11399  }
11400  }
11401 
11402  private class PrepareStatement implements DbCommand {
11403 
11404  private final Connection connection;
11405  private final String input;
11406  private PreparedStatement preparedStatement = null;
11407 
11408  PrepareStatement(Connection connection, String input) {
11409  this.connection = connection;
11410  this.input = input;
11411  }
11412 
11413  PreparedStatement getPreparedStatement() {
11414  return preparedStatement;
11415  }
11416 
11417  @Override
11418  public void execute() throws SQLException {
11419  preparedStatement = connection.prepareStatement(input);
11420  }
11421  }
11422 
11423  private class PrepareStatementGenerateKeys implements DbCommand {
11424 
11425  private final Connection connection;
11426  private final String input;
11427  private final int generateKeys;
11428  private PreparedStatement preparedStatement = null;
11429 
11430  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
11431  this.connection = connection;
11432  this.input = input;
11433  this.generateKeys = generateKeysInput;
11434  }
11435 
11436  PreparedStatement getPreparedStatement() {
11437  return preparedStatement;
11438  }
11439 
11440  @Override
11441  public void execute() throws SQLException {
11442  preparedStatement = connection.prepareStatement(input, generateKeys);
11443  }
11444  }
11445 
11446  abstract void executeCommand(DbCommand command) throws SQLException;
11447 
11448  private final Connection connection;
11449  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
11450 
11451  CaseDbConnection(Connection connection) {
11452  this.connection = connection;
11453  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
11454  }
11455 
11456  boolean isOpen() {
11457  return this.connection != null;
11458  }
11459 
11460  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
11461  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
11462  }
11463 
11464  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
11465  // Lazy statement preparation.
11466  PreparedStatement statement;
11467  if (this.preparedStatements.containsKey(statementKey)) {
11468  statement = this.preparedStatements.get(statementKey);
11469  } else {
11470  statement = prepareStatement(statementKey.getSQL(), generateKeys);
11471  this.preparedStatements.put(statementKey, statement);
11472  }
11473  return statement;
11474  }
11475 
11476  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11477  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
11478  executeCommand(prepareStatement);
11479  return prepareStatement.getPreparedStatement();
11480  }
11481 
11482  Statement createStatement() throws SQLException {
11483  CreateStatement createStatement = new CreateStatement(this.connection);
11484  executeCommand(createStatement);
11485  return createStatement.getStatement();
11486  }
11487 
11488  void beginTransaction() throws SQLException {
11489  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
11490  executeCommand(setAutoCommit);
11491  }
11492 
11493  void commitTransaction() throws SQLException {
11494  Commit commit = new Commit(connection);
11495  executeCommand(commit);
11496  // You must turn auto commit back on when done with the transaction.
11497  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
11498  executeCommand(setAutoCommit);
11499  }
11500 
11506  void rollbackTransaction() {
11507  try {
11508  connection.rollback();
11509  } catch (SQLException e) {
11510  logger.log(Level.SEVERE, "Error rolling back transaction", e);
11511  }
11512  try {
11513  connection.setAutoCommit(true);
11514  } catch (SQLException e) {
11515  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
11516  }
11517  }
11518 
11526  void rollbackTransactionWithThrow() throws SQLException {
11527  try {
11528  connection.rollback();
11529  } finally {
11530  connection.setAutoCommit(true);
11531  }
11532  }
11533 
11534  ResultSet executeQuery(Statement statement, String query) throws SQLException {
11535  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
11536  executeCommand(queryCommand);
11537  return queryCommand.getResultSet();
11538  }
11539 
11549  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
11550  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
11551  executeCommand(executePreparedStatementQuery);
11552  return executePreparedStatementQuery.getResultSet();
11553  }
11554 
11555  void executeUpdate(Statement statement, String update) throws SQLException {
11556  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
11557  }
11558 
11559  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11560  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
11561  executeCommand(executeStatementUpdate);
11562  }
11563 
11564  void executeUpdate(PreparedStatement statement) throws SQLException {
11565  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
11566  executeCommand(executePreparedStatementUpdate);
11567  }
11568 
11572  @Override
11573  public void close() {
11574  try {
11575  connection.close();
11576  } catch (SQLException ex) {
11577  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
11578  }
11579  }
11580 
11581  Connection getConnection() {
11582  return this.connection;
11583  }
11584  }
11585 
11589  private final class SQLiteConnection extends CaseDbConnection {
11590 
11591  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
11592  private static final int SQLITE_BUSY_ERROR = 5;
11593 
11594  SQLiteConnection(Connection conn) {
11595  super(conn);
11596  }
11597 
11598  @Override
11599  void executeCommand(DbCommand command) throws SQLException {
11600  int retryCounter = 0;
11601  while (true) {
11602  try {
11603  command.execute(); // Perform the operation
11604  break;
11605  } catch (SQLException ex) {
11606  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
11607  try {
11608 
11609  // We do not notify of error here, as this is not an
11610  // error condition. It is likely a temporary busy or
11611  // locked issue and we will retry.
11612  retryCounter++;
11613  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11614  } catch (InterruptedException exp) {
11615  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11616  }
11617  } else {
11618  throw ex;
11619  }
11620  }
11621  }
11622  }
11623  }
11624 
11628  private final class PostgreSQLConnection extends CaseDbConnection {
11629 
11630  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
11631  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
11632  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
11633  private static final int MAX_RETRIES = 3;
11634 
11635  PostgreSQLConnection(Connection conn) {
11636  super(conn);
11637  }
11638 
11639  @Override
11640  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11641  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
11642  executeCommand(executeStatementUpdateGenerateKeys);
11643  }
11644 
11645  @Override
11646  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11647  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
11648  executeCommand(prepareStatementGenerateKeys);
11649  return prepareStatementGenerateKeys.getPreparedStatement();
11650  }
11651 
11652  @Override
11653  void executeCommand(DbCommand command) throws SQLException {
11654  SQLException lastException = null;
11655  for (int retries = 0; retries < MAX_RETRIES; retries++) {
11656  try {
11657  command.execute();
11658  lastException = null; // reset since we had a successful execution
11659  break;
11660  } catch (SQLException ex) {
11661  lastException = ex;
11662  String sqlState = ex.getSQLState();
11663  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
11664  try {
11665  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11666  } catch (InterruptedException exp) {
11667  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11668  }
11669  } else {
11670  throw ex;
11671  }
11672  }
11673  }
11674 
11675  // rethrow the exception if we bailed because of too many retries
11676  if (lastException != null) {
11677  throw lastException;
11678  }
11679  }
11680  }
11681 
11690  public static final class CaseDbTransaction {
11691 
11692  private final CaseDbConnection connection;
11693  private boolean hasWriteLock = false;
11694  private SleuthkitCase sleuthkitCase;
11695 
11696  private CaseDbTransaction(SleuthkitCase sleuthkitCase, CaseDbConnection connection) throws TskCoreException {
11697  this.connection = connection;
11698  this.sleuthkitCase = sleuthkitCase;
11699  try {
11700  this.connection.beginTransaction();
11701  } catch (SQLException ex) {
11702  throw new TskCoreException("Failed to create transaction on case database", ex);
11703  }
11704  }
11705 
11713  CaseDbConnection getConnection() {
11714  return this.connection;
11715  }
11716 
11728  if (!hasWriteLock) {
11729  hasWriteLock = true;
11730  sleuthkitCase.acquireSingleUserCaseWriteLock();
11731  }
11732  }
11733 
11740  public void commit() throws TskCoreException {
11741  try {
11742  this.connection.commitTransaction();
11743  } catch (SQLException ex) {
11744  throw new TskCoreException("Failed to commit transaction on case database", ex);
11745  } finally {
11746  close();
11747  }
11748  }
11749 
11756  public void rollback() throws TskCoreException {
11757  try {
11758  this.connection.rollbackTransactionWithThrow();
11759  } catch (SQLException ex) {
11760  throw new TskCoreException("Case database transaction rollback failed", ex);
11761  } finally {
11762  close();
11763  }
11764  }
11765 
11770  void close() {
11771  this.connection.close();
11772  if (hasWriteLock) {
11773  sleuthkitCase.releaseSingleUserCaseWriteLock();
11774  hasWriteLock = false;
11775  }
11776  }
11777  }
11778 
11788  public final class CaseDbQuery implements AutoCloseable {
11789 
11790  private ResultSet resultSet;
11791  private CaseDbConnection connection;
11792 
11793  private CaseDbQuery(String query) throws TskCoreException {
11794  this(query, false);
11795  }
11796 
11797  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
11798  if (!allowWriteQuery) {
11799  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
11800  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
11801  }
11802  }
11803  try {
11804  connection = connections.getConnection();
11805  } catch (TskCoreException ex) {
11806  throw new TskCoreException("Error getting connection for query: ", ex);
11807  }
11808 
11809  try {
11811  resultSet = connection.executeQuery(connection.createStatement(), query);
11812  } catch (SQLException ex) {
11814  throw new TskCoreException("Error executing query: ", ex);
11815  }
11816  }
11817 
11823  public ResultSet getResultSet() {
11824  return resultSet;
11825  }
11826 
11827  @Override
11828  public void close() throws TskCoreException {
11829  try {
11830  if (resultSet != null) {
11831  final Statement statement = resultSet.getStatement();
11832  if (statement != null) {
11833  statement.close();
11834  }
11835  resultSet.close();
11836  }
11837  connection.close();
11838  } catch (SQLException ex) {
11839  throw new TskCoreException("Error closing query: ", ex);
11840  } finally {
11842  }
11843  }
11844  }
11845 
11853  @Deprecated
11854  public void addErrorObserver(ErrorObserver observer) {
11855  sleuthkitCaseErrorObservers.add(observer);
11856  }
11857 
11865  @Deprecated
11866  public void removeErrorObserver(ErrorObserver observer) {
11867  int i = sleuthkitCaseErrorObservers.indexOf(observer);
11868  if (i >= 0) {
11869  sleuthkitCaseErrorObservers.remove(i);
11870  }
11871  }
11872 
11881  @Deprecated
11882  public void submitError(String context, String errorMessage) {
11883  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
11884  if (observer != null) {
11885  try {
11886  observer.receiveError(context, errorMessage);
11887  } catch (Exception ex) {
11888  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
11889 
11890  }
11891  }
11892  }
11893  }
11894 
11900  @Deprecated
11901  public interface ErrorObserver {
11902 
11909  public enum Context {
11910 
11914  IMAGE_READ_ERROR("Image File Read Error"),
11918  DATABASE_READ_ERROR("Database Read Error");
11919 
11920  private final String contextString;
11921 
11922  private Context(String context) {
11923  this.contextString = context;
11924  }
11925 
11926  public String getContextString() {
11927  return contextString;
11928  }
11929  };
11930 
11931  void receiveError(String context, String errorMessage);
11932  }
11933 
11944  @Deprecated
11945  long getDataSourceObjectId(long objectId) {
11946  try {
11947  CaseDbConnection connection = connections.getConnection();
11948  try {
11949  return getDataSourceObjectId(connection, objectId);
11950  } finally {
11951  connection.close();
11952  }
11953  } catch (TskCoreException ex) {
11954  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
11955  return 0;
11956  }
11957  }
11958 
11968  @Deprecated
11969  public long getLastObjectId() throws TskCoreException {
11970  CaseDbConnection connection = connections.getConnection();
11972  ResultSet rs = null;
11973  try {
11974  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
11975  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
11976  rs = connection.executeQuery(statement);
11977  long id = -1;
11978  if (rs.next()) {
11979  id = rs.getLong("max_obj_id");
11980  }
11981  return id;
11982  } catch (SQLException e) {
11983  throw new TskCoreException("Error getting last object id", e);
11984  } finally {
11985  closeResultSet(rs);
11986  connection.close();
11988  }
11989  }
11990 
12004  @Deprecated
12005  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
12006  CaseDbConnection connection = connections.getConnection();
12008  Statement s = null;
12009  ResultSet rs = null;
12010  try {
12011  s = connection.createStatement();
12012  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
12013  List<FsContent> results = new ArrayList<FsContent>();
12014  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
12015  for (AbstractFile f : temp) {
12016  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
12017  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
12018  results.add((FsContent) f);
12019  }
12020  }
12021  return results;
12022  } catch (SQLException e) {
12023  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
12024  } finally {
12025  closeResultSet(rs);
12026  closeStatement(s);
12027  connection.close();
12029  }
12030  }
12031 
12043  @Deprecated
12044  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
12045  CaseDbConnection connection = connections.getConnection();
12047  Statement s = null;
12048  ResultSet rs = null;
12049  try {
12050  s = connection.createStatement();
12051  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
12052  int typeId = -1;
12053  if (rs.next()) {
12054  typeId = rs.getInt("artifact_type_id");
12055  }
12056  return typeId;
12057  } catch (SQLException ex) {
12058  throw new TskCoreException("Error getting artifact type id", ex);
12059  } finally {
12060  closeResultSet(rs);
12061  closeStatement(s);
12062  connection.close();
12064  }
12065  }
12066 
12076  @Deprecated
12077  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
12078  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
12079  }
12080 
12094  @Deprecated
12095  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
12096  try {
12097  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
12098  } catch (TskDataException ex) {
12099  throw new TskCoreException("Failed to add artifact type.", ex);
12100  }
12101  }
12102 
12116  @Deprecated
12117  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
12118  try {
12119  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
12120  } catch (TskDataException ex) {
12121  throw new TskCoreException("Couldn't add new attribute type");
12122  }
12123  }
12124 
12135  @Deprecated
12136  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
12137  CaseDbConnection connection = connections.getConnection();
12139  Statement s = null;
12140  ResultSet rs = null;
12141  try {
12142  s = connection.createStatement();
12143  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
12144  int typeId = -1;
12145  if (rs.next()) {
12146  typeId = rs.getInt("attribute_type_id");
12147  }
12148  return typeId;
12149  } catch (SQLException ex) {
12150  throw new TskCoreException("Error getting attribute type id", ex);
12151  } finally {
12152  closeResultSet(rs);
12153  closeStatement(s);
12154  connection.close();
12156  }
12157  }
12158 
12171  @Deprecated
12172  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
12173  CaseDbConnection connection = connections.getConnection();
12175  Statement s = null;
12176  ResultSet rs = null;
12177  try {
12178  s = connection.createStatement();
12179  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12180  if (rs.next()) {
12181  return rs.getString("type_name");
12182  } else {
12183  throw new TskCoreException("No type with that id");
12184  }
12185  } catch (SQLException ex) {
12186  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12187  } finally {
12188  closeResultSet(rs);
12189  closeStatement(s);
12190  connection.close();
12192  }
12193  }
12194 
12207  @Deprecated
12208  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
12209  CaseDbConnection connection = connections.getConnection();
12211  Statement s = null;
12212  ResultSet rs = null;
12213  try {
12214  s = connection.createStatement();
12215  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12216  if (rs.next()) {
12217  return rs.getString("display_name");
12218  } else {
12219  throw new TskCoreException("No type with that id");
12220  }
12221  } catch (SQLException ex) {
12222  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12223  } finally {
12224  closeResultSet(rs);
12225  closeStatement(s);
12226  connection.close();
12228  }
12229  }
12230 
12240  @Deprecated
12241  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
12242  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
12243  }
12244 
12260  @Deprecated
12261  public ResultSet runQuery(String query) throws SQLException {
12262  CaseDbConnection connection;
12263  try {
12264  connection = connections.getConnection();
12265  } catch (TskCoreException ex) {
12266  throw new SQLException("Error getting connection for ad hoc query", ex);
12267  }
12269  try {
12270  return connection.executeQuery(connection.createStatement(), query);
12271  } finally {
12272  //TODO unlock should be done in closeRunQuery()
12273  //but currently not all code calls closeRunQuery - need to fix this
12274  connection.close();
12276  }
12277  }
12278 
12288  @Deprecated
12289  public void closeRunQuery(ResultSet resultSet) throws SQLException {
12290  final Statement statement = resultSet.getStatement();
12291  resultSet.close();
12292  if (statement != null) {
12293  statement.close();
12294  }
12295  }
12296 
12313  @Deprecated
12314  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
12315  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
12316  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
12317  files.add(carvedFile);
12318  CarvingResult carvingResult;
12319  Content parent = getContentById(containerId);
12320  if (parent instanceof FileSystem
12321  || parent instanceof Volume
12322  || parent instanceof Image) {
12323  carvingResult = new CarvingResult(parent, files);
12324  } else {
12325  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
12326  }
12327  return addCarvedFiles(carvingResult).get(0);
12328  }
12329 
12343  @Deprecated
12344  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
12345  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
12346  for (CarvedFileContainer container : filesToAdd) {
12347  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
12348  carvedFiles.add(carvedFile);
12349  }
12350  CarvingResult carvingResult;
12351  Content parent = getContentById(filesToAdd.get(0).getId());
12352  if (parent instanceof FileSystem
12353  || parent instanceof Volume
12354  || parent instanceof Image) {
12355  carvingResult = new CarvingResult(parent, carvedFiles);
12356  } else {
12357  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
12358  }
12359  return addCarvedFiles(carvingResult);
12360  }
12361 
12391  @Deprecated
12392  public DerivedFile addDerivedFile(String fileName, String localPath,
12393  long size, long ctime, long crtime, long atime, long mtime,
12394  boolean isFile, AbstractFile parentFile,
12395  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
12396  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12397  isFile, parentFile, rederiveDetails, toolName, toolVersion,
12398  otherDetails, TskData.EncodingType.NONE);
12399  }
12400 
12425  @Deprecated
12426  public LocalFile addLocalFile(String fileName, String localPath,
12427  long size, long ctime, long crtime, long atime, long mtime,
12428  boolean isFile,
12429  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
12430  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
12431  TskData.EncodingType.NONE, parent, transaction);
12432  }
12433 
12453  @Deprecated
12454  public LocalFile addLocalFile(String fileName, String localPath,
12455  long size, long ctime, long crtime, long atime, long mtime,
12456  boolean isFile,
12457  AbstractFile parent) throws TskCoreException {
12458  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12459  isFile, TskData.EncodingType.NONE, parent);
12460  }
12461 
12478  @Deprecated
12479  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
12480  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
12481  }
12482 
12490  @Deprecated
12491  public void acquireExclusiveLock() {
12493  }
12494 
12502  @Deprecated
12503  public void releaseExclusiveLock() {
12505  }
12506 
12514  @Deprecated
12515  public void acquireSharedLock() {
12517  }
12518 
12526  @Deprecated
12527  public void releaseSharedLock() {
12529  }
12530 };
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value)
final IngestJobInfo addIngestJob(Content dataSource, String hostName, List< IngestModuleInfo > ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir)
FS
File that can be found in file system tree.
Definition: TskData.java:676
static FileKnown valueOf(byte known)
Definition: TskData.java:801
BlackboardArtifact getArtifactByArtifactId(long id)
AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans)
BlackboardArtifact getArtifactById(long id)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType)
LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value)
void addBlackboardAttributes(Collection< BlackboardAttribute > attributes, int artifactTypeId)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
CommunicationsManager getCommunicationsManager()
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)
boolean isCompatible(CaseDbSchemaVersionNumber dbSchemaVersion)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:206
static TSK_FS_TYPE_ENUM valueOf(int fsTypeValue)
Definition: TskData.java:501
CaseDbSchemaVersionNumber getDBSchemaCreationVersion()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
void addErrorObserver(ErrorObserver observer)
DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
void setFileMIMEType(AbstractFile file, String mimeType)
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:207
void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent, CaseDbTransaction transaction)
final List< LayoutFile > addLayoutFiles(Content parent, List< TskFileRange > fileRanges)
int addArtifactType(String artifactTypeName, String displayName)
synchronized CaseDbAccessManager getCaseDbAccessManager()
BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value)
List< AbstractFile > openFiles(Content dataSource, String filePath)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)
final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version)
long getBlackboardArtifactsCount(String artifactTypeName, long obj_id)
static IngestJobStatusType fromID(int typeId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value)
LAYOUT_FILE
Set of blocks from an image that have been designated as a file.
Definition: TskData.java:685
static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir)
List< VirtualDirectory > getVirtualDirectoryRoots()
LayoutFile addLayoutFile(String fileName, long size, TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag, long ctime, long crtime, long atime, long mtime, List< TskFileRange > fileRanges, Content parent)
long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
ContentTag getContentTagByID(long contentTagID)
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:679
Map< Long, List< String > > getImagePaths()
List< Long > findAllFileIdsWhere(String sqlWhereClause)
BlackboardArtifact getBlackboardArtifact(long artifactID)
List< BlackboardArtifact.Type > getArtifactTypesInUse()
BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
CARVED
Set of blocks for a file found from carving. Could be on top of a TSK_DB_FILES_TYPE_UNALLOC_BLOCKS ra...
Definition: TskData.java:677
BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
long countFilesWhere(String sqlWhereClause)
long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id)
FS
File System - see tsk_fs_info for more details.
Definition: TskData.java:631
Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction)
boolean isFileFromSource(Content dataSource, long fileId)
ArrayList< BlackboardArtifact > getMatchingArtifacts(String whereClause)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypesInUse()
int getAttrTypeID(String attrTypeName)
Report addReport(String localPath, String sourceModuleName, String reportName, Content parent)
List< Content > getChildren()
USED
Metadata structure has been allocated at least once.
Definition: TskData.java:208
void unregisterForEvents(Object listener)
LOCAL_DIR
Local directory that was added (not from a disk image)
Definition: TskData.java:684
final List< LayoutFile > addCarvedFiles(CarvingResult carvingResult)
VOL
Volume - see tsk_vs_parts for more details.
Definition: TskData.java:630
void closeRunQuery(ResultSet resultSet)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
int addAttrType(String attrTypeString, String displayName)
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag)
long getContentTagsCountByTagName(TagName tagName, long dsObjId)
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static String escapeSingleQuotes(String text)
String getAttrTypeDisplayName(int attrTypeID)
List< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
List< AbstractFile > findFiles(Content dataSource, String fileName)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:70
REPORT
Artifact - see blackboard_artifacts for more details.
Definition: TskData.java:634
List< AbstractFile > findFilesByMd5(String md5Hash)
BlackboardArtifact.Type getArtifactType(String artTypeName)
BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:678
List< LayoutFile > addCarvedFiles(List< CarvedFileContainer > filesToAdd)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName)
static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath)
Report addReport(String localPath, String sourceModuleName, String reportName)
List< BlackboardArtifactTag > getAllBlackboardArtifactTags()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName, long obj_id)
Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List< String > imagePaths, String timezone, String md5, String sha1, String sha256, String deviceId, CaseDbTransaction transaction)
void removeErrorObserver(ErrorObserver observer)
List< AbstractFile > findFiles(Content dataSource, String fileName, String dirSubString)
FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount, long rootInum, long firstInum, long lastInum, String displayName, CaseDbTransaction transaction)
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:680
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
ArrayList< BlackboardAttribute > getMatchingAttributes(String whereClause)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
long getBlackboardArtifactsTypeCount(int artifactTypeID)
List< ContentTag > getContentTagsByTagName(TagName tagName, long dsObjId)
static ObjectType valueOf(short objectType)
Definition: TskData.java:659
long getContentTagsCountByTagName(TagName tagName)
FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, String fileName, long metaAddr, int metaSeq, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parent)
void updateImagePath(String newPath, long objectId)
VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset, long blockSize, CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:782
List< TagName > getTagNamesInUse(long dsObjId)
List< AbstractFile > findAllFilesWhere(String sqlWhereClause)
boolean setKnown(AbstractFile file, FileKnown fileKnown)
static void tryConnect(CaseDbConnectionInfo info)
static SleuthkitCase openCase(String dbPath)
CaseDbQuery executeInsertOrUpdate(String query)
static String createNonUniquePath(String uniquePath)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId)
Volume addVolume(long parentObjId, long addr, long start, long length, String desc, long flags, CaseDbTransaction transaction)
long getBlackboardArtifactsCount(int artifactTypeID, long obj_id)
void submitError(String context, String errorMessage)
final List< IngestJobInfo > getIngestJobs()
VIRTUAL_DIR
Virtual directory (not on fs) with no meta-data entry that can be used to group files of types other ...
Definition: TskData.java:682
static SleuthkitCase newCase(String dbPath)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
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:632
ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
DataSource getDataSource(long objectId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith)
Iterable< BlackboardArtifact.Type > getArtifactTypes()
List< BlackboardAttribute.Type > getAttributeTypes()
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction)
AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath)
List< FsContent > findFilesWhere(String sqlWhereClause)
List< TskFileRange > getFileRanges(long id)
BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName)
CaseDbQuery executeQuery(String query)
void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus)
void setImagePaths(long obj_id, List< String > paths)
VS
Volume System - see tsk_vs_info for more details.
Definition: TskData.java:629
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:628
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:157
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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