Sleuth Kit Java Bindings (JNI)  4.8.0
Java bindings for using The Sleuth Kit
SleuthkitCase.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-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 
2949  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
2950  CaseDbConnection connection = connections.getConnection();
2952  ResultSet rs = null;
2953  try {
2954  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
2955  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
2956  statement.clearParameters();
2957  statement.setInt(2, artifactTypeID);
2958  statement.setLong(1, dataSourceID);
2959  rs = connection.executeQuery(statement);
2960  long count = 0;
2961  if (rs.next()) {
2962  count = rs.getLong("count");
2963  }
2964  return count;
2965  } catch (SQLException ex) {
2966  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
2967  } finally {
2968  closeResultSet(rs);
2969  connection.close();
2971  }
2972  }
2973 
2988  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
2989  CaseDbConnection connection = connections.getConnection();
2991  Statement s = null;
2992  ResultSet rs = null;
2993  try {
2994  s = connection.createStatement();
2995  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
2996  + "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, "
2997  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
2998  + " arts.review_status_id AS review_status_id " //NON-NLS
2999  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3000  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3001  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3002  + " AND attrs.value_text = '" + value + "'"
3003  + " AND types.artifact_type_id=arts.artifact_type_id"
3004  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
3005  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3006  while (rs.next()) {
3007  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3008  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3009  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3010  }
3011  return artifacts;
3012  } catch (SQLException ex) {
3013  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3014  } finally {
3015  closeResultSet(rs);
3016  closeStatement(s);
3017  connection.close();
3019  }
3020  }
3021 
3039  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3040  String valSubStr = "%" + subString; //NON-NLS
3041  if (startsWith == false) {
3042  valSubStr += "%"; //NON-NLS
3043  }
3044  CaseDbConnection connection = connections.getConnection();
3046  Statement s = null;
3047  ResultSet rs = null;
3048  try {
3049  s = connection.createStatement();
3050  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3051  + " 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
3052  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3053  + " arts.review_status_id AS review_status_id " //NON-NLS
3054  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3055  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3056  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3057  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3058  + " AND types.artifact_type_id=arts.artifact_type_id "
3059  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3060  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3061  while (rs.next()) {
3062  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3063  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3064  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3065  }
3066  return artifacts;
3067  } catch (SQLException ex) {
3068  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3069  } finally {
3070  closeResultSet(rs);
3071  closeStatement(s);
3072  connection.close();
3074  }
3075  }
3076 
3091  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3092  CaseDbConnection connection = connections.getConnection();
3094  Statement s = null;
3095  ResultSet rs = null;
3096  try {
3097  s = connection.createStatement();
3098  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3099  + " 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, "
3100  + " types.type_name AS type_name, types.display_name AS display_name, "
3101  + " arts.review_status_id AS review_status_id "//NON-NLS
3102  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3103  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3104  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3105  + " AND attrs.value_int32 = " + value //NON-NLS
3106  + " AND types.artifact_type_id=arts.artifact_type_id "
3107  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3108  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3109  while (rs.next()) {
3110  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3111  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3112  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3113  }
3114  return artifacts;
3115  } catch (SQLException ex) {
3116  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3117  } finally {
3118  closeResultSet(rs);
3119  closeStatement(s);
3120  connection.close();
3122  }
3123  }
3124 
3139  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3140  CaseDbConnection connection = connections.getConnection();
3142  Statement s = null;
3143  ResultSet rs = null;
3144  try {
3145  s = connection.createStatement();
3146  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3147  + " 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, "
3148  + " types.type_name AS type_name, types.display_name AS display_name, "
3149  + " arts.review_status_id AS review_status_id "//NON-NLS
3150  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3151  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3152  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3153  + " AND attrs.value_int64 = " + value //NON-NLS
3154  + " AND types.artifact_type_id=arts.artifact_type_id "
3155  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3156  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3157  while (rs.next()) {
3158  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3159  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3160  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3161  }
3162  return artifacts;
3163  } catch (SQLException ex) {
3164  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3165  } finally {
3166  closeResultSet(rs);
3167  closeStatement(s);
3168  connection.close();
3170  }
3171  }
3172 
3187  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3188  CaseDbConnection connection = connections.getConnection();
3190  Statement s = null;
3191  ResultSet rs = null;
3192  try {
3193  s = connection.createStatement();
3194  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3195  + " 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, "
3196  + " types.type_name AS type_name, types.display_name AS display_name, "
3197  + " arts.review_status_id AS review_status_id "//NON-NLS
3198  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3199  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3200  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3201  + " AND attrs.value_double = " + value //NON-NLS
3202  + " AND types.artifact_type_id=arts.artifact_type_id "
3203  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3204  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3205  while (rs.next()) {
3206  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3207  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3208  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3209  }
3210  return artifacts;
3211  } catch (SQLException ex) {
3212  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3213  } finally {
3214  closeResultSet(rs);
3215  closeStatement(s);
3216  connection.close();
3218  }
3219  }
3220 
3235  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3236  CaseDbConnection connection = connections.getConnection();
3238  Statement s = null;
3239  ResultSet rs = null;
3240  try {
3241  s = connection.createStatement();
3242  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3243  + " 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, "
3244  + " types.type_name AS type_name, types.display_name AS display_name, "
3245  + " arts.review_status_id AS review_status_id "//NON-NLS
3246  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3247  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3248  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3249  + " AND attrs.value_byte = " + value //NON-NLS
3250  + " AND types.artifact_type_id=arts.artifact_type_id "
3251  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3252  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3253  while (rs.next()) {
3254  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3255  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3256  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3257  }
3258  return artifacts;
3259  } catch (SQLException ex) {
3260  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3261  } finally {
3262  closeResultSet(rs);
3263  closeStatement(s);
3264  connection.close();
3266  }
3267  }
3268 
3276  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3277  CaseDbConnection connection = connections.getConnection();
3279  Statement s = null;
3280  ResultSet rs = null;
3281  try {
3282  s = connection.createStatement();
3283  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types"); //NON-NLS
3284  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
3285  while (rs.next()) {
3286  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3287  rs.getString("type_name"), rs.getString("display_name")));
3288  }
3289  return artifactTypes;
3290  } catch (SQLException ex) {
3291  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
3292  } finally {
3293  closeResultSet(rs);
3294  closeStatement(s);
3295  connection.close();
3297  }
3298  }
3299 
3308  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
3309  String typeIdList = "";
3310  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
3311  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
3312  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
3313  typeIdList += ", ";
3314  }
3315  }
3316  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
3317  + "WHERE artifact_type_id IN (" + typeIdList + ")";
3318  CaseDbConnection connection = connections.getConnection();
3320  Statement s = null;
3321  ResultSet rs = null;
3322  try {
3323  s = connection.createStatement();
3324  rs = connection.executeQuery(s, query);
3325  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
3326  while (rs.next()) {
3327  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
3328  }
3329  return usedArts;
3330  } catch (SQLException ex) {
3331  throw new TskCoreException("Error getting artifact types in use", ex);
3332  } finally {
3333  closeResultSet(rs);
3334  closeStatement(s);
3335  connection.close();
3337  }
3338  }
3339 
3350  public List<BlackboardArtifact.Type> getArtifactTypesInUse() 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,
3358  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
3359  + "types.type_name AS type_name, types.display_name AS display_name "
3360  + "FROM blackboard_artifact_types AS types "
3361  + "INNER JOIN blackboard_artifacts AS arts "
3362  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
3363  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
3364  while (rs.next()) {
3365  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3366  rs.getString("type_name"), rs.getString("display_name")));
3367  }
3368  return uniqueArtifactTypes;
3369  } catch (SQLException ex) {
3370  throw new TskCoreException("Error getting attribute types", ex);
3371  } finally {
3372  closeResultSet(rs);
3373  closeStatement(s);
3374  connection.close();
3376  }
3377  }
3378 
3386  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
3387  CaseDbConnection connection = connections.getConnection();
3389  Statement s = null;
3390  ResultSet rs = null;
3391  try {
3392  s = connection.createStatement();
3393  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
3394  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
3395  while (rs.next()) {
3396  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3397  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
3398  }
3399  return attribute_types;
3400  } catch (SQLException ex) {
3401  throw new TskCoreException("Error getting attribute types", ex);
3402  } finally {
3403  closeResultSet(rs);
3404  closeStatement(s);
3405  connection.close();
3407  }
3408  }
3409 
3421  public int getBlackboardAttributeTypesCount() throws TskCoreException {
3422  CaseDbConnection connection = connections.getConnection();
3424  Statement s = null;
3425  ResultSet rs = null;
3426  try {
3427  s = connection.createStatement();
3428  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
3429  int count = 0;
3430  if (rs.next()) {
3431  count = rs.getInt("count");
3432  }
3433  return count;
3434  } catch (SQLException ex) {
3435  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3436  } finally {
3437  closeResultSet(rs);
3438  closeStatement(s);
3439  connection.close();
3441  }
3442  }
3443 
3456  ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
3457  CaseDbConnection connection = connections.getConnection();
3459  ResultSet rs = null;
3460  try {
3461  Statement statement = connection.createStatement();
3462  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
3463  + "blackboard_artifacts.obj_id AS obj_id, "
3464  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
3465  + "blackboard_artifacts.data_source_obj_id AS data_source_obj_id, "
3466  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
3467  + "blackboard_artifact_types.type_name AS type_name, "
3468  + "blackboard_artifact_types.display_name AS display_name, "
3469  + "blackboard_artifacts.review_status_id AS review_status_id "
3470  + "FROM blackboard_artifacts, blackboard_artifact_types "
3471  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
3472  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
3473  + " AND " + whereClause;
3474  rs = connection.executeQuery(statement, query);
3475  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3476  while (rs.next()) {
3477  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3478  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3479  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3480  }
3481  return artifacts;
3482  } catch (SQLException ex) {
3483  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
3484  } finally {
3485  closeResultSet(rs);
3486  connection.close();
3488  }
3489  }
3490 
3503  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
3504  CaseDbConnection connection = connections.getConnection();
3506  ResultSet rs = null;
3507  try {
3508  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
3509  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
3510  statement.clearParameters();
3511  statement.setLong(1, obj_id);
3512  statement.setInt(2, artifactTypeID);
3513  rs = connection.executeQuery(statement);
3514  long count = 0;
3515  if (rs.next()) {
3516  count = rs.getLong("count");
3517  }
3518  return count;
3519  } catch (SQLException ex) {
3520  throw new TskCoreException("Error getting blackboard artifact count", ex);
3521  } finally {
3522  closeResultSet(rs);
3523  connection.close();
3525  }
3526  }
3527 
3540  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
3541  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3542  }
3543 
3556  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
3557  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
3558  }
3559 
3572  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3573  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
3574  }
3575 
3588  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
3589  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
3590  if (artifactTypeID == -1) {
3591  return 0;
3592  }
3593  return getArtifactsCountHelper(artifactTypeID, obj_id);
3594  }
3595 
3608  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
3609  return getArtifactsCountHelper(artifactTypeID, obj_id);
3610  }
3611 
3624  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3625  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
3626  }
3627 
3639  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
3640  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3641  }
3642 
3654  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
3655  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
3656  }
3657 
3671  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3672  CaseDbConnection connection = connections.getConnection();
3674  Statement s = null;
3675  ResultSet rs = null;
3676  try {
3677  s = connection.createStatement();
3678  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3679  + "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, "
3680  + "types.type_name AS type_name, types.display_name AS display_name,"
3681  + "arts.review_status_id AS review_status_id "//NON-NLS
3682  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3683  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3684  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3685  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
3686  + " AND attrs.value_text = '" + value + "'" //NON-NLS
3687  + " AND types.artifact_type_id=arts.artifact_type_id"
3688  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3689  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3690  while (rs.next()) {
3691  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3692  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3693  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3694  }
3695  return artifacts;
3696  } catch (SQLException ex) {
3697  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
3698  } finally {
3699  closeResultSet(rs);
3700  closeStatement(s);
3701  connection.close();
3703  }
3704  }
3705 
3716  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
3717  CaseDbConnection connection = connections.getConnection();
3719  ResultSet rs = null;
3720  Statement s;
3721  try {
3722  s = connection.createStatement();
3723  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
3724  + "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, "
3725  + "types.type_name AS type_name, types.display_name AS display_name,"
3726  + "arts.review_status_id AS review_status_id "//NON-NLS
3727  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
3728  + "WHERE arts.artifact_id = " + artifactID
3729  + " AND arts.artifact_type_id = types.artifact_type_id");
3730  if (rs.next()) {
3731  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3732  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3733  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
3734  } else {
3735  /*
3736  * I think this should actually return null (or Optional) when
3737  * there is no artifact with the given id, but it looks like
3738  * existing code is not expecting that. -jm
3739  */
3740  throw new TskCoreException("No blackboard artifact with id " + artifactID);
3741  }
3742  } catch (SQLException ex) {
3743  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
3744  } finally {
3745  closeResultSet(rs);
3746  connection.close();
3748  }
3749  }
3750 
3759  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
3760  CaseDbConnection connection = connections.getConnection();
3762  try {
3763  addBlackBoardAttribute(attr, artifactTypeId, connection);
3764  } catch (SQLException ex) {
3765  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
3766  } finally {
3767  connection.close();
3769  }
3770  }
3771 
3781  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
3782  CaseDbConnection connection = connections.getConnection();
3784  try {
3785  connection.beginTransaction();
3786  for (final BlackboardAttribute attr : attributes) {
3787  addBlackBoardAttribute(attr, artifactTypeId, connection);
3788  }
3789  connection.commitTransaction();
3790  } catch (SQLException ex) {
3791  connection.rollbackTransaction();
3792  throw new TskCoreException("Error adding blackboard attributes", ex);
3793  } finally {
3794  connection.close();
3796  }
3797  }
3798 
3799  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
3800  PreparedStatement statement;
3801  switch (attr.getAttributeType().getValueType()) {
3802  case STRING:
3803  case JSON:
3804  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
3805  statement.clearParameters();
3806  statement.setString(7, attr.getValueString());
3807  break;
3808  case BYTE:
3809  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
3810  statement.clearParameters();
3811  statement.setBytes(7, attr.getValueBytes());
3812  break;
3813  case INTEGER:
3814  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
3815  statement.clearParameters();
3816  statement.setInt(7, attr.getValueInt());
3817  break;
3818  case LONG:
3819  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3820  statement.clearParameters();
3821  statement.setLong(7, attr.getValueLong());
3822  break;
3823  case DOUBLE:
3824  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
3825  statement.clearParameters();
3826  statement.setDouble(7, attr.getValueDouble());
3827  break;
3828  case DATETIME:
3829  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3830  statement.clearParameters();
3831  statement.setLong(7, attr.getValueLong());
3832  break;
3833  default:
3834  throw new TskCoreException("Unrecognized artifact attribute value type");
3835  }
3836  statement.setLong(1, attr.getArtifactID());
3837  statement.setInt(2, artifactTypeId);
3838  statement.setString(3, attr.getSourcesCSV());
3839  statement.setString(4, "");
3840  statement.setInt(5, attr.getAttributeType().getTypeID());
3841  statement.setLong(6, attr.getAttributeType().getValueType().getType());
3842  connection.executeUpdate(statement);
3843  }
3844 
3855  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
3856  /*
3857  * WARNING: This is a temporary implementation that is not safe and
3858  * denormalizes the case datbase.
3859  *
3860  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
3861  * the sources of artifact attributes.
3862  */
3863  if (null == source || source.isEmpty()) {
3864  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
3865  }
3866  CaseDbConnection connection = connections.getConnection();
3868  Statement queryStmt = null;
3869  Statement updateStmt = null;
3870  ResultSet result = null;
3871  String newSources = "";
3872  try {
3873  connection.beginTransaction();
3874  String valueClause = "";
3875  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
3876  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
3877  switch (valueType) {
3878  case STRING:
3879  case JSON:
3880  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
3881  break;
3882  case INTEGER:
3883  valueClause = " value_int32 = " + attr.getValueInt();
3884  break;
3885  case LONG:
3886  case DATETIME:
3887  valueClause = " value_int64 = " + attr.getValueLong();
3888  break;
3889  case DOUBLE:
3890  valueClause = " value_double = " + attr.getValueDouble();
3891  break;
3892  default:
3893  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
3894  }
3895  String query = "SELECT source FROM blackboard_attributes WHERE"
3896  + " artifact_id = " + attr.getArtifactID()
3897  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
3898  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
3899  + " AND " + valueClause + ";";
3900  queryStmt = connection.createStatement();
3901  updateStmt = connection.createStatement();
3902  result = connection.executeQuery(queryStmt, query);
3903  } else {
3904  /*
3905  * SELECT source FROM blackboard_attributes WHERE artifact_id =
3906  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
3907  * = ?
3908  */
3909  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
3910  statement.clearParameters();
3911  statement.setLong(1, attr.getArtifactID());
3912  statement.setLong(2, attr.getAttributeType().getTypeID());
3913  statement.setBytes(3, attr.getValueBytes());
3914  result = connection.executeQuery(statement);
3915  }
3916  while (result.next()) {
3917  String oldSources = result.getString("source");
3918  if (null != oldSources && !oldSources.isEmpty()) {
3919  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
3920  if (!uniqueSources.contains(source)) {
3921  newSources = oldSources + "," + source;
3922  } else {
3923  newSources = oldSources;
3924  }
3925  } else {
3926  newSources = source;
3927  }
3928  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
3929  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
3930  + " artifact_id = " + attr.getArtifactID()
3931  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
3932  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
3933  + " AND " + valueClause + ";";
3934  connection.executeUpdate(updateStmt, update);
3935  } else {
3936  /*
3937  * UPDATE blackboard_attributes SET source = ? WHERE
3938  * artifact_id = ? AND attribute_type_id = ? AND value_type
3939  * = 4 AND value_byte = ?
3940  */
3941  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
3942  statement.clearParameters();
3943  statement.setString(1, newSources);
3944  statement.setLong(2, attr.getArtifactID());
3945  statement.setLong(3, attr.getAttributeType().getTypeID());
3946  statement.setBytes(4, attr.getValueBytes());
3947  connection.executeUpdate(statement);
3948  }
3949  }
3950  connection.commitTransaction();
3951  return newSources;
3952  } catch (SQLException ex) {
3953  connection.rollbackTransaction();
3954  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
3955  } finally {
3956  closeResultSet(result);
3957  closeStatement(updateStmt);
3958  closeStatement(queryStmt);
3959  connection.close();
3961  }
3962  }
3963 
3978  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
3979  CaseDbConnection connection = connections.getConnection();
3981  Statement s = null;
3982  ResultSet rs = null;
3983  try {
3984  connection.beginTransaction();
3985  s = connection.createStatement();
3986  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
3987  if (!rs.next()) {
3988  rs.close();
3989  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
3990  int maxID = 0;
3991  if (rs.next()) {
3992  maxID = rs.getInt("highest_id");
3993  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
3994  maxID = MIN_USER_DEFINED_TYPE_ID;
3995  } else {
3996  maxID++;
3997  }
3998  }
3999  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
4000  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
4001  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4002  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4003  connection.commitTransaction();
4004  return type;
4005  } else {
4006  throw new TskDataException("The attribute type that was added was already within the system.");
4007  }
4008 
4009  } catch (SQLException ex) {
4010  connection.rollbackTransaction();
4011  throw new TskCoreException("Error adding attribute type", ex);
4012  } finally {
4013  closeResultSet(rs);
4014  closeStatement(s);
4015  connection.close();
4017  }
4018  }
4019 
4030  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4031  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
4032  return this.typeNameToAttributeTypeMap.get(attrTypeName);
4033  }
4034  CaseDbConnection connection = connections.getConnection();
4036  Statement s = null;
4037  ResultSet rs = null;
4038  try {
4039  s = connection.createStatement();
4040  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
4041  BlackboardAttribute.Type type = null;
4042  if (rs.next()) {
4043  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4044  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4045  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4046  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
4047  }
4048  return type;
4049  } catch (SQLException ex) {
4050  throw new TskCoreException("Error getting attribute type id", ex);
4051  } finally {
4052  closeResultSet(rs);
4053  closeStatement(s);
4054  connection.close();
4056  }
4057  }
4058 
4069  private BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
4070  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
4071  return this.typeIdToAttributeTypeMap.get(typeID);
4072  }
4073  CaseDbConnection connection = connections.getConnection();
4075  Statement s = null;
4076  ResultSet rs = null;
4077  try {
4078  s = connection.createStatement();
4079  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
4080  BlackboardAttribute.Type type = null;
4081  if (rs.next()) {
4082  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4083  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4084  this.typeIdToAttributeTypeMap.put(typeID, type);
4085  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4086  }
4087  return type;
4088  } catch (SQLException ex) {
4089  throw new TskCoreException("Error getting attribute type id", ex);
4090  } finally {
4091  closeResultSet(rs);
4092  closeStatement(s);
4093  connection.close();
4095  }
4096  }
4097 
4108  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4109  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
4110  return this.typeNameToArtifactTypeMap.get(artTypeName);
4111  }
4112  CaseDbConnection connection = connections.getConnection();
4114  Statement s = null;
4115  ResultSet rs = null;
4116  try {
4117  s = connection.createStatement();
4118  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
4119  BlackboardArtifact.Type type = null;
4120  if (rs.next()) {
4121  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4122  rs.getString("type_name"), rs.getString("display_name"));
4123  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4124  this.typeNameToArtifactTypeMap.put(artTypeName, type);
4125  }
4126  return type;
4127  } catch (SQLException ex) {
4128  throw new TskCoreException("Error getting artifact type from the database", ex);
4129  } finally {
4130  closeResultSet(rs);
4131  closeStatement(s);
4132  connection.close();
4134  }
4135  }
4136 
4147  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
4148  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
4149  return typeIdToArtifactTypeMap.get(artTypeId);
4150  }
4151  CaseDbConnection connection = connections.getConnection();
4153  Statement s = null;
4154  ResultSet rs = null;
4155  try {
4156  s = connection.createStatement();
4157  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
4158  BlackboardArtifact.Type type = null;
4159  if (rs.next()) {
4160  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4161  rs.getString("type_name"), rs.getString("display_name"));
4162  this.typeIdToArtifactTypeMap.put(artTypeId, type);
4163  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4164  }
4165  return type;
4166  } catch (SQLException ex) {
4167  throw new TskCoreException("Error getting artifact type from the database", ex);
4168  } finally {
4169  closeResultSet(rs);
4170  closeStatement(s);
4171  connection.close();
4173  }
4174  }
4175 
4188  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4189  CaseDbConnection connection = connections.getConnection();
4191  Statement s = null;
4192  ResultSet rs = null;
4193  try {
4194  connection.beginTransaction();
4195  s = connection.createStatement();
4196  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
4197  if (!rs.next()) {
4198  rs.close();
4199  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
4200  int maxID = 0;
4201  if (rs.next()) {
4202  maxID = rs.getInt("highest_id");
4203  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4204  maxID = MIN_USER_DEFINED_TYPE_ID;
4205  } else {
4206  maxID++;
4207  }
4208  }
4209  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
4210  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName);
4211  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4212  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4213  connection.commitTransaction();
4214  return type;
4215  } else {
4216  throw new TskDataException("The attribute type that was added was already within the system.");
4217  }
4218  } catch (SQLException ex) {
4219  connection.rollbackTransaction();
4220  throw new TskCoreException("Error adding artifact type", ex);
4221  } finally {
4222  closeResultSet(rs);
4223  closeStatement(s);
4224  connection.close();
4226  }
4227  }
4228 
4229  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4230  CaseDbConnection connection = connections.getConnection();
4232  ResultSet rs = null;
4233  try {
4234  Statement statement = connection.createStatement();
4235  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
4236  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
4237  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4238  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4239  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
4240  + "types.type_name AS type_name, types.display_name AS display_name "
4241  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
4242  + " AND attrs.attribute_type_id = types.attribute_type_id");
4243  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
4244  while (rs.next()) {
4245  int attributeTypeId = rs.getInt("attribute_type_id");
4246  String attributeTypeName = rs.getString("type_name");
4247  BlackboardAttribute.Type attributeType;
4248  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
4249  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
4250  } else {
4251  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
4252  rs.getString("display_name"),
4254  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
4255  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
4256  }
4257 
4258  final BlackboardAttribute attr = new BlackboardAttribute(
4259  rs.getLong("artifact_id"),
4260  attributeType,
4261  rs.getString("source"),
4262  rs.getString("context"),
4263  rs.getInt("value_int32"),
4264  rs.getLong("value_int64"),
4265  rs.getDouble("value_double"),
4266  rs.getString("value_text"),
4267  rs.getBytes("value_byte"), this
4268  );
4269  attributes.add(attr);
4270  }
4271  return attributes;
4272  } catch (SQLException ex) {
4273  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
4274  } finally {
4275  closeResultSet(rs);
4276  connection.close();
4278  }
4279  }
4280 
4293  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
4294  CaseDbConnection connection = connections.getConnection();
4296  Statement s = null;
4297  ResultSet rs = null;
4298  try {
4299  s = connection.createStatement();
4300  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
4301  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
4302  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
4303  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
4304  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
4305  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
4306  + "FROM blackboard_attributes " + whereClause); //NON-NLS
4307  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
4308  while (rs.next()) {
4310  // attribute type is cached, so this does not necessarily call to the db
4311  type = this.getAttributeType(rs.getInt("attribute_type_id"));
4313  rs.getLong("artifact_id"),
4314  type,
4315  rs.getString("source"),
4316  rs.getString("context"),
4317  rs.getInt("value_int32"),
4318  rs.getLong("value_int64"),
4319  rs.getDouble("value_double"),
4320  rs.getString("value_text"),
4321  rs.getBytes("value_byte"), this
4322  );
4323  matches.add(attr);
4324  }
4325  return matches;
4326  } catch (SQLException ex) {
4327  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4328  } finally {
4329  closeResultSet(rs);
4330  closeStatement(s);
4331  connection.close();
4333  }
4334  }
4335 
4347  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
4348  CaseDbConnection connection = connections.getConnection();
4350  ResultSet rs = null;
4351  Statement s = null;
4352  try {
4353  s = connection.createStatement();
4354  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
4355  + "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, "
4356  + "blackboard_artifacts.review_status_id AS review_status_id "
4357  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
4358  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
4359  while (rs.next()) {
4360  BlackboardArtifact.Type type;
4361  // artifact type is cached, so this does not necessarily call to the db
4362  type = this.getArtifactType(rs.getInt("artifact_type_id"));
4363  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
4364  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
4365  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
4366  matches.add(artifact);
4367  }
4368  return matches;
4369  } catch (SQLException ex) {
4370  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4371  } finally {
4372  closeResultSet(rs);
4373  closeStatement(s);
4374  connection.close();
4376  }
4377  }
4378 
4392  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
4393  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
4394  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName());
4395  }
4396 
4408  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4409  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
4410  }
4411 
4412  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
4413  CaseDbConnection connection = connections.getConnection();
4415  ResultSet resultSet = null;
4416  try {
4417  long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
4418  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
4419 
4420  PreparedStatement statement = null;
4421  if (dbType == DbType.POSTGRESQL) {
4422  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4423  statement.clearParameters();
4424  statement.setLong(1, obj_id);
4425  statement.setLong(2, artifact_obj_id);
4426  statement.setLong(3, data_source_obj_id);
4427  statement.setInt(4, artifact_type_id);
4428 
4429  } else {
4430  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4431  statement.clearParameters();
4432  this.nextArtifactId++;
4433  statement.setLong(1, this.nextArtifactId);
4434  statement.setLong(2, obj_id);
4435  statement.setLong(3, artifact_obj_id);
4436  statement.setLong(4, data_source_obj_id);
4437  statement.setInt(5, artifact_type_id);
4438 
4439  }
4440  connection.executeUpdate(statement);
4441  resultSet = statement.getGeneratedKeys();
4442  resultSet.next();
4443  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
4444  obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
4445  } catch (SQLException ex) {
4446  throw new TskCoreException("Error creating a blackboard artifact", ex);
4447  } finally {
4448  closeResultSet(resultSet);
4449  connection.close();
4451  }
4452  }
4453 
4466  boolean getContentHasChildren(Content content) throws TskCoreException {
4467  CaseDbConnection connection = connections.getConnection();
4469  ResultSet rs = null;
4470  try {
4471  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4472  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4473  statement.clearParameters();
4474  statement.setLong(1, content.getId());
4475  rs = connection.executeQuery(statement);
4476  boolean hasChildren = false;
4477  if (rs.next()) {
4478  hasChildren = rs.getInt("count") > 0;
4479  }
4480  return hasChildren;
4481  } catch (SQLException e) {
4482  throw new TskCoreException("Error checking for children of parent " + content, e);
4483  } finally {
4484  closeResultSet(rs);
4485  connection.close();
4487  }
4488  }
4489 
4502  int getContentChildrenCount(Content content) throws TskCoreException {
4503 
4504  if (!this.getHasChildren(content)) {
4505  return 0;
4506  }
4507 
4508  CaseDbConnection connection = connections.getConnection();
4510  ResultSet rs = null;
4511  try {
4512  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4513  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4514  statement.clearParameters();
4515  statement.setLong(1, content.getId());
4516  rs = connection.executeQuery(statement);
4517  int countChildren = -1;
4518  if (rs.next()) {
4519  countChildren = rs.getInt("count");
4520  }
4521  return countChildren;
4522  } catch (SQLException e) {
4523  throw new TskCoreException("Error checking for children of parent " + content, e);
4524  } finally {
4525  closeResultSet(rs);
4526  connection.close();
4528  }
4529  }
4530 
4542  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4543  CaseDbConnection connection = connections.getConnection();
4545  ResultSet rs = null;
4546  try {
4547  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
4548  statement.clearParameters();
4549  long parentId = parent.getId();
4550  statement.setLong(1, parentId);
4551  statement.setShort(2, type.getFileType());
4552  rs = connection.executeQuery(statement);
4553  return fileChildren(rs, connection, parentId);
4554  } catch (SQLException ex) {
4555  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4556  } finally {
4557  closeResultSet(rs);
4558  connection.close();
4560  }
4561  }
4562 
4572  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
4573  CaseDbConnection connection = connections.getConnection();
4575  ResultSet rs = null;
4576  try {
4577  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
4578  statement.clearParameters();
4579  long parentId = parent.getId();
4580  statement.setLong(1, parentId);
4581  rs = connection.executeQuery(statement);
4582  return fileChildren(rs, connection, parentId);
4583  } catch (SQLException ex) {
4584  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4585  } finally {
4586  closeResultSet(rs);
4587  connection.close();
4589  }
4590  }
4591 
4603  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4604  CaseDbConnection connection = connections.getConnection();
4606  ResultSet rs = null;
4607  try {
4608  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
4609  statement.clearParameters();
4610  statement.setLong(1, parent.getId());
4611  statement.setShort(2, type.getFileType());
4612  rs = connection.executeQuery(statement);
4613  List<Long> children = new ArrayList<Long>();
4614  while (rs.next()) {
4615  children.add(rs.getLong("obj_id"));
4616  }
4617  return children;
4618  } catch (SQLException ex) {
4619  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4620  } finally {
4621  closeResultSet(rs);
4622  connection.close();
4624  }
4625  }
4626 
4636  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
4637  CaseDbConnection connection = connections.getConnection();
4639  ResultSet rs = null;
4640  try {
4641  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
4642  statement.clearParameters();
4643  statement.setLong(1, parent.getId());
4644  rs = connection.executeQuery(statement);
4645  List<Long> children = new ArrayList<Long>();
4646  while (rs.next()) {
4647  children.add(rs.getLong("obj_id"));
4648  }
4649  return children;
4650  } catch (SQLException ex) {
4651  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4652  } finally {
4653  closeResultSet(rs);
4654  connection.close();
4656  }
4657  }
4658 
4669  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
4670  CaseDbConnection connection = connections.getConnection();
4672  ResultSet rs = null;
4673  try {
4674  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
4675  statement.clearParameters();
4676  statement.setLong(1, parent.getId());
4677  rs = connection.executeQuery(statement);
4678  List<Long> children = new ArrayList<Long>();
4679  while (rs.next()) {
4680  children.add(rs.getLong("obj_id"));
4681  }
4682  return children;
4683  } catch (SQLException ex) {
4684  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
4685  } finally {
4686  closeResultSet(rs);
4687  connection.close();
4689  }
4690  }
4691 
4701  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
4702 
4703  long parentId = parent.getId();
4704  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
4705 
4706  List<Content> lc = new ArrayList<Content>();
4707  lc.addAll(artsArray);
4708  return lc;
4709  }
4710 
4719  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
4720  CaseDbConnection connection = connections.getConnection();
4722  Statement s = null;
4723  ResultSet rs = null;
4724  try {
4725  s = connection.createStatement();
4726  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
4727  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
4728  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
4729  + "WHERE tsk_objects.par_obj_id = " + c.getId()
4730  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
4731  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
4732  while (rs.next()) {
4733  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
4734  }
4735  return infos;
4736  } catch (SQLException ex) {
4737  throw new TskCoreException("Error getting Children Info for Content", ex);
4738  } finally {
4739  closeResultSet(rs);
4740  closeStatement(s);
4741  connection.close();
4743  }
4744  }
4745 
4756  ObjectInfo getParentInfo(Content c) throws TskCoreException {
4757  return getParentInfo(c.getId());
4758  }
4759 
4770  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
4771  CaseDbConnection connection = connections.getConnection();
4773  Statement s = null;
4774  ResultSet rs = null;
4775  try {
4776  s = connection.createStatement();
4777  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
4778  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
4779  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
4780  + "WHERE child.obj_id = " + contentId); //NON-NLS
4781  if (rs.next()) {
4782  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
4783  } else {
4784  return null;
4785  }
4786  } catch (SQLException ex) {
4787  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
4788  } finally {
4789  closeResultSet(rs);
4790  closeStatement(s);
4791  connection.close();
4793  }
4794  }
4795 
4806  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
4807  if (fsc.isRoot()) {
4808  // Given FsContent is a root object and can't have parent directory
4809  return null;
4810  } else {
4811  ObjectInfo parentInfo = getParentInfo(fsc);
4812  if (parentInfo == null) {
4813  return null;
4814  }
4815  Directory parent = null;
4816  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
4817  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
4818  } else {
4819  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
4820  }
4821  return parent;
4822  }
4823  }
4824 
4836  public Content getContentById(long id) throws TskCoreException {
4837  // First check to see if this exists in our frequently used content cache.
4838  Content content = frequentlyUsedContentMap.get(id);
4839  if (null != content) {
4840  return content;
4841  }
4842 
4843  CaseDbConnection connection = connections.getConnection();
4845  Statement s = null;
4846  ResultSet rs = null;
4847  long parentId;
4848  TskData.ObjectType type;
4849 
4850  try {
4851  s = connection.createStatement();
4852  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
4853  if (!rs.next()) {
4854  return null;
4855  }
4856  parentId = rs.getLong("par_obj_id"); //NON-NLS
4857  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
4858  } catch (SQLException ex) {
4859  throw new TskCoreException("Error getting Content by ID.", ex);
4860  } finally {
4861  closeResultSet(rs);
4862  closeStatement(s);
4863  connection.close();
4865  }
4866 
4867  // Construct the object
4868  switch (type) {
4869  case IMG:
4870  content = getImageById(id);
4871  frequentlyUsedContentMap.put(id, content);
4872  break;
4873  case VS:
4874  content = getVolumeSystemById(id, parentId);
4875  break;
4876  case VOL:
4877  content = getVolumeById(id, parentId);
4878  frequentlyUsedContentMap.put(id, content);
4879  break;
4880  case POOL:
4881  content = getPoolById(id, parentId);
4882  break;
4883  case FS:
4884  content = getFileSystemById(id, parentId);
4885  frequentlyUsedContentMap.put(id, content);
4886  break;
4887  case ABSTRACTFILE:
4888  content = getAbstractFileById(id);
4889 
4890  // Add virtual and root directories to frequently used map.
4891  // Calling isRoot() on local directories goes up the entire directory structure
4892  // and they can only be the root of portable cases, so skip trying to add
4893  // them to the cache.
4894  if (((AbstractFile) content).isVirtual()
4895  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
4896  frequentlyUsedContentMap.put(id, content);
4897  }
4898  break;
4899  case ARTIFACT:
4900  content = getArtifactById(id);
4901  break;
4902  case REPORT:
4903  content = getReportById(id);
4904  break;
4905  default:
4906  throw new TskCoreException("Could not obtain Content object with ID: " + id);
4907  }
4908 
4909  return content;
4910  }
4911 
4919  String getFilePath(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  String filePath = null;
4929  ResultSet rs = null;
4930  try {
4931  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
4932  statement.clearParameters();
4933  statement.setLong(1, id);
4934  rs = connection.executeQuery(statement);
4935  if (rs.next()) {
4936  filePath = rs.getString("path");
4937  }
4938  } catch (SQLException ex) {
4939  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
4940  } finally {
4941  closeResultSet(rs);
4942  connection.close();
4944  }
4945  return filePath;
4946  }
4947 
4955  TskData.EncodingType getEncodingType(long id) {
4956  CaseDbConnection connection;
4957  try {
4958  connection = connections.getConnection();
4959  } catch (TskCoreException ex) {
4960  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
4961  return null;
4962  }
4963  TskData.EncodingType type = TskData.EncodingType.NONE;
4965  ResultSet rs = null;
4966  try {
4967  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
4968  statement.clearParameters();
4969  statement.setLong(1, id);
4970  rs = connection.executeQuery(statement);
4971  if (rs.next()) {
4972  type = TskData.EncodingType.valueOf(rs.getInt(1));
4973  }
4974  } catch (SQLException ex) {
4975  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
4976  } finally {
4977  closeResultSet(rs);
4978  connection.close();
4980  }
4981  return type;
4982  }
4983 
4992  String getFileParentPath(long objectId, CaseDbConnection connection) {
4993  String parentPath = null;
4995  ResultSet rs = null;
4996  try {
4997  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
4998  statement.clearParameters();
4999  statement.setLong(1, objectId);
5000  rs = connection.executeQuery(statement);
5001  if (rs.next()) {
5002  parentPath = rs.getString("parent_path");
5003  }
5004  } catch (SQLException ex) {
5005  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5006  } finally {
5007  closeResultSet(rs);
5009  }
5010  return parentPath;
5011  }
5012 
5021  String getFileName(long objectId, CaseDbConnection connection) {
5022  String fileName = null;
5024  ResultSet rs = null;
5025  try {
5026  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5027  statement.clearParameters();
5028  statement.setLong(1, objectId);
5029  rs = connection.executeQuery(statement);
5030  if (rs.next()) {
5031  fileName = rs.getString("name");
5032  }
5033  } catch (SQLException ex) {
5034  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5035  } finally {
5036  closeResultSet(rs);
5038  }
5039  return fileName;
5040  }
5041 
5052  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5053  CaseDbConnection connection = connections.getConnection();
5054  DerivedFile.DerivedMethod method = null;
5056  ResultSet rs1 = null;
5057  ResultSet rs2 = null;
5058  try {
5059  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5060  statement.clearParameters();
5061  statement.setLong(1, id);
5062  rs1 = connection.executeQuery(statement);
5063  if (rs1.next()) {
5064  int method_id = rs1.getInt("derived_id");
5065  String rederive = rs1.getString("rederive");
5066  method = new DerivedFile.DerivedMethod(method_id, rederive);
5067  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5068  statement.clearParameters();
5069  statement.setInt(1, method_id);
5070  rs2 = connection.executeQuery(statement);
5071  if (rs2.next()) {
5072  method.setToolName(rs2.getString("tool_name"));
5073  method.setToolVersion(rs2.getString("tool_version"));
5074  method.setOther(rs2.getString("other"));
5075  }
5076  }
5077  } catch (SQLException e) {
5078  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5079  } finally {
5080  closeResultSet(rs2);
5081  closeResultSet(rs1);
5082  connection.close();
5084  }
5085  return method;
5086  }
5087 
5098  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5099  CaseDbConnection connection = connections.getConnection();
5100  try {
5101  return getAbstractFileById(id, connection);
5102  } finally {
5103  connection.close();
5104  }
5105  }
5106 
5119  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
5121  ResultSet rs = null;
5122  try {
5123  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
5124  statement.clearParameters();
5125  statement.setLong(1, objectId);
5126  rs = connection.executeQuery(statement);
5127  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
5128  if (files.size() > 0) {
5129  return files.get(0);
5130  } else {
5131  return null;
5132  }
5133  } catch (SQLException ex) {
5134  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
5135  } finally {
5136  closeResultSet(rs);
5138  }
5139  }
5140 
5151  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
5152  CaseDbConnection connection = connections.getConnection();
5154  ResultSet rs = null;
5155  try {
5156  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID);
5157  statement.clearParameters();
5158  statement.setLong(1, id);
5159  rs = connection.executeQuery(statement);
5160  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5161  if (artifacts.size() > 0) {
5162  return artifacts.get(0);
5163  } else {
5164  return null;
5165  }
5166  } catch (SQLException ex) {
5167  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
5168  } finally {
5169  closeResultSet(rs);
5170  connection.close();
5172  }
5173  }
5174 
5185  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
5186  CaseDbConnection connection = connections.getConnection();
5188  ResultSet rs = null;
5189  try {
5190  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_ID);
5191  statement.clearParameters();
5192  statement.setLong(1, id);
5193  rs = connection.executeQuery(statement);
5194  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5195  if (artifacts.size() > 0) {
5196  return artifacts.get(0);
5197  } else {
5198  return null;
5199  }
5200  } catch (SQLException ex) {
5201  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
5202  } finally {
5203  closeResultSet(rs);
5204  connection.close();
5206  }
5207  }
5208 
5221  private long getFileSystemId(long fileId, CaseDbConnection connection) {
5223  ResultSet rs = null;
5224  long ret = -1;
5225  try {
5226  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
5227  statement.clearParameters();
5228  statement.setLong(1, fileId);
5229  rs = connection.executeQuery(statement);
5230  if (rs.next()) {
5231  ret = rs.getLong("fs_obj_id");
5232  if (ret == 0) {
5233  ret = -1;
5234  }
5235  }
5236  } catch (SQLException e) {
5237  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
5238  } finally {
5239  closeResultSet(rs);
5241  }
5242  return ret;
5243  }
5244 
5256  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
5257  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
5258  CaseDbConnection connection = connections.getConnection();
5260  Statement statement = null;
5261  ResultSet resultSet = null;
5262  try {
5263  statement = connection.createStatement();
5264  resultSet = connection.executeQuery(statement, query);
5265  resultSet.next();
5266  return (resultSet.getLong("count") > 0L);
5267  } catch (SQLException ex) {
5268  throw new TskCoreException(String.format("Error executing query %s", query), ex);
5269  } finally {
5270  closeResultSet(resultSet);
5271  closeStatement(statement);
5272  connection.close();
5274  }
5275  }
5276 
5288  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
5289  List<AbstractFile> files = new ArrayList<AbstractFile>();
5290  CaseDbConnection connection = connections.getConnection();
5292  ResultSet resultSet = null;
5293  try {
5294  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
5295  statement.clearParameters();
5296  statement.setString(1, fileName.toLowerCase());
5297  statement.setLong(2, dataSource.getId());
5298  resultSet = connection.executeQuery(statement);
5299  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5300  } catch (SQLException e) {
5301  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
5302  } finally {
5303  closeResultSet(resultSet);
5304  connection.close();
5306  }
5307  return files;
5308  }
5309 
5323  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
5324  List<AbstractFile> files = new ArrayList<AbstractFile>();
5325  CaseDbConnection connection = connections.getConnection();
5327  ResultSet resultSet = null;
5328  try {
5329  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
5330  statement.clearParameters();
5331  statement.setString(1, fileName.toLowerCase());
5332  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
5333  statement.setLong(3, dataSource.getId());
5334  resultSet = connection.executeQuery(statement);
5335  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5336  } catch (SQLException e) {
5337  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
5338  } finally {
5339  closeResultSet(resultSet);
5340  connection.close();
5342  }
5343  return files;
5344  }
5345 
5357  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
5358  CaseDbTransaction localTrans = beginTransaction();
5359  localTrans.acquireSingleUserCaseWriteLock();
5360  try {
5361  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
5362  localTrans.commit();
5363  localTrans = null;
5364  return newVD;
5365  } finally {
5366  // NOTE: write lock will be released by transaction
5367  if (null != localTrans) {
5368  try {
5369  localTrans.rollback();
5370  } catch (TskCoreException ex2) {
5371  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
5372  }
5373  }
5374  }
5375  }
5376 
5389  private long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
5390  ResultSet resultSet = null;
5392  try {
5393  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5394  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5395  statement.clearParameters();
5396  if (parentId != 0) {
5397  statement.setLong(1, parentId);
5398  } else {
5399  statement.setNull(1, java.sql.Types.BIGINT);
5400  }
5401  statement.setInt(2, objectType);
5402  connection.executeUpdate(statement);
5403  resultSet = statement.getGeneratedKeys();
5404 
5405  if (resultSet.next()) {
5406  if (parentId != 0) {
5407  setHasChildren(parentId);
5408  }
5409  return resultSet.getLong(1); //last_insert_rowid()
5410  } else {
5411  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
5412  }
5413  } finally {
5414  closeResultSet(resultSet);
5416  }
5417  }
5418 
5436  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5437  if (transaction == null) {
5438  throw new TskCoreException("Passed null CaseDbTransaction");
5439  }
5440 
5441  transaction.acquireSingleUserCaseWriteLock();
5442  ResultSet resultSet = null;
5443  try {
5444  // Get the parent path.
5445  CaseDbConnection connection = transaction.getConnection();
5446 
5447  String parentPath;
5448  Content parent = this.getAbstractFileById(parentId, connection);
5449  if (parent instanceof AbstractFile) {
5450  if (isRootDirectory((AbstractFile) parent, transaction)) {
5451  parentPath = "/";
5452  } else {
5453  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
5454  }
5455  } else {
5456  // The parent was either null or not an abstract file
5457  parentPath = "/";
5458  }
5459 
5460  // Insert a row for the virtual directory into the tsk_objects table.
5461  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5462 
5463  // Insert a row for the virtual directory into the tsk_files table.
5464  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5465  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension)
5466  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5467  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5468  statement.clearParameters();
5469  statement.setLong(1, newObjId);
5470 
5471  // If the parent is part of a file system, grab its file system ID
5472  if (0 != parentId) {
5473  long parentFs = this.getFileSystemId(parentId, connection);
5474  if (parentFs != -1) {
5475  statement.setLong(2, parentFs);
5476  } else {
5477  statement.setNull(2, java.sql.Types.BIGINT);
5478  }
5479  } else {
5480  statement.setNull(2, java.sql.Types.BIGINT);
5481  }
5482 
5483  // name
5484  statement.setString(3, directoryName);
5485 
5486  //type
5487  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5488  statement.setShort(5, (short) 1);
5489 
5490  //flags
5492  statement.setShort(6, dirType.getValue());
5494  statement.setShort(7, metaType.getValue());
5495 
5496  //allocated
5498  statement.setShort(8, dirFlag.getValue());
5499  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5500  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5501  statement.setShort(9, metaFlags);
5502 
5503  //size
5504  statement.setLong(10, 0);
5505 
5506  // nulls for params 11-14
5507  statement.setNull(11, java.sql.Types.BIGINT);
5508  statement.setNull(12, java.sql.Types.BIGINT);
5509  statement.setNull(13, java.sql.Types.BIGINT);
5510  statement.setNull(14, java.sql.Types.BIGINT);
5511 
5512  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5513  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5514  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5515 
5516  // parent path
5517  statement.setString(18, parentPath);
5518 
5519  // data source object id (same as object id if this is a data source)
5520  long dataSourceObjectId;
5521  if (0 == parentId) {
5522  dataSourceObjectId = newObjId;
5523  } else {
5524  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5525  }
5526  statement.setLong(19, dataSourceObjectId);
5527 
5528  //extension, since this is not really file we just set it to null
5529  statement.setString(20, null);
5530  connection.executeUpdate(statement);
5531 
5532  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5533  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5534  parentPath);
5535  } catch (SQLException e) {
5536  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
5537  } finally {
5538  closeResultSet(resultSet);
5539  // NOTE: write lock will be released by transaction
5540  }
5541  }
5542 
5555  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
5557  CaseDbTransaction localTrans = beginTransaction();
5558  try {
5559  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
5560  localTrans.commit();
5561  return newLD;
5562  } catch (TskCoreException ex) {
5563  try {
5564  localTrans.rollback();
5565  } catch (TskCoreException ex2) {
5566  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5567  }
5568  throw ex;
5569  } finally {
5571  }
5572  }
5573 
5591  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5592  if (transaction == null) {
5593  throw new TskCoreException("Passed null CaseDbTransaction");
5594  }
5595 
5596  transaction.acquireSingleUserCaseWriteLock();
5597  ResultSet resultSet = null;
5598  try {
5599  // Get the parent path.
5600  CaseDbConnection connection = transaction.getConnection();
5601  AbstractFile parent = getAbstractFileById(parentId, connection);
5602  String parentPath;
5603  if ((parent == null) || isRootDirectory(parent, transaction)) {
5604  parentPath = "/";
5605  } else {
5606  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
5607  }
5608 
5609  // Insert a row for the local directory into the tsk_objects table.
5610  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5611 
5612  // Insert a row for the local directory into the tsk_files table.
5613  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5614  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id)
5615  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5616  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5617  statement.clearParameters();
5618  statement.setLong(1, newObjId);
5619 
5620  // The parent of a local directory will never be a file system
5621  statement.setNull(2, java.sql.Types.BIGINT);
5622 
5623  // name
5624  statement.setString(3, directoryName);
5625 
5626  //type
5627  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
5628  statement.setShort(5, (short) 1);
5629 
5630  //flags
5632  statement.setShort(6, dirType.getValue());
5634  statement.setShort(7, metaType.getValue());
5635 
5636  //allocated
5638  statement.setShort(8, dirFlag.getValue());
5639  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5640  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5641  statement.setShort(9, metaFlags);
5642 
5643  //size
5644  statement.setLong(10, 0);
5645 
5646  // nulls for params 11-14
5647  statement.setNull(11, java.sql.Types.BIGINT);
5648  statement.setNull(12, java.sql.Types.BIGINT);
5649  statement.setNull(13, java.sql.Types.BIGINT);
5650  statement.setNull(14, java.sql.Types.BIGINT);
5651 
5652  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5653  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5654  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5655 
5656  // parent path
5657  statement.setString(18, parentPath);
5658 
5659  // data source object id
5660  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5661  statement.setLong(19, dataSourceObjectId);
5662 
5663  //extension, since this is a directory we just set it to null
5664  statement.setString(20, null);
5665 
5666  connection.executeUpdate(statement);
5667 
5668  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5669  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5670  parentPath);
5671  } catch (SQLException e) {
5672  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
5673  } finally {
5674  closeResultSet(resultSet);
5675  // NOTE: write lock will be released by transaction
5676  }
5677  }
5678 
5698  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
5700  Statement statement = null;
5701  try {
5702  // Insert a row for the root virtual directory of the data source
5703  // into the tsk_objects table.
5704  CaseDbConnection connection = transaction.getConnection();
5705  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5706 
5707  // Insert a row for the virtual directory of the data source into
5708  // the data_source_info table.
5709  statement = connection.createStatement();
5710  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
5711  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');");
5712 
5713  // Insert a row for the root virtual directory of the data source
5714  // into the tsk_files table. Note that its data source object id is
5715  // its own object id.
5716  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
5717  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
5718  // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension)
5719  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5720  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5721  preparedStatement.clearParameters();
5722  preparedStatement.setLong(1, newObjId);
5723  preparedStatement.setNull(2, java.sql.Types.BIGINT);
5724  preparedStatement.setString(3, rootDirectoryName);
5725  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5726  preparedStatement.setShort(5, (short) 1);
5728  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
5730  preparedStatement.setShort(7, metaType.getValue());
5732  preparedStatement.setShort(8, dirFlag.getValue());
5733  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5734  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5735  preparedStatement.setShort(9, metaFlags);
5736  preparedStatement.setLong(10, 0);
5737  preparedStatement.setNull(11, java.sql.Types.BIGINT);
5738  preparedStatement.setNull(12, java.sql.Types.BIGINT);
5739  preparedStatement.setNull(13, java.sql.Types.BIGINT);
5740  preparedStatement.setNull(14, java.sql.Types.BIGINT);
5741  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
5742  preparedStatement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5743  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5744  String parentPath = "/"; //NON-NLS
5745  preparedStatement.setString(18, parentPath);
5746  preparedStatement.setLong(19, newObjId);
5747  preparedStatement.setString(20, null); //extension, just set it to null
5748  connection.executeUpdate(preparedStatement);
5749 
5750  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, FileKnown.UNKNOWN, parentPath);
5751 
5752  } catch (SQLException ex) {
5753  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
5754  } finally {
5755  closeStatement(statement);
5757  }
5758  }
5759 
5779  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
5780  String timezone, String md5, String sha1, String sha256,
5781  String deviceId,
5782  CaseDbTransaction transaction) throws TskCoreException {
5784  Statement statement = null;
5785  try {
5786  // Insert a row for the Image into the tsk_objects table.
5787  CaseDbConnection connection = transaction.getConnection();
5788  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
5789 
5790  // Add a row to tsk_image_info
5791  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
5792  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
5793  preparedStatement.clearParameters();
5794  preparedStatement.setLong(1, newObjId);
5795  preparedStatement.setShort(2, (short) type.getValue());
5796  preparedStatement.setLong(3, sectorSize);
5797  preparedStatement.setString(4, timezone);
5798  //prevent negative size
5799  long savedSize = size < 0 ? 0 : size;
5800  preparedStatement.setLong(5, savedSize);
5801  preparedStatement.setString(6, md5);
5802  preparedStatement.setString(7, sha1);
5803  preparedStatement.setString(8, sha256);
5804  preparedStatement.setString(9, displayName);
5805  connection.executeUpdate(preparedStatement);
5806 
5807  // If there are paths, add them to tsk_image_names
5808  for (int i = 0; i < imagePaths.size(); i++) {
5809  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
5810  preparedStatement.clearParameters();
5811  preparedStatement.setLong(1, newObjId);
5812  preparedStatement.setString(2, imagePaths.get(i));
5813  preparedStatement.setLong(3, i);
5814  connection.executeUpdate(preparedStatement);
5815  }
5816 
5817  // Add a row to data_source_info
5818  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
5819  statement = connection.createStatement();
5820  preparedStatement.setLong(1, newObjId);
5821  preparedStatement.setString(2, deviceId);
5822  preparedStatement.setString(3, timezone);
5823  connection.executeUpdate(preparedStatement);
5824 
5825  // Create the new Image object
5826  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, displayName,
5827  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
5828  } catch (SQLException ex) {
5829  if (!imagePaths.isEmpty()) {
5830  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
5831  } else {
5832  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
5833  }
5834  } finally {
5835  closeStatement(statement);
5837  }
5838  }
5839 
5853  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
5854  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
5856  try {
5857  // Insert a row for the VolumeSystem into the tsk_objects table.
5858  CaseDbConnection connection = transaction.getConnection();
5859  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
5860 
5861  // Add a row to tsk_vs_info
5862  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
5863  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
5864  preparedStatement.clearParameters();
5865  preparedStatement.setLong(1, newObjId);
5866  preparedStatement.setShort(2, (short) type.getVsType());
5867  preparedStatement.setLong(3, imgOffset);
5868  preparedStatement.setLong(4, blockSize);
5869  connection.executeUpdate(preparedStatement);
5870 
5871  // Create the new VolumeSystem object
5872  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
5873  } catch (SQLException ex) {
5874  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
5875  parentObjId, imgOffset), ex);
5876  } finally {
5878  }
5879  }
5880 
5896  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
5897  long flags, CaseDbTransaction transaction) throws TskCoreException {
5899  Statement statement = null;
5900  try {
5901  // Insert a row for the Volume into the tsk_objects table.
5902  CaseDbConnection connection = transaction.getConnection();
5903  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
5904 
5905  // Add a row to tsk_vs_parts
5906  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
5907  PreparedStatement preparedStatement;
5908  if (this.dbType == DbType.POSTGRESQL) {
5909  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
5910  } else {
5911  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
5912  }
5913  preparedStatement.clearParameters();
5914  preparedStatement.setLong(1, newObjId);
5915  preparedStatement.setLong(2, addr);
5916  preparedStatement.setLong(3, start);
5917  preparedStatement.setLong(4, length);
5918  preparedStatement.setString(5, desc);
5919  preparedStatement.setShort(6, (short) flags);
5920  connection.executeUpdate(preparedStatement);
5921 
5922  // Create the new Volume object
5923  return new Volume(this, newObjId, addr, start, length, flags, desc);
5924  } catch (SQLException ex) {
5925  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
5926  } finally {
5927  closeStatement(statement);
5929  }
5930  }
5931 
5943  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
5945  Statement statement = null;
5946  try {
5947  // Insert a row for the Pool into the tsk_objects table.
5948  CaseDbConnection connection = transaction.getConnection();
5949  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
5950 
5951  // Add a row to tsk_pool_info
5952  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
5953  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
5954  preparedStatement.clearParameters();
5955  preparedStatement.setLong(1, newObjId);
5956  preparedStatement.setShort(2, type.getValue());
5957  connection.executeUpdate(preparedStatement);
5958 
5959  // Create the new Pool object
5960  return new Pool(this, newObjId, type.getName(), type.getValue());
5961  } catch (SQLException ex) {
5962  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
5963  } finally {
5964  closeStatement(statement);
5966  }
5967  }
5968 
5987  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
5988  long rootInum, long firstInum, long lastInum, String displayName,
5989  CaseDbTransaction transaction) throws TskCoreException {
5991  Statement statement = null;
5992  try {
5993  // Insert a row for the FileSystem into the tsk_objects table.
5994  CaseDbConnection connection = transaction.getConnection();
5995  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
5996 
5997  // Add a row to tsk_fs_info
5998  // INSERT INTO tsk_fs_info (obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)
5999  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
6000  preparedStatement.clearParameters();
6001  preparedStatement.setLong(1, newObjId);
6002  preparedStatement.setLong(2, imgOffset);
6003  preparedStatement.setShort(3, (short) type.getValue());
6004  preparedStatement.setLong(4, blockSize);
6005  preparedStatement.setLong(5, blockCount);
6006  preparedStatement.setLong(6, rootInum);
6007  preparedStatement.setLong(7, firstInum);
6008  preparedStatement.setLong(8, lastInum);
6009  preparedStatement.setString(9, displayName);
6010  connection.executeUpdate(preparedStatement);
6011 
6012  // Create the new FileSystem object
6013  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
6014  firstInum, lastInum);
6015  } catch (SQLException ex) {
6016  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
6017  imgOffset, parentObjId), ex);
6018  } finally {
6019  closeStatement(statement);
6021  }
6022  }
6023 
6049  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
6050  String fileName,
6051  long metaAddr, int metaSeq,
6052  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
6053  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
6054  long ctime, long crtime, long atime, long mtime,
6055  boolean isFile, Content parent) throws TskCoreException {
6056 
6057  TimelineManager timelineManager = getTimelineManager();
6058 
6059  CaseDbTransaction transaction = beginTransaction();
6060  Statement queryStatement = null;
6061  try {
6062  CaseDbConnection connection = transaction.getConnection();
6063  transaction.acquireSingleUserCaseWriteLock();
6064 
6065  // Insert a row for the local/logical file into the tsk_objects table.
6066  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6067  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6068 
6069  String parentPath;
6070 
6071  if (parent instanceof AbstractFile) {
6072  AbstractFile parentFile = (AbstractFile) parent;
6073  if (isRootDirectory(parentFile, transaction)) {
6074  parentPath = "/";
6075  } else {
6076  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
6077  }
6078  } else {
6079  parentPath = "/";
6080  }
6081 
6082  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
6083  statement.clearParameters();
6084  statement.setLong(1, objectId); // obj_is
6085  statement.setLong(2, fsObjId); // fs_obj_id
6086  statement.setLong(3, dataSourceObjId); // data_source_obj_id
6087  statement.setShort(4, (short) attrType.getValue()); // attr_type
6088  statement.setInt(5, attrId); // attr_id
6089  statement.setString(6, fileName); // name
6090  statement.setLong(7, metaAddr); // meta_addr
6091  statement.setInt(8, metaSeq); // meta_addr
6092  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
6093  statement.setShort(10, (short) 1); // has_path
6095  statement.setShort(11, dirType.getValue()); // dir_type
6097  statement.setShort(12, metaType.getValue()); // meta_type
6098  statement.setShort(13, dirFlag.getValue()); // dir_flags
6099  statement.setShort(14, metaFlags); // meta_flags
6100  statement.setLong(15, size < 0 ? 0 : size);
6101  statement.setLong(16, ctime);
6102  statement.setLong(17, crtime);
6103  statement.setLong(18, atime);
6104  statement.setLong(19, mtime);
6105  statement.setString(20, parentPath);
6106  final String extension = extractExtension(fileName);
6107  statement.setString(21, extension);
6108 
6109  connection.executeUpdate(statement);
6110 
6111  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
6112  size, ctime, crtime, atime, mtime, null, null, parentPath, null, parent.getId(), null, null, extension);
6113 
6114  timelineManager.addEventsForNewFile(derivedFile, connection);
6115 
6116  transaction.commit();
6117  transaction = null;
6118 
6119  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
6120  attrType, attrId, fileName, metaAddr, metaSeq,
6121  dirType, metaType, dirFlag, metaFlags,
6122  size, ctime, crtime, atime, mtime,
6123  (short) 0, 0, 0, null, null, parentPath, null,
6124  extension);
6125 
6126  } catch (SQLException ex) {
6127  logger.log(Level.WARNING, "Failed to add file system file", ex);
6128  } finally {
6129  closeStatement(queryStatement);
6130  if (null != transaction) {
6131  try {
6132  transaction.rollback();
6133  } catch (TskCoreException ex2) {
6134  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6135  }
6136  }
6137  }
6138  return null;
6139  }
6140 
6149  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
6150  CaseDbConnection connection = connections.getConnection();
6152  Statement s = null;
6153  ResultSet rs = null;
6154  try {
6155  s = connection.createStatement();
6156  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
6157  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
6158  + " AND obj_id = data_source_obj_id"
6159  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
6160  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
6161  while (rs.next()) {
6162  virtDirRootIds.add(virtualDirectory(rs, connection));
6163  }
6164  return virtDirRootIds;
6165  } catch (SQLException ex) {
6166  throw new TskCoreException("Error getting local files virtual folder id", ex);
6167  } finally {
6168  closeResultSet(rs);
6169  closeStatement(s);
6170  connection.close();
6172  }
6173  }
6174 
6187  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
6188  assert (null != fileRanges);
6189  if (null == fileRanges) {
6190  throw new TskCoreException("TskFileRange object is null");
6191  }
6192 
6193  assert (null != parent);
6194  if (null == parent) {
6195  throw new TskCoreException("Conent is null");
6196  }
6197 
6198  CaseDbTransaction transaction = null;
6199  Statement statement = null;
6200  ResultSet resultSet = null;
6201 
6202  try {
6203  transaction = beginTransaction();
6204  transaction.acquireSingleUserCaseWriteLock();
6205  CaseDbConnection connection = transaction.getConnection();
6206 
6207  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
6208  for (TskFileRange fileRange : fileRanges) {
6209  /*
6210  * Insert a row for the Tsk file range into the tsk_objects
6211  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
6212  * ?)
6213  */
6214  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6215  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
6216  /*
6217  * Insert a row for the Tsk file range into the tsk_files table:
6218  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6219  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6220  * ctime, crtime, atime, mtime, md5, known, mime_type,
6221  * parent_path, data_source_obj_id,extension) VALUES (?, ?, ?,
6222  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6223  */
6224  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6225  prepStmt.clearParameters();
6226  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
6227  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6228  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]
6229  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
6230  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
6231  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6232  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6233  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6234  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6235  prepStmt.setLong(10, fileRange.getByteLen()); // size
6236  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6237  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6238  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6239  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6240  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6241  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6242  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6243  prepStmt.setNull(18, java.sql.Types.VARCHAR); // parent path
6244  prepStmt.setLong(19, parent.getId()); // data_source_obj_id
6245 
6246  //extension, since this is not a FS file we just set it to null
6247  prepStmt.setString(20, null);
6248  connection.executeUpdate(prepStmt);
6249 
6250  /*
6251  * Insert a row in the tsk_layout_file table for each chunk of
6252  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6253  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6254  */
6255  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6256  prepStmt.clearParameters();
6257  prepStmt.setLong(1, fileRangeId); // obj_id
6258  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
6259  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
6260  prepStmt.setLong(4, fileRange.getSequence()); // sequence
6261  connection.executeUpdate(prepStmt);
6262 
6263  /*
6264  * Create a layout file representation of the carved file.
6265  */
6266  fileRangeLayoutFiles.add(new LayoutFile(this,
6267  fileRangeId,
6268  parent.getId(),
6269  Long.toString(fileRange.getSequence()),
6274  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6275  fileRange.getByteLen(),
6276  0L, 0L, 0L, 0L,
6277  null,
6279  parent.getUniquePath(),
6280  null));
6281  }
6282 
6283  transaction.commit();
6284  transaction = null;
6285  return fileRangeLayoutFiles;
6286 
6287  } catch (SQLException ex) {
6288  throw new TskCoreException("Failed to add layout files to case database", ex);
6289  } finally {
6290  closeResultSet(resultSet);
6291  closeStatement(statement);
6292 
6293  // NOTE: write lock will be released by transaction
6294  if (null != transaction) {
6295  try {
6296  transaction.rollback();
6297  } catch (TskCoreException ex2) {
6298  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6299  }
6300  }
6301  }
6302  }
6303 
6315  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
6316  assert (null != carvingResult);
6317  if (null == carvingResult) {
6318  throw new TskCoreException("Carving is null");
6319  }
6320  assert (null != carvingResult.getParent());
6321  if (null == carvingResult.getParent()) {
6322  throw new TskCoreException("Carving result has null parent");
6323  }
6324  assert (null != carvingResult.getCarvedFiles());
6325  if (null == carvingResult.getCarvedFiles()) {
6326  throw new TskCoreException("Carving result has null carved files");
6327  }
6328  CaseDbTransaction transaction = null;
6329  Statement statement = null;
6330  ResultSet resultSet = null;
6331  long newCacheKey = 0; // Used to roll back cache if transaction is rolled back.
6332  try {
6333  transaction = beginTransaction();
6334  transaction.acquireSingleUserCaseWriteLock();
6335  CaseDbConnection connection = transaction.getConnection();
6336 
6337  /*
6338  * Carved files are "re-parented" as children of the $CarvedFiles
6339  * virtual directory of the root file system, volume, or image
6340  * ancestor of the carved files parent, but if no such ancestor is
6341  * found, then the parent specified in the carving result is used.
6342  */
6343  Content root = carvingResult.getParent();
6344  while (null != root) {
6345  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
6346  break;
6347  }
6348  root = root.getParent();
6349  }
6350  if (null == root) {
6351  root = carvingResult.getParent();
6352  }
6353 
6354  /*
6355  * Get or create the $CarvedFiles virtual directory for the root
6356  * ancestor.
6357  */
6358  VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
6359  if (null == carvedFilesDir) {
6360  List<Content> rootChildren;
6361  if (root instanceof FileSystem) {
6362  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
6363  } else {
6364  rootChildren = root.getChildren();
6365  }
6366  for (Content child : rootChildren) {
6367  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
6368  carvedFilesDir = (VirtualDirectory) child;
6369  break;
6370  }
6371  }
6372  if (null == carvedFilesDir) {
6373  long parId = root.getId();
6374  // $CarvedFiles should be a child of the root directory, not the file system
6375  if (root instanceof FileSystem) {
6376  Content rootDir = ((FileSystem) root).getRootDirectory();
6377  parId = rootDir.getId();
6378  }
6379  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED, transaction);
6380  }
6381  newCacheKey = root.getId();
6382  rootIdsToCarvedFileDirs.put(newCacheKey, carvedFilesDir);
6383  }
6384 
6385  /*
6386  * Add the carved files to the database as children of the
6387  * $CarvedFile directory of the root ancestor.
6388  */
6389  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
6390  List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>();
6391  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
6392  /*
6393  * Insert a row for the carved file into the tsk_objects table:
6394  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6395  */
6396  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6397 
6398  /*
6399  * Insert a row for the carved file into the tsk_files table:
6400  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6401  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6402  * ctime, crtime, atime, mtime, md5, known, mime_type,
6403  * parent_path, data_source_obj_id,extenion) VALUES (?, ?, ?, ?,
6404  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6405  */
6406  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6407  prepStmt.clearParameters();
6408  prepStmt.setLong(1, carvedFileId); // obj_id
6409  if (root instanceof FileSystem) {
6410  prepStmt.setLong(2, root.getId()); // fs_obj_id
6411  } else {
6412  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6413  }
6414  prepStmt.setString(3, carvedFile.getName()); // name
6415  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
6416  prepStmt.setShort(5, (short) 1); // has_path
6417  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6418  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6419  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6420  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6421  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
6422  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6423  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6424  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6425  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6426  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6427  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6428  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6429  prepStmt.setString(18, parentPath); // parent path
6430  prepStmt.setLong(19, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
6431  prepStmt.setString(20, extractExtension(carvedFile.getName())); //extension
6432  connection.executeUpdate(prepStmt);
6433 
6434  /*
6435  * Insert a row in the tsk_layout_file table for each chunk of
6436  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6437  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6438  */
6439  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6440  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
6441  prepStmt.clearParameters();
6442  prepStmt.setLong(1, carvedFileId); // obj_id
6443  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
6444  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
6445  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
6446  connection.executeUpdate(prepStmt);
6447  }
6448 
6449  /*
6450  * Create a layout file representation of the carved file.
6451  */
6452  carvedFiles.add(new LayoutFile(this,
6453  carvedFileId,
6454  carvedFilesDir.getDataSourceObjectId(),
6455  carvedFile.getName(),
6460  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6461  carvedFile.getSizeInBytes(),
6462  0L, 0L, 0L, 0L,
6463  null,
6465  parentPath,
6466  null));
6467  }
6468 
6469  transaction.commit();
6470  transaction = null;
6471  return carvedFiles;
6472 
6473  } catch (SQLException ex) {
6474  throw new TskCoreException("Failed to add carved files to case database", ex);
6475  } finally {
6476  closeResultSet(resultSet);
6477  closeStatement(statement);
6478 
6479  // NOTE: write lock will be released by transaction
6480  if (null != transaction) {
6481  try {
6482  transaction.rollback();
6483  } catch (TskCoreException ex2) {
6484  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6485  }
6486  if (0 != newCacheKey) {
6487  rootIdsToCarvedFileDirs.remove(newCacheKey);
6488  }
6489  }
6490  }
6491  }
6492 
6523  public DerivedFile addDerivedFile(String fileName, String localPath,
6524  long size, long ctime, long crtime, long atime, long mtime,
6525  boolean isFile, Content parentObj,
6526  String rederiveDetails, String toolName, String toolVersion,
6527  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6528  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6529  localPath = localPath.replaceAll("^[/\\\\]+", "");
6530 
6532  TimelineManager timelineManager = getTimelineManager();
6533 
6534  CaseDbTransaction transaction = beginTransaction();
6535  CaseDbConnection connection = transaction.getConnection();
6536  try {
6537  final long parentId = parentObj.getId();
6538  String parentPath = "";
6539  if (parentObj instanceof BlackboardArtifact) {
6540  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6541  } else if (parentObj instanceof AbstractFile) {
6542  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6543  }
6544 
6545  // Insert a row for the derived file into the tsk_objects table.
6546  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6547  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6548 
6549  // Insert a row for the virtual directory into the tsk_files table.
6550  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6551  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6552  // parent_path, data_source_obj_id, extension)
6553  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6554  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6555  statement.clearParameters();
6556  statement.setLong(1, newObjId);
6557 
6558  // If the parentFile is part of a file system, use its file system object ID.
6559  long fsObjId = this.getFileSystemId(parentId, connection);
6560  if (fsObjId != -1) {
6561  statement.setLong(2, fsObjId);
6562  } else {
6563  statement.setNull(2, java.sql.Types.BIGINT);
6564  }
6565  statement.setString(3, fileName);
6566 
6567  //type, has_path
6568  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6569  statement.setShort(5, (short) 1);
6570 
6571  //flags
6573  statement.setShort(6, dirType.getValue());
6575  statement.setShort(7, metaType.getValue());
6576 
6577  //note: using alloc under assumption that derived files derive from alloc files
6579  statement.setShort(8, dirFlag.getValue());
6580  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6581  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6582  statement.setShort(9, metaFlags);
6583 
6584  //size
6585  //prevent negative size
6586  long savedSize = size < 0 ? 0 : size;
6587  statement.setLong(10, savedSize);
6588 
6589  //mactimes
6590  //long ctime, long crtime, long atime, long mtime,
6591  statement.setLong(11, ctime);
6592  statement.setLong(12, crtime);
6593  statement.setLong(13, atime);
6594  statement.setLong(14, mtime);
6595 
6596  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6597  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6598  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
6599 
6600  //parent path
6601  statement.setString(18, parentPath);
6602 
6603  // root data source object id
6604  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6605  statement.setLong(19, dataSourceObjId);
6606  final String extension = extractExtension(fileName);
6607  //extension
6608  statement.setString(20, extension);
6609 
6610  connection.executeUpdate(statement);
6611 
6612  //add localPath
6613  addFilePath(connection, newObjId, localPath, encodingType);
6614 
6615  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
6616  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6617 
6618  timelineManager.addEventsForNewFile(derivedFile, connection);
6619  transaction.commit();
6620  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
6621  return derivedFile;
6622  } catch (SQLException ex) {
6623  connection.rollbackTransaction();
6624  throw new TskCoreException("Failed to add derived file to case database", ex);
6625  } finally {
6626  connection.close();
6628  }
6629  }
6630 
6661  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
6662  long size, long ctime, long crtime, long atime, long mtime,
6663  boolean isFile, String mimeType,
6664  String rederiveDetails, String toolName, String toolVersion,
6665  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6666 
6667  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6668  localPath = localPath.replaceAll("^[/\\\\]+", "");
6669 
6670  CaseDbConnection connection = connections.getConnection();
6672  ResultSet rs = null;
6673  try {
6674  Content parentObj = derivedFile.getParent();
6675  connection.beginTransaction();
6676  final long parentId = parentObj.getId();
6677  String parentPath = "";
6678  if (parentObj instanceof BlackboardArtifact) {
6679  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6680  } else if (parentObj instanceof AbstractFile) {
6681  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6682  }
6683  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
6684  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
6685  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
6686  statement.clearParameters();
6687 
6688  //type
6689  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6690 
6691  //flags
6693  statement.setShort(2, dirType.getValue());
6695  statement.setShort(3, metaType.getValue());
6696 
6697  //note: using alloc under assumption that derived files derive from alloc files
6699  statement.setShort(4, dirFlag.getValue());
6700  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6701  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6702  statement.setShort(5, metaFlags);
6703 
6704  //size
6705  //prevent negative size
6706  long savedSize = size < 0 ? 0 : size;
6707  statement.setLong(6, savedSize);
6708 
6709  //mactimes
6710  //long ctime, long crtime, long atime, long mtime,
6711  statement.setLong(7, ctime);
6712  statement.setLong(8, crtime);
6713  statement.setLong(9, atime);
6714  statement.setLong(10, mtime);
6715  statement.setString(11, mimeType);
6716  statement.setString(12, String.valueOf(derivedFile.getId()));
6717  connection.executeUpdate(statement);
6718 
6719  //add localPath
6720  updateFilePath(connection, derivedFile.getId(), localPath, encodingType);
6721 
6722  connection.commitTransaction();
6723 
6724  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6725  final String extension = extractExtension(derivedFile.getName());
6726  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
6727  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6728  } catch (SQLException ex) {
6729  connection.rollbackTransaction();
6730  throw new TskCoreException("Failed to add derived file to case database", ex);
6731  } finally {
6732  closeResultSet(rs);
6733  connection.close();
6735  }
6736  }
6737 
6757  public LocalFile addLocalFile(String fileName, String localPath,
6758  long size, long ctime, long crtime, long atime, long mtime,
6759  boolean isFile, TskData.EncodingType encodingType,
6760  AbstractFile parent) throws TskCoreException {
6761 
6762  CaseDbTransaction localTrans = beginTransaction();
6763  try {
6764  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
6765  localTrans.commit();
6766  localTrans = null;
6767  return created;
6768  } finally {
6769  if (null != localTrans) {
6770  try {
6771  localTrans.rollback();
6772  } catch (TskCoreException ex2) {
6773  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6774  }
6775  }
6776  }
6777  }
6778 
6803  public LocalFile addLocalFile(String fileName, String localPath,
6804  long size, long ctime, long crtime, long atime, long mtime,
6805  boolean isFile, TskData.EncodingType encodingType,
6806  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6807 
6808  return addLocalFile(fileName, localPath,
6809  size, ctime, crtime, atime, mtime,
6810  null, null, null,
6811  isFile, encodingType,
6812  parent, transaction);
6813  }
6814 
6842  public LocalFile addLocalFile(String fileName, String localPath,
6843  long size, long ctime, long crtime, long atime, long mtime,
6844  String md5, FileKnown known, String mimeType,
6845  boolean isFile, TskData.EncodingType encodingType,
6846  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6847  CaseDbConnection connection = transaction.getConnection();
6848  transaction.acquireSingleUserCaseWriteLock();
6849  Statement queryStatement = null;
6850  try {
6851 
6852  // Insert a row for the local/logical file into the tsk_objects table.
6853  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6854  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6855 
6856  // Insert a row for the local/logical file into the tsk_files table.
6857  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6858  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6859  // parent_path, data_source_obj_id,extension)
6860  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6861  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6862  statement.clearParameters();
6863  statement.setLong(1, objectId);
6864  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
6865  statement.setString(3, fileName);
6866  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
6867  statement.setShort(5, (short) 1);
6869  statement.setShort(6, dirType.getValue());
6871  statement.setShort(7, metaType.getValue());
6873  statement.setShort(8, dirFlag.getValue());
6874  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
6875  statement.setShort(9, metaFlags);
6876  //prevent negative size
6877  long savedSize = size < 0 ? 0 : size;
6878  statement.setLong(10, savedSize);
6879  statement.setLong(11, ctime);
6880  statement.setLong(12, crtime);
6881  statement.setLong(13, atime);
6882  statement.setLong(14, mtime);
6883  statement.setString(15, md5);
6884  if (known != null) {
6885  statement.setByte(16, known.getFileKnownValue());
6886  } else {
6887  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue());
6888  }
6889  statement.setString(17, mimeType);
6890  String parentPath;
6891  long dataSourceObjId;
6892 
6893  if (parent instanceof AbstractFile) {
6894  AbstractFile parentFile = (AbstractFile) parent;
6895  if (isRootDirectory(parentFile, transaction)) {
6896  parentPath = "/";
6897  } else {
6898  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
6899  }
6900  dataSourceObjId = parentFile.getDataSourceObjectId();
6901  } else {
6902  parentPath = "/";
6903  dataSourceObjId = getDataSourceObjectId(connection, parent.getId());
6904  }
6905  statement.setString(18, parentPath);
6906  statement.setLong(19, dataSourceObjId);
6907  final String extension = extractExtension(fileName);
6908  statement.setString(20, extension);
6909 
6910  connection.executeUpdate(statement);
6911  addFilePath(connection, objectId, localPath, encodingType);
6912  LocalFile localFile = new LocalFile(this,
6913  objectId,
6914  fileName,
6916  dirType,
6917  metaType,
6918  dirFlag,
6919  metaFlags,
6920  savedSize,
6921  ctime, crtime, atime, mtime,
6922  mimeType, md5, known,
6923  parent.getId(), parentPath,
6924  dataSourceObjId,
6925  localPath,
6926  encodingType, extension);
6927  getTimelineManager().addEventsForNewFile(localFile, connection);
6928  return localFile;
6929 
6930  } catch (SQLException ex) {
6931  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);
6932  } finally {
6933  closeStatement(queryStatement);
6934  // NOTE: write lock will be released by transaction
6935  }
6936  }
6937 
6950  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
6951  CaseDbConnection connection = transaction.getConnection();
6952  transaction.acquireSingleUserCaseWriteLock();
6953  Statement statement = null;
6954  ResultSet resultSet = null;
6955 
6956  try {
6957  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
6958  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
6959  + "WHERE ChildRow.obj_id = %s;", file.getId());
6960 
6961  statement = connection.createStatement();
6962  resultSet = statement.executeQuery(query);
6963  if (resultSet.next()) {
6964  long parentId = resultSet.getLong("parent_object_id");
6965  if (parentId == 0) {
6966  return true;
6967  }
6968  int type = resultSet.getInt("parent_type");
6969  return (type == TskData.ObjectType.IMG.getObjectType()
6970  || type == TskData.ObjectType.VS.getObjectType()
6971  || type == TskData.ObjectType.VOL.getObjectType()
6972  || type == TskData.ObjectType.FS.getObjectType());
6973 
6974  } else {
6975  return true; // The file has no parent
6976  }
6977  } catch (SQLException ex) {
6978  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
6979  } finally {
6980  closeResultSet(resultSet);
6981  closeStatement(statement);
6982  // NOTE: write lock will be released by transaction
6983  }
6984  }
6985 
7005  public LayoutFile addLayoutFile(String fileName,
7006  long size,
7007  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
7008  long ctime, long crtime, long atime, long mtime,
7009  List<TskFileRange> fileRanges,
7010  Content parent) throws TskCoreException {
7011 
7012  if (null == parent) {
7013  throw new TskCoreException("Parent can not be null");
7014  }
7015 
7016  String parentPath;
7017  if (parent instanceof AbstractFile) {
7018  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7019  } else {
7020  parentPath = "/";
7021  }
7022 
7023  CaseDbTransaction transaction = null;
7024  Statement statement = null;
7025  ResultSet resultSet = null;
7026  try {
7027  transaction = beginTransaction();
7028  transaction.acquireSingleUserCaseWriteLock();
7029  CaseDbConnection connection = transaction.getConnection();
7030 
7031  /*
7032  * Insert a row for the layout file into the tsk_objects table:
7033  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7034  */
7035  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7036 
7037  /*
7038  * Insert a row for the file into the tsk_files table: INSERT INTO
7039  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
7040  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
7041  * mtime, md5, known, mime_type, parent_path,
7042  * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,
7043  * ?, ?, ?, ?, ?, ?, ?,?)
7044  */
7045  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7046  prepStmt.clearParameters();
7047  prepStmt.setLong(1, newFileId); // obj_id
7048 
7049  // If the parent is part of a file system, grab its file system ID
7050  if (0 != parent.getId()) {
7051  long parentFs = this.getFileSystemId(parent.getId(), connection);
7052  if (parentFs != -1) {
7053  prepStmt.setLong(2, parentFs);
7054  } else {
7055  prepStmt.setNull(2, java.sql.Types.BIGINT);
7056  }
7057  } else {
7058  prepStmt.setNull(2, java.sql.Types.BIGINT);
7059  }
7060  prepStmt.setString(3, fileName); // name
7061  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
7062  prepStmt.setShort(5, (short) 0); // has_path
7063  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7064  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7065  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
7066  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
7067  //prevent negative size
7068  long savedSize = size < 0 ? 0 : size;
7069  prepStmt.setLong(10, savedSize); // size
7070  prepStmt.setLong(11, ctime); // ctime
7071  prepStmt.setLong(12, crtime); // crtime
7072  prepStmt.setLong(13, atime); // atime
7073  prepStmt.setLong(14, mtime); // mtime
7074  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7075  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7076  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
7077  prepStmt.setString(18, parentPath); // parent path
7078  prepStmt.setLong(19, parent.getDataSource().getId()); // data_source_obj_id
7079 
7080  prepStmt.setString(20, extractExtension(fileName)); //extension
7081  connection.executeUpdate(prepStmt);
7082 
7083  /*
7084  * Insert a row in the tsk_layout_file table for each chunk of the
7085  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
7086  * byte_len, sequence) VALUES (?, ?, ?, ?)
7087  */
7088  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7089  for (TskFileRange tskFileRange : fileRanges) {
7090  prepStmt.clearParameters();
7091  prepStmt.setLong(1, newFileId); // obj_id
7092  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7093  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7094  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7095  connection.executeUpdate(prepStmt);
7096  }
7097 
7098  /*
7099  * Create a layout file representation of the carved file.
7100  */
7101  LayoutFile layoutFile = new LayoutFile(this,
7102  newFileId,
7103  parent.getDataSource().getId(),
7104  fileName,
7108  dirFlag,
7109  metaFlag.getValue(),
7110  savedSize,
7111  ctime, crtime, atime, mtime,
7112  null,
7114  parentPath,
7115  null);
7116 
7117  transaction.commit();
7118  transaction = null;
7119  return layoutFile;
7120 
7121  } catch (SQLException ex) {
7122  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
7123  } finally {
7124  closeResultSet(resultSet);
7125  closeStatement(statement);
7126 
7127  // NOTE: write lock will be released by transaction
7128  if (null != transaction) {
7129  try {
7130  transaction.rollback();
7131  } catch (TskCoreException ex2) {
7132  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7133  }
7134  }
7135  }
7136  }
7137 
7150  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
7152  Statement statement = null;
7153  ResultSet resultSet = null;
7154  try {
7155  statement = connection.createStatement();
7156  long dataSourceObjId;
7157  long ancestorId = objectId;
7158  do {
7159  dataSourceObjId = ancestorId;
7160  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
7161  resultSet = statement.executeQuery(query);
7162  if (resultSet.next()) {
7163  ancestorId = resultSet.getLong("par_obj_id");
7164  } else {
7165  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
7166  }
7167  resultSet.close();
7168  resultSet = null;
7169  } while (0 != ancestorId); // Not NULL
7170  return dataSourceObjId;
7171  } catch (SQLException ex) {
7172  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
7173  } finally {
7174  closeResultSet(resultSet);
7175  closeStatement(statement);
7177  }
7178  }
7179 
7191  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7192  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
7193  statement.clearParameters();
7194  statement.setLong(1, objId);
7195  statement.setString(2, path);
7196  statement.setInt(3, type.getType());
7197  connection.executeUpdate(statement);
7198  }
7199 
7211  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7212  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
7213  statement.clearParameters();
7214  statement.setString(1, path);
7215  statement.setInt(2, type.getType());
7216  statement.setLong(3, objId);
7217  connection.executeUpdate(statement);
7218  }
7219 
7235  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
7236  return findFiles(dataSource, fileName, parentFile.getName());
7237  }
7238 
7250  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
7251  CaseDbConnection connection = connections.getConnection();
7253  Statement s = null;
7254  ResultSet rs = null;
7255  try {
7256  s = connection.createStatement();
7257  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7258  rs.next();
7259  return rs.getLong("count");
7260  } catch (SQLException e) {
7261  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
7262  } finally {
7263  closeResultSet(rs);
7264  closeStatement(s);
7265  connection.close();
7267  }
7268  }
7269 
7287  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
7288  CaseDbConnection connection = connections.getConnection();
7290  Statement s = null;
7291  ResultSet rs = null;
7292  try {
7293  s = connection.createStatement();
7294  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7295  return resultSetToAbstractFiles(rs, connection);
7296  } catch (SQLException e) {
7297  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
7298  } finally {
7299  closeResultSet(rs);
7300  closeStatement(s);
7301  connection.close();
7303  }
7304  }
7305 
7318  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
7319  CaseDbConnection connection = connections.getConnection();
7321  Statement s = null;
7322  ResultSet rs = null;
7323  try {
7324  s = connection.createStatement();
7325  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7326  List<Long> ret = new ArrayList<Long>();
7327  while (rs.next()) {
7328  ret.add(rs.getLong("obj_id"));
7329  }
7330  return ret;
7331  } catch (SQLException e) {
7332  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
7333  } finally {
7334  closeResultSet(rs);
7335  closeStatement(s);
7336  connection.close();
7338  }
7339  }
7340 
7352  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
7353 
7354  // get the non-unique path (strip of image and volume path segments, if
7355  // the exist.
7356  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
7357 
7358  // split the file name from the parent path
7359  int lastSlash = path.lastIndexOf('/'); //NON-NLS
7360 
7361  // if the last slash is at the end, strip it off
7362  if (lastSlash == path.length()) {
7363  path = path.substring(0, lastSlash - 1);
7364  lastSlash = path.lastIndexOf('/'); //NON-NLS
7365  }
7366 
7367  String parentPath = path.substring(0, lastSlash);
7368  String fileName = path.substring(lastSlash);
7369 
7370  return findFiles(dataSource, fileName, parentPath);
7371  }
7372 
7383  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
7384  CaseDbConnection connection = connections.getConnection();
7386  Statement s = null;
7387  ResultSet rs = null;
7388  try {
7389  s = connection.createStatement();
7390  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
7391  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
7392  while (rs.next()) {
7393  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
7394  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
7395  ranges.add(range);
7396  }
7397  return ranges;
7398  } catch (SQLException ex) {
7399  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
7400  } finally {
7401  closeResultSet(rs);
7402  closeStatement(s);
7403  connection.close();
7405  }
7406  }
7407 
7418  public Image getImageById(long id) throws TskCoreException {
7419  CaseDbConnection connection = connections.getConnection();
7421  Statement s1 = null;
7422  ResultSet rs1 = null;
7423  Statement s2 = null;
7424  ResultSet rs2 = null;
7425  try {
7426  s1 = connection.createStatement();
7427  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 "
7428  + "FROM tsk_image_info "
7429  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
7430  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
7431  if (rs1.next()) {
7432  s2 = connection.createStatement();
7433  rs2 = connection.executeQuery(s2, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + id); //NON-NLS
7434  List<String> imagePaths = new ArrayList<String>();
7435  while (rs2.next()) {
7436  imagePaths.add(rs2.getString("name"));
7437  }
7438  long type = rs1.getLong("type"); //NON-NLS
7439  long ssize = rs1.getLong("ssize"); //NON-NLS
7440  String tzone = rs1.getString("tzone"); //NON-NLS
7441  long size = rs1.getLong("size"); //NON-NLS
7442  String md5 = rs1.getString("md5"); //NON-NLS
7443  String sha1 = rs1.getString("sha1"); //NON-NLS
7444  String sha256 = rs1.getString("sha256"); //NON-NLS
7445  String name = rs1.getString("display_name");
7446  if (name == null) {
7447  if (imagePaths.size() > 0) {
7448  String path = imagePaths.get(0);
7449  name = (new java.io.File(path)).getName();
7450  } else {
7451  name = "";
7452  }
7453  }
7454  String device_id = rs1.getString("device_id");
7455 
7456  return new Image(this, id, type, device_id, ssize, name,
7457  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
7458  } else {
7459  throw new TskCoreException("No image found for id: " + id);
7460  }
7461  } catch (SQLException ex) {
7462  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
7463  } finally {
7464  closeResultSet(rs2);
7465  closeStatement(s2);
7466  closeResultSet(rs1);
7467  closeStatement(s1);
7468  connection.close();
7470  }
7471  }
7472 
7484  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
7485  CaseDbConnection connection = connections.getConnection();
7487  Statement s = null;
7488  ResultSet rs = null;
7489  try {
7490  s = connection.createStatement();
7491  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
7492  + "where obj_id = " + id); //NON-NLS
7493  if (rs.next()) {
7494  long type = rs.getLong("vs_type"); //NON-NLS
7495  long imgOffset = rs.getLong("img_offset"); //NON-NLS
7496  long blockSize = rs.getLong("block_size"); //NON-NLS
7497  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
7498  vs.setParent(parent);
7499  return vs;
7500  } else {
7501  throw new TskCoreException("No volume system found for id:" + id);
7502  }
7503  } catch (SQLException ex) {
7504  throw new TskCoreException("Error getting Volume System by ID.", ex);
7505  } finally {
7506  closeResultSet(rs);
7507  closeStatement(s);
7508  connection.close();
7510  }
7511  }
7512 
7521  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
7522  VolumeSystem vs = getVolumeSystemById(id, null);
7523  vs.setParentId(parentId);
7524  return vs;
7525  }
7526 
7538  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
7539  return getFileSystemByIdHelper(id, parent);
7540  }
7541 
7550  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
7551  Volume vol = null;
7552  FileSystem fs = getFileSystemById(id, vol);
7553  fs.setParentId(parentId);
7554  return fs;
7555  }
7556 
7568  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
7569  return getFileSystemByIdHelper(id, parent);
7570  }
7571 
7583  Pool getPoolById(long id, Content parent) throws TskCoreException {
7584  return getPoolByIdHelper(id, parent);
7585  }
7586 
7595  Pool getPoolById(long id, long parentId) throws TskCoreException {
7596  Pool pool = getPoolById(id, null);
7597  pool.setParentId(parentId);
7598  return pool;
7599  }
7600 
7612  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
7613 
7615  try (CaseDbConnection connection = connections.getConnection();
7616  Statement s = connection.createStatement();
7617  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
7618  + "where obj_id = " + id);) { //NON-NLS
7619  if (rs.next()) {
7620  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
7621  pool.setParent(parent);
7622 
7623  return pool;
7624  } else {
7625  throw new TskCoreException("No pool found for ID:" + id);
7626  }
7627  } catch (SQLException ex) {
7628  throw new TskCoreException("Error getting Pool by ID", ex);
7629  } finally {
7631  }
7632  }
7633 
7645  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
7646  // see if we already have it
7647  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
7648  // but it should be the same...
7649  synchronized (fileSystemIdMap) {
7650  if (fileSystemIdMap.containsKey(id)) {
7651  return fileSystemIdMap.get(id);
7652  }
7653  }
7654  CaseDbConnection connection = connections.getConnection();
7656  Statement s = null;
7657  ResultSet rs = null;
7658  try {
7659  s = connection.createStatement();
7660  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
7661  + "where obj_id = " + id); //NON-NLS
7662  if (rs.next()) {
7663  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7664  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7665  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7666  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7667  fs.setParent(parent);
7668  // save it for the next call
7669  synchronized (fileSystemIdMap) {
7670  fileSystemIdMap.put(id, fs);
7671  }
7672  return fs;
7673  } else {
7674  throw new TskCoreException("No file system found for id:" + id);
7675  }
7676  } catch (SQLException ex) {
7677  throw new TskCoreException("Error getting File System by ID", ex);
7678  } finally {
7679  closeResultSet(rs);
7680  closeStatement(s);
7681  connection.close();
7683  }
7684  }
7685 
7697  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
7698  CaseDbConnection connection = connections.getConnection();
7700  Statement s = null;
7701  ResultSet rs = null;
7702  try {
7703  s = connection.createStatement();
7704  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
7705  + "where obj_id = " + id); //NON-NLS
7706  if (rs.next()) {
7714  String description;
7715  try {
7716  description = rs.getString("desc");
7717  } catch (Exception ex) {
7718  description = rs.getString("descr");
7719  }
7720  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
7721  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
7722  description);
7723  vol.setParent(parent);
7724  return vol;
7725  } else {
7726  throw new TskCoreException("No volume found for id:" + id);
7727  }
7728  } catch (SQLException ex) {
7729  throw new TskCoreException("Error getting Volume by ID", ex);
7730  } finally {
7731  closeResultSet(rs);
7732  closeStatement(s);
7733  connection.close();
7735  }
7736  }
7737 
7746  Volume getVolumeById(long id, long parentId) throws TskCoreException {
7747  Volume vol = getVolumeById(id, null);
7748  vol.setParentId(parentId);
7749  return vol;
7750  }
7751 
7763  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
7764  CaseDbConnection connection = connections.getConnection();
7766  Statement s = null;
7767  ResultSet rs = null;
7768  try {
7769  s = connection.createStatement();
7770  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
7771  + "WHERE obj_id = " + id);
7772  Directory temp = null; //NON-NLS
7773  if (rs.next()) {
7774  final short type = rs.getShort("type"); //NON-NLS
7775  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
7776  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
7777  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
7778  temp = directory(rs, parentFs);
7779  }
7780  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
7781  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
7782  }
7783  } else {
7784  throw new TskCoreException("No Directory found for id:" + id);
7785  }
7786  return temp;
7787  } catch (SQLException ex) {
7788  throw new TskCoreException("Error getting Directory by ID", ex);
7789  } finally {
7790  closeResultSet(rs);
7791  closeStatement(s);
7792  connection.close();
7794  }
7795  }
7796 
7804  public Collection<FileSystem> getFileSystems(Image image) {
7805  List<FileSystem> fileSystems = new ArrayList<FileSystem>();
7806  CaseDbConnection connection;
7807  try {
7808  connection = connections.getConnection();
7809  } catch (TskCoreException ex) {
7810  logger.log(Level.SEVERE, "Error getting file systems for image " + image.getId(), ex); //NON-NLS
7811  return fileSystems;
7812  }
7814  Statement s = null;
7815  ResultSet rs = null;
7816  try {
7817  s = connection.createStatement();
7818 
7819  // Get all the file systems.
7820  List<FileSystem> allFileSystems = new ArrayList<FileSystem>();
7821  try {
7822  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info"); //NON-NLS
7823  while (rs.next()) {
7824  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7825  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7826  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7827  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7828  fs.setParent(null);
7829  allFileSystems.add(fs);
7830  }
7831  } catch (SQLException ex) {
7832  logger.log(Level.SEVERE, "There was a problem while trying to obtain all file systems", ex); //NON-NLS
7833  } finally {
7834  closeResultSet(rs);
7835  rs = null;
7836  }
7837 
7838  // For each file system, find the image to which it belongs by iteratively
7839  // climbing the tsk_ojbects hierarchy only taking those file systems
7840  // that belong to this image.
7841  for (FileSystem fs : allFileSystems) {
7842  Long imageID = null;
7843  Long currentObjID = fs.getId();
7844  while (imageID == null) {
7845  try {
7846  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS
7847  rs.next();
7848  currentObjID = rs.getLong("par_obj_id"); //NON-NLS
7849  if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS
7850  imageID = rs.getLong("obj_id"); //NON-NLS
7851  }
7852  } catch (SQLException ex) {
7853  logger.log(Level.SEVERE, "There was a problem while trying to obtain this image's file systems", ex); //NON-NLS
7854  } finally {
7855  closeResultSet(rs);
7856  rs = null;
7857  }
7858  }
7859 
7860  // see if imageID is this image's ID
7861  if (imageID == image.getId()) {
7862  fileSystems.add(fs);
7863  }
7864  }
7865  } catch (SQLException ex) {
7866  logger.log(Level.SEVERE, "Error getting case database connection", ex); //NON-NLS
7867  } finally {
7868  closeResultSet(rs);
7869  closeStatement(s);
7870  connection.close();
7872  }
7873  return fileSystems;
7874  }
7875 
7886  List<Content> getImageChildren(Image img) throws TskCoreException {
7887  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
7888  List<Content> children = new ArrayList<Content>();
7889  for (ObjectInfo info : childInfos) {
7890  if (null != info.type) {
7891  switch (info.type) {
7892  case VS:
7893  children.add(getVolumeSystemById(info.id, img));
7894  break;
7895  case POOL:
7896  children.add(getPoolById(info.id, img));
7897  break;
7898  case FS:
7899  children.add(getFileSystemById(info.id, img));
7900  break;
7901  case ABSTRACTFILE:
7902  AbstractFile f = getAbstractFileById(info.id);
7903  if (f != null) {
7904  children.add(f);
7905  }
7906  break;
7907  case ARTIFACT:
7908  BlackboardArtifact art = getArtifactById(info.id);
7909  if (art != null) {
7910  children.add(art);
7911  }
7912  break;
7913  case REPORT:
7914  // Do nothing for now - see JIRA-3673
7915  break;
7916  default:
7917  throw new TskCoreException("Image has child of invalid type: " + info.type);
7918  }
7919  }
7920  }
7921  return children;
7922  }
7923 
7934  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
7935  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
7936  List<Long> children = new ArrayList<Long>();
7937  for (ObjectInfo info : childInfos) {
7938  if (info.type == ObjectType.VS
7939  || info.type == ObjectType.POOL
7940  || info.type == ObjectType.FS
7941  || info.type == ObjectType.ABSTRACTFILE
7942  || info.type == ObjectType.ARTIFACT) {
7943  children.add(info.id);
7944  } else if (info.type == ObjectType.REPORT) {
7945  // Do nothing for now - see JIRA-3673
7946  } else {
7947  throw new TskCoreException("Image has child of invalid type: " + info.type);
7948  }
7949  }
7950  return children;
7951  }
7952 
7963  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
7964  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
7965  List<Content> children = new ArrayList<Content>();
7966  for (ObjectInfo info : childInfos) {
7967  if (null != info.type) {
7968  switch (info.type) {
7969  case VS:
7970  children.add(getVolumeSystemById(info.id, pool));
7971  break;
7972  case ABSTRACTFILE:
7973  AbstractFile f = getAbstractFileById(info.id);
7974  if (f != null) {
7975  children.add(f);
7976  }
7977  break;
7978  case ARTIFACT:
7979  BlackboardArtifact art = getArtifactById(info.id);
7980  if (art != null) {
7981  children.add(art);
7982  }
7983  break;
7984  default:
7985  throw new TskCoreException("Pool has child of invalid type: " + info.type);
7986  }
7987  }
7988  }
7989  return children;
7990  }
7991 
8002  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
8003  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
8004  List<Long> children = new ArrayList<Long>();
8005  for (ObjectInfo info : childInfos) {
8006  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8007  children.add(info.id);
8008  } else {
8009  throw new TskCoreException("Pool has child of invalid type: " + info.type);
8010  }
8011  }
8012  return children;
8013  }
8014 
8025  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
8026  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
8027  List<Content> children = new ArrayList<Content>();
8028  for (ObjectInfo info : childInfos) {
8029  if (null != info.type) {
8030  switch (info.type) {
8031  case VOL:
8032  children.add(getVolumeById(info.id, vs));
8033  break;
8034  case ABSTRACTFILE:
8035  AbstractFile f = getAbstractFileById(info.id);
8036  if (f != null) {
8037  children.add(f);
8038  }
8039  break;
8040  case ARTIFACT:
8041  BlackboardArtifact art = getArtifactById(info.id);
8042  if (art != null) {
8043  children.add(art);
8044  }
8045  break;
8046  default:
8047  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8048  }
8049  }
8050  }
8051  return children;
8052  }
8053 
8064  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
8065  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
8066  List<Long> children = new ArrayList<Long>();
8067  for (ObjectInfo info : childInfos) {
8068  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8069  children.add(info.id);
8070  } else {
8071  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8072  }
8073  }
8074  return children;
8075  }
8076 
8087  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
8088  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8089  List<Content> children = new ArrayList<Content>();
8090  for (ObjectInfo info : childInfos) {
8091  if (null != info.type) {
8092  switch (info.type) {
8093  case POOL:
8094  children.add(getPoolById(info.id, vol));
8095  break;
8096  case FS:
8097  children.add(getFileSystemById(info.id, vol));
8098  break;
8099  case ABSTRACTFILE:
8100  AbstractFile f = getAbstractFileById(info.id);
8101  if (f != null) {
8102  children.add(f);
8103  }
8104  break;
8105  case ARTIFACT:
8106  BlackboardArtifact art = getArtifactById(info.id);
8107  if (art != null) {
8108  children.add(art);
8109  }
8110  break;
8111  default:
8112  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8113  }
8114  }
8115  }
8116  return children;
8117  }
8118 
8129  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
8130  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8131  final List<Long> children = new ArrayList<Long>();
8132  for (ObjectInfo info : childInfos) {
8133  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8134  children.add(info.id);
8135  } else {
8136  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8137  }
8138  }
8139  return children;
8140  }
8141 
8155  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
8156  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, this);
8157  return getImageById(imageId);
8158  }
8159 
8169  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
8170  CaseDbConnection connection = connections.getConnection();
8172  Statement s1 = null;
8173  Statement s2 = null;
8174  ResultSet rs1 = null;
8175  ResultSet rs2 = null;
8176  try {
8177  s1 = connection.createStatement();
8178  rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8179  s2 = connection.createStatement();
8180  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
8181  while (rs1.next()) {
8182  long obj_id = rs1.getLong("obj_id"); //NON-NLS
8183  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
8184  List<String> paths = new ArrayList<String>();
8185  while (rs2.next()) {
8186  paths.add(rs2.getString("name"));
8187  }
8188  rs2.close();
8189  rs2 = null;
8190  imgPaths.put(obj_id, paths);
8191  }
8192  return imgPaths;
8193  } catch (SQLException ex) {
8194  throw new TskCoreException("Error getting image paths.", ex);
8195  } finally {
8196  closeResultSet(rs2);
8197  closeStatement(s2);
8198  closeResultSet(rs1);
8199  closeStatement(s1);
8200  connection.close();
8202  }
8203  }
8204 
8215  private List<String> getImagePathsById(long objectId) throws TskCoreException {
8216  List<String> imagePaths = new ArrayList<String>();
8217  CaseDbConnection connection = connections.getConnection();
8219  Statement statement = null;
8220  ResultSet resultSet = null;
8221  try {
8222  statement = connection.createStatement();
8223  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
8224  while (resultSet.next()) {
8225  imagePaths.add(resultSet.getString("name"));
8226  }
8227  } catch (SQLException ex) {
8228  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
8229  } finally {
8230  closeResultSet(resultSet);
8231  closeStatement(statement);
8232  connection.close();
8234  }
8235 
8236  return imagePaths;
8237  }
8238 
8245  public List<Image> getImages() throws TskCoreException {
8246  CaseDbConnection connection = connections.getConnection();
8248  Statement s = null;
8249  ResultSet rs = null;
8250  try {
8251  s = connection.createStatement();
8252  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8253  Collection<Long> imageIDs = new ArrayList<Long>();
8254  while (rs.next()) {
8255  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
8256  }
8257  List<Image> images = new ArrayList<Image>();
8258  for (long id : imageIDs) {
8259  images.add(getImageById(id));
8260  }
8261  return images;
8262  } catch (SQLException ex) {
8263  throw new TskCoreException("Error retrieving images.", ex);
8264  } finally {
8265  closeResultSet(rs);
8266  closeStatement(s);
8267  connection.close();
8269  }
8270  }
8271 
8282  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
8283  CaseDbConnection connection = connections.getConnection();
8285  PreparedStatement statement = null;
8286  try {
8287  connection.beginTransaction();
8288  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
8289  statement.clearParameters();
8290  statement.setLong(1, obj_id);
8291  connection.executeUpdate(statement);
8292  for (int i = 0; i < paths.size(); i++) {
8293  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
8294  statement.clearParameters();
8295  statement.setLong(1, obj_id);
8296  statement.setString(2, paths.get(i));
8297  statement.setLong(3, i);
8298  connection.executeUpdate(statement);
8299  }
8300  connection.commitTransaction();
8301  } catch (SQLException ex) {
8302  connection.rollbackTransaction();
8303  throw new TskCoreException("Error updating image paths.", ex);
8304  } finally {
8305  connection.close();
8307  }
8308  }
8309 
8321  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
8322  CaseDbConnection connection = connections.getConnection();
8323  Statement statement = null;
8325  try {
8326  statement = connection.createStatement();
8327  connection.beginTransaction();
8328  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
8329  // all associated rows from tsk_object and its children. For large data sources this may take some time.
8330  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
8331  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
8332  // associated rows from accounts table and its children.
8333  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
8334  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
8335  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
8336  statement.execute(accountSql);
8337  connection.commitTransaction();
8338  } catch (SQLException ex) {
8339  connection.rollbackTransaction();
8340  throw new TskCoreException("Error deleting data source.", ex);
8341  } finally {
8342  connection.close();
8344  }
8345  }
8346 
8372  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
8373  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
8374  try {
8375  while (rs.next()) {
8376  final short type = rs.getShort("type"); //NON-NLS
8377  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
8378  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
8379  FsContent result;
8380  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
8381  result = directory(rs, null);
8382  } else {
8383  result = file(rs, null);
8384  }
8385  results.add(result);
8386  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
8387  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
8388  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
8389  results.add(virtDir);
8390  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
8391  final LocalDirectory localDir = localDirectory(rs);
8392  results.add(localDir);
8393  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
8394  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
8395  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
8396  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
8397  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
8398  String parentPath = rs.getString("parent_path"); //NON-NLS
8399  if (parentPath == null) {
8400  parentPath = "/"; //NON-NLS
8401  }
8402  LayoutFile lf = new LayoutFile(this,
8403  rs.getLong("obj_id"), //NON-NLS
8404  rs.getLong("data_source_obj_id"),
8405  rs.getString("name"), //NON-NLS
8406  atype,
8407  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8408  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8409  rs.getLong("size"), //NON-NLS
8410  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8411  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS
8412  results.add(lf);
8413  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
8414  final DerivedFile df;
8415  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
8416  results.add(df);
8417  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
8418  final LocalFile lf;
8419  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
8420  results.add(lf);
8421  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
8422  final SlackFile sf = slackFile(rs, null);
8423  results.add(sf);
8424  }
8425  } //end for each resultSet
8426  } catch (SQLException e) {
8427  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
8428  }
8429 
8430  return results;
8431  }
8432 
8433  // This following methods generate AbstractFile objects from a ResultSet
8445  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
8446  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
8447  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8448  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8449  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8450  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8451  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8452  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8453  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8454  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8455  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8456  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8457  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8458  f.setFileSystem(fs);
8459  return f;
8460  }
8461 
8473  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
8474  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8475  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8476  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8477  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8478  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8479  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8480  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8481  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8482  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8483  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8484  rs.getString("parent_path")); //NON-NLS
8485  dir.setFileSystem(fs);
8486  return dir;
8487  }
8488 
8499  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
8500  String parentPath = rs.getString("parent_path"); //NON-NLS
8501  if (parentPath == null) {
8502  parentPath = "";
8503  }
8504 
8505  long objId = rs.getLong("obj_id");
8506  long dsObjId = rs.getLong("data_source_obj_id");
8507  if (objId == dsObjId) { // virtual directory is a data source
8508 
8509  String deviceId = "";
8510  String timeZone = "";
8511  Statement s = null;
8512  ResultSet rsDataSourceInfo = null;
8513 
8515  try {
8516  s = connection.createStatement();
8517  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
8518  if (rsDataSourceInfo.next()) {
8519  deviceId = rsDataSourceInfo.getString("device_id");
8520  timeZone = rsDataSourceInfo.getString("time_zone");
8521  }
8522  } catch (SQLException ex) {
8523  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
8524  } finally {
8525  closeResultSet(rsDataSourceInfo);
8526  closeStatement(s);
8528  }
8529 
8530  return new LocalFilesDataSource(this,
8531  objId, dsObjId,
8532  deviceId,
8533  rs.getString("name"),
8534  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8535  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8536  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
8537  rs.getShort("meta_flags"),
8538  timeZone,
8539  rs.getString("md5"),
8540  FileKnown.valueOf(rs.getByte("known")),
8541  parentPath);
8542  } else {
8543  final VirtualDirectory vd = new VirtualDirectory(this,
8544  objId, dsObjId,
8545  rs.getString("name"), //NON-NLS
8546  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8547  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8548  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8549  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8550  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8551  return vd;
8552  }
8553  }
8554 
8564  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
8565  String parentPath = rs.getString("parent_path"); //NON-NLS
8566  if (parentPath == null) {
8567  parentPath = "";
8568  }
8569  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
8570  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
8571  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8572  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8573  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8574  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8575  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8576  return ld;
8577  }
8578 
8592  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8593  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
8594  long objId = rs.getLong("obj_id"); //NON-NLS
8595  String localPath = null;
8596  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8597  if (hasLocalPath) {
8598  ResultSet rsFilePath = null;
8600  try {
8601  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8602  statement.clearParameters();
8603  statement.setLong(1, objId);
8604  rsFilePath = connection.executeQuery(statement);
8605  if (rsFilePath.next()) {
8606  localPath = rsFilePath.getString("path");
8607  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8608  }
8609  } catch (SQLException ex) {
8610  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8611  } finally {
8612  closeResultSet(rsFilePath);
8614  }
8615  }
8616  String parentPath = rs.getString("parent_path"); //NON-NLS
8617  if (parentPath == null) {
8618  parentPath = "";
8619  }
8620  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
8621  rs.getString("name"), //NON-NLS
8622  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8623  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8624  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8625  rs.getLong("size"), //NON-NLS
8626  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8627  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8628  parentPath, localPath, parentId, rs.getString("mime_type"),
8629  encodingType, rs.getString("extension"));
8630  return df;
8631  }
8632 
8646  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8647  long objId = rs.getLong("obj_id"); //NON-NLS
8648  String localPath = null;
8649  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8650  if (rs.getBoolean("has_path")) {
8651  ResultSet rsFilePath = null;
8653  try {
8654  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8655  statement.clearParameters();
8656  statement.setLong(1, objId);
8657  rsFilePath = connection.executeQuery(statement);
8658  if (rsFilePath.next()) {
8659  localPath = rsFilePath.getString("path");
8660  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8661  }
8662  } catch (SQLException ex) {
8663  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8664  } finally {
8665  closeResultSet(rsFilePath);
8667  }
8668  }
8669  String parentPath = rs.getString("parent_path"); //NON-NLS
8670  if (null == parentPath) {
8671  parentPath = "";
8672  }
8673  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
8674  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
8675  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8676  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8677  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8678  rs.getLong("size"), //NON-NLS
8679  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8680  rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8681  parentId, parentPath, rs.getLong("data_source_obj_id"),
8682  localPath, encodingType, rs.getString("extension"));
8683  return file;
8684  }
8685 
8697  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
8698  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
8699  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8700  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8701  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8702  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8703  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8704  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8705  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8706  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8707  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8708  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8709  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8710  f.setFileSystem(fs);
8711  return f;
8712  }
8713 
8725  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8726  List<Content> children = new ArrayList<Content>();
8727 
8728  while (rs.next()) {
8729  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
8730 
8731  if (null != type) {
8732  switch (type) {
8733  case FS:
8734  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
8735  FsContent result;
8736  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
8737  result = directory(rs, null);
8738  } else {
8739  result = file(rs, null);
8740  }
8741  children.add(result);
8742  } else {
8743  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8744  children.add(virtDir);
8745  }
8746  break;
8747  case VIRTUAL_DIR:
8748  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8749  children.add(virtDir);
8750  break;
8751  case LOCAL_DIR:
8752  LocalDirectory localDir = localDirectory(rs);
8753  children.add(localDir);
8754  break;
8755  case UNALLOC_BLOCKS:
8756  case UNUSED_BLOCKS:
8757  case CARVED:
8758  case LAYOUT_FILE: {
8759  String parentPath = rs.getString("parent_path");
8760  if (parentPath == null) {
8761  parentPath = "";
8762  }
8763  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
8764  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
8765  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
8766  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
8767  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
8768  rs.getLong("size"),
8769  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
8770  rs.getString("md5"),
8771  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"));
8772  children.add(lf);
8773  break;
8774  }
8775  case DERIVED:
8776  final DerivedFile df = derivedFile(rs, connection, parentId);
8777  children.add(df);
8778  break;
8779  case LOCAL: {
8780  final LocalFile lf = localFile(rs, connection, parentId);
8781  children.add(lf);
8782  break;
8783  }
8784  case SLACK: {
8785  final SlackFile sf = slackFile(rs, null);
8786  children.add(sf);
8787  break;
8788  }
8789  default:
8790  break;
8791  }
8792  }
8793  }
8794  return children;
8795  }
8796 
8812  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException, TskCoreException {
8813  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
8814  try {
8815  while (rs.next()) {
8816  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
8817  if (artifactType != null) {
8818  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
8819  rs.getInt("artifact_type_id"), artifactType.getTypeName(), artifactType.getDisplayName(),
8820  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
8821  } else {
8822  throw new TskCoreException("Error looking up artifact type ID " + rs.getInt("artifact_type_id") + " from artifact " + rs.getLong("artifact_id"));
8823  }
8824  } //end for each resultSet
8825  } catch (SQLException e) {
8826  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
8827  }
8828 
8829  return artifacts;
8830  }
8831 
8853  public CaseDbQuery executeQuery(String query) throws TskCoreException {
8854  return new CaseDbQuery(query);
8855  }
8856 
8878  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
8879  return new CaseDbQuery(query, true);
8880  }
8881 
8889  CaseDbConnection getConnection() throws TskCoreException {
8890  return connections.getConnection();
8891  }
8892 
8893  synchronized long getCaseDbPointer() throws TskCoreException {
8894  if (caseHandle != null) {
8895  return caseHandle.getCaseDbPointer();
8896  }
8897  throw new TskCoreException("Case has been closed");
8898  }
8899 
8900  @Override
8901  protected void finalize() throws Throwable {
8902  try {
8903  close();
8904  } finally {
8905  super.finalize();
8906  }
8907  }
8908 
8912  public synchronized void close() {
8914 
8915  try {
8916  connections.close();
8917  } catch (TskCoreException ex) {
8918  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
8919  }
8920 
8921  fileSystemIdMap.clear();
8922 
8923  try {
8924  if (this.caseHandle != null) {
8925  this.caseHandle.free();
8926  this.caseHandle = null;
8927  }
8928  } catch (TskCoreException ex) {
8929  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
8930  } finally {
8932  }
8933  }
8934 
8947  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
8948  long id = file.getId();
8949  FileKnown currentKnown = file.getKnown();
8950  if (currentKnown.compareTo(fileKnown) > 0) {
8951  return false;
8952  }
8953  CaseDbConnection connection = connections.getConnection();
8955  Statement statement = null;
8956  try {
8957  statement = connection.createStatement();
8958  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
8959  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
8960  + "WHERE obj_id=" + id); //NON-NLS
8961 
8962  file.setKnown(fileKnown);
8963  } catch (SQLException ex) {
8964  throw new TskCoreException("Error setting Known status.", ex);
8965  } finally {
8966  closeStatement(statement);
8967  connection.close();
8969  }
8970  return true;
8971  }
8972 
8981  void setFileName(String name, long objId) throws TskCoreException {
8982 
8983  CaseDbConnection connection = connections.getConnection();
8985  try {
8986  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
8987  preparedStatement.clearParameters();
8988  preparedStatement.setString(1, name);
8989  preparedStatement.setLong(2, objId);
8990  connection.executeUpdate(preparedStatement);
8991  } catch (SQLException ex) {
8992  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
8993  } finally {
8994  connection.close();
8996  }
8997  }
8998 
9007  void setImageName(String name, long objId) throws TskCoreException {
9008 
9009  CaseDbConnection connection = connections.getConnection();
9011  try {
9012  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
9013  preparedStatement.clearParameters();
9014  preparedStatement.setString(1, name);
9015  preparedStatement.setLong(2, objId);
9016  connection.executeUpdate(preparedStatement);
9017  } catch (SQLException ex) {
9018  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
9019  } finally {
9020  connection.close();
9022  }
9023  }
9024 
9034  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
9035  CaseDbConnection connection = connections.getConnection();
9036  Statement statement = null;
9037  ResultSet rs = null;
9039  try {
9040  statement = connection.createStatement();
9041  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
9042  file.setMIMEType(mimeType);
9043  } catch (SQLException ex) {
9044  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
9045  } finally {
9046  closeResultSet(rs);
9047  closeStatement(statement);
9048  connection.close();
9050  }
9051  }
9052 
9062  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
9063  if (md5Hash == null) {
9064  return;
9065  }
9066  long id = file.getId();
9067  CaseDbConnection connection = connections.getConnection();
9069  try {
9070  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
9071  statement.clearParameters();
9072  statement.setString(1, md5Hash.toLowerCase());
9073  statement.setLong(2, id);
9074  connection.executeUpdate(statement);
9075  file.setMd5Hash(md5Hash.toLowerCase());
9076  } catch (SQLException ex) {
9077  throw new TskCoreException("Error setting MD5 hash", ex);
9078  } finally {
9079  connection.close();
9081  }
9082  }
9083 
9093  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
9094  if (md5Hash == null) {
9095  return;
9096  }
9097  long id = img.getId();
9098  CaseDbConnection connection = connections.getConnection();
9100  try {
9101  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
9102  statement.clearParameters();
9103  statement.setString(1, md5Hash.toLowerCase());
9104  statement.setLong(2, id);
9105  connection.executeUpdate(statement);
9106  } catch (SQLException ex) {
9107  throw new TskCoreException("Error setting MD5 hash", ex);
9108  } finally {
9109  connection.close();
9111  }
9112  }
9113 
9124  String getMd5ImageHash(Image img) throws TskCoreException {
9125  long id = img.getId();
9126  CaseDbConnection connection = connections.getConnection();
9128  ResultSet rs = null;
9129  String hash = "";
9130  try {
9131  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
9132  statement.clearParameters();
9133  statement.setLong(1, id);
9134  rs = connection.executeQuery(statement);
9135  if (rs.next()) {
9136  hash = rs.getString("md5");
9137  }
9138  return hash;
9139  } catch (SQLException ex) {
9140  throw new TskCoreException("Error getting MD5 hash", ex);
9141  } finally {
9142  closeResultSet(rs);
9143  connection.close();
9145  }
9146  }
9147 
9157  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
9158  if (sha1Hash == null) {
9159  return;
9160  }
9161  long id = img.getId();
9162  CaseDbConnection connection = connections.getConnection();
9164  try {
9165  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
9166  statement.clearParameters();
9167  statement.setString(1, sha1Hash.toLowerCase());
9168  statement.setLong(2, id);
9169  connection.executeUpdate(statement);
9170  } catch (SQLException ex) {
9171  throw new TskCoreException("Error setting SHA1 hash", ex);
9172  } finally {
9173  connection.close();
9175  }
9176  }
9177 
9188  String getSha1ImageHash(Image img) throws TskCoreException {
9189  long id = img.getId();
9190  CaseDbConnection connection = connections.getConnection();
9192  ResultSet rs = null;
9193  String hash = "";
9194  try {
9195  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
9196  statement.clearParameters();
9197  statement.setLong(1, id);
9198  rs = connection.executeQuery(statement);
9199  if (rs.next()) {
9200  hash = rs.getString("sha1");
9201  }
9202  return hash;
9203  } catch (SQLException ex) {
9204  throw new TskCoreException("Error getting SHA1 hash", ex);
9205  } finally {
9206  closeResultSet(rs);
9207  connection.close();
9209  }
9210  }
9211 
9221  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
9222  if (sha256Hash == null) {
9223  return;
9224  }
9225  long id = img.getId();
9226  CaseDbConnection connection = connections.getConnection();
9228  try {
9229  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
9230  statement.clearParameters();
9231  statement.setString(1, sha256Hash.toLowerCase());
9232  statement.setLong(2, id);
9233  connection.executeUpdate(statement);
9234  } catch (SQLException ex) {
9235  throw new TskCoreException("Error setting SHA256 hash", ex);
9236  } finally {
9237  connection.close();
9239  }
9240  }
9241 
9252  String getSha256ImageHash(Image img) throws TskCoreException {
9253  long id = img.getId();
9254  CaseDbConnection connection = connections.getConnection();
9256  ResultSet rs = null;
9257  String hash = "";
9258  try {
9259  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
9260  statement.clearParameters();
9261  statement.setLong(1, id);
9262  rs = connection.executeQuery(statement);
9263  if (rs.next()) {
9264  hash = rs.getString("sha256");
9265  }
9266  return hash;
9267  } catch (SQLException ex) {
9268  throw new TskCoreException("Error setting SHA256 hash", ex);
9269  } finally {
9270  closeResultSet(rs);
9271  connection.close();
9273  }
9274  }
9275 
9284  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
9285 
9286  long id = datasource.getId();
9287  CaseDbConnection connection = connections.getConnection();
9289  try {
9290  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
9291  statement.clearParameters();
9292  statement.setString(1, details);
9293  statement.setLong(2, id);
9294  connection.executeUpdate(statement);
9295  } catch (SQLException ex) {
9296  throw new TskCoreException("Error setting acquisition details", ex);
9297  } finally {
9298  connection.close();
9300  }
9301  }
9302 
9312  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
9313  long id = datasource.getId();
9314  CaseDbConnection connection = connections.getConnection();
9316  ResultSet rs = null;
9317  String hash = "";
9318  try {
9319  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
9320  statement.clearParameters();
9321  statement.setLong(1, id);
9322  rs = connection.executeQuery(statement);
9323  if (rs.next()) {
9324  hash = rs.getString("acquisition_details");
9325  }
9326  return hash;
9327  } catch (SQLException ex) {
9328  throw new TskCoreException("Error setting acquisition details", ex);
9329  } finally {
9330  closeResultSet(rs);
9331  connection.close();
9333  }
9334  }
9335 
9346  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
9347  if (newStatus == null) {
9348  return;
9349  }
9350  CaseDbConnection connection = connections.getConnection();
9352  Statement statement = null;
9353  try {
9354  statement = connection.createStatement();
9355  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
9356  + " SET review_status_id=" + newStatus.getID()
9357  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
9358  } catch (SQLException ex) {
9359  throw new TskCoreException("Error setting review status", ex);
9360  } finally {
9361  closeStatement(statement);
9362  connection.close();
9364  }
9365  }
9366 
9377  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
9378  CaseDbConnection connection = connections.getConnection();
9380  Statement s = null;
9381  ResultSet rs = null;
9382  try {
9383  s = connection.createStatement();
9384  Short contentShort = contentType.getValue();
9385  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
9386  int count = 0;
9387  if (rs.next()) {
9388  count = rs.getInt("count");
9389  }
9390  return count;
9391  } catch (SQLException ex) {
9392  throw new TskCoreException("Error getting number of objects.", ex);
9393  } finally {
9394  closeResultSet(rs);
9395  closeStatement(s);
9396  connection.close();
9398  }
9399  }
9400 
9409  public static String escapeSingleQuotes(String text) {
9410  String escapedText = null;
9411  if (text != null) {
9412  escapedText = text.replaceAll("'", "''");
9413  }
9414  return escapedText;
9415  }
9416 
9424  public List<AbstractFile> findFilesByMd5(String md5Hash) {
9425  if (md5Hash == null) {
9426  return Collections.<AbstractFile>emptyList();
9427  }
9428  CaseDbConnection connection;
9429  try {
9430  connection = connections.getConnection();
9431  } catch (TskCoreException ex) {
9432  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
9433  return Collections.<AbstractFile>emptyList();
9434  }
9436  Statement s = null;
9437  ResultSet rs = null;
9438  try {
9439  s = connection.createStatement();
9440  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
9441  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
9442  + "AND size > 0"); //NON-NLS
9443  return resultSetToAbstractFiles(rs, connection);
9444  } catch (SQLException ex) {
9445  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
9446  return Collections.<AbstractFile>emptyList();
9447  } finally {
9448  closeResultSet(rs);
9449  closeStatement(s);
9450  connection.close();
9452  }
9453  }
9454 
9461  public boolean allFilesMd5Hashed() {
9462  CaseDbConnection connection;
9463  try {
9464  connection = connections.getConnection();
9465  } catch (TskCoreException ex) {
9466  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
9467  return false;
9468  }
9469  boolean allFilesAreHashed = false;
9471  Statement s = null;
9472  ResultSet rs = null;
9473  try {
9474  s = connection.createStatement();
9475  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9476  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
9477  + "AND md5 IS NULL " //NON-NLS
9478  + "AND size > '0'"); //NON-NLS
9479  if (rs.next() && rs.getInt("count") == 0) {
9480  allFilesAreHashed = true;
9481  }
9482  } catch (SQLException ex) {
9483  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
9484  } finally {
9485  closeResultSet(rs);
9486  closeStatement(s);
9487  connection.close();
9489  }
9490  return allFilesAreHashed;
9491  }
9492 
9498  public int countFilesMd5Hashed() {
9499  CaseDbConnection connection;
9500  try {
9501  connection = connections.getConnection();
9502  } catch (TskCoreException ex) {
9503  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
9504  return 0;
9505  }
9506  int count = 0;
9508  Statement s = null;
9509  ResultSet rs = null;
9510  try {
9511  s = connection.createStatement();
9512  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9513  + "WHERE md5 IS NOT NULL " //NON-NLS
9514  + "AND size > '0'"); //NON-NLS
9515  if (rs.next()) {
9516  count = rs.getInt("count");
9517  }
9518  } catch (SQLException ex) {
9519  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
9520  } finally {
9521  closeResultSet(rs);
9522  closeStatement(s);
9523  connection.close();
9525  }
9526  return count;
9527 
9528  }
9529 
9538  public List<TagName> getAllTagNames() throws TskCoreException {
9539  CaseDbConnection connection = connections.getConnection();
9541  ResultSet resultSet = null;
9542  try {
9543  // SELECT * FROM tag_names
9544  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
9545  resultSet = connection.executeQuery(statement);
9546  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9547  while (resultSet.next()) {
9548  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9549  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9550  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9551  }
9552  return tagNames;
9553  } catch (SQLException ex) {
9554  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9555  } finally {
9556  closeResultSet(resultSet);
9557  connection.close();
9559  }
9560  }
9561 
9572  public List<TagName> getTagNamesInUse() throws TskCoreException {
9573  CaseDbConnection connection = connections.getConnection();
9575  ResultSet resultSet = null;
9576  try {
9577  // 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)
9578  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
9579  resultSet = connection.executeQuery(statement);
9580  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9581  while (resultSet.next()) {
9582  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9583  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9584  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9585  }
9586  return tagNames;
9587  } catch (SQLException ex) {
9588  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9589  } finally {
9590  closeResultSet(resultSet);
9591  connection.close();
9593  }
9594  }
9595 
9608  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
9609 
9610  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9611  // SELECT * FROM tag_names WHERE tag_name_id IN
9612  // ( 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 = ? "
9613  // UNION
9614  // 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 = ? )
9615  // )
9616  CaseDbConnection connection = connections.getConnection();
9618  ResultSet resultSet = null;
9619 
9620  try {
9621  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
9622  statement.setLong(1, dsObjId);
9623  statement.setLong(2, dsObjId);
9624  resultSet = connection.executeQuery(statement); //NON-NLS
9625  while (resultSet.next()) {
9626  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9627  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9628  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS
9629  }
9630  return tagNames;
9631  } catch (SQLException ex) {
9632  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
9633  } finally {
9634  closeResultSet(resultSet);
9635  connection.close();
9637  }
9638  }
9639 
9653  @Deprecated
9654  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
9655  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
9656  }
9657 
9672  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
9673  CaseDbConnection connection = connections.getConnection();
9675  ResultSet resultSet = null;
9676  try {
9677  PreparedStatement statement;
9678  // INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?
9679  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME, Statement.RETURN_GENERATED_KEYS);
9680  statement.clearParameters();
9681  statement.setString(5, description);
9682  statement.setString(6, color.getName());
9683  statement.setByte(7, knownStatus.getFileKnownValue());
9684  statement.setString(1, displayName);
9685  statement.setString(2, description);
9686  statement.setString(3, color.getName());
9687  statement.setByte(4, knownStatus.getFileKnownValue());
9688  connection.executeUpdate(statement);
9689  resultSet = statement.getGeneratedKeys();
9690  resultSet.next();
9691  return new TagName(resultSet.getLong(1), //last_insert_rowid()
9692  displayName, description, color, knownStatus);
9693  } catch (SQLException ex) {
9694  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
9695  } finally {
9696  closeResultSet(resultSet);
9697  connection.close();
9699  }
9700  }
9701 
9715  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
9716  CaseDbConnection connection = connections.getConnection();
9718  ResultSet resultSet = null;
9719  try {
9720  Examiner currentExaminer = getCurrentExaminer();
9721  // INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)
9722  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_CONTENT_TAG, Statement.RETURN_GENERATED_KEYS);
9723  statement.clearParameters();
9724  statement.setLong(1, content.getId());
9725  statement.setLong(2, tagName.getId());
9726  statement.setString(3, comment);
9727  statement.setLong(4, beginByteOffset);
9728  statement.setLong(5, endByteOffset);
9729  statement.setLong(6, currentExaminer.getId());
9730  connection.executeUpdate(statement);
9731  resultSet = statement.getGeneratedKeys();
9732  resultSet.next();
9733  return new ContentTag(resultSet.getLong(1), //last_insert_rowid()
9734  content, tagName, comment, beginByteOffset, endByteOffset, currentExaminer.getLoginName());
9735  } catch (SQLException ex) {
9736  throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex);
9737  } finally {
9738  closeResultSet(resultSet);
9739  connection.close();
9741  }
9742  }
9743 
9744  /*
9745  * Deletes a row from the content_tags table in the case database. @param
9746  * tag A ContentTag data transfer object (DTO) for the row to delete.
9747  * @throws TskCoreException
9748  */
9749  public void deleteContentTag(ContentTag tag) throws TskCoreException {
9750  CaseDbConnection connection = connections.getConnection();
9752  try {
9753  // DELETE FROM content_tags WHERE tag_id = ?
9754  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
9755  statement.clearParameters();
9756  statement.setLong(1, tag.getId());
9757  connection.executeUpdate(statement);
9758  } catch (SQLException ex) {
9759  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
9760  } finally {
9761  connection.close();
9763  }
9764  }
9765 
9774  public List<ContentTag> getAllContentTags() throws TskCoreException {
9775  CaseDbConnection connection = connections.getConnection();
9777  ResultSet resultSet = null;
9778  try {
9779  // 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
9780  // FROM content_tags
9781  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
9782  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9783  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
9784  resultSet = connection.executeQuery(statement);
9785  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9786  while (resultSet.next()) {
9787  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9788  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9789  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
9790  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
9791  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
9792  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
9793  }
9794  return tags;
9795  } catch (SQLException ex) {
9796  throw new TskCoreException("Error selecting rows from content_tags table", ex);
9797  } finally {
9798  closeResultSet(resultSet);
9799  connection.close();
9801  }
9802  }
9803 
9814  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
9815  if (tagName.getId() == Tag.ID_NOT_SET) {
9816  throw new TskCoreException("TagName object is invalid, id not set");
9817  }
9818  CaseDbConnection connection = connections.getConnection();
9820  ResultSet resultSet = null;
9821  try {
9822  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
9823  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
9824  statement.clearParameters();
9825  statement.setLong(1, tagName.getId());
9826  resultSet = connection.executeQuery(statement);
9827  if (resultSet.next()) {
9828  return resultSet.getLong("count");
9829  } else {
9830  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
9831  }
9832  } catch (SQLException ex) {
9833  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
9834  } finally {
9835  closeResultSet(resultSet);
9836  connection.close();
9838  }
9839  }
9840 
9856  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
9857 
9858  if (tagName.getId() == Tag.ID_NOT_SET) {
9859  throw new TskCoreException("TagName object is invalid, id not set");
9860  }
9861 
9862  CaseDbConnection connection = connections.getConnection();
9864  ResultSet resultSet = null;
9865  try {
9866  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
9867  // + " AND content_tags.tag_name_id = ? "
9868  // + " AND tsk_files.data_source_obj_id = ? "
9869  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
9870  statement.clearParameters();
9871  statement.setLong(1, tagName.getId());
9872  statement.setLong(2, dsObjId);
9873 
9874  resultSet = connection.executeQuery(statement);
9875  if (resultSet.next()) {
9876  return resultSet.getLong("count");
9877  } else {
9878  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
9879  }
9880  } catch (SQLException ex) {
9881  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
9882  } finally {
9883  closeResultSet(resultSet);
9884  connection.close();
9886  }
9887  }
9888 
9899  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
9900 
9901  CaseDbConnection connection = connections.getConnection();
9903  ResultSet resultSet = null;
9904  ContentTag tag = null;
9905  try {
9906  // 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
9907  // FROM content_tags
9908  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
9909  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9910  // WHERE tag_id = ?
9911  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
9912  statement.clearParameters();
9913  statement.setLong(1, contentTagID);
9914  resultSet = connection.executeQuery(statement);
9915 
9916  while (resultSet.next()) {
9917  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9918  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9919  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
9920  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
9921  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
9922  }
9923  resultSet.close();
9924 
9925  } catch (SQLException ex) {
9926  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
9927  } finally {
9928  closeResultSet(resultSet);
9929  connection.close();
9931  }
9932  return tag;
9933  }
9934 
9946  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
9947  if (tagName.getId() == Tag.ID_NOT_SET) {
9948  throw new TskCoreException("TagName object is invalid, id not set");
9949  }
9950  CaseDbConnection connection = connections.getConnection();
9952  ResultSet resultSet = null;
9953  try {
9954  // 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
9955  // FROM content_tags
9956  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9957  // WHERE tag_name_id = ?
9958  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
9959  statement.clearParameters();
9960  statement.setLong(1, tagName.getId());
9961  resultSet = connection.executeQuery(statement);
9962  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9963  while (resultSet.next()) {
9964  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
9965  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
9966  tags.add(tag);
9967  }
9968  resultSet.close();
9969  return tags;
9970  } catch (SQLException ex) {
9971  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
9972  } finally {
9973  closeResultSet(resultSet);
9974  connection.close();
9976  }
9977  }
9978 
9991  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
9992 
9993  CaseDbConnection connection = connections.getConnection();
9995  ResultSet resultSet = null;
9996  try {
9997 
9998  // 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
9999  // FROM content_tags as content_tags, tsk_files as tsk_files
10000  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10001  // WHERE content_tags.obj_id = tsk_files.obj_id
10002  // AND content_tags.tag_name_id = ?
10003  // AND tsk_files.data_source_obj_id = ?
10004  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10005  statement.clearParameters();
10006  statement.setLong(1, tagName.getId());
10007  statement.setLong(2, dsObjId);
10008  resultSet = connection.executeQuery(statement);
10009  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10010  while (resultSet.next()) {
10011  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
10012  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10013  tags.add(tag);
10014  }
10015  resultSet.close();
10016  return tags;
10017  } catch (SQLException ex) {
10018  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
10019  } finally {
10020  closeResultSet(resultSet);
10021  connection.close();
10023  }
10024  }
10025 
10037  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
10038  CaseDbConnection connection = connections.getConnection();
10040  ResultSet resultSet = null;
10041  try {
10042  // 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
10043  // FROM content_tags
10044  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
10045  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10046  // WHERE content_tags.obj_id = ?
10047  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
10048  statement.clearParameters();
10049  statement.setLong(1, content.getId());
10050  resultSet = connection.executeQuery(statement);
10051  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10052  while (resultSet.next()) {
10053  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10054  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10055  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10056  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
10057  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10058  tags.add(tag);
10059  }
10060  return tags;
10061  } catch (SQLException ex) {
10062  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
10063  } finally {
10064  closeResultSet(resultSet);
10065  connection.close();
10067  }
10068  }
10069 
10083  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
10084  CaseDbConnection connection = connections.getConnection();
10086  ResultSet resultSet = null;
10087  try {
10088  Examiner currentExaminer = getCurrentExaminer();
10089  // "INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) VALUES (?, ?, ?, ?)"), //NON-NLS
10090  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT_TAG, Statement.RETURN_GENERATED_KEYS);
10091  statement.clearParameters();
10092  statement.setLong(1, artifact.getArtifactID());
10093  statement.setLong(2, tagName.getId());
10094  statement.setString(3, comment);
10095  statement.setLong(4, currentExaminer.getId());
10096  connection.executeUpdate(statement);
10097  resultSet = statement.getGeneratedKeys();
10098  resultSet.next();
10099  return new BlackboardArtifactTag(resultSet.getLong(1), //last_insert_rowid()
10100  artifact, getContentById(artifact.getObjectID()), tagName, comment, currentExaminer.getLoginName());
10101  } catch (SQLException ex) {
10102  throw new TskCoreException("Error adding row to blackboard_artifact_tags table (obj_id = " + artifact.getArtifactID() + ", tag_name_id = " + tagName.getId() + ")", ex);
10103  } finally {
10104  closeResultSet(resultSet);
10105  connection.close();
10107  }
10108  }
10109 
10110  /*
10111  * Deletes a row from the blackboard_artifact_tags table in the case
10112  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
10113  * representing the row to delete. @throws TskCoreException
10114  */
10115  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
10116  CaseDbConnection connection = connections.getConnection();
10118  try {
10119  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
10120  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
10121  statement.clearParameters();
10122  statement.setLong(1, tag.getId());
10123  connection.executeUpdate(statement);
10124  } catch (SQLException ex) {
10125  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
10126  } finally {
10127  connection.close();
10129  }
10130  }
10131 
10141  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
10142  CaseDbConnection connection = connections.getConnection();
10144  ResultSet resultSet = null;
10145  try {
10146  // 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
10147  // FROM blackboard_artifact_tags
10148  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10149  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10150  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
10151  resultSet = connection.executeQuery(statement);
10152  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10153  while (resultSet.next()) {
10154  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10155  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10156  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10157  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10158  Content content = getContentById(artifact.getObjectID());
10159  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10160  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10161  tags.add(tag);
10162  }
10163  return tags;
10164  } catch (SQLException ex) {
10165  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
10166  } finally {
10167  closeResultSet(resultSet);
10168  connection.close();
10170  }
10171  }
10172 
10183  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
10184  if (tagName.getId() == Tag.ID_NOT_SET) {
10185  throw new TskCoreException("TagName object is invalid, id not set");
10186  }
10187  CaseDbConnection connection = connections.getConnection();
10189  ResultSet resultSet = null;
10190  try {
10191  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
10192  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
10193  statement.clearParameters();
10194  statement.setLong(1, tagName.getId());
10195  resultSet = connection.executeQuery(statement);
10196  if (resultSet.next()) {
10197  return resultSet.getLong("count");
10198  } else {
10199  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
10200  }
10201  } catch (SQLException ex) {
10202  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
10203  } finally {
10204  closeResultSet(resultSet);
10205  connection.close();
10207  }
10208  }
10209 
10224  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10225 
10226  if (tagName.getId() == Tag.ID_NOT_SET) {
10227  throw new TskCoreException("TagName object is invalid, id not set");
10228  }
10229 
10230  CaseDbConnection connection = connections.getConnection();
10232  ResultSet resultSet = null;
10233  try {
10234  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
10235  // + " AND artifact_tags.tag_name_id = ?"
10236  // + " AND arts.data_source_obj_id = ? "
10237  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
10238  statement.clearParameters();
10239  statement.setLong(1, tagName.getId());
10240  statement.setLong(2, dsObjId);
10241  resultSet = connection.executeQuery(statement);
10242  if (resultSet.next()) {
10243  return resultSet.getLong("count");
10244  } else {
10245  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
10246  }
10247  } catch (SQLException ex) {
10248  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10249  } finally {
10250  closeResultSet(resultSet);
10251  connection.close();
10253  }
10254  }
10255 
10267  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
10268  if (tagName.getId() == Tag.ID_NOT_SET) {
10269  throw new TskCoreException("TagName object is invalid, id not set");
10270  }
10271  CaseDbConnection connection = connections.getConnection();
10273  ResultSet resultSet = null;
10274  try {
10275  // 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
10276  // FROM blackboard_artifact_tags
10277  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10278  // WHERE tag_name_id = ?
10279  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
10280  statement.clearParameters();
10281  statement.setLong(1, tagName.getId());
10282  resultSet = connection.executeQuery(statement);
10283  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10284  while (resultSet.next()) {
10285  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10286  Content content = getContentById(artifact.getObjectID());
10287  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10288  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10289  tags.add(tag);
10290  }
10291  return tags;
10292  } catch (SQLException ex) {
10293  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
10294  } finally {
10295  closeResultSet(resultSet);
10296  connection.close();
10298  }
10299  }
10300 
10315  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10316 
10317  if (tagName.getId() == Tag.ID_NOT_SET) {
10318  throw new TskCoreException("TagName object is invalid, id not set");
10319  }
10320 
10321  CaseDbConnection connection = connections.getConnection();
10323  ResultSet resultSet = null;
10324  try {
10325  // 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
10326  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
10327  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
10328  // WHERE artifact_tags.artifact_id = arts.artifact_id
10329  // AND artifact_tags.tag_name_id = ?
10330  // AND arts.data_source_obj_id = ?
10331  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10332  statement.clearParameters();
10333  statement.setLong(1, tagName.getId());
10334  statement.setLong(2, dsObjId);
10335  resultSet = connection.executeQuery(statement);
10336  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10337  while (resultSet.next()) {
10338  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10339  Content content = getContentById(artifact.getObjectID());
10340  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10341  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10342  tags.add(tag);
10343  }
10344  return tags;
10345  } catch (SQLException ex) {
10346  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10347  } finally {
10348  closeResultSet(resultSet);
10349  connection.close();
10351  }
10352 
10353  }
10354 
10366  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
10367 
10368  CaseDbConnection connection = connections.getConnection();
10370  ResultSet resultSet = null;
10371  BlackboardArtifactTag tag = null;
10372  try {
10373  //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
10374  // FROM blackboard_artifact_tags
10375  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10376  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10377  // WHERE blackboard_artifact_tags.tag_id = ?
10378  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
10379  statement.clearParameters();
10380  statement.setLong(1, artifactTagID);
10381  resultSet = connection.executeQuery(statement);
10382 
10383  while (resultSet.next()) {
10384  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10385  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10386  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")));
10387  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10388  Content content = getContentById(artifact.getObjectID());
10389  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10390  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
10391  }
10392  resultSet.close();
10393 
10394  } catch (SQLException ex) {
10395  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
10396  } finally {
10397  closeResultSet(resultSet);
10398  connection.close();
10400  }
10401  return tag;
10402  }
10403 
10416  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
10417  CaseDbConnection connection = connections.getConnection();
10419  ResultSet resultSet = null;
10420  try {
10421  // 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
10422  // FROM blackboard_artifact_tags
10423  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10424  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10425  // WHERE blackboard_artifact_tags.artifact_id = ?
10426  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
10427  statement.clearParameters();
10428  statement.setLong(1, artifact.getArtifactID());
10429  resultSet = connection.executeQuery(statement);
10430  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10431  while (resultSet.next()) {
10432  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10433  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10434  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus"))); //NON-NLS
10435  Content content = getContentById(artifact.getObjectID());
10436  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10437  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10438  tags.add(tag);
10439  }
10440  return tags;
10441  } catch (SQLException ex) {
10442  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
10443  } finally {
10444  closeResultSet(resultSet);
10445  connection.close();
10447  }
10448  }
10449 
10458  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
10459  CaseDbConnection connection = connections.getConnection();
10461  try {
10462  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
10463  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
10464  statement.clearParameters();
10465  statement.setString(1, newPath);
10466  statement.setLong(2, objectId);
10467  connection.executeUpdate(statement);
10468  } catch (SQLException ex) {
10469  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
10470  } finally {
10471  connection.close();
10473  }
10474  }
10475 
10489  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
10490  return addReport(localPath, sourceModuleName, reportName, null);
10491  }
10492 
10508  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
10509  // Make sure the local path of the report is in the database directory
10510  // or one of its subdirectories.
10511  String relativePath = ""; //NON-NLS
10512  long createTime = 0;
10513  String localPathLower = localPath.toLowerCase();
10514 
10515  if (localPathLower.startsWith("http")) {
10516  relativePath = localPathLower;
10517  createTime = System.currentTimeMillis() / 1000;
10518  } else {
10519  /*
10520  * Note: The following call to .relativize() may be dangerous in
10521  * case-sensitive operating systems and should be looked at. For
10522  * now, we are simply relativizing the paths as all lower case, then
10523  * using the length of the result to pull out the appropriate number
10524  * of characters from the localPath String.
10525  */
10526  try {
10527  String casePathLower = getDbDirPath().toLowerCase();
10528  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
10529  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
10530  } catch (IllegalArgumentException ex) {
10531  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
10532  throw new TskCoreException(errorMessage, ex);
10533  }
10534  try {
10535  // get its file time
10536  java.io.File tempFile = new java.io.File(localPath);
10537  // Convert to UNIX epoch (seconds, not milliseconds).
10538  createTime = tempFile.lastModified() / 1000;
10539  } catch (Exception ex) {
10540  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
10541  }
10542  }
10543 
10544  // Write the report data to the database.
10545  CaseDbConnection connection = connections.getConnection();
10547  ResultSet resultSet = null;
10548  try {
10549  // Insert a row for the report into the tsk_objects table.
10550  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
10551  long parentObjId = 0;
10552  if (parent != null) {
10553  parentObjId = parent.getId();
10554  }
10555  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
10556 
10557  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
10558  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
10559  statement.clearParameters();
10560  statement.setLong(1, objectId);
10561  statement.setString(2, relativePath);
10562  statement.setLong(3, createTime);
10563  statement.setString(4, sourceModuleName);
10564  statement.setString(5, reportName);
10565  connection.executeUpdate(statement);
10566  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
10567  } catch (SQLException ex) {
10568  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
10569  } finally {
10570  closeResultSet(resultSet);
10571  connection.close();
10573  }
10574  }
10575 
10584  public List<Report> getAllReports() throws TskCoreException {
10585  CaseDbConnection connection = connections.getConnection();
10587  ResultSet resultSet = null;
10588  ResultSet parentResultSet = null;
10589  PreparedStatement statement = null;
10590  Statement parentStatement = null;
10591  try {
10592  // SELECT * FROM reports
10593  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
10594  parentStatement = connection.createStatement();
10595  resultSet = connection.executeQuery(statement);
10596  ArrayList<Report> reports = new ArrayList<Report>();
10597  while (resultSet.next()) {
10598  String localpath = resultSet.getString("path");
10599  if (localpath.toLowerCase().startsWith("http") == false) {
10600  // make path absolute
10601  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
10602  }
10603 
10604  // get the report parent
10605  Content parent = null;
10606  long reportId = resultSet.getLong("obj_id"); // NON-NLS
10607  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
10608  parentResultSet = parentStatement.executeQuery(parentQuery);
10609  if (parentResultSet.next()) {
10610  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10611  parent = this.getContentById(parentId);
10612  }
10613  parentResultSet.close();
10614 
10615  reports.add(new Report(this,
10616  reportId,
10617  localpath,
10618  resultSet.getLong("crtime"), //NON-NLS
10619  resultSet.getString("src_module_name"), //NON-NLS
10620  resultSet.getString("report_name"),
10621  parent)); //NON-NLS
10622  }
10623  return reports;
10624  } catch (SQLException ex) {
10625  throw new TskCoreException("Error querying reports table", ex);
10626  } finally {
10627  closeResultSet(resultSet);
10628  closeResultSet(parentResultSet);
10629  closeStatement(statement);
10630  closeStatement(parentStatement);
10631 
10632  connection.close();
10634  }
10635  }
10636 
10646  public Report getReportById(long id) throws TskCoreException {
10647  CaseDbConnection connection = connections.getConnection();
10649  PreparedStatement statement = null;
10650  Statement parentStatement = null;
10651  ResultSet resultSet = null;
10652  ResultSet parentResultSet = null;
10653  Report report = null;
10654  try {
10655  // SELECT * FROM reports WHERE obj_id = ?
10656  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
10657  parentStatement = connection.createStatement();
10658  statement.clearParameters();
10659  statement.setLong(1, id);
10660  resultSet = connection.executeQuery(statement);
10661 
10662  if (resultSet.next()) {
10663  // get the report parent
10664  Content parent = null;
10665  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
10666  parentResultSet = parentStatement.executeQuery(parentQuery);
10667  if (parentResultSet.next()) {
10668  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10669  parent = this.getContentById(parentId);
10670  }
10671 
10672  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
10673  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
10674  resultSet.getLong("crtime"), //NON-NLS
10675  resultSet.getString("src_module_name"), //NON-NLS
10676  resultSet.getString("report_name"),
10677  parent); //NON-NLS
10678  } else {
10679  throw new TskCoreException("No report found for id: " + id);
10680  }
10681  } catch (SQLException ex) {
10682  throw new TskCoreException("Error querying reports table for id: " + id, ex);
10683  } finally {
10684  closeResultSet(resultSet);
10685  closeResultSet(parentResultSet);
10686  closeStatement(statement);
10687  closeStatement(parentStatement);
10688  connection.close();
10690  }
10691 
10692  return report;
10693  }
10694 
10702  public void deleteReport(Report report) throws TskCoreException {
10703  CaseDbConnection connection = connections.getConnection();
10705  try {
10706  // DELETE FROM reports WHERE reports.obj_id = ?
10707  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
10708  statement.setLong(1, report.getId());
10709  connection.executeUpdate(statement);
10710  } catch (SQLException ex) {
10711  throw new TskCoreException("Error querying reports table", ex);
10712  } finally {
10713  connection.close();
10715  }
10716  }
10717 
10718  static void closeResultSet(ResultSet resultSet) {
10719  if (resultSet != null) {
10720  try {
10721  resultSet.close();
10722  } catch (SQLException ex) {
10723  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
10724  }
10725  }
10726  }
10727 
10728  static void closeStatement(Statement statement) {
10729  if (statement != null) {
10730  try {
10731  statement.close();
10732  } catch (SQLException ex) {
10733  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
10734 
10735  }
10736  }
10737  }
10738 
10747  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
10748  CaseDbConnection connection = connections.getConnection();
10750  try {
10751  Statement statement = connection.createStatement();
10752  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
10753  } catch (SQLException ex) {
10754  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
10755  } finally {
10756  connection.close();
10758  }
10759  }
10760 
10761  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
10762  CaseDbConnection connection = connections.getConnection();
10764  try {
10765  Statement statement = connection.createStatement();
10766  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
10767  } catch (SQLException ex) {
10768  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
10769  } finally {
10770  connection.close();
10772  }
10773  }
10774 
10791  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
10792  CaseDbConnection connection = connections.getConnection();
10794  ResultSet resultSet = null;
10795  Statement statement;
10796  try {
10797  connection.beginTransaction();
10798  statement = connection.createStatement();
10799  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
10800  insertStatement.setLong(1, dataSource.getId());
10801  insertStatement.setString(2, hostName);
10802  insertStatement.setLong(3, jobStart.getTime());
10803  insertStatement.setLong(4, jobEnd.getTime());
10804  insertStatement.setInt(5, status.ordinal());
10805  insertStatement.setString(6, settingsDir);
10806  connection.executeUpdate(insertStatement);
10807  resultSet = insertStatement.getGeneratedKeys();
10808  resultSet.next();
10809  long id = resultSet.getLong(1); //last_insert_rowid()
10810  for (int i = 0; i < ingestModules.size(); i++) {
10811  IngestModuleInfo ingestModule = ingestModules.get(i);
10812  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
10813  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
10814  }
10815  resultSet.close();
10816  resultSet = null;
10817  connection.commitTransaction();
10818  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
10819  } catch (SQLException ex) {
10820  connection.rollbackTransaction();
10821  throw new TskCoreException("Error adding the ingest job.", ex);
10822  } finally {
10823  closeResultSet(resultSet);
10824  connection.close();
10826  }
10827  }
10828 
10842  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
10843  CaseDbConnection connection = connections.getConnection();
10844  ResultSet resultSet = null;
10845  Statement statement = null;
10846  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
10848  try {
10849  statement = connection.createStatement();
10850  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10851  if (!resultSet.next()) {
10852  resultSet.close();
10853  resultSet = null;
10854  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
10855  insertStatement.setString(1, displayName);
10856  insertStatement.setString(2, uniqueName);
10857  insertStatement.setInt(3, type.ordinal());
10858  insertStatement.setString(4, version);
10859  connection.executeUpdate(insertStatement);
10860  resultSet = statement.getGeneratedKeys();
10861  resultSet.next();
10862  long id = resultSet.getLong(1); //last_insert_rowid()
10863  resultSet.close();
10864  resultSet = null;
10865  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
10866  } else {
10867  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10868  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10869  }
10870  } catch (SQLException ex) {
10871  try {
10872  closeStatement(statement);
10873  statement = connection.createStatement();
10874  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10875  if (resultSet.next()) {
10876  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10877  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10878  } else {
10879  throw new TskCoreException("Couldn't add new module to database.", ex);
10880  }
10881  } catch (SQLException ex1) {
10882  throw new TskCoreException("Couldn't add new module to database.", ex1);
10883  }
10884  } finally {
10885  closeResultSet(resultSet);
10886  closeStatement(statement);
10887  connection.close();
10889  }
10890  }
10891 
10899  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
10900  CaseDbConnection connection = connections.getConnection();
10901  ResultSet resultSet = null;
10902  Statement statement = null;
10903  List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>();
10905  try {
10906  statement = connection.createStatement();
10907  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
10908  while (resultSet.next()) {
10909  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
10910  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
10911  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
10912  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
10913  }
10914  return ingestJobs;
10915  } catch (SQLException ex) {
10916  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
10917  } finally {
10918  closeResultSet(resultSet);
10919  closeStatement(statement);
10920  connection.close();
10922  }
10923  }
10924 
10935  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
10936  ResultSet resultSet = null;
10937  Statement statement = null;
10938  List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>();
10940  try {
10941  statement = connection.createStatement();
10942  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
10943  + "ingest_job_modules.pipeline_position AS pipeline_position, "
10944  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
10945  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
10946  + "FROM ingest_job_modules, ingest_modules "
10947  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
10948  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
10949  + "ORDER BY (ingest_job_modules.pipeline_position);");
10950  while (resultSet.next()) {
10951  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10952  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
10953  }
10954  return ingestModules;
10955  } finally {
10956  closeResultSet(resultSet);
10957  closeStatement(statement);
10959 
10960  }
10961  }
10962 
10966  static class ObjectInfo {
10967 
10968  private long id;
10969  private TskData.ObjectType type;
10970 
10971  ObjectInfo(long id, ObjectType type) {
10972  this.id = id;
10973  this.type = type;
10974  }
10975 
10976  long getId() {
10977  return id;
10978  }
10979 
10980  TskData.ObjectType getType() {
10981  return type;
10982  }
10983  }
10984 
10985  private interface DbCommand {
10986 
10987  void execute() throws SQLException;
10988  }
10989 
10990  private enum PREPARED_STATEMENT {
10991 
10992  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
10993  + "WHERE artifact_type_id = ?"), //NON-NLS
10994  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
10995  COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE data_source_obj_id = ? AND artifact_type_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
10996  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
10997  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
10998  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
10999  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11000  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11001  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
11002  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
11003  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
11004  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11005  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11006  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
11007  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
11008  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
11009  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11010  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11011  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
11012  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
11013  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11014  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11015  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
11016  + "AND tsk_files.type = ? )"), //NON-NLS
11017  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
11018  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
11019  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
11020  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
11021  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
11022  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
11023  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
11024  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
11025  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11026  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
11027  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11028  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
11029  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11030  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
11031  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11032  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
11033  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11034  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
11035  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
11036  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
11037  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
11038  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
11039  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
11040  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11041  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11042  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11043  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
11044  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
11045  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
11046  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
11047  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
11048  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11049  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11050  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
11051  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
11052  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
11053  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
11054  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
11055  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
11056  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)"
11057  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
11058  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
11059  + "WHERE obj_id = ?"), //NON-NLS
11060  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
11061  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11062  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
11063  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
11064  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
11065  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
11066  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
11067  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
11068  + "WHERE tag_name_id IN " //NON-NLS
11069  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
11070  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
11071  + "WHERE tag_name_id IN "
11072  + "( SELECT content_tags.tag_name_id as tag_name_id "
11073  + "FROM content_tags as content_tags, tsk_files as tsk_files"
11074  + " WHERE content_tags.obj_id = tsk_files.obj_id"
11075  + " AND tsk_files.data_source_obj_id = ?"
11076  + " UNION "
11077  + "SELECT artifact_tags.tag_name_id as tag_name_id "
11078  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
11079  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
11080  + " AND arts.data_source_obj_id = ?"
11081  + " )"),
11082  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
11083  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11084  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
11085  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
11086  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
11087  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11088  + " AND content_tags.tag_name_id = ? "
11089  + " AND tsk_files.data_source_obj_id = ? "
11090  ),
11091  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 "
11092  + "FROM content_tags "
11093  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11094  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11095  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 "
11096  + "FROM content_tags "
11097  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11098  + "WHERE tag_name_id = ?"), //NON-NLS
11099  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 "
11100  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
11101  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
11102  + " AND content_tags.obj_id = tsk_files.obj_id"
11103  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
11104  + " AND content_tags.tag_name_id = ?"
11105  + " AND tsk_files.data_source_obj_id = ? "),
11106  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 "
11107  + "FROM content_tags "
11108  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11109  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11110  + "WHERE tag_id = ?"), //NON-NLS
11111  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 "
11112  + "FROM content_tags "
11113  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11114  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11115  + "WHERE content_tags.obj_id = ?"), //NON-NLS
11116  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
11117  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11118  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
11119  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 "
11120  + "FROM blackboard_artifact_tags "
11121  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11122  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11123  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
11124  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"
11125  + " AND artifact_tags.tag_name_id = ?"
11126  + " AND arts.data_source_obj_id = ? "),
11127  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 "
11128  + "FROM blackboard_artifact_tags "
11129  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11130  + "WHERE tag_name_id = ?"), //NON-NLS
11131  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 "
11132  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
11133  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
11134  + " AND artifact_tags.artifact_id = arts.artifact_id"
11135  + " AND artifact_tags.tag_name_id = ? "
11136  + " AND arts.data_source_obj_id = ? "),
11137  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 "
11138  + "FROM blackboard_artifact_tags "
11139  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11140  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11141  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
11142  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 "
11143  + "FROM blackboard_artifact_tags "
11144  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11145  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11146  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
11147  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
11148  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
11149  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
11150  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
11151  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11152  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
11153  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
11154  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
11155  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
11156  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
11157  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
11158  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
11159  + "WHERE (tsk_objects.par_obj_id = ?)"),
11160  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 = ?"),
11161  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
11162  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
11163  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
11164  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
11165  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
11166  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
11167  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
11168  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
11169  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone) VALUES (?, ?, ?)"),
11170  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
11171  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11172  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11173  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
11174  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)"
11175  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
11176 
11177  private final String sql;
11178 
11179  private PREPARED_STATEMENT(String sql) {
11180  this.sql = sql;
11181  }
11182 
11183  String getSQL() {
11184  return sql;
11185  }
11186  }
11187 
11193  abstract private class ConnectionPool {
11194 
11195  private PooledDataSource pooledDataSource;
11196 
11197  public ConnectionPool() {
11198  pooledDataSource = null;
11199  }
11200 
11201  CaseDbConnection getConnection() throws TskCoreException {
11202  if (pooledDataSource == null) {
11203  throw new TskCoreException("Error getting case database connection - case is closed");
11204  }
11205  try {
11206  return getPooledConnection();
11207  } catch (SQLException exp) {
11208  throw new TskCoreException(exp.getMessage());
11209  }
11210  }
11211 
11212  void close() throws TskCoreException {
11213  if (pooledDataSource != null) {
11214  try {
11215  pooledDataSource.close();
11216  } catch (SQLException exp) {
11217  throw new TskCoreException(exp.getMessage());
11218  } finally {
11219  pooledDataSource = null;
11220  }
11221  }
11222  }
11223 
11224  abstract CaseDbConnection getPooledConnection() throws SQLException;
11225 
11226  public PooledDataSource getPooledDataSource() {
11227  return pooledDataSource;
11228  }
11229 
11230  public void setPooledDataSource(PooledDataSource pooledDataSource) {
11231  this.pooledDataSource = pooledDataSource;
11232  }
11233  }
11234 
11239  private final class SQLiteConnections extends ConnectionPool {
11240 
11241  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
11242 
11243  SQLiteConnections(String dbPath) throws SQLException {
11244  configurationOverrides.put("acquireIncrement", "2");
11245  configurationOverrides.put("initialPoolSize", "5");
11246  configurationOverrides.put("minPoolSize", "5");
11247  /*
11248  * NOTE: max pool size and max statements are related. If you
11249  * increase max pool size, then also increase statements.
11250  */
11251  configurationOverrides.put("maxPoolSize", "20");
11252  configurationOverrides.put("maxStatements", "200");
11253  configurationOverrides.put("maxStatementsPerConnection", "20");
11254 
11255  SQLiteConfig config = new SQLiteConfig();
11256  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
11257  config.setReadUncommited(true);
11258  config.enforceForeignKeys(true); // Enforce foreign key constraints.
11259  SQLiteDataSource unpooled = new SQLiteDataSource(config);
11260  unpooled.setUrl("jdbc:sqlite:" + dbPath);
11261  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
11262  }
11263 
11264  @Override
11265  public CaseDbConnection getPooledConnection() throws SQLException {
11266  return new SQLiteConnection(getPooledDataSource().getConnection());
11267  }
11268  }
11269 
11274  private final class PostgreSQLConnections extends ConnectionPool {
11275 
11276  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
11277  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
11278  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
11279  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
11280  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
11281  comboPooledDataSource.setUser(userName);
11282  comboPooledDataSource.setPassword(password);
11283  comboPooledDataSource.setAcquireIncrement(2);
11284  comboPooledDataSource.setInitialPoolSize(5);
11285  comboPooledDataSource.setMinPoolSize(5);
11286  /*
11287  * NOTE: max pool size and max statements are related. If you
11288  * increase max pool size, then also increase statements.
11289  */
11290  comboPooledDataSource.setMaxPoolSize(20);
11291  comboPooledDataSource.setMaxStatements(200);
11292  comboPooledDataSource.setMaxStatementsPerConnection(20);
11293  setPooledDataSource(comboPooledDataSource);
11294  }
11295 
11296  @Override
11297  public CaseDbConnection getPooledConnection() throws SQLException {
11298  return new PostgreSQLConnection(getPooledDataSource().getConnection());
11299  }
11300  }
11301 
11305  abstract class CaseDbConnection implements AutoCloseable {
11306 
11307  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
11308  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
11309 
11310  private class CreateStatement implements DbCommand {
11311 
11312  private final Connection connection;
11313  private Statement statement = null;
11314 
11315  CreateStatement(Connection connection) {
11316  this.connection = connection;
11317  }
11318 
11319  Statement getStatement() {
11320  return statement;
11321  }
11322 
11323  @Override
11324  public void execute() throws SQLException {
11325  statement = connection.createStatement();
11326  }
11327  }
11328 
11329  private class SetAutoCommit implements DbCommand {
11330 
11331  private final Connection connection;
11332  private final boolean mode;
11333 
11334  SetAutoCommit(Connection connection, boolean mode) {
11335  this.connection = connection;
11336  this.mode = mode;
11337  }
11338 
11339  @Override
11340  public void execute() throws SQLException {
11341  connection.setAutoCommit(mode);
11342  }
11343  }
11344 
11345  private class Commit implements DbCommand {
11346 
11347  private final Connection connection;
11348 
11349  Commit(Connection connection) {
11350  this.connection = connection;
11351  }
11352 
11353  @Override
11354  public void execute() throws SQLException {
11355  connection.commit();
11356  }
11357  }
11358 
11359  private class ExecuteQuery implements DbCommand {
11360 
11361  private final Statement statement;
11362  private final String query;
11363  private ResultSet resultSet;
11364 
11365  ExecuteQuery(Statement statement, String query) {
11366  this.statement = statement;
11367  this.query = query;
11368  }
11369 
11370  ResultSet getResultSet() {
11371  return resultSet;
11372  }
11373 
11374  @Override
11375  public void execute() throws SQLException {
11376  resultSet = statement.executeQuery(query);
11377  }
11378  }
11379 
11380  private class ExecutePreparedStatementQuery implements DbCommand {
11381 
11382  private final PreparedStatement preparedStatement;
11383  private ResultSet resultSet;
11384 
11385  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
11386  this.preparedStatement = preparedStatement;
11387  }
11388 
11389  ResultSet getResultSet() {
11390  return resultSet;
11391  }
11392 
11393  @Override
11394  public void execute() throws SQLException {
11395  resultSet = preparedStatement.executeQuery();
11396  }
11397  }
11398 
11399  private class ExecutePreparedStatementUpdate implements DbCommand {
11400 
11401  private final PreparedStatement preparedStatement;
11402 
11403  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
11404  this.preparedStatement = preparedStatement;
11405  }
11406 
11407  @Override
11408  public void execute() throws SQLException {
11409  preparedStatement.executeUpdate();
11410  }
11411  }
11412 
11413  private class ExecuteStatementUpdate implements DbCommand {
11414 
11415  private final Statement statement;
11416  private final String updateCommand;
11417 
11418  ExecuteStatementUpdate(Statement statement, String updateCommand) {
11419  this.statement = statement;
11420  this.updateCommand = updateCommand;
11421  }
11422 
11423  @Override
11424  public void execute() throws SQLException {
11425  statement.executeUpdate(updateCommand);
11426  }
11427  }
11428 
11429  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
11430 
11431  private final Statement statement;
11432  private final int generateKeys;
11433  private final String updateCommand;
11434 
11435  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
11436  this.statement = statement;
11437  this.generateKeys = generateKeys;
11438  this.updateCommand = updateCommand;
11439  }
11440 
11441  @Override
11442  public void execute() throws SQLException {
11443  statement.executeUpdate(updateCommand, generateKeys);
11444  }
11445  }
11446 
11447  private class PrepareStatement implements DbCommand {
11448 
11449  private final Connection connection;
11450  private final String input;
11451  private PreparedStatement preparedStatement = null;
11452 
11453  PrepareStatement(Connection connection, String input) {
11454  this.connection = connection;
11455  this.input = input;
11456  }
11457 
11458  PreparedStatement getPreparedStatement() {
11459  return preparedStatement;
11460  }
11461 
11462  @Override
11463  public void execute() throws SQLException {
11464  preparedStatement = connection.prepareStatement(input);
11465  }
11466  }
11467 
11468  private class PrepareStatementGenerateKeys implements DbCommand {
11469 
11470  private final Connection connection;
11471  private final String input;
11472  private final int generateKeys;
11473  private PreparedStatement preparedStatement = null;
11474 
11475  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
11476  this.connection = connection;
11477  this.input = input;
11478  this.generateKeys = generateKeysInput;
11479  }
11480 
11481  PreparedStatement getPreparedStatement() {
11482  return preparedStatement;
11483  }
11484 
11485  @Override
11486  public void execute() throws SQLException {
11487  preparedStatement = connection.prepareStatement(input, generateKeys);
11488  }
11489  }
11490 
11491  abstract void executeCommand(DbCommand command) throws SQLException;
11492 
11493  private final Connection connection;
11494  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
11495 
11496  CaseDbConnection(Connection connection) {
11497  this.connection = connection;
11498  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
11499  }
11500 
11501  boolean isOpen() {
11502  return this.connection != null;
11503  }
11504 
11505  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
11506  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
11507  }
11508 
11509  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
11510  // Lazy statement preparation.
11511  PreparedStatement statement;
11512  if (this.preparedStatements.containsKey(statementKey)) {
11513  statement = this.preparedStatements.get(statementKey);
11514  } else {
11515  statement = prepareStatement(statementKey.getSQL(), generateKeys);
11516  this.preparedStatements.put(statementKey, statement);
11517  }
11518  return statement;
11519  }
11520 
11521  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11522  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
11523  executeCommand(prepareStatement);
11524  return prepareStatement.getPreparedStatement();
11525  }
11526 
11527  Statement createStatement() throws SQLException {
11528  CreateStatement createStatement = new CreateStatement(this.connection);
11529  executeCommand(createStatement);
11530  return createStatement.getStatement();
11531  }
11532 
11533  void beginTransaction() throws SQLException {
11534  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
11535  executeCommand(setAutoCommit);
11536  }
11537 
11538  void commitTransaction() throws SQLException {
11539  Commit commit = new Commit(connection);
11540  executeCommand(commit);
11541  // You must turn auto commit back on when done with the transaction.
11542  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
11543  executeCommand(setAutoCommit);
11544  }
11545 
11551  void rollbackTransaction() {
11552  try {
11553  connection.rollback();
11554  } catch (SQLException e) {
11555  logger.log(Level.SEVERE, "Error rolling back transaction", e);
11556  }
11557  try {
11558  connection.setAutoCommit(true);
11559  } catch (SQLException e) {
11560  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
11561  }
11562  }
11563 
11571  void rollbackTransactionWithThrow() throws SQLException {
11572  try {
11573  connection.rollback();
11574  } finally {
11575  connection.setAutoCommit(true);
11576  }
11577  }
11578 
11579  ResultSet executeQuery(Statement statement, String query) throws SQLException {
11580  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
11581  executeCommand(queryCommand);
11582  return queryCommand.getResultSet();
11583  }
11584 
11594  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
11595  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
11596  executeCommand(executePreparedStatementQuery);
11597  return executePreparedStatementQuery.getResultSet();
11598  }
11599 
11600  void executeUpdate(Statement statement, String update) throws SQLException {
11601  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
11602  }
11603 
11604  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11605  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
11606  executeCommand(executeStatementUpdate);
11607  }
11608 
11609  void executeUpdate(PreparedStatement statement) throws SQLException {
11610  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
11611  executeCommand(executePreparedStatementUpdate);
11612  }
11613 
11617  @Override
11618  public void close() {
11619  try {
11620  connection.close();
11621  } catch (SQLException ex) {
11622  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
11623  }
11624  }
11625 
11626  Connection getConnection() {
11627  return this.connection;
11628  }
11629  }
11630 
11634  private final class SQLiteConnection extends CaseDbConnection {
11635 
11636  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
11637  private static final int SQLITE_BUSY_ERROR = 5;
11638 
11639  SQLiteConnection(Connection conn) {
11640  super(conn);
11641  }
11642 
11643  @Override
11644  void executeCommand(DbCommand command) throws SQLException {
11645  int retryCounter = 0;
11646  while (true) {
11647  try {
11648  command.execute(); // Perform the operation
11649  break;
11650  } catch (SQLException ex) {
11651  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
11652  try {
11653 
11654  // We do not notify of error here, as this is not an
11655  // error condition. It is likely a temporary busy or
11656  // locked issue and we will retry.
11657  retryCounter++;
11658  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11659  } catch (InterruptedException exp) {
11660  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11661  }
11662  } else {
11663  throw ex;
11664  }
11665  }
11666  }
11667  }
11668  }
11669 
11673  private final class PostgreSQLConnection extends CaseDbConnection {
11674 
11675  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
11676  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
11677  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
11678  private static final int MAX_RETRIES = 3;
11679 
11680  PostgreSQLConnection(Connection conn) {
11681  super(conn);
11682  }
11683 
11684  @Override
11685  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11686  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
11687  executeCommand(executeStatementUpdateGenerateKeys);
11688  }
11689 
11690  @Override
11691  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11692  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
11693  executeCommand(prepareStatementGenerateKeys);
11694  return prepareStatementGenerateKeys.getPreparedStatement();
11695  }
11696 
11697  @Override
11698  void executeCommand(DbCommand command) throws SQLException {
11699  SQLException lastException = null;
11700  for (int retries = 0; retries < MAX_RETRIES; retries++) {
11701  try {
11702  command.execute();
11703  lastException = null; // reset since we had a successful execution
11704  break;
11705  } catch (SQLException ex) {
11706  lastException = ex;
11707  String sqlState = ex.getSQLState();
11708  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
11709  try {
11710  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11711  } catch (InterruptedException exp) {
11712  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11713  }
11714  } else {
11715  throw ex;
11716  }
11717  }
11718  }
11719 
11720  // rethrow the exception if we bailed because of too many retries
11721  if (lastException != null) {
11722  throw lastException;
11723  }
11724  }
11725  }
11726 
11735  public static final class CaseDbTransaction {
11736 
11737  private final CaseDbConnection connection;
11738  private boolean hasWriteLock = false;
11739  private SleuthkitCase sleuthkitCase;
11740 
11741  private CaseDbTransaction(SleuthkitCase sleuthkitCase, CaseDbConnection connection) throws TskCoreException {
11742  this.connection = connection;
11743  this.sleuthkitCase = sleuthkitCase;
11744  try {
11745  this.connection.beginTransaction();
11746  } catch (SQLException ex) {
11747  throw new TskCoreException("Failed to create transaction on case database", ex);
11748  }
11749  }
11750 
11758  CaseDbConnection getConnection() {
11759  return this.connection;
11760  }
11761 
11773  if (!hasWriteLock) {
11774  hasWriteLock = true;
11775  sleuthkitCase.acquireSingleUserCaseWriteLock();
11776  }
11777  }
11778 
11785  public void commit() throws TskCoreException {
11786  try {
11787  this.connection.commitTransaction();
11788  } catch (SQLException ex) {
11789  throw new TskCoreException("Failed to commit transaction on case database", ex);
11790  } finally {
11791  close();
11792  }
11793  }
11794 
11801  public void rollback() throws TskCoreException {
11802  try {
11803  this.connection.rollbackTransactionWithThrow();
11804  } catch (SQLException ex) {
11805  throw new TskCoreException("Case database transaction rollback failed", ex);
11806  } finally {
11807  close();
11808  }
11809  }
11810 
11815  void close() {
11816  this.connection.close();
11817  if (hasWriteLock) {
11818  sleuthkitCase.releaseSingleUserCaseWriteLock();
11819  hasWriteLock = false;
11820  }
11821  }
11822  }
11823 
11833  public final class CaseDbQuery implements AutoCloseable {
11834 
11835  private ResultSet resultSet;
11836  private CaseDbConnection connection;
11837 
11838  private CaseDbQuery(String query) throws TskCoreException {
11839  this(query, false);
11840  }
11841 
11842  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
11843  if (!allowWriteQuery) {
11844  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
11845  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
11846  }
11847  }
11848  try {
11849  connection = connections.getConnection();
11850  } catch (TskCoreException ex) {
11851  throw new TskCoreException("Error getting connection for query: ", ex);
11852  }
11853 
11854  try {
11856  resultSet = connection.executeQuery(connection.createStatement(), query);
11857  } catch (SQLException ex) {
11859  throw new TskCoreException("Error executing query: ", ex);
11860  }
11861  }
11862 
11868  public ResultSet getResultSet() {
11869  return resultSet;
11870  }
11871 
11872  @Override
11873  public void close() throws TskCoreException {
11874  try {
11875  if (resultSet != null) {
11876  final Statement statement = resultSet.getStatement();
11877  if (statement != null) {
11878  statement.close();
11879  }
11880  resultSet.close();
11881  }
11882  connection.close();
11883  } catch (SQLException ex) {
11884  throw new TskCoreException("Error closing query: ", ex);
11885  } finally {
11887  }
11888  }
11889  }
11890 
11898  @Deprecated
11899  public void addErrorObserver(ErrorObserver observer) {
11900  sleuthkitCaseErrorObservers.add(observer);
11901  }
11902 
11910  @Deprecated
11911  public void removeErrorObserver(ErrorObserver observer) {
11912  int i = sleuthkitCaseErrorObservers.indexOf(observer);
11913  if (i >= 0) {
11914  sleuthkitCaseErrorObservers.remove(i);
11915  }
11916  }
11917 
11926  @Deprecated
11927  public void submitError(String context, String errorMessage) {
11928  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
11929  if (observer != null) {
11930  try {
11931  observer.receiveError(context, errorMessage);
11932  } catch (Exception ex) {
11933  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
11934 
11935  }
11936  }
11937  }
11938  }
11939 
11945  @Deprecated
11946  public interface ErrorObserver {
11947 
11954  public enum Context {
11955 
11959  IMAGE_READ_ERROR("Image File Read Error"),
11963  DATABASE_READ_ERROR("Database Read Error");
11964 
11965  private final String contextString;
11966 
11967  private Context(String context) {
11968  this.contextString = context;
11969  }
11970 
11971  public String getContextString() {
11972  return contextString;
11973  }
11974  };
11975 
11976  void receiveError(String context, String errorMessage);
11977  }
11978 
11989  @Deprecated
11990  long getDataSourceObjectId(long objectId) {
11991  try {
11992  CaseDbConnection connection = connections.getConnection();
11993  try {
11994  return getDataSourceObjectId(connection, objectId);
11995  } finally {
11996  connection.close();
11997  }
11998  } catch (TskCoreException ex) {
11999  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
12000  return 0;
12001  }
12002  }
12003 
12013  @Deprecated
12014  public long getLastObjectId() throws TskCoreException {
12015  CaseDbConnection connection = connections.getConnection();
12017  ResultSet rs = null;
12018  try {
12019  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
12020  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
12021  rs = connection.executeQuery(statement);
12022  long id = -1;
12023  if (rs.next()) {
12024  id = rs.getLong("max_obj_id");
12025  }
12026  return id;
12027  } catch (SQLException e) {
12028  throw new TskCoreException("Error getting last object id", e);
12029  } finally {
12030  closeResultSet(rs);
12031  connection.close();
12033  }
12034  }
12035 
12049  @Deprecated
12050  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
12051  CaseDbConnection connection = connections.getConnection();
12053  Statement s = null;
12054  ResultSet rs = null;
12055  try {
12056  s = connection.createStatement();
12057  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
12058  List<FsContent> results = new ArrayList<FsContent>();
12059  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
12060  for (AbstractFile f : temp) {
12061  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
12062  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
12063  results.add((FsContent) f);
12064  }
12065  }
12066  return results;
12067  } catch (SQLException e) {
12068  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
12069  } finally {
12070  closeResultSet(rs);
12071  closeStatement(s);
12072  connection.close();
12074  }
12075  }
12076 
12088  @Deprecated
12089  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
12090  CaseDbConnection connection = connections.getConnection();
12092  Statement s = null;
12093  ResultSet rs = null;
12094  try {
12095  s = connection.createStatement();
12096  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
12097  int typeId = -1;
12098  if (rs.next()) {
12099  typeId = rs.getInt("artifact_type_id");
12100  }
12101  return typeId;
12102  } catch (SQLException ex) {
12103  throw new TskCoreException("Error getting artifact type id", ex);
12104  } finally {
12105  closeResultSet(rs);
12106  closeStatement(s);
12107  connection.close();
12109  }
12110  }
12111 
12121  @Deprecated
12122  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
12123  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
12124  }
12125 
12139  @Deprecated
12140  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
12141  try {
12142  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
12143  } catch (TskDataException ex) {
12144  throw new TskCoreException("Failed to add artifact type.", ex);
12145  }
12146  }
12147 
12161  @Deprecated
12162  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
12163  try {
12164  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
12165  } catch (TskDataException ex) {
12166  throw new TskCoreException("Couldn't add new attribute type");
12167  }
12168  }
12169 
12180  @Deprecated
12181  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
12182  CaseDbConnection connection = connections.getConnection();
12184  Statement s = null;
12185  ResultSet rs = null;
12186  try {
12187  s = connection.createStatement();
12188  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
12189  int typeId = -1;
12190  if (rs.next()) {
12191  typeId = rs.getInt("attribute_type_id");
12192  }
12193  return typeId;
12194  } catch (SQLException ex) {
12195  throw new TskCoreException("Error getting attribute type id", ex);
12196  } finally {
12197  closeResultSet(rs);
12198  closeStatement(s);
12199  connection.close();
12201  }
12202  }
12203 
12216  @Deprecated
12217  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
12218  CaseDbConnection connection = connections.getConnection();
12220  Statement s = null;
12221  ResultSet rs = null;
12222  try {
12223  s = connection.createStatement();
12224  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12225  if (rs.next()) {
12226  return rs.getString("type_name");
12227  } else {
12228  throw new TskCoreException("No type with that id");
12229  }
12230  } catch (SQLException ex) {
12231  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12232  } finally {
12233  closeResultSet(rs);
12234  closeStatement(s);
12235  connection.close();
12237  }
12238  }
12239 
12252  @Deprecated
12253  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
12254  CaseDbConnection connection = connections.getConnection();
12256  Statement s = null;
12257  ResultSet rs = null;
12258  try {
12259  s = connection.createStatement();
12260  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12261  if (rs.next()) {
12262  return rs.getString("display_name");
12263  } else {
12264  throw new TskCoreException("No type with that id");
12265  }
12266  } catch (SQLException ex) {
12267  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12268  } finally {
12269  closeResultSet(rs);
12270  closeStatement(s);
12271  connection.close();
12273  }
12274  }
12275 
12285  @Deprecated
12286  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
12287  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
12288  }
12289 
12305  @Deprecated
12306  public ResultSet runQuery(String query) throws SQLException {
12307  CaseDbConnection connection;
12308  try {
12309  connection = connections.getConnection();
12310  } catch (TskCoreException ex) {
12311  throw new SQLException("Error getting connection for ad hoc query", ex);
12312  }
12314  try {
12315  return connection.executeQuery(connection.createStatement(), query);
12316  } finally {
12317  //TODO unlock should be done in closeRunQuery()
12318  //but currently not all code calls closeRunQuery - need to fix this
12319  connection.close();
12321  }
12322  }
12323 
12333  @Deprecated
12334  public void closeRunQuery(ResultSet resultSet) throws SQLException {
12335  final Statement statement = resultSet.getStatement();
12336  resultSet.close();
12337  if (statement != null) {
12338  statement.close();
12339  }
12340  }
12341 
12358  @Deprecated
12359  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
12360  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
12361  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
12362  files.add(carvedFile);
12363  CarvingResult carvingResult;
12364  Content parent = getContentById(containerId);
12365  if (parent instanceof FileSystem
12366  || parent instanceof Volume
12367  || parent instanceof Image) {
12368  carvingResult = new CarvingResult(parent, files);
12369  } else {
12370  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
12371  }
12372  return addCarvedFiles(carvingResult).get(0);
12373  }
12374 
12388  @Deprecated
12389  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
12390  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
12391  for (CarvedFileContainer container : filesToAdd) {
12392  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
12393  carvedFiles.add(carvedFile);
12394  }
12395  CarvingResult carvingResult;
12396  Content parent = getContentById(filesToAdd.get(0).getId());
12397  if (parent instanceof FileSystem
12398  || parent instanceof Volume
12399  || parent instanceof Image) {
12400  carvingResult = new CarvingResult(parent, carvedFiles);
12401  } else {
12402  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
12403  }
12404  return addCarvedFiles(carvingResult);
12405  }
12406 
12436  @Deprecated
12437  public DerivedFile addDerivedFile(String fileName, String localPath,
12438  long size, long ctime, long crtime, long atime, long mtime,
12439  boolean isFile, AbstractFile parentFile,
12440  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
12441  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12442  isFile, parentFile, rederiveDetails, toolName, toolVersion,
12443  otherDetails, TskData.EncodingType.NONE);
12444  }
12445 
12470  @Deprecated
12471  public LocalFile addLocalFile(String fileName, String localPath,
12472  long size, long ctime, long crtime, long atime, long mtime,
12473  boolean isFile,
12474  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
12475  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
12476  TskData.EncodingType.NONE, parent, transaction);
12477  }
12478 
12498  @Deprecated
12499  public LocalFile addLocalFile(String fileName, String localPath,
12500  long size, long ctime, long crtime, long atime, long mtime,
12501  boolean isFile,
12502  AbstractFile parent) throws TskCoreException {
12503  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12504  isFile, TskData.EncodingType.NONE, parent);
12505  }
12506 
12523  @Deprecated
12524  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
12525  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
12526  }
12527 
12535  @Deprecated
12536  public void acquireExclusiveLock() {
12538  }
12539 
12547  @Deprecated
12548  public void releaseExclusiveLock() {
12550  }
12551 
12559  @Deprecated
12560  public void acquireSharedLock() {
12562  }
12563 
12571  @Deprecated
12572  public void releaseSharedLock() {
12574  }
12575 };
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)
long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID)
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-2020 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.