Sleuth Kit Java Bindings (JNI)  4.10.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-2020 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.Properties;
61 import java.util.ResourceBundle;
62 import java.util.Set;
63 import java.util.UUID;
64 import java.util.concurrent.ConcurrentHashMap;
65 import java.util.concurrent.locks.ReentrantReadWriteLock;
66 import java.util.logging.Level;
67 import java.util.logging.Logger;
68 import org.postgresql.util.PSQLState;
84 import org.sqlite.SQLiteConfig;
85 import org.sqlite.SQLiteDataSource;
86 import org.sqlite.SQLiteJDBCLoader;
87 
92 public class SleuthkitCase {
93 
94  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
95 
100  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
101  = new CaseDbSchemaVersionNumber(8, 5);
102 
103  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
104  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
105  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
106  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
107  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
108  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
109  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
110  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
111  private static final String SQL_ERROR_LIMIT_GROUP = "54";
112  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
113  private static final int MIN_USER_DEFINED_TYPE_ID = 10000;
114 
115  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
116  "tsk_events",
117  "tsk_event_descriptions",
118  "tsk_event_types",
119  "tsk_db_info",
120  "tsk_objects",
121  "tsk_image_info",
122  "tsk_image_names",
123  "tsk_vs_info",
124  "tsk_vs_parts",
125  "tsk_fs_info",
126  "tsk_file_layout",
127  "tsk_files",
128  "tsk_files_path",
129  "tsk_files_derived",
130  "tsk_files_derived_method",
131  "tag_names",
132  "content_tags",
133  "blackboard_artifact_tags",
134  "blackboard_artifacts",
135  "blackboard_attributes",
136  "blackboard_artifact_types",
137  "blackboard_attribute_types",
138  "data_source_info",
139  "file_encoding_types",
140  "ingest_module_types",
141  "ingest_job_status_types",
142  "ingest_modules",
143  "ingest_jobs",
144  "ingest_job_modules",
145  "account_types",
146  "accounts",
147  "account_relationships",
148  "review_statuses",
149  "reports,");
150 
151  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
152  "parObjId",
153  "layout_objID",
154  "artifact_objID",
155  "artifact_artifact_objID",
156  "artifact_typeID",
157  "attrsArtifactID",
158  "mime_type",
159  "file_extension",
160  "relationships_account1",
161  "relationships_account2",
162  "relationships_relationship_source_obj_id",
163  "relationships_date_time",
164  "relationships_relationship_type",
165  "relationships_data_source_obj_id",
166  "events_time",
167  "events_type",
168  "events_data_source_obj_id",
169  "events_file_obj_id",
170  "events_artifact_id");
171 
172  private static final String TSK_VERSION_KEY = "TSK_VER";
173  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
174  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
175  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
176  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
177 
178  private final ConnectionPool connections;
179  private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<>();
180  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
181  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
182  private final String databaseName;
183  private final String dbPath;
184  private final DbType dbType;
185  private final String caseDirPath;
186  private SleuthkitJNI.CaseDbHandle caseHandle;
187  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
188  private String dbBackupPath;
189  private Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap;
190  private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
191  private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
192  private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
193  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
194 
195  /*
196  * First parameter is used to specify the SparseBitSet to use, as object IDs
197  * can be larger than the max size of a SparseBitSet
198  */
199  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
200 
201  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
202  // This read/write lock is used to implement a layer of locking on top of
203  // the locking protocol provided by the underlying SQLite database. The Java
204  // locking protocol improves performance for reasons that are not currently
205  // understood. Note that the lock is contructed to use a fairness policy.
206  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
207 
208  private CommunicationsManager communicationsMgr;
209  private TimelineManager timelineMgr;
210  private Blackboard blackboard;
211  private CaseDbAccessManager dbAccessManager;
212  private TaggingManager taggingMgr;
213 
214  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
215 
216  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
217 
218  public void registerForEvents(Object listener) {
219  eventBus.register(listener);
220  }
221 
222  public void unregisterForEvents(Object listener) {
223  eventBus.unregister(listener);
224  }
225 
226  void fireTSKEvent(Object event) {
227  eventBus.post(event);
228  }
229 
230  // Cache of frequently used content objects (e.g. data source, file system).
231  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
232 
233  private Examiner cachedCurrentExaminer = null;
234 
235  static {
236  Properties p = new Properties(System.getProperties());
237  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
238  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
239  System.setProperties(p);
240  }
241 
256  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
257  // Check if we can talk to the database.
258  if (info.getHost() == null || info.getHost().isEmpty()) {
259  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
260  } else if (info.getPort() == null || info.getPort().isEmpty()) {
261  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
262  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
263  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
264  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
265  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
266  }
267 
268  try {
269  Class.forName("org.postgresql.Driver"); //NON-NLS
270  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
271  if (conn != null) {
272  conn.close();
273  }
274  } catch (SQLException ex) {
275  String result;
276  String sqlState = ex.getSQLState().toLowerCase();
277  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
278  try {
279  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
280  // if we can reach the host, then it's probably port problem
281  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
282  } else {
283  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
284  }
285  } catch (IOException | MissingResourceException any) {
286  // it may be anything
287  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
288  }
289  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
290  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
291  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
292  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
293  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
294  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
295  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
296  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
297  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
298  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
299  } else {
300  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
301  }
302  throw new TskCoreException(result);
303  } catch (ClassNotFoundException ex) {
304  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
305  }
306  }
307 
319  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
320  Class.forName("org.sqlite.JDBC");
321  this.dbPath = dbPath;
322  this.dbType = dbType;
323  File dbFile = new File(dbPath);
324  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
325  this.databaseName = dbFile.getName();
326  this.connections = new SQLiteConnections(dbPath);
327  this.caseHandle = caseHandle;
328  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
329  init();
330  logSQLiteJDBCDriverInfo();
331  }
332 
350  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
351  this.dbPath = "";
352  this.databaseName = dbName;
353  this.dbType = dbType;
354  this.caseDirPath = caseDirPath;
355  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
356  this.caseHandle = caseHandle;
357  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
358  init();
359  }
360 
361  private void init() throws Exception {
362  typeIdToArtifactTypeMap = new ConcurrentHashMap<>();
363  typeIdToAttributeTypeMap = new ConcurrentHashMap<>();
364  typeNameToArtifactTypeMap = new ConcurrentHashMap<>();
365  typeNameToAttributeTypeMap = new ConcurrentHashMap<>();
366 
367  /*
368  * The following methods need to be called before updateDatabaseSchema
369  * due to the way that updateFromSchema2toSchema3 was implemented.
370  */
371  initBlackboardArtifactTypes();
372  initBlackboardAttributeTypes();
373  initNextArtifactId();
374  updateDatabaseSchema(null);
375 
376  try (CaseDbConnection connection = connections.getConnection()) {
377  initIngestModuleTypes(connection);
378  initIngestStatusTypes(connection);
379  initReviewStatuses(connection);
380  initEncodingTypes(connection);
381  populateHasChildrenMap(connection);
382  updateExaminers(connection);
383  initDBSchemaCreationVersion(connection);
384  }
385 
386  blackboard = new Blackboard(this);
387  communicationsMgr = new CommunicationsManager(this);
388  timelineMgr = new TimelineManager(this);
389  dbAccessManager = new CaseDbAccessManager(this);
390  taggingMgr = new TaggingManager(this);
391  }
392 
398  static Set<String> getCoreTableNames() {
399  return CORE_TABLE_NAMES;
400  }
401 
407  static Set<String> getCoreIndexNames() {
408  return CORE_INDEX_NAMES;
409  }
410 
419  boolean getHasChildren(Content content) {
420  long objId = content.getId();
421  long mapIndex = objId / Integer.MAX_VALUE;
422  int mapValue = (int) (objId % Integer.MAX_VALUE);
423 
424  synchronized (hasChildrenBitSetMap) {
425  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
426  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
427  }
428  return false;
429  }
430  }
431 
437  private void setHasChildren(Long objId) {
438  long mapIndex = objId / Integer.MAX_VALUE;
439  int mapValue = (int) (objId % Integer.MAX_VALUE);
440 
441  synchronized (hasChildrenBitSetMap) {
442  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
443  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
444  } else {
445  SparseBitSet bitSet = new SparseBitSet();
446  bitSet.set(mapValue);
447  hasChildrenBitSetMap.put(mapIndex, bitSet);
448  }
449  }
450  }
451 
460  return communicationsMgr;
461  }
462 
469  return blackboard;
470  }
471 
480  return timelineMgr;
481  }
482 
483  /*
484  * Gets the case database access manager for this case.
485  *
486  * @return The per case CaseDbAccessManager object.
487  *
488  * @throws org.sleuthkit.datamodel.TskCoreException
489  */
491  return dbAccessManager;
492  }
493 
499  public synchronized TaggingManager getTaggingManager() {
500  return taggingMgr;
501  }
502 
509  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
510  CaseDbConnection connection = connections.getConnection();
511  Statement statement = null;
512  ResultSet resultSet = null;
514  try {
515  statement = connection.createStatement();
516  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
517  try {
518  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS
519  } catch (SQLException ex) {
520  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS
521  resultSet.next();
522  if (resultSet.getLong("count") == 0) {
523  throw ex;
524  }
525  resultSet.close();
526  resultSet = null;
527  }
528  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
529  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
530  }
531  if (dbType == DbType.POSTGRESQL) {
532  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
533  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
534  }
535  } finally {
536  closeResultSet(resultSet);
537  closeStatement(statement);
538  connection.close();
540  }
541  }
542 
550  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
551  CaseDbConnection connection = connections.getConnection();
552  Statement statement = null;
553  ResultSet resultSet = null;
555  try {
556  statement = connection.createStatement();
557  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
558  try {
559  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
560  } catch (SQLException ex) {
561  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS
562  resultSet.next();
563  if (resultSet.getLong("count") == 0) {
564  throw ex;
565  }
566  resultSet.close();
567  resultSet = null;
568  }
569  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
570  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
571  }
572  if (this.dbType == DbType.POSTGRESQL) {
573  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
574  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
575  }
576  } finally {
577  closeResultSet(resultSet);
578  closeStatement(statement);
579  connection.close();
581  }
582  }
583 
593  private void initNextArtifactId() throws SQLException, TskCoreException {
594  CaseDbConnection connection = connections.getConnection();
595  Statement statement = null;
596  ResultSet resultSet = null;
598  try {
599  statement = connection.createStatement();
600  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
601  resultSet.next();
602  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
603  if (this.nextArtifactId == 1) {
604  this.nextArtifactId = BASE_ARTIFACT_ID;
605  }
606  } finally {
607  closeResultSet(resultSet);
608  closeStatement(statement);
609  connection.close();
611  }
612  }
613 
621  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
622  Statement statement = null;
623  ResultSet resultSet = null;
625  try {
626  statement = connection.createStatement();
627  for (IngestModuleType type : IngestModuleType.values()) {
628  try {
629  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
630  } catch (SQLException ex) {
631  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
632  resultSet.next();
633  if (resultSet.getLong("count") == 0) {
634  throw ex;
635  }
636  resultSet.close();
637  resultSet = null;
638  }
639  }
640  } finally {
641  closeResultSet(resultSet);
642  closeStatement(statement);
644  }
645  }
646 
654  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
655  Statement statement = null;
656  ResultSet resultSet = null;
658  try {
659  statement = connection.createStatement();
660  for (IngestJobStatusType type : IngestJobStatusType.values()) {
661  try {
662  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
663  } catch (SQLException ex) {
664  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
665  resultSet.next();
666  if (resultSet.getLong("count") == 0) {
667  throw ex;
668  }
669  resultSet.close();
670  resultSet = null;
671  }
672  }
673  } finally {
674  closeResultSet(resultSet);
675  closeStatement(statement);
677  }
678  }
679 
686  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
687  Statement statement = null;
688  ResultSet resultSet = null;
690  try {
691  statement = connection.createStatement();
692  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
693  try {
694  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
695  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
696  } catch (SQLException ex) {
697  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
698  resultSet.next();
699  if (resultSet.getLong("count") == 0) {
700  throw ex;
701  }
702  resultSet.close();
703  resultSet = null;
704  }
705  }
706  } finally {
707  closeResultSet(resultSet);
708  closeStatement(statement);
710  }
711  }
712 
720  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
721  Statement statement = null;
722  ResultSet resultSet = null;
724  try {
725  statement = connection.createStatement();
726  for (TskData.EncodingType type : TskData.EncodingType.values()) {
727  try {
728  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
729  } catch (SQLException ex) {
730  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
731  resultSet.next();
732  if (resultSet.getLong("count") == 0) {
733  throw ex;
734  }
735  resultSet.close();
736  resultSet = null;
737  }
738  }
739  } finally {
740  closeResultSet(resultSet);
741  closeStatement(statement);
743  }
744  }
745 
754  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
755 
756  String loginName = System.getProperty("user.name");
757  if (loginName.isEmpty()) {
758  logger.log(Level.SEVERE, "Cannot determine logged in user name");
759  return;
760  }
761 
763  try {
764  PreparedStatement statement;
765  switch (getDatabaseType()) {
766  case POSTGRESQL:
767  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
768  break;
769  case SQLITE:
770  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
771  break;
772  default:
773  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
774  }
775  statement.clearParameters();
776  statement.setString(1, loginName);
777  connection.executeUpdate(statement);
778  } catch (SQLException ex) {
779  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
780  } finally {
782  }
783  }
784 
792  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
793  long timestamp = System.currentTimeMillis();
794 
795  Statement statement = null;
796  ResultSet resultSet = null;
798  try {
799  statement = connection.createStatement();
800  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
801 
802  synchronized (hasChildrenBitSetMap) {
803  while (resultSet.next()) {
804  setHasChildren(resultSet.getLong("par_obj_id"));
805  }
806  }
807  long delay = System.currentTimeMillis() - timestamp;
808  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
809  } catch (SQLException ex) {
810  throw new TskCoreException("Error populating parent node cache", ex);
811  } finally {
812  closeResultSet(resultSet);
813  closeStatement(statement);
815  }
816  }
817 
824  void addDataSourceToHasChildrenMap() throws TskCoreException {
825 
826  CaseDbConnection connection = connections.getConnection();
827  try {
828  populateHasChildrenMap(connection);
829  } finally {
830  if (connection != null) {
831  connection.close();
832  }
833  }
834  }
835 
845  private void updateDatabaseSchema(String dbPath) throws Exception {
846  CaseDbConnection connection = connections.getConnection();
847  ResultSet resultSet = null;
848  Statement statement = null;
850  try {
851  connection.beginTransaction();
852 
853  boolean hasMinorVersion = false;
854  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
855  while (columns.next()) {
856  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
857  hasMinorVersion = true;
858  }
859  }
860 
861  // Get the schema version number of the case database from the tsk_db_info table.
862  int dbSchemaMajorVersion;
863  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
864 
865  statement = connection.createStatement();
866  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
867  + (hasMinorVersion ? ", schema_minor_ver" : "")
868  + " FROM tsk_db_info"); //NON-NLS
869  if (resultSet.next()) {
870  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
871  if (hasMinorVersion) {
872  //if there is a minor version column, use it, else default to zero.
873  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
874  }
875  } else {
876  throw new TskCoreException();
877  }
878  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
879 
880  resultSet.close();
881  resultSet = null;
882  statement.close();
883  statement = null;
884  //check schema compatibility
885  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
886  //we cannot open a db with a major schema version higher than the current one.
887  throw new TskUnsupportedSchemaVersionException(
888  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
889  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
890  //The schema version is compatible,possibly after upgrades.
891 
892  if (null != dbPath) {
893  // Make a backup copy of the database. Client code can get the path of the backup
894  // using the getBackupDatabasePath() method.
895  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
896  copyCaseDB(backupFilePath);
897  dbBackupPath = backupFilePath;
898  }
899 
900  // ***CALL SCHEMA UPDATE METHODS HERE***
901  // Each method should examine the schema version passed to it and either:
902  // a. do nothing and return the schema version unchanged, or
903  // b. upgrade the database and return the schema version that the db was upgraded to.
904  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
905  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
906  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
907  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
908  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
909  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
910  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
911  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
912  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
913  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
914  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
915  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
916  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
917  statement = connection.createStatement();
918  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
919  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
920  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
921  statement.close();
922  statement = null;
923  }
924 
925  connection.commitTransaction();
926  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
927  connection.rollbackTransaction();
928  throw ex;
929  } finally {
930  closeResultSet(resultSet);
931  closeStatement(statement);
932  connection.close();
934  }
935  }
936 
944  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
945 
946  Statement statement = null;
947  ResultSet resultSet = null;
948  String createdSchemaMajorVersion = "0";
949  String createdSchemaMinorVersion = "0";
951  try {
952  statement = connection.createStatement();
953  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
954  while (resultSet.next()) {
955  String name = resultSet.getString("name");
956  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
957  createdSchemaMajorVersion = resultSet.getString("value");
958  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
959  createdSchemaMinorVersion = resultSet.getString("value");
960  }
961  }
962 
963  } finally {
964  closeResultSet(resultSet);
965  closeStatement(statement);
967  }
968 
969  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
970  }
971 
981  public void copyCaseDB(String newDBPath) throws IOException {
982  if (dbPath.isEmpty()) {
983  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
984  }
985  InputStream in = null;
986  OutputStream out = null;
988  try {
989  InputStream inFile = new FileInputStream(dbPath);
990  in = new BufferedInputStream(inFile);
991  OutputStream outFile = new FileOutputStream(newDBPath);
992  out = new BufferedOutputStream(outFile);
993  int bytesRead = in.read();
994  while (bytesRead != -1) {
995  out.write(bytesRead);
996  bytesRead = in.read();
997  }
998  } finally {
999  try {
1000  if (in != null) {
1001  in.close();
1002  }
1003  if (out != null) {
1004  out.flush();
1005  out.close();
1006  }
1007  } catch (IOException e) {
1008  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1009  }
1011  }
1012  }
1013 
1017  private void logSQLiteJDBCDriverInfo() {
1018  try {
1019  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1020  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1021  ? "native" : "pure-java")); //NON-NLS
1022  } catch (Exception ex) {
1023  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1024  }
1025  }
1026 
1040  @SuppressWarnings("deprecation")
1041  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1042  if (schemaVersion.getMajor() != 2) {
1043  return schemaVersion;
1044  }
1045  Statement statement = null;
1046  Statement updateStatement = null;
1047  ResultSet resultSet = null;
1049  try {
1050  statement = connection.createStatement();
1051 
1052  // Add new tables for tags.
1053  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
1054  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
1055  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
1056 
1057  // Add a new table for reports.
1058  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
1059 
1060  // Add new columns to the image info table.
1061  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1062  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1063  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1064 
1065  // Add a new column to the file system info table.
1066  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1067 
1068  // Add a new column to the file table.
1069  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1070 
1071  // Add new columns and indexes to the attributes table and populate the
1072  // new column. Note that addition of the new column is a denormalization
1073  // to optimize attribute queries.
1074  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1075  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1076  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1077  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1078  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1079  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1080  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1081  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1082  + "FROM blackboard_attributes AS attrs " //NON-NLS
1083  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1084  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1085  updateStatement = connection.createStatement();
1086  while (resultSet.next()) {
1087  long artifactId = resultSet.getLong("artifact_id");
1088  int artifactTypeId = resultSet.getInt("artifact_type_id");
1089  updateStatement.executeUpdate(
1090  "UPDATE blackboard_attributes " //NON-NLS
1091  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1092  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1093  }
1094  resultSet.close();
1095  resultSet = null;
1096 
1097  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1098  // TODO: This code depends on prepared statements that could evolve with
1099  // time, breaking this upgrade. The code that follows should be rewritten
1100  // to do everything with SQL specific to case database schema version 2.
1101  HashMap<String, TagName> tagNames = new HashMap<String, TagName>();
1102  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_FILE)) {
1103  Content content = getContentById(artifact.getObjectID());
1104  String name = ""; //NON-NLS
1105  String comment = ""; //NON-NLS
1106  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
1107  for (BlackboardAttribute attribute : attributes) {
1108  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
1109  name = attribute.getValueString();
1110  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
1111  comment = attribute.getValueString();
1112  }
1113  }
1114  if (!name.isEmpty()) {
1115  TagName tagName;
1116  if (tagNames.containsKey(name)) {
1117  tagName = tagNames.get(name);
1118  } else {
1119  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
1120  tagNames.put(name, tagName);
1121  }
1122  addContentTag(content, tagName, comment, 0, content.getSize() - 1);
1123  }
1124  }
1125  for (BlackboardArtifact artifact : getBlackboardArtifacts(ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
1126  long taggedArtifactId = -1;
1127  String name = ""; //NON-NLS
1128  String comment = ""; //NON-NLS
1129  ArrayList<BlackboardAttribute> attributes = getBlackboardAttributes(artifact);
1130  for (BlackboardAttribute attribute : attributes) {
1131  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
1132  name = attribute.getValueString();
1133  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
1134  comment = attribute.getValueString();
1135  } else if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
1136  taggedArtifactId = attribute.getValueLong();
1137  }
1138  }
1139  if (taggedArtifactId != -1 && !name.isEmpty()) {
1140  TagName tagName;
1141  if (tagNames.containsKey(name)) {
1142  tagName = tagNames.get(name);
1143  } else {
1144  tagName = addTagName(name, "", TagName.HTML_COLOR.NONE); //NON-NLS
1145  tagNames.put(name, tagName);
1146  }
1147  addBlackboardArtifactTag(getBlackboardArtifact(taggedArtifactId), tagName, comment);
1148  }
1149  }
1150  statement.execute(
1151  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1152  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1153  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1154  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1155  statement.execute(
1156  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1157  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1158  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1159 
1160  return new CaseDbSchemaVersionNumber(3, 0);
1161  } finally {
1162  closeStatement(updateStatement);
1163  closeResultSet(resultSet);
1164  closeStatement(statement);
1165  connection.close();
1167  }
1168  }
1169 
1183  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1184  if (schemaVersion.getMajor() != 3) {
1185  return schemaVersion;
1186  }
1187 
1188  Statement statement = null;
1189  ResultSet resultSet = null;
1190  Statement queryStatement = null;
1191  ResultSet queryResultSet = null;
1192  Statement updateStatement = null;
1194  try {
1195  // Add mime_type column to tsk_files table. Populate with general
1196  // info artifact file signature data.
1197  statement = connection.createStatement();
1198  updateStatement = connection.createStatement();
1199  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1200  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1201  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1202  + "WHERE files.obj_id = arts.obj_id AND "
1203  + "arts.artifact_id = attrs.artifact_id AND "
1204  + "arts.artifact_type_id = 1 AND "
1205  + "attrs.attribute_type_id = 62");
1206  while (resultSet.next()) {
1207  updateStatement.executeUpdate(
1208  "UPDATE tsk_files " //NON-NLS
1209  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1210  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1211  }
1212  resultSet.close();
1213 
1214  // Add value_type column to blackboard_attribute_types table.
1215  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1216  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1217  while (resultSet.next()) {
1218  int attributeTypeId = resultSet.getInt("attribute_type_id");
1219  String attributeLabel = resultSet.getString("type_name");
1220  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
1221  updateStatement.executeUpdate(
1222  "UPDATE blackboard_attribute_types " //NON-NLS
1223  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1224  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1225  }
1226  }
1227  resultSet.close();
1228 
1229  // Add a data_sources_info table.
1230  queryStatement = connection.createStatement();
1231  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));");
1232  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1233  while (resultSet.next()) {
1234  long objectId = resultSet.getLong("obj_id");
1235  String timeZone = "";
1236  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1237  if (queryResultSet.next()) {
1238  timeZone = queryResultSet.getString("tzone");
1239  }
1240  queryResultSet.close();
1241  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1242  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1243  }
1244  resultSet.close();
1245 
1246  // Add data_source_obj_id column to the tsk_files table.
1247  //
1248  // NOTE: A new case database will have the following FK constraint:
1249  //
1250  // REFERENCES data_source_info (obj_id)
1251  //
1252  // The constraint is sacrificed here to avoid having to create and
1253  // populate a new tsk_files table.
1254  //
1255  // TODO: Do this right.
1256  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1257  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");
1258  while (resultSet.next()) {
1259  long fileId = resultSet.getLong("obj_id");
1260  long dataSourceId = getDataSourceObjectId(connection, fileId);
1261  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1262  }
1263  resultSet.close();
1264  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1265  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1266  if (this.dbType.equals(DbType.SQLITE)) {
1267  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
1268  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
1269  } else {
1270  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
1271  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
1272  }
1273 
1274  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
1275  initIngestModuleTypes(connection);
1276  initIngestStatusTypes(connection);
1277 
1278  return new CaseDbSchemaVersionNumber(4, 0);
1279 
1280  } finally {
1281  closeResultSet(queryResultSet);
1282  closeStatement(queryStatement);
1283  closeStatement(updateStatement);
1284  closeResultSet(resultSet);
1285  closeStatement(statement);
1287  }
1288  }
1289 
1303  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1304  if (schemaVersion.getMajor() != 4) {
1305  return schemaVersion;
1306  }
1307 
1308  Statement statement = null;
1310  try {
1311  // Add the review_statuses lookup table.
1312  statement = connection.createStatement();
1313  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1314 
1315  /*
1316  * Add review_status_id column to artifacts table.
1317  *
1318  * NOTE: For DBs created with schema 5 we define a foreign key
1319  * constraint on the review_status_column. We don't bother with this
1320  * for DBs updated to schema 5 because of limitations of the SQLite
1321  * ALTER TABLE command.
1322  */
1323  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1324 
1325  // Add the encoding table
1326  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1327  initEncodingTypes(connection);
1328 
1329  /*
1330  * This needs to be done due to a Autopsy/TSK out of synch problem.
1331  * Without this, it is possible to upgrade from version 4 to 5 and
1332  * then 5 to 6, but not from 4 to 6.
1333  */
1334  initReviewStatuses(connection);
1335 
1336  // Add encoding type column to tsk_files_path
1337  // This should really have the FOREIGN KEY constraint but there are problems
1338  // getting that to work, so we don't add it on this upgrade path.
1339  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1340 
1341  return new CaseDbSchemaVersionNumber(5, 0);
1342 
1343  } finally {
1344  closeStatement(statement);
1346  }
1347  }
1348 
1362  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1363  if (schemaVersion.getMajor() != 5) {
1364  return schemaVersion;
1365  }
1366 
1367  /*
1368  * This upgrade fixes a bug where some releases had artifact review
1369  * status support in the case database and others did not.
1370  */
1371  Statement statement = null;
1372  ResultSet resultSet = null;
1374  try {
1375  /*
1376  * Add the review_statuses lookup table, if missing.
1377  */
1378  statement = connection.createStatement();
1379  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)");
1380 
1381  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1382  resultSet.next();
1383  if (resultSet.getLong("count") == 0) {
1384  /*
1385  * Add review_status_id column to artifacts table.
1386  *
1387  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1388  * key constraint on the review_status_column. We don't bother
1389  * with this for DBs updated to schema 5 or 6 because of
1390  * limitations of the SQLite ALTER TABLE command.
1391  */
1392  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1393  }
1394 
1395  return new CaseDbSchemaVersionNumber(6, 0);
1396 
1397  } finally {
1398  closeResultSet(resultSet);
1399  closeStatement(statement);
1401  }
1402  }
1403 
1417  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1418  if (schemaVersion.getMajor() != 6) {
1419  return schemaVersion;
1420  }
1421 
1422  /*
1423  * This upgrade adds an indexed extension column to the tsk_files table.
1424  */
1425  Statement statement = null;
1426  Statement updstatement = null;
1427  ResultSet resultSet = null;
1429  try {
1430  statement = connection.createStatement();
1431  updstatement = connection.createStatement();
1432  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1433 
1434  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1435  while (resultSet.next()) {
1436  long objID = resultSet.getLong("obj_id");
1437  String name = resultSet.getString("name");
1438  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1439  + "WHERE obj_id = " + objID);
1440  }
1441 
1442  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1443 
1444  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1445  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1446 
1447  return new CaseDbSchemaVersionNumber(7, 0);
1448 
1449  } finally {
1450  closeResultSet(resultSet);
1451  closeStatement(statement);
1452  closeStatement(updstatement);
1454  }
1455  }
1456 
1470  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1471  if (schemaVersion.getMajor() != 7) {
1472  return schemaVersion;
1473  }
1474 
1475  if (schemaVersion.getMinor() != 0) {
1476  return schemaVersion;
1477  }
1478 
1479  /*
1480  * This upgrade adds a minor version number column.
1481  */
1482  Statement statement = null;
1483  ResultSet resultSet = null;
1485  try {
1486  statement = connection.createStatement();
1487 
1488  //add the schema minor version number column.
1489  if (schemaVersion.getMinor() == 0) {
1490  //add the schema minor version number column.
1491  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1492  }
1493  return new CaseDbSchemaVersionNumber(7, 1);
1494 
1495  } finally {
1496  closeResultSet(resultSet);
1497  closeStatement(statement);
1499  }
1500  }
1501 
1515  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1516  if (schemaVersion.getMajor() != 7) {
1517  return schemaVersion;
1518  }
1519 
1520  if (schemaVersion.getMinor() != 1) {
1521  return schemaVersion;
1522  }
1523 
1524  Statement statement = null;
1525  Statement updstatement = null;
1526  ResultSet resultSet = null;
1528  try {
1529  //add the data_source_obj_id column to blackboard_artifacts.
1530  statement = connection.createStatement();
1531  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1532 
1533  // populate data_source_obj_id for each artifact
1534  updstatement = connection.createStatement();
1535  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1536  while (resultSet.next()) {
1537  long artifact_id = resultSet.getLong("artifact_id");
1538  long obj_id = resultSet.getLong("obj_id");
1539  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1540  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1541  + "WHERE artifact_id = " + artifact_id);
1542  }
1543  closeResultSet(resultSet);
1544  closeStatement(statement);
1545  closeStatement(updstatement);
1546 
1547  /*
1548  * Add a knownStatus column to the tag_names table.
1549  */
1550  statement = connection.createStatement();
1551  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1552 
1553  // Create account_types, accounts, and account_relationships table
1554  if (this.dbType.equals(DbType.SQLITE)) {
1555  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1556  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))");
1557  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))");
1558  } else {
1559  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1560  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))");
1561  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))");
1562  }
1563 
1564  // Create indexes
1565  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1566  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1567  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1568  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1569  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1570  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1571  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1572 
1573  return new CaseDbSchemaVersionNumber(7, 2);
1574  } finally {
1575  closeResultSet(resultSet);
1576  closeStatement(statement);
1577  closeStatement(updstatement);
1579  }
1580  }
1581 
1595  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1596  if (schemaVersion.getMajor() != 7) {
1597  return schemaVersion;
1598  }
1599 
1600  if (schemaVersion.getMinor() != 2) {
1601  return schemaVersion;
1602  }
1603 
1604  Statement updateSchemaStatement = connection.createStatement();
1605  Statement getExistingReportsStatement = connection.createStatement();
1606  ResultSet resultSet = null;
1607  ResultSet existingReports = null;
1608 
1610  try {
1611  // Update the schema to turn report_id into an object id.
1612 
1613  // Unfortunately, SQLite doesn't support adding a constraint
1614  // to an existing table so we have to rename the old...
1615  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1616 
1617  // ...create the new...
1618  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))");
1619 
1620  // ...add the existing report records back...
1621  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1622  while (existingReports.next()) {
1623  String path = existingReports.getString(2);
1624  long crtime = existingReports.getInt(3);
1625  String sourceModule = existingReports.getString(4);
1626  String reportName = existingReports.getString(5);
1627 
1628  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1629  insertObjectStatement.clearParameters();
1630  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1631  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1632  connection.executeUpdate(insertObjectStatement);
1633  resultSet = insertObjectStatement.getGeneratedKeys();
1634  if (!resultSet.next()) {
1635  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1636  }
1637  long objectId = resultSet.getLong(1); //last_insert_rowid()
1638 
1639  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1640  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1641  insertReportStatement.clearParameters();
1642  insertReportStatement.setLong(1, objectId);
1643  insertReportStatement.setString(2, path);
1644  insertReportStatement.setLong(3, crtime);
1645  insertReportStatement.setString(4, sourceModule);
1646  insertReportStatement.setString(5, reportName);
1647  connection.executeUpdate(insertReportStatement);
1648  }
1649 
1650  // ...and drop the old table.
1651  updateSchemaStatement.execute("DROP TABLE old_reports");
1652 
1653  return new CaseDbSchemaVersionNumber(8, 0);
1654  } finally {
1655  closeResultSet(resultSet);
1656  closeResultSet(existingReports);
1657  closeStatement(updateSchemaStatement);
1658  closeStatement(getExistingReportsStatement);
1660  }
1661  }
1662 
1676  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1677  if (schemaVersion.getMajor() != 8) {
1678  return schemaVersion;
1679  }
1680 
1681  if (schemaVersion.getMinor() != 0) {
1682  return schemaVersion;
1683  }
1684 
1686 
1687  try (Statement statement = connection.createStatement();) {
1688  // create examiners table
1689  if (this.dbType.equals(DbType.SQLITE)) {
1690  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1691  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1692  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1693  } else {
1694  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1695  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1696  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1697  }
1698 
1699  return new CaseDbSchemaVersionNumber(8, 1);
1700  } finally {
1702  }
1703  }
1704 
1718  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1719  if (schemaVersion.getMajor() != 8) {
1720  return schemaVersion;
1721  }
1722 
1723  if (schemaVersion.getMinor() != 1) {
1724  return schemaVersion;
1725  }
1726 
1728 
1729  try (Statement statement = connection.createStatement();) {
1730  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1731  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1732 
1733  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1734 
1735  /*
1736  * Add new tsk_db_extended_info table with TSK version, creation
1737  * time schema and schema version numbers as the initial data. The
1738  * creation time schema version is set to 0, 0 to indicate that it
1739  * is not known.
1740  */
1741  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1742  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1743  result.next();
1744  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1745  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1746  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1747  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1748  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1749 
1750  String primaryKeyType;
1751  switch (getDatabaseType()) {
1752  case POSTGRESQL:
1753  primaryKeyType = "BIGSERIAL";
1754  break;
1755  case SQLITE:
1756  primaryKeyType = "INTEGER";
1757  break;
1758  default:
1759  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1760  }
1761 
1762  //create and initialize tsk_event_types tables
1763  statement.execute("CREATE TABLE tsk_event_types ("
1764  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1765  + " display_name TEXT UNIQUE NOT NULL, "
1766  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1767  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1768  + " values( 0, 'Event Types', null)");
1769  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1770  + " values(1, 'File System', 0)");
1771  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1772  + " values(2, 'Web Activity', 0)");
1773  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1774  + " values(3, 'Misc Types', 0)");
1775  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1776  + " values(4, 'Modified', 1)");
1777  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1778  + " values(5, 'Accessed', 1)");
1779  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1780  + " values(6, 'Created', 1)");
1781  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1782  + " values(7, 'Changed', 1)");
1783 
1784  //create tsk_events tables
1785  statement.execute("CREATE TABLE tsk_event_descriptions ("
1786  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1787  + " full_description TEXT NOT NULL, "
1788  + " med_description TEXT, "
1789  + " short_description TEXT,"
1790  + " data_source_obj_id BIGINT NOT NULL, "
1791  + " file_obj_id BIGINT NOT NULL, "
1792  + " artifact_id BIGINT, "
1793  + " hash_hit INTEGER NOT NULL, " //boolean
1794  + " tagged INTEGER NOT NULL, " //boolean
1795  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1796  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1797  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1798  );
1799 
1800  statement.execute("CREATE TABLE tsk_events ( "
1801  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1802  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1803  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1804  + " time INTEGER NOT NULL) "
1805  );
1806 
1807  //create tsk_events indices
1808  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1809  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1810  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1811  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1812  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1813  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1814  return new CaseDbSchemaVersionNumber(8, 2);
1815 
1816  } finally {
1818  }
1819  }
1820 
1834  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1835  if (schemaVersion.getMajor() != 8) {
1836  return schemaVersion;
1837  }
1838 
1839  if (schemaVersion.getMinor() != 2) {
1840  return schemaVersion;
1841  }
1842 
1844 
1845  ResultSet resultSet = null;
1846 
1847  try (Statement statement = connection.createStatement();) {
1848 
1849  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1850  // Unfortunately, SQLite doesn't support adding a constraint
1851  // to an existing table so we have to rename the old...
1852  String primaryKeyType;
1853  switch (getDatabaseType()) {
1854  case POSTGRESQL:
1855  primaryKeyType = "BIGSERIAL";
1856  break;
1857  case SQLITE:
1858  primaryKeyType = "INTEGER";
1859  break;
1860  default:
1861  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1862  }
1863 
1864  //create and initialize tsk_event_types tables which may or may not exist
1865  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
1866  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1867  + " display_name TEXT UNIQUE NOT NULL, "
1868  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1869 
1870  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
1871 
1872  // If there is something in resultSet then the table must have previously
1873  // existing therefore there is not need to populate
1874  if (!resultSet.next()) {
1875 
1876  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1877  + " values( 0, 'Event Types', null)");
1878  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1879  + " values(1, 'File System', 0)");
1880  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1881  + " values(2, 'Web Activity', 0)");
1882  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1883  + " values(3, 'Misc Types', 0)");
1884  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1885  + " values(4, 'Modified', 1)");
1886  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1887  + " values(5, 'Accessed', 1)");
1888  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1889  + " values(6, 'Created', 1)");
1890  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1891  + " values(7, 'Changed', 1)");
1892  }
1893 
1894  // Delete the old table that may have been created with the upgrade
1895  // from 8.1 to 8.2.
1896  statement.execute("DROP TABLE IF EXISTS tsk_events");
1897 
1898  // Delete the old table that may have been created with the upgrade
1899  // from 8.1 to 8.2
1900  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
1901 
1902  //create new tsk_event_description table
1903  statement.execute("CREATE TABLE tsk_event_descriptions ("
1904  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1905  + " full_description TEXT NOT NULL, "
1906  + " med_description TEXT, "
1907  + " short_description TEXT,"
1908  + " data_source_obj_id BIGINT NOT NULL, "
1909  + " file_obj_id BIGINT NOT NULL, "
1910  + " artifact_id BIGINT, "
1911  + " hash_hit INTEGER NOT NULL, " //boolean
1912  + " tagged INTEGER NOT NULL, " //boolean
1913  + " UNIQUE(full_description, file_obj_id, artifact_id), "
1914  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1915  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1916  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1917  );
1918 
1919  // create a new table
1920  statement.execute("CREATE TABLE tsk_events ( "
1921  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1922  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1923  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1924  + " time INTEGER NOT NULL, "
1925  + " UNIQUE (event_type_id, event_description_id, time))"
1926  );
1927 
1928  // Fix mistakenly set names in tsk_db_info_extended
1929  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
1930  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
1931 
1932  return new CaseDbSchemaVersionNumber(8, 3);
1933  } finally {
1934  closeResultSet(resultSet);
1936  }
1937  }
1938 
1960  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1961  if (schemaVersion.getMajor() != 8) {
1962  return schemaVersion;
1963  }
1964 
1965  if (schemaVersion.getMinor() != 3) {
1966  return schemaVersion;
1967  }
1968 
1969  Statement statement = connection.createStatement();
1970  ResultSet results = null;
1971 
1973  try {
1974  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
1975  // the previous update code.
1976  if (null == getDatabaseType()) {
1977  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1978  }
1979 
1980  switch (getDatabaseType()) {
1981  case POSTGRESQL:
1982  // Check if the misnamed column is present
1983  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
1984  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
1985  if (results.next()) {
1986  // In PostgreSQL we can rename the column if it exists
1987  statement.execute("ALTER TABLE tsk_event_descriptions "
1988  + "RENAME COLUMN file_obj_id TO content_obj_id");
1989 
1990  // 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
1991  // Fix the schema, preserving any data if exists.
1992  statement.execute("CREATE TABLE temp_tsk_events ( "
1993  + " event_id BIGSERIAL PRIMARY KEY, "
1994  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1995  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
1996  + " time BIGINT NOT NULL, "
1997  + " UNIQUE (event_type_id, event_description_id, time))"
1998  );
1999 
2000  // Copy the data
2001  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2002  + "event_description_id, time) SELECT * FROM tsk_events");
2003 
2004  // Drop the old table
2005  statement.execute("DROP TABLE tsk_events");
2006 
2007  // Rename the new table
2008  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2009 
2010  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2011  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2012  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2013  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2014  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2015  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2016  }
2017  break;
2018  case SQLITE:
2019  boolean hasMisnamedColumn = false;
2020  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2021  while (results.next()) {
2022  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2023  hasMisnamedColumn = true;
2024  break;
2025  }
2026  }
2027 
2028  if (hasMisnamedColumn) {
2029  // Since we can't rename the column we'll need to make new tables and copy the data
2030  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2031  + " event_description_id INTEGER PRIMARY KEY, "
2032  + " full_description TEXT NOT NULL, "
2033  + " med_description TEXT, "
2034  + " short_description TEXT,"
2035  + " data_source_obj_id BIGINT NOT NULL, "
2036  + " content_obj_id BIGINT NOT NULL, "
2037  + " artifact_id BIGINT, "
2038  + " hash_hit INTEGER NOT NULL, " //boolean
2039  + " tagged INTEGER NOT NULL, " //boolean
2040  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2041  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2042  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2043  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2044  );
2045 
2046  statement.execute("CREATE TABLE temp_tsk_events ( "
2047  + " event_id INTEGER PRIMARY KEY, "
2048  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2049  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2050  + " time INTEGER NOT NULL, "
2051  + " UNIQUE (event_type_id, event_description_id, time))"
2052  );
2053 
2054  // Copy the data
2055  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2056  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2057  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2058 
2059  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2060  + "event_description_id, time) SELECT * FROM tsk_events");
2061 
2062  // Drop the old tables
2063  statement.execute("DROP TABLE tsk_events");
2064  statement.execute("DROP TABLE tsk_event_descriptions");
2065 
2066  // Rename the new tables
2067  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2068  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2069 
2070  //create tsk_events indices
2071  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2072  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2073  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2074  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2075  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2076  }
2077  break;
2078  default:
2079  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2080  }
2081 
2082  // create pool info table
2083  if (this.dbType.equals(DbType.SQLITE)) {
2084  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)");
2085  } else {
2086  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)");
2087  }
2088 
2089  // Add new account types for newly supported messaging applications, if they dont exists already.
2090  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2091  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2092  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2093  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2094  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2095  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2096  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2097  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2098  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2099  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2100 
2101  return new CaseDbSchemaVersionNumber(8, 4);
2102  } finally {
2103  closeResultSet(results);
2104  closeStatement(statement);
2106  }
2107  }
2108 
2109  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2110  if (schemaVersion.getMajor() != 8) {
2111  return schemaVersion;
2112  }
2113 
2114  if (schemaVersion.getMinor() != 4) {
2115  return schemaVersion;
2116  }
2117 
2118  Statement statement = connection.createStatement();
2120  try {
2121  switch (getDatabaseType()) {
2122  case POSTGRESQL:
2123  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2124  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2125  break;
2126  case SQLITE:
2127  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2128  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2129  break;
2130  }
2131 
2132  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2133 
2134  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2135  if (getDatabaseType() == DbType.POSTGRESQL) {
2136  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2137  } else {
2138  statement.execute(insertStmt);
2139  }
2140  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2141  if (resultSet != null && resultSet.next()) {
2142  int tagSetId = resultSet.getInt(1);
2143 
2144  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2145  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2146  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2147  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2148  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2149  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2150 
2151  String deleteContentTag = "DELETE FROM content_tags WHERE tag_name_id IN (SELECT tag_name_id from tag_names WHERE display_name LIKE 'CAT-0: Uncategorized')";
2152  String deleteArtifactTag = "DELETE FROM blackboard_artifact_tags WHERE tag_name_id IN (SELECT tag_name_id from tag_names WHERE display_name LIKE 'CAT-0: Uncategorized')";
2153  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2154  statement.executeUpdate(deleteContentTag);
2155  statement.executeUpdate(deleteArtifactTag);
2156  statement.executeUpdate(deleteCat0);
2157 
2158  } else {
2159  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2160  }
2161  }
2162 
2163  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2164  // this column will have a foreign key constraint on the data_source_info table.
2165  // There does not seem to be a reasonable way to do this in an upgrade,
2166  // so upgraded cases will be missing the foreign key.
2167  switch (getDatabaseType()) {
2168  case POSTGRESQL:
2169  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2170  break;
2171  case SQLITE:
2172  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2173  break;
2174  }
2175  Statement updateStatement = connection.createStatement();
2176  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2177  while (resultSet.next()) {
2178  long fsId = resultSet.getLong("obj_id");
2179  long dataSourceId = getDataSourceObjectId(connection, fsId);
2180  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2181  }
2182  } finally {
2183  closeStatement(updateStatement);
2184  }
2185 
2186  return new CaseDbSchemaVersionNumber(8, 5);
2187 
2188  } finally {
2189  closeStatement(statement);
2191  }
2192  }
2193 
2205  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2206 
2207  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2208  switch (getDatabaseType()) {
2209  case POSTGRESQL:
2210  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2211  break;
2212  case SQLITE:
2213  insertSQL = "INSERT OR IGNORE " + insertSQL;
2214  break;
2215  default:
2216  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2217  }
2218  statement.execute(insertSQL); //NON-NLS
2219  }
2220 
2228  static String extractExtension(final String fileName) {
2229  String ext;
2230  int i = fileName.lastIndexOf(".");
2231  // > 0 because we assume it's not an extension if period is the first character
2232  if ((i > 0) && ((i + 1) < fileName.length())) {
2233  ext = fileName.substring(i + 1);
2234  } else {
2235  return "";
2236  }
2237  // we added this at one point to deal with files that had crazy names based on URLs
2238  // it's too hard though to clean those up and not mess up basic extensions though.
2239  // We need to add '-' to the below if we use it again
2240  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2241  // if (findNonAlphanumeric.length > 1) {
2242  // ext = findNonAlphanumeric[0];
2243  // }
2244  return ext.toLowerCase();
2245  }
2246 
2257  @Deprecated
2258  public int getSchemaVersion() {
2259  return getDBSchemaVersion().getMajor();
2260  }
2261 
2268  return CURRENT_DB_SCHEMA_VERSION;
2269  }
2270 
2278  return caseDBSchemaCreationVersion;
2279  }
2280 
2287  return this.dbType;
2288  }
2289 
2296  public String getBackupDatabasePath() {
2297  return dbBackupPath;
2298  }
2299 
2314  public CaseDbTransaction beginTransaction() throws TskCoreException {
2315  return new CaseDbTransaction(this, connections.getConnection());
2316  }
2317 
2323  public String getDatabaseName() {
2324  return databaseName;
2325  }
2326 
2333  public String getDbDirPath() {
2334  return caseDirPath;
2335  }
2336 
2343  if (dbType == DbType.SQLITE) {
2344  rwLock.writeLock().lock();
2345  }
2346  }
2347 
2354  if (dbType == DbType.SQLITE) {
2355  rwLock.writeLock().unlock();
2356  }
2357  }
2358 
2365  if (dbType == DbType.SQLITE) {
2366  rwLock.readLock().lock();
2367  }
2368  }
2369 
2376  if (dbType == DbType.SQLITE) {
2377  rwLock.readLock().unlock();
2378  }
2379  }
2380 
2390  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2391  try {
2392  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2393  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2395  //don't wrap in new TskCoreException
2396  throw ex;
2397  } catch (Exception ex) {
2398  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
2399  }
2400  }
2401 
2413  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
2414  try {
2415  /*
2416  * The flow of this method involves trying to open case and if
2417  * successful, return that case. If unsuccessful, an exception is
2418  * thrown. We catch any exceptions, and use tryConnect() to attempt
2419  * to obtain further information about the error. If tryConnect() is
2420  * unable to successfully connect, tryConnect() will throw a
2421  * TskCoreException with a message containing user-level error
2422  * reporting. If tryConnect() is able to connect, flow continues and
2423  * we rethrow the original exception obtained from trying to create
2424  * the case. In this way, we obtain more detailed information if we
2425  * are able, but do not lose any information if unable.
2426  */
2427  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2428  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
2429  } catch (PropertyVetoException exp) {
2430  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2431  throw new TskCoreException(exp.getMessage(), exp);
2433  //don't wrap in new TskCoreException
2434  throw ex;
2435  } catch (Exception exp) {
2436  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2437  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2438  }
2439  }
2440 
2450  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
2451  try {
2452  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
2453  factory.createCaseDatabase();
2454 
2455  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2456  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2457  } catch (Exception ex) {
2458  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
2459  }
2460  }
2461 
2477  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
2478  String databaseName = createCaseDataBaseName(caseName);
2479  try {
2492  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
2493  factory.createCaseDatabase();
2494 
2495  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2496  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
2497  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
2498  } catch (PropertyVetoException exp) {
2499  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2500  throw new TskCoreException(exp.getMessage(), exp);
2501  } catch (Exception exp) {
2502  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2503  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2504  }
2505  }
2506 
2516  private static String createCaseDataBaseName(String candidateDbName) {
2517  String dbName;
2518  if (!candidateDbName.isEmpty()) {
2519  /*
2520  * Replace all non-ASCII characters.
2521  */
2522  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
2523 
2524  /*
2525  * Replace all control characters.
2526  */
2527  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
2528 
2529  /*
2530  * Replace /, \, :, ?, space, ' ".
2531  */
2532  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
2533 
2534  /*
2535  * Make it all lowercase.
2536  */
2537  dbName = dbName.toLowerCase();
2538 
2539  /*
2540  * Must start with letter or underscore. If not, prepend an
2541  * underscore.
2542  */
2543  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
2544  dbName = "_" + dbName;
2545  }
2546 
2547  /*
2548  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
2549  * uniqueness.
2550  */
2551  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
2552  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
2553  }
2554 
2555  } else {
2556  /*
2557  * Must start with letter or underscore.
2558  */
2559  dbName = "_";
2560  }
2561  /*
2562  * Add the time stmap.
2563  */
2564  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
2565  Date date = new Date();
2566  dbName = dbName + "_" + dateFormat.format(date);
2567 
2568  return dbName;
2569  }
2570 
2578  public Examiner getCurrentExaminer() throws TskCoreException {
2579 
2580  // return cached value if there's one
2581  if (cachedCurrentExaminer != null) {
2582  return cachedCurrentExaminer;
2583  }
2584  String loginName = System.getProperty("user.name");
2585  if (loginName == null || loginName.isEmpty()) {
2586  throw new TskCoreException("Failed to determine logged in user name.");
2587  }
2588 
2589  CaseDbConnection connection = connections.getConnection();
2591  ResultSet resultSet = null;
2592  try {
2593  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
2594  statement.clearParameters();
2595  statement.setString(1, loginName);
2596  resultSet = connection.executeQuery(statement);
2597  if (resultSet.next()) {
2598  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
2599  return cachedCurrentExaminer;
2600  } else {
2601  throw new TskCoreException("Error getting examaminer for name = " + loginName);
2602  }
2603 
2604  } catch (SQLException ex) {
2605  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
2606  } finally {
2607  closeResultSet(resultSet);
2608  connection.close();
2610  }
2611 
2612  }
2613 
2623  Examiner getExaminerById(long id) throws TskCoreException {
2624 
2625  CaseDbConnection connection = connections.getConnection();
2627  ResultSet resultSet = null;
2628  try {
2629  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
2630  statement.clearParameters();
2631  statement.setLong(1, id);
2632  resultSet = connection.executeQuery(statement);
2633  if (resultSet.next()) {
2634  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
2635  } else {
2636  throw new TskCoreException("Error getting examaminer for id = " + id);
2637  }
2638  } catch (SQLException ex) {
2639  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
2640  } finally {
2641  closeResultSet(resultSet);
2642  connection.close();
2644  }
2645  }
2646 
2664  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
2665  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
2666  }
2667 
2676  public List<Content> getRootObjects() throws TskCoreException {
2677  CaseDbConnection connection = connections.getConnection();
2679  Statement s = null;
2680  ResultSet rs = null;
2681  try {
2682  s = connection.createStatement();
2683  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
2684  + "WHERE par_obj_id IS NULL"); //NON-NLS
2685  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
2686  while (rs.next()) {
2687  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
2688  }
2689 
2690  List<Content> rootObjs = new ArrayList<Content>();
2691  for (ObjectInfo i : infos) {
2692  if (null != i.type) {
2693  switch (i.type) {
2694  case IMG:
2695  rootObjs.add(getImageById(i.id));
2696  break;
2697  case ABSTRACTFILE:
2698  // Check if virtual dir for local files.
2699  AbstractFile af = getAbstractFileById(i.id);
2700  if (af instanceof VirtualDirectory) {
2701  rootObjs.add(af);
2702  } else {
2703  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
2704  }
2705  break;
2706  case REPORT:
2707  break;
2708  default:
2709  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
2710  }
2711  }
2712  }
2713  return rootObjs;
2714  } catch (SQLException ex) {
2715  throw new TskCoreException("Error getting root objects", ex);
2716  } finally {
2717  closeResultSet(rs);
2718  closeStatement(s);
2719  connection.close();
2721  }
2722  }
2723 
2735  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
2736 
2737  // check cached map first
2738  synchronized (deviceIdToDatasourceObjIdMap) {
2739  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
2740  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
2741  }
2742 
2743  CaseDbConnection connection = connections.getConnection();
2745  Statement s = null;
2746  ResultSet rs = null;
2747  try {
2748  s = connection.createStatement();
2749  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
2750  List<Long> dataSourceObjIds = new ArrayList<Long>();
2751  while (rs.next()) {
2752  dataSourceObjIds.add(rs.getLong("obj_id"));
2753 
2754  // Add to map of deviceID to data_source_obj_id.
2755  long ds_obj_id = rs.getLong("obj_id");
2756  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
2757  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
2758  } else {
2759  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
2760  }
2761  }
2762  return dataSourceObjIds;
2763  } catch (SQLException ex) {
2764  throw new TskCoreException("Error getting data sources", ex);
2765  } finally {
2766  closeResultSet(rs);
2767  closeStatement(s);
2768  connection.close();
2770  }
2771  }
2772  }
2773 
2790  public List<DataSource> getDataSources() throws TskCoreException {
2791  CaseDbConnection connection = connections.getConnection();
2793  Statement statement = null;
2794  ResultSet resultSet = null;
2795  Statement statement2 = null;
2796  ResultSet resultSet2 = null;
2797  try {
2798  statement = connection.createStatement();
2799  statement2 = connection.createStatement();
2800  resultSet = connection.executeQuery(statement,
2801  "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 "
2802  + "FROM data_source_info AS ds "
2803  + "LEFT JOIN tsk_image_info AS img "
2804  + "ON ds.obj_id = img.obj_id"); //NON-NLS
2805 
2806  List<DataSource> dataSourceList = new ArrayList<DataSource>();
2807  Map<Long, List<String>> imagePathsMap = getImagePaths();
2808 
2809  while (resultSet.next()) {
2810  DataSource dataSource;
2811  Long objectId = resultSet.getLong("obj_id");
2812  String deviceId = resultSet.getString("device_id");
2813  String timezone = resultSet.getString("time_zone");
2814  String type = resultSet.getString("type");
2815 
2816  if (type == null) {
2817  /*
2818  * No data found in 'tsk_image_info', so we build a
2819  * LocalFilesDataSource.
2820  */
2821 
2822  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
2823  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
2824  resultSet2.close();
2825 
2829  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
2830  | TSK_FS_META_FLAG_ENUM.USED.getValue());
2831  String parentPath = "/"; //NON-NLS
2832  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
2833  } else {
2834  /*
2835  * Data found in 'tsk_image_info', so we build an Image.
2836  */
2837  Long ssize = resultSet.getLong("ssize");
2838  Long size = resultSet.getLong("size");
2839  String md5 = resultSet.getString("md5");
2840  String sha1 = resultSet.getString("sha1");
2841  String sha256 = resultSet.getString("sha256");
2842  String name = resultSet.getString("display_name");
2843 
2844  List<String> imagePaths = imagePathsMap.get(objectId);
2845  if (name == null) {
2846  if (imagePaths.size() > 0) {
2847  String path = imagePaths.get(0);
2848  name = (new java.io.File(path)).getName();
2849  } else {
2850  name = "";
2851  }
2852  }
2853 
2854  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
2855  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
2856  }
2857 
2858  dataSourceList.add(dataSource);
2859  }
2860 
2861  return dataSourceList;
2862 
2863  } catch (SQLException ex) {
2864  throw new TskCoreException("Error getting data sources", ex);
2865  } finally {
2866  closeResultSet(resultSet);
2867  closeStatement(statement);
2868  closeResultSet(resultSet2);
2869  closeStatement(statement2);
2870  connection.close();
2872  }
2873  }
2874 
2894  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
2895  DataSource dataSource = null;
2896  CaseDbConnection connection = connections.getConnection();
2898  Statement statement = null;
2899  ResultSet resultSet = null;
2900  Statement statement2 = null;
2901  ResultSet resultSet2 = null;
2902  try {
2903  statement = connection.createStatement();
2904  statement2 = connection.createStatement();
2905  resultSet = connection.executeQuery(statement,
2906  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
2907  + "FROM data_source_info AS ds "
2908  + "LEFT JOIN tsk_image_info AS img "
2909  + "ON ds.obj_id = img.obj_id "
2910  + "WHERE ds.obj_id = " + objectId); //NON-NLS
2911  if (resultSet.next()) {
2912  String deviceId = resultSet.getString("device_id");
2913  String timezone = resultSet.getString("time_zone");
2914  String type = resultSet.getString("type");
2915 
2916  if (type == null) {
2917  /*
2918  * No data found in 'tsk_image_info', so we build an
2919  * LocalFilesDataSource.
2920  */
2921 
2922  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
2923  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
2924 
2928  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
2929  | TSK_FS_META_FLAG_ENUM.USED.getValue());
2930  String parentPath = "/"; //NON-NLS
2931  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath);
2932  } else {
2933  /*
2934  * Data found in 'tsk_image_info', so we build an Image.
2935  */
2936  Long ssize = resultSet.getLong("ssize");
2937  Long size = resultSet.getLong("size");
2938  String md5 = resultSet.getString("md5");
2939  String sha1 = resultSet.getString("sha1");
2940  String sha256 = resultSet.getString("sha256");
2941  String name = resultSet.getString("display_name");
2942 
2943  List<String> imagePaths = getImagePathsById(objectId);
2944  if (name == null) {
2945  if (imagePaths.size() > 0) {
2946  String path = imagePaths.get(0);
2947  name = (new java.io.File(path)).getName();
2948  } else {
2949  name = "";
2950  }
2951  }
2952 
2953  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
2954  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
2955  }
2956  } else {
2957  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
2958  }
2959  } catch (SQLException ex) {
2960  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
2961  } finally {
2962  closeResultSet(resultSet);
2963  closeStatement(statement);
2964  closeResultSet(resultSet2);
2965  closeStatement(statement2);
2966  connection.close();
2968  }
2969 
2970  return dataSource;
2971  }
2972 
2983  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
2984  return getArtifactsHelper("blackboard_artifacts.artifact_type_id = " + artifactTypeID);
2985  }
2986 
2997  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
2998  CaseDbConnection connection = connections.getConnection();
3000  ResultSet rs = null;
3001  try {
3002  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3003  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3004  statement.clearParameters();
3005  statement.setLong(1, objId);
3006  rs = connection.executeQuery(statement);
3007  long count = 0;
3008  if (rs.next()) {
3009  count = rs.getLong("count");
3010  }
3011  return count;
3012  } catch (SQLException ex) {
3013  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3014  } finally {
3015  closeResultSet(rs);
3016  connection.close();
3018  }
3019  }
3020 
3031  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3032  CaseDbConnection connection = connections.getConnection();
3034  ResultSet rs = null;
3035  try {
3036  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3037  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3038  statement.clearParameters();
3039  statement.setInt(1, artifactTypeID);
3040  rs = connection.executeQuery(statement);
3041  long count = 0;
3042  if (rs.next()) {
3043  count = rs.getLong("count");
3044  }
3045  return count;
3046  } catch (SQLException ex) {
3047  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3048  } finally {
3049  closeResultSet(rs);
3050  connection.close();
3052  }
3053  }
3054 
3066  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3067  CaseDbConnection connection = connections.getConnection();
3069  ResultSet rs = null;
3070  try {
3071  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3072  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3073  statement.clearParameters();
3074  statement.setInt(2, artifactTypeID);
3075  statement.setLong(1, dataSourceID);
3076  rs = connection.executeQuery(statement);
3077  long count = 0;
3078  if (rs.next()) {
3079  count = rs.getLong("count");
3080  }
3081  return count;
3082  } catch (SQLException ex) {
3083  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3084  } finally {
3085  closeResultSet(rs);
3086  connection.close();
3088  }
3089  }
3090 
3105  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3106  CaseDbConnection connection = connections.getConnection();
3108  Statement s = null;
3109  ResultSet rs = null;
3110  try {
3111  s = connection.createStatement();
3112  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3113  + "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, "
3114  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3115  + " arts.review_status_id AS review_status_id " //NON-NLS
3116  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3117  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3118  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3119  + " AND attrs.value_text = '" + value + "'"
3120  + " AND types.artifact_type_id=arts.artifact_type_id"
3121  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
3122  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3123  while (rs.next()) {
3124  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3125  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3126  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3127  }
3128  return artifacts;
3129  } catch (SQLException ex) {
3130  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3131  } finally {
3132  closeResultSet(rs);
3133  closeStatement(s);
3134  connection.close();
3136  }
3137  }
3138 
3156  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3157  String valSubStr = "%" + subString; //NON-NLS
3158  if (startsWith == false) {
3159  valSubStr += "%"; //NON-NLS
3160  }
3161  CaseDbConnection connection = connections.getConnection();
3163  Statement s = null;
3164  ResultSet rs = null;
3165  try {
3166  s = connection.createStatement();
3167  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3168  + " 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
3169  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3170  + " arts.review_status_id AS review_status_id " //NON-NLS
3171  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3172  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3173  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3174  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3175  + " AND types.artifact_type_id=arts.artifact_type_id "
3176  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3177  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3178  while (rs.next()) {
3179  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3180  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3181  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3182  }
3183  return artifacts;
3184  } catch (SQLException ex) {
3185  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3186  } finally {
3187  closeResultSet(rs);
3188  closeStatement(s);
3189  connection.close();
3191  }
3192  }
3193 
3208  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3209  CaseDbConnection connection = connections.getConnection();
3211  Statement s = null;
3212  ResultSet rs = null;
3213  try {
3214  s = connection.createStatement();
3215  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3216  + " 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, "
3217  + " types.type_name AS type_name, types.display_name AS display_name, "
3218  + " arts.review_status_id AS review_status_id "//NON-NLS
3219  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3220  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3221  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3222  + " AND attrs.value_int32 = " + value //NON-NLS
3223  + " AND types.artifact_type_id=arts.artifact_type_id "
3224  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3225  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3226  while (rs.next()) {
3227  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3228  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3229  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3230  }
3231  return artifacts;
3232  } catch (SQLException ex) {
3233  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3234  } finally {
3235  closeResultSet(rs);
3236  closeStatement(s);
3237  connection.close();
3239  }
3240  }
3241 
3256  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3257  CaseDbConnection connection = connections.getConnection();
3259  Statement s = null;
3260  ResultSet rs = null;
3261  try {
3262  s = connection.createStatement();
3263  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3264  + " 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, "
3265  + " types.type_name AS type_name, types.display_name AS display_name, "
3266  + " arts.review_status_id AS review_status_id "//NON-NLS
3267  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3268  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3269  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3270  + " AND attrs.value_int64 = " + value //NON-NLS
3271  + " AND types.artifact_type_id=arts.artifact_type_id "
3272  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3273  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3274  while (rs.next()) {
3275  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3276  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3277  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3278  }
3279  return artifacts;
3280  } catch (SQLException ex) {
3281  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3282  } finally {
3283  closeResultSet(rs);
3284  closeStatement(s);
3285  connection.close();
3287  }
3288  }
3289 
3304  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3305  CaseDbConnection connection = connections.getConnection();
3307  Statement s = null;
3308  ResultSet rs = null;
3309  try {
3310  s = connection.createStatement();
3311  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3312  + " 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, "
3313  + " types.type_name AS type_name, types.display_name AS display_name, "
3314  + " arts.review_status_id AS review_status_id "//NON-NLS
3315  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3316  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3317  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3318  + " AND attrs.value_double = " + value //NON-NLS
3319  + " AND types.artifact_type_id=arts.artifact_type_id "
3320  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3321  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3322  while (rs.next()) {
3323  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3324  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3325  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3326  }
3327  return artifacts;
3328  } catch (SQLException ex) {
3329  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3330  } finally {
3331  closeResultSet(rs);
3332  closeStatement(s);
3333  connection.close();
3335  }
3336  }
3337 
3352  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3353  CaseDbConnection connection = connections.getConnection();
3355  Statement s = null;
3356  ResultSet rs = null;
3357  try {
3358  s = connection.createStatement();
3359  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3360  + " 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, "
3361  + " types.type_name AS type_name, types.display_name AS display_name, "
3362  + " arts.review_status_id AS review_status_id "//NON-NLS
3363  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3364  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3365  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3366  + " AND attrs.value_byte = " + value //NON-NLS
3367  + " AND types.artifact_type_id=arts.artifact_type_id "
3368  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3369  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3370  while (rs.next()) {
3371  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3372  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3373  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3374  }
3375  return artifacts;
3376  } catch (SQLException ex) {
3377  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3378  } finally {
3379  closeResultSet(rs);
3380  closeStatement(s);
3381  connection.close();
3383  }
3384  }
3385 
3393  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3394  CaseDbConnection connection = connections.getConnection();
3396  Statement s = null;
3397  ResultSet rs = null;
3398  try {
3399  s = connection.createStatement();
3400  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types"); //NON-NLS
3401  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
3402  while (rs.next()) {
3403  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3404  rs.getString("type_name"), rs.getString("display_name")));
3405  }
3406  return artifactTypes;
3407  } catch (SQLException ex) {
3408  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
3409  } finally {
3410  closeResultSet(rs);
3411  closeStatement(s);
3412  connection.close();
3414  }
3415  }
3416 
3425  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
3426  String typeIdList = "";
3427  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
3428  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
3429  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
3430  typeIdList += ", ";
3431  }
3432  }
3433  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
3434  + "WHERE artifact_type_id IN (" + typeIdList + ")";
3435  CaseDbConnection connection = connections.getConnection();
3437  Statement s = null;
3438  ResultSet rs = null;
3439  try {
3440  s = connection.createStatement();
3441  rs = connection.executeQuery(s, query);
3442  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
3443  while (rs.next()) {
3444  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
3445  }
3446  return usedArts;
3447  } catch (SQLException ex) {
3448  throw new TskCoreException("Error getting artifact types in use", ex);
3449  } finally {
3450  closeResultSet(rs);
3451  closeStatement(s);
3452  connection.close();
3454  }
3455  }
3456 
3467  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
3468  CaseDbConnection connection = connections.getConnection();
3470  Statement s = null;
3471  ResultSet rs = null;
3472  try {
3473  s = connection.createStatement();
3474  rs = connection.executeQuery(s,
3475  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
3476  + "types.type_name AS type_name, types.display_name AS display_name "
3477  + "FROM blackboard_artifact_types AS types "
3478  + "INNER JOIN blackboard_artifacts AS arts "
3479  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
3480  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
3481  while (rs.next()) {
3482  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3483  rs.getString("type_name"), rs.getString("display_name")));
3484  }
3485  return uniqueArtifactTypes;
3486  } catch (SQLException ex) {
3487  throw new TskCoreException("Error getting attribute types", ex);
3488  } finally {
3489  closeResultSet(rs);
3490  closeStatement(s);
3491  connection.close();
3493  }
3494  }
3495 
3503  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
3504  CaseDbConnection connection = connections.getConnection();
3506  Statement s = null;
3507  ResultSet rs = null;
3508  try {
3509  s = connection.createStatement();
3510  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
3511  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
3512  while (rs.next()) {
3513  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3514  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
3515  }
3516  return attribute_types;
3517  } catch (SQLException ex) {
3518  throw new TskCoreException("Error getting attribute types", ex);
3519  } finally {
3520  closeResultSet(rs);
3521  closeStatement(s);
3522  connection.close();
3524  }
3525  }
3526 
3538  public int getBlackboardAttributeTypesCount() throws TskCoreException {
3539  CaseDbConnection connection = connections.getConnection();
3541  Statement s = null;
3542  ResultSet rs = null;
3543  try {
3544  s = connection.createStatement();
3545  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
3546  int count = 0;
3547  if (rs.next()) {
3548  count = rs.getInt("count");
3549  }
3550  return count;
3551  } catch (SQLException ex) {
3552  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3553  } finally {
3554  closeResultSet(rs);
3555  closeStatement(s);
3556  connection.close();
3558  }
3559  }
3560 
3573  ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
3574  CaseDbConnection connection = connections.getConnection();
3576  ResultSet rs = null;
3577  try {
3578  Statement statement = connection.createStatement();
3579  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
3580  + "blackboard_artifacts.obj_id AS obj_id, "
3581  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
3582  + "blackboard_artifacts.data_source_obj_id AS data_source_obj_id, "
3583  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
3584  + "blackboard_artifact_types.type_name AS type_name, "
3585  + "blackboard_artifact_types.display_name AS display_name, "
3586  + "blackboard_artifacts.review_status_id AS review_status_id "
3587  + "FROM blackboard_artifacts, blackboard_artifact_types "
3588  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
3589  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
3590  + " AND " + whereClause;
3591  rs = connection.executeQuery(statement, query);
3592  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3593  while (rs.next()) {
3594  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3595  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3596  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3597  }
3598  return artifacts;
3599  } catch (SQLException ex) {
3600  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
3601  } finally {
3602  closeResultSet(rs);
3603  connection.close();
3605  }
3606  }
3607 
3620  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
3621  CaseDbConnection connection = connections.getConnection();
3623  ResultSet rs = null;
3624  try {
3625  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
3626  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
3627  statement.clearParameters();
3628  statement.setLong(1, obj_id);
3629  statement.setInt(2, artifactTypeID);
3630  rs = connection.executeQuery(statement);
3631  long count = 0;
3632  if (rs.next()) {
3633  count = rs.getLong("count");
3634  }
3635  return count;
3636  } catch (SQLException ex) {
3637  throw new TskCoreException("Error getting blackboard artifact count", ex);
3638  } finally {
3639  closeResultSet(rs);
3640  connection.close();
3642  }
3643  }
3644 
3657  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
3658  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3659  }
3660 
3673  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
3674  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
3675  }
3676 
3689  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3690  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
3691  }
3692 
3705  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
3706  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
3707  if (artifactTypeID == -1) {
3708  return 0;
3709  }
3710  return getArtifactsCountHelper(artifactTypeID, obj_id);
3711  }
3712 
3725  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
3726  return getArtifactsCountHelper(artifactTypeID, obj_id);
3727  }
3728 
3741  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
3742  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
3743  }
3744 
3756  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
3757  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
3758  }
3759 
3771  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
3772  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
3773  }
3774 
3788  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3789  CaseDbConnection connection = connections.getConnection();
3791  Statement s = null;
3792  ResultSet rs = null;
3793  try {
3794  s = connection.createStatement();
3795  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3796  + "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, "
3797  + "types.type_name AS type_name, types.display_name AS display_name,"
3798  + "arts.review_status_id AS review_status_id "//NON-NLS
3799  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3800  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3801  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3802  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
3803  + " AND attrs.value_text = '" + value + "'" //NON-NLS
3804  + " AND types.artifact_type_id=arts.artifact_type_id"
3805  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3806  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3807  while (rs.next()) {
3808  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3809  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3810  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3811  }
3812  return artifacts;
3813  } catch (SQLException ex) {
3814  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
3815  } finally {
3816  closeResultSet(rs);
3817  closeStatement(s);
3818  connection.close();
3820  }
3821  }
3822 
3833  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
3834  CaseDbConnection connection = connections.getConnection();
3836  ResultSet rs = null;
3837  Statement s;
3838  try {
3839  s = connection.createStatement();
3840  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
3841  + "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, "
3842  + "types.type_name AS type_name, types.display_name AS display_name,"
3843  + "arts.review_status_id AS review_status_id "//NON-NLS
3844  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
3845  + "WHERE arts.artifact_id = " + artifactID
3846  + " AND arts.artifact_type_id = types.artifact_type_id");
3847  if (rs.next()) {
3848  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
3849  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3850  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
3851  } else {
3852  /*
3853  * I think this should actually return null (or Optional) when
3854  * there is no artifact with the given id, but it looks like
3855  * existing code is not expecting that. -jm
3856  */
3857  throw new TskCoreException("No blackboard artifact with id " + artifactID);
3858  }
3859  } catch (SQLException ex) {
3860  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
3861  } finally {
3862  closeResultSet(rs);
3863  connection.close();
3865  }
3866  }
3867 
3876  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
3877  CaseDbConnection connection = connections.getConnection();
3879  try {
3880  addBlackBoardAttribute(attr, artifactTypeId, connection);
3881  } catch (SQLException ex) {
3882  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
3883  } finally {
3884  connection.close();
3886  }
3887  }
3888 
3898  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
3899  CaseDbConnection connection = connections.getConnection();
3901  try {
3902  connection.beginTransaction();
3903  for (final BlackboardAttribute attr : attributes) {
3904  addBlackBoardAttribute(attr, artifactTypeId, connection);
3905  }
3906  connection.commitTransaction();
3907  } catch (SQLException ex) {
3908  connection.rollbackTransaction();
3909  throw new TskCoreException("Error adding blackboard attributes", ex);
3910  } finally {
3911  connection.close();
3913  }
3914  }
3915 
3916  private void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
3917  PreparedStatement statement;
3918  switch (attr.getAttributeType().getValueType()) {
3919  case STRING:
3920  case JSON:
3921  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
3922  statement.clearParameters();
3923  statement.setString(7, attr.getValueString());
3924  break;
3925  case BYTE:
3926  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
3927  statement.clearParameters();
3928  statement.setBytes(7, attr.getValueBytes());
3929  break;
3930  case INTEGER:
3931  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
3932  statement.clearParameters();
3933  statement.setInt(7, attr.getValueInt());
3934  break;
3935  case LONG:
3936  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3937  statement.clearParameters();
3938  statement.setLong(7, attr.getValueLong());
3939  break;
3940  case DOUBLE:
3941  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
3942  statement.clearParameters();
3943  statement.setDouble(7, attr.getValueDouble());
3944  break;
3945  case DATETIME:
3946  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
3947  statement.clearParameters();
3948  statement.setLong(7, attr.getValueLong());
3949  break;
3950  default:
3951  throw new TskCoreException("Unrecognized artifact attribute value type");
3952  }
3953  statement.setLong(1, attr.getArtifactID());
3954  statement.setInt(2, artifactTypeId);
3955  statement.setString(3, attr.getSourcesCSV());
3956  statement.setString(4, "");
3957  statement.setInt(5, attr.getAttributeType().getTypeID());
3958  statement.setLong(6, attr.getAttributeType().getValueType().getType());
3959  connection.executeUpdate(statement);
3960  }
3961 
3972  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
3973  /*
3974  * WARNING: This is a temporary implementation that is not safe and
3975  * denormalizes the case datbase.
3976  *
3977  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
3978  * the sources of artifact attributes.
3979  */
3980  if (null == source || source.isEmpty()) {
3981  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
3982  }
3983  CaseDbConnection connection = connections.getConnection();
3985  Statement queryStmt = null;
3986  Statement updateStmt = null;
3987  ResultSet result = null;
3988  String newSources = "";
3989  try {
3990  connection.beginTransaction();
3991  String valueClause = "";
3992  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
3993  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
3994  switch (valueType) {
3995  case STRING:
3996  case JSON:
3997  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
3998  break;
3999  case INTEGER:
4000  valueClause = " value_int32 = " + attr.getValueInt();
4001  break;
4002  case LONG:
4003  case DATETIME:
4004  valueClause = " value_int64 = " + attr.getValueLong();
4005  break;
4006  case DOUBLE:
4007  valueClause = " value_double = " + attr.getValueDouble();
4008  break;
4009  default:
4010  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4011  }
4012  String query = "SELECT source FROM blackboard_attributes WHERE"
4013  + " artifact_id = " + attr.getArtifactID()
4014  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4015  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4016  + " AND " + valueClause + ";";
4017  queryStmt = connection.createStatement();
4018  updateStmt = connection.createStatement();
4019  result = connection.executeQuery(queryStmt, query);
4020  } else {
4021  /*
4022  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4023  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4024  * = ?
4025  */
4026  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4027  statement.clearParameters();
4028  statement.setLong(1, attr.getArtifactID());
4029  statement.setLong(2, attr.getAttributeType().getTypeID());
4030  statement.setBytes(3, attr.getValueBytes());
4031  result = connection.executeQuery(statement);
4032  }
4033  while (result.next()) {
4034  String oldSources = result.getString("source");
4035  if (null != oldSources && !oldSources.isEmpty()) {
4036  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4037  if (!uniqueSources.contains(source)) {
4038  newSources = oldSources + "," + source;
4039  } else {
4040  newSources = oldSources;
4041  }
4042  } else {
4043  newSources = source;
4044  }
4045  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4046  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4047  + " artifact_id = " + attr.getArtifactID()
4048  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4049  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4050  + " AND " + valueClause + ";";
4051  connection.executeUpdate(updateStmt, update);
4052  } else {
4053  /*
4054  * UPDATE blackboard_attributes SET source = ? WHERE
4055  * artifact_id = ? AND attribute_type_id = ? AND value_type
4056  * = 4 AND value_byte = ?
4057  */
4058  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4059  statement.clearParameters();
4060  statement.setString(1, newSources);
4061  statement.setLong(2, attr.getArtifactID());
4062  statement.setLong(3, attr.getAttributeType().getTypeID());
4063  statement.setBytes(4, attr.getValueBytes());
4064  connection.executeUpdate(statement);
4065  }
4066  }
4067  connection.commitTransaction();
4068  return newSources;
4069  } catch (SQLException ex) {
4070  connection.rollbackTransaction();
4071  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4072  } finally {
4073  closeResultSet(result);
4074  closeStatement(updateStmt);
4075  closeStatement(queryStmt);
4076  connection.close();
4078  }
4079  }
4080 
4095  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4096  CaseDbConnection connection = connections.getConnection();
4098  Statement s = null;
4099  ResultSet rs = null;
4100  try {
4101  connection.beginTransaction();
4102  s = connection.createStatement();
4103  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
4104  if (!rs.next()) {
4105  rs.close();
4106  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
4107  int maxID = 0;
4108  if (rs.next()) {
4109  maxID = rs.getInt("highest_id");
4110  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4111  maxID = MIN_USER_DEFINED_TYPE_ID;
4112  } else {
4113  maxID++;
4114  }
4115  }
4116  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
4117  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
4118  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4119  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4120  connection.commitTransaction();
4121  return type;
4122  } else {
4123  throw new TskDataException("The attribute type that was added was already within the system.");
4124  }
4125 
4126  } catch (SQLException ex) {
4127  connection.rollbackTransaction();
4128  throw new TskCoreException("Error adding attribute type", ex);
4129  } finally {
4130  closeResultSet(rs);
4131  closeStatement(s);
4132  connection.close();
4134  }
4135  }
4136 
4147  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4148  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
4149  return this.typeNameToAttributeTypeMap.get(attrTypeName);
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 attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
4158  BlackboardAttribute.Type type = null;
4159  if (rs.next()) {
4160  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4161  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4162  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4163  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
4164  }
4165  return type;
4166  } catch (SQLException ex) {
4167  throw new TskCoreException("Error getting attribute type id", ex);
4168  } finally {
4169  closeResultSet(rs);
4170  closeStatement(s);
4171  connection.close();
4173  }
4174  }
4175 
4186  private BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
4187  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
4188  return this.typeIdToAttributeTypeMap.get(typeID);
4189  }
4190  CaseDbConnection connection = connections.getConnection();
4192  Statement s = null;
4193  ResultSet rs = null;
4194  try {
4195  s = connection.createStatement();
4196  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
4197  BlackboardAttribute.Type type = null;
4198  if (rs.next()) {
4199  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4200  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4201  this.typeIdToAttributeTypeMap.put(typeID, type);
4202  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4203  }
4204  return type;
4205  } catch (SQLException ex) {
4206  throw new TskCoreException("Error getting attribute type id", ex);
4207  } finally {
4208  closeResultSet(rs);
4209  closeStatement(s);
4210  connection.close();
4212  }
4213  }
4214 
4225  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4226  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
4227  return this.typeNameToArtifactTypeMap.get(artTypeName);
4228  }
4229  CaseDbConnection connection = connections.getConnection();
4231  Statement s = null;
4232  ResultSet rs = null;
4233  try {
4234  s = connection.createStatement();
4235  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
4236  BlackboardArtifact.Type type = null;
4237  if (rs.next()) {
4238  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4239  rs.getString("type_name"), rs.getString("display_name"));
4240  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4241  this.typeNameToArtifactTypeMap.put(artTypeName, type);
4242  }
4243  return type;
4244  } catch (SQLException ex) {
4245  throw new TskCoreException("Error getting artifact type from the database", ex);
4246  } finally {
4247  closeResultSet(rs);
4248  closeStatement(s);
4249  connection.close();
4251  }
4252  }
4253 
4264  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
4265  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
4266  return typeIdToArtifactTypeMap.get(artTypeId);
4267  }
4268  CaseDbConnection connection = connections.getConnection();
4270  Statement s = null;
4271  ResultSet rs = null;
4272  try {
4273  s = connection.createStatement();
4274  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
4275  BlackboardArtifact.Type type = null;
4276  if (rs.next()) {
4277  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4278  rs.getString("type_name"), rs.getString("display_name"));
4279  this.typeIdToArtifactTypeMap.put(artTypeId, type);
4280  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4281  }
4282  return type;
4283  } catch (SQLException ex) {
4284  throw new TskCoreException("Error getting artifact type from the database", ex);
4285  } finally {
4286  closeResultSet(rs);
4287  closeStatement(s);
4288  connection.close();
4290  }
4291  }
4292 
4305  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4306  CaseDbConnection connection = connections.getConnection();
4308  Statement s = null;
4309  ResultSet rs = null;
4310  try {
4311  connection.beginTransaction();
4312  s = connection.createStatement();
4313  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
4314  if (!rs.next()) {
4315  rs.close();
4316  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
4317  int maxID = 0;
4318  if (rs.next()) {
4319  maxID = rs.getInt("highest_id");
4320  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4321  maxID = MIN_USER_DEFINED_TYPE_ID;
4322  } else {
4323  maxID++;
4324  }
4325  }
4326  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "')"); //NON-NLS
4327  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName);
4328  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4329  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4330  connection.commitTransaction();
4331  return type;
4332  } else {
4333  throw new TskDataException("The attribute type that was added was already within the system.");
4334  }
4335  } catch (SQLException ex) {
4336  connection.rollbackTransaction();
4337  throw new TskCoreException("Error adding artifact type", ex);
4338  } finally {
4339  closeResultSet(rs);
4340  closeStatement(s);
4341  connection.close();
4343  }
4344  }
4345 
4346  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4347  CaseDbConnection connection = connections.getConnection();
4349  ResultSet rs = null;
4350  try {
4351  Statement statement = connection.createStatement();
4352  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
4353  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
4354  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4355  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4356  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
4357  + "types.type_name AS type_name, types.display_name AS display_name "
4358  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
4359  + " AND attrs.attribute_type_id = types.attribute_type_id");
4360  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
4361  while (rs.next()) {
4362  int attributeTypeId = rs.getInt("attribute_type_id");
4363  String attributeTypeName = rs.getString("type_name");
4364  BlackboardAttribute.Type attributeType;
4365  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
4366  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
4367  } else {
4368  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
4369  rs.getString("display_name"),
4371  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
4372  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
4373  }
4374 
4375  final BlackboardAttribute attr = new BlackboardAttribute(
4376  rs.getLong("artifact_id"),
4377  attributeType,
4378  rs.getString("source"),
4379  rs.getString("context"),
4380  rs.getInt("value_int32"),
4381  rs.getLong("value_int64"),
4382  rs.getDouble("value_double"),
4383  rs.getString("value_text"),
4384  rs.getBytes("value_byte"), this
4385  );
4386  attributes.add(attr);
4387  }
4388  return attributes;
4389  } catch (SQLException ex) {
4390  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
4391  } finally {
4392  closeResultSet(rs);
4393  connection.close();
4395  }
4396  }
4397 
4410  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
4411  CaseDbConnection connection = connections.getConnection();
4413  Statement s = null;
4414  ResultSet rs = null;
4415  try {
4416  s = connection.createStatement();
4417  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
4418  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
4419  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
4420  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
4421  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
4422  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
4423  + "FROM blackboard_attributes " + whereClause); //NON-NLS
4424  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
4425  while (rs.next()) {
4427  // attribute type is cached, so this does not necessarily call to the db
4428  type = this.getAttributeType(rs.getInt("attribute_type_id"));
4430  rs.getLong("artifact_id"),
4431  type,
4432  rs.getString("source"),
4433  rs.getString("context"),
4434  rs.getInt("value_int32"),
4435  rs.getLong("value_int64"),
4436  rs.getDouble("value_double"),
4437  rs.getString("value_text"),
4438  rs.getBytes("value_byte"), this
4439  );
4440  matches.add(attr);
4441  }
4442  return matches;
4443  } catch (SQLException ex) {
4444  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4445  } finally {
4446  closeResultSet(rs);
4447  closeStatement(s);
4448  connection.close();
4450  }
4451  }
4452 
4464  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
4465  CaseDbConnection connection = connections.getConnection();
4467  ResultSet rs = null;
4468  Statement s = null;
4469  try {
4470  s = connection.createStatement();
4471  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
4472  + "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, "
4473  + "blackboard_artifacts.review_status_id AS review_status_id "
4474  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
4475  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
4476  while (rs.next()) {
4477  BlackboardArtifact.Type type;
4478  // artifact type is cached, so this does not necessarily call to the db
4479  type = this.getArtifactType(rs.getInt("artifact_type_id"));
4480  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
4481  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
4482  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
4483  matches.add(artifact);
4484  }
4485  return matches;
4486  } catch (SQLException ex) {
4487  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4488  } finally {
4489  closeResultSet(rs);
4490  closeStatement(s);
4491  connection.close();
4493  }
4494  }
4495 
4509  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
4510  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
4511  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName());
4512  }
4513 
4525  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4526  return newBlackboardArtifact(artifactType.getTypeID(), obj_id, artifactType.getLabel(), artifactType.getDisplayName());
4527  }
4528 
4541  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
4542  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
4543  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id);
4544  }
4545 
4546  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
4547  try (CaseDbConnection connection = connections.getConnection()) {
4548  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
4549  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id);
4550  }
4551  }
4552 
4553  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id) throws TskCoreException {
4555  try (CaseDbConnection connection = connections.getConnection()) {
4556  long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
4557  PreparedStatement statement = null;
4558  if (dbType == DbType.POSTGRESQL) {
4559  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4560  statement.clearParameters();
4561  statement.setLong(1, obj_id);
4562  statement.setLong(2, artifact_obj_id);
4563  statement.setLong(3, data_source_obj_id);
4564  statement.setInt(4, artifact_type_id);
4565 
4566  } else {
4567  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
4568  statement.clearParameters();
4569  this.nextArtifactId++;
4570  statement.setLong(1, this.nextArtifactId);
4571  statement.setLong(2, obj_id);
4572  statement.setLong(3, artifact_obj_id);
4573  statement.setLong(4, data_source_obj_id);
4574  statement.setInt(5, artifact_type_id);
4575 
4576  }
4577  connection.executeUpdate(statement);
4578  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4579  resultSet.next();
4580  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
4581  obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
4582  }
4583  } catch (SQLException ex) {
4584  throw new TskCoreException("Error creating a blackboard artifact", ex);
4585  } finally {
4587  }
4588  }
4589 
4602  boolean getContentHasChildren(Content content) throws TskCoreException {
4603  CaseDbConnection connection = connections.getConnection();
4605  ResultSet rs = null;
4606  try {
4607  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4608  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4609  statement.clearParameters();
4610  statement.setLong(1, content.getId());
4611  rs = connection.executeQuery(statement);
4612  boolean hasChildren = false;
4613  if (rs.next()) {
4614  hasChildren = rs.getInt("count") > 0;
4615  }
4616  return hasChildren;
4617  } catch (SQLException e) {
4618  throw new TskCoreException("Error checking for children of parent " + content, e);
4619  } finally {
4620  closeResultSet(rs);
4621  connection.close();
4623  }
4624  }
4625 
4638  int getContentChildrenCount(Content content) throws TskCoreException {
4639 
4640  if (!this.getHasChildren(content)) {
4641  return 0;
4642  }
4643 
4644  CaseDbConnection connection = connections.getConnection();
4646  ResultSet rs = null;
4647  try {
4648  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
4649  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
4650  statement.clearParameters();
4651  statement.setLong(1, content.getId());
4652  rs = connection.executeQuery(statement);
4653  int countChildren = -1;
4654  if (rs.next()) {
4655  countChildren = rs.getInt("count");
4656  }
4657  return countChildren;
4658  } catch (SQLException e) {
4659  throw new TskCoreException("Error checking for children of parent " + content, e);
4660  } finally {
4661  closeResultSet(rs);
4662  connection.close();
4664  }
4665  }
4666 
4678  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4679  CaseDbConnection connection = connections.getConnection();
4681  ResultSet rs = null;
4682  try {
4683  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
4684  statement.clearParameters();
4685  long parentId = parent.getId();
4686  statement.setLong(1, parentId);
4687  statement.setShort(2, type.getFileType());
4688  rs = connection.executeQuery(statement);
4689  return fileChildren(rs, connection, parentId);
4690  } catch (SQLException ex) {
4691  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4692  } finally {
4693  closeResultSet(rs);
4694  connection.close();
4696  }
4697  }
4698 
4708  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
4709  CaseDbConnection connection = connections.getConnection();
4711  ResultSet rs = null;
4712  try {
4713  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
4714  statement.clearParameters();
4715  long parentId = parent.getId();
4716  statement.setLong(1, parentId);
4717  rs = connection.executeQuery(statement);
4718  return fileChildren(rs, connection, parentId);
4719  } catch (SQLException ex) {
4720  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4721  } finally {
4722  closeResultSet(rs);
4723  connection.close();
4725  }
4726  }
4727 
4739  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
4740  CaseDbConnection connection = connections.getConnection();
4742  ResultSet rs = null;
4743  try {
4744  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
4745  statement.clearParameters();
4746  statement.setLong(1, parent.getId());
4747  statement.setShort(2, type.getFileType());
4748  rs = connection.executeQuery(statement);
4749  List<Long> children = new ArrayList<Long>();
4750  while (rs.next()) {
4751  children.add(rs.getLong("obj_id"));
4752  }
4753  return children;
4754  } catch (SQLException ex) {
4755  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4756  } finally {
4757  closeResultSet(rs);
4758  connection.close();
4760  }
4761  }
4762 
4772  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
4773  CaseDbConnection connection = connections.getConnection();
4775  ResultSet rs = null;
4776  try {
4777  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
4778  statement.clearParameters();
4779  statement.setLong(1, parent.getId());
4780  rs = connection.executeQuery(statement);
4781  List<Long> children = new ArrayList<Long>();
4782  while (rs.next()) {
4783  children.add(rs.getLong("obj_id"));
4784  }
4785  return children;
4786  } catch (SQLException ex) {
4787  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
4788  } finally {
4789  closeResultSet(rs);
4790  connection.close();
4792  }
4793  }
4794 
4805  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
4806  CaseDbConnection connection = connections.getConnection();
4808  ResultSet rs = null;
4809  try {
4810  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
4811  statement.clearParameters();
4812  statement.setLong(1, parent.getId());
4813  rs = connection.executeQuery(statement);
4814  List<Long> children = new ArrayList<Long>();
4815  while (rs.next()) {
4816  children.add(rs.getLong("obj_id"));
4817  }
4818  return children;
4819  } catch (SQLException ex) {
4820  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
4821  } finally {
4822  closeResultSet(rs);
4823  connection.close();
4825  }
4826  }
4827 
4837  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
4838 
4839  long parentId = parent.getId();
4840  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
4841 
4842  List<Content> lc = new ArrayList<Content>();
4843  lc.addAll(artsArray);
4844  return lc;
4845  }
4846 
4855  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
4856  CaseDbConnection connection = connections.getConnection();
4858  Statement s = null;
4859  ResultSet rs = null;
4860  try {
4861  s = connection.createStatement();
4862  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
4863  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
4864  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
4865  + "WHERE tsk_objects.par_obj_id = " + c.getId()
4866  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
4867  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
4868  while (rs.next()) {
4869  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
4870  }
4871  return infos;
4872  } catch (SQLException ex) {
4873  throw new TskCoreException("Error getting Children Info for Content", ex);
4874  } finally {
4875  closeResultSet(rs);
4876  closeStatement(s);
4877  connection.close();
4879  }
4880  }
4881 
4892  ObjectInfo getParentInfo(Content c) throws TskCoreException {
4893  return getParentInfo(c.getId());
4894  }
4895 
4906  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
4907  CaseDbConnection connection = connections.getConnection();
4909  Statement s = null;
4910  ResultSet rs = null;
4911  try {
4912  s = connection.createStatement();
4913  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
4914  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
4915  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
4916  + "WHERE child.obj_id = " + contentId); //NON-NLS
4917  if (rs.next()) {
4918  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
4919  } else {
4920  return null;
4921  }
4922  } catch (SQLException ex) {
4923  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
4924  } finally {
4925  closeResultSet(rs);
4926  closeStatement(s);
4927  connection.close();
4929  }
4930  }
4931 
4942  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
4943  if (fsc.isRoot()) {
4944  // Given FsContent is a root object and can't have parent directory
4945  return null;
4946  } else {
4947  ObjectInfo parentInfo = getParentInfo(fsc);
4948  if (parentInfo == null) {
4949  return null;
4950  }
4951  Directory parent = null;
4952  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
4953  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
4954  } else {
4955  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
4956  }
4957  return parent;
4958  }
4959  }
4960 
4972  public Content getContentById(long id) throws TskCoreException {
4973  // First check to see if this exists in our frequently used content cache.
4974  Content content = frequentlyUsedContentMap.get(id);
4975  if (null != content) {
4976  return content;
4977  }
4978 
4979  CaseDbConnection connection = connections.getConnection();
4981  Statement s = null;
4982  ResultSet rs = null;
4983  long parentId;
4984  TskData.ObjectType type;
4985 
4986  try {
4987  s = connection.createStatement();
4988  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
4989  if (!rs.next()) {
4990  return null;
4991  }
4992  parentId = rs.getLong("par_obj_id"); //NON-NLS
4993  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
4994  } catch (SQLException ex) {
4995  throw new TskCoreException("Error getting Content by ID.", ex);
4996  } finally {
4997  closeResultSet(rs);
4998  closeStatement(s);
4999  connection.close();
5001  }
5002 
5003  // Construct the object
5004  switch (type) {
5005  case IMG:
5006  content = getImageById(id);
5007  frequentlyUsedContentMap.put(id, content);
5008  break;
5009  case VS:
5010  content = getVolumeSystemById(id, parentId);
5011  break;
5012  case VOL:
5013  content = getVolumeById(id, parentId);
5014  frequentlyUsedContentMap.put(id, content);
5015  break;
5016  case POOL:
5017  content = getPoolById(id, parentId);
5018  break;
5019  case FS:
5020  content = getFileSystemById(id, parentId);
5021  frequentlyUsedContentMap.put(id, content);
5022  break;
5023  case ABSTRACTFILE:
5024  content = getAbstractFileById(id);
5025 
5026  // Add virtual and root directories to frequently used map.
5027  // Calling isRoot() on local directories goes up the entire directory structure
5028  // and they can only be the root of portable cases, so skip trying to add
5029  // them to the cache.
5030  if (((AbstractFile) content).isVirtual()
5031  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5032  frequentlyUsedContentMap.put(id, content);
5033  }
5034  break;
5035  case ARTIFACT:
5036  content = getArtifactById(id);
5037  break;
5038  case REPORT:
5039  content = getReportById(id);
5040  break;
5041  default:
5042  throw new TskCoreException("Could not obtain Content object with ID: " + id);
5043  }
5044 
5045  return content;
5046  }
5047 
5055  String getFilePath(long id) {
5056  CaseDbConnection connection;
5057  try {
5058  connection = connections.getConnection();
5059  } catch (TskCoreException ex) {
5060  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5061  return null;
5062  }
5063  String filePath = null;
5065  ResultSet rs = null;
5066  try {
5067  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5068  statement.clearParameters();
5069  statement.setLong(1, id);
5070  rs = connection.executeQuery(statement);
5071  if (rs.next()) {
5072  filePath = rs.getString("path");
5073  }
5074  } catch (SQLException ex) {
5075  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5076  } finally {
5077  closeResultSet(rs);
5078  connection.close();
5080  }
5081  return filePath;
5082  }
5083 
5091  TskData.EncodingType getEncodingType(long id) {
5092  CaseDbConnection connection;
5093  try {
5094  connection = connections.getConnection();
5095  } catch (TskCoreException ex) {
5096  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5097  return null;
5098  }
5099  TskData.EncodingType type = TskData.EncodingType.NONE;
5101  ResultSet rs = null;
5102  try {
5103  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5104  statement.clearParameters();
5105  statement.setLong(1, id);
5106  rs = connection.executeQuery(statement);
5107  if (rs.next()) {
5108  type = TskData.EncodingType.valueOf(rs.getInt(1));
5109  }
5110  } catch (SQLException ex) {
5111  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5112  } finally {
5113  closeResultSet(rs);
5114  connection.close();
5116  }
5117  return type;
5118  }
5119 
5128  String getFileParentPath(long objectId, CaseDbConnection connection) {
5129  String parentPath = null;
5131  ResultSet rs = null;
5132  try {
5133  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5134  statement.clearParameters();
5135  statement.setLong(1, objectId);
5136  rs = connection.executeQuery(statement);
5137  if (rs.next()) {
5138  parentPath = rs.getString("parent_path");
5139  }
5140  } catch (SQLException ex) {
5141  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5142  } finally {
5143  closeResultSet(rs);
5145  }
5146  return parentPath;
5147  }
5148 
5157  String getFileName(long objectId, CaseDbConnection connection) {
5158  String fileName = null;
5160  ResultSet rs = null;
5161  try {
5162  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5163  statement.clearParameters();
5164  statement.setLong(1, objectId);
5165  rs = connection.executeQuery(statement);
5166  if (rs.next()) {
5167  fileName = rs.getString("name");
5168  }
5169  } catch (SQLException ex) {
5170  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5171  } finally {
5172  closeResultSet(rs);
5174  }
5175  return fileName;
5176  }
5177 
5188  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5189  CaseDbConnection connection = connections.getConnection();
5190  DerivedFile.DerivedMethod method = null;
5192  ResultSet rs1 = null;
5193  ResultSet rs2 = null;
5194  try {
5195  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5196  statement.clearParameters();
5197  statement.setLong(1, id);
5198  rs1 = connection.executeQuery(statement);
5199  if (rs1.next()) {
5200  int method_id = rs1.getInt("derived_id");
5201  String rederive = rs1.getString("rederive");
5202  method = new DerivedFile.DerivedMethod(method_id, rederive);
5203  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5204  statement.clearParameters();
5205  statement.setInt(1, method_id);
5206  rs2 = connection.executeQuery(statement);
5207  if (rs2.next()) {
5208  method.setToolName(rs2.getString("tool_name"));
5209  method.setToolVersion(rs2.getString("tool_version"));
5210  method.setOther(rs2.getString("other"));
5211  }
5212  }
5213  } catch (SQLException e) {
5214  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5215  } finally {
5216  closeResultSet(rs2);
5217  closeResultSet(rs1);
5218  connection.close();
5220  }
5221  return method;
5222  }
5223 
5234  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5235  CaseDbConnection connection = connections.getConnection();
5236  try {
5237  return getAbstractFileById(id, connection);
5238  } finally {
5239  connection.close();
5240  }
5241  }
5242 
5255  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
5257  ResultSet rs = null;
5258  try {
5259  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
5260  statement.clearParameters();
5261  statement.setLong(1, objectId);
5262  rs = connection.executeQuery(statement);
5263  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
5264  if (files.size() > 0) {
5265  return files.get(0);
5266  } else {
5267  return null;
5268  }
5269  } catch (SQLException ex) {
5270  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
5271  } finally {
5272  closeResultSet(rs);
5274  }
5275  }
5276 
5287  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
5288  CaseDbConnection connection = connections.getConnection();
5290  ResultSet rs = null;
5291  try {
5292  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID);
5293  statement.clearParameters();
5294  statement.setLong(1, id);
5295  rs = connection.executeQuery(statement);
5296  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5297  if (artifacts.size() > 0) {
5298  return artifacts.get(0);
5299  } else {
5300  return null;
5301  }
5302  } catch (SQLException ex) {
5303  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
5304  } finally {
5305  closeResultSet(rs);
5306  connection.close();
5308  }
5309  }
5310 
5321  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
5322  CaseDbConnection connection = connections.getConnection();
5324  ResultSet rs = null;
5325  try {
5326  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_ID);
5327  statement.clearParameters();
5328  statement.setLong(1, id);
5329  rs = connection.executeQuery(statement);
5330  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
5331  if (artifacts.size() > 0) {
5332  return artifacts.get(0);
5333  } else {
5334  return null;
5335  }
5336  } catch (SQLException ex) {
5337  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
5338  } finally {
5339  closeResultSet(rs);
5340  connection.close();
5342  }
5343  }
5344 
5357  private long getFileSystemId(long fileId, CaseDbConnection connection) {
5359  ResultSet rs = null;
5360  long ret = -1;
5361  try {
5362  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
5363  statement.clearParameters();
5364  statement.setLong(1, fileId);
5365  rs = connection.executeQuery(statement);
5366  if (rs.next()) {
5367  ret = rs.getLong("fs_obj_id");
5368  if (ret == 0) {
5369  ret = -1;
5370  }
5371  }
5372  } catch (SQLException e) {
5373  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
5374  } finally {
5375  closeResultSet(rs);
5377  }
5378  return ret;
5379  }
5380 
5392  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
5393  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
5394  CaseDbConnection connection = connections.getConnection();
5396  Statement statement = null;
5397  ResultSet resultSet = null;
5398  try {
5399  statement = connection.createStatement();
5400  resultSet = connection.executeQuery(statement, query);
5401  resultSet.next();
5402  return (resultSet.getLong("count") > 0L);
5403  } catch (SQLException ex) {
5404  throw new TskCoreException(String.format("Error executing query %s", query), ex);
5405  } finally {
5406  closeResultSet(resultSet);
5407  closeStatement(statement);
5408  connection.close();
5410  }
5411  }
5412 
5424  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
5425  List<AbstractFile> files = new ArrayList<AbstractFile>();
5426  CaseDbConnection connection = connections.getConnection();
5428  ResultSet resultSet = null;
5429  try {
5430  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
5431  statement.clearParameters();
5432  statement.setString(1, fileName.toLowerCase());
5433  statement.setLong(2, dataSource.getId());
5434  resultSet = connection.executeQuery(statement);
5435  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5436  } catch (SQLException e) {
5437  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
5438  } finally {
5439  closeResultSet(resultSet);
5440  connection.close();
5442  }
5443  return files;
5444  }
5445 
5459  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
5460  List<AbstractFile> files = new ArrayList<AbstractFile>();
5461  CaseDbConnection connection = connections.getConnection();
5463  ResultSet resultSet = null;
5464  try {
5465  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
5466  statement.clearParameters();
5467  statement.setString(1, fileName.toLowerCase());
5468  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
5469  statement.setLong(3, dataSource.getId());
5470  resultSet = connection.executeQuery(statement);
5471  files.addAll(resultSetToAbstractFiles(resultSet, connection));
5472  } catch (SQLException e) {
5473  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
5474  } finally {
5475  closeResultSet(resultSet);
5476  connection.close();
5478  }
5479  return files;
5480  }
5481 
5493  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
5494  CaseDbTransaction localTrans = beginTransaction();
5495  try {
5496  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
5497  localTrans.commit();
5498  localTrans = null;
5499  return newVD;
5500  } finally {
5501  if (null != localTrans) {
5502  try {
5503  localTrans.rollback();
5504  } catch (TskCoreException ex2) {
5505  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
5506  }
5507  }
5508  }
5509  }
5510 
5523  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
5524  ResultSet resultSet = null;
5526  try {
5527  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
5528  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
5529  statement.clearParameters();
5530  if (parentId != 0) {
5531  statement.setLong(1, parentId);
5532  } else {
5533  statement.setNull(1, java.sql.Types.BIGINT);
5534  }
5535  statement.setInt(2, objectType);
5536  connection.executeUpdate(statement);
5537  resultSet = statement.getGeneratedKeys();
5538 
5539  if (resultSet.next()) {
5540  if (parentId != 0) {
5541  setHasChildren(parentId);
5542  }
5543  return resultSet.getLong(1); //last_insert_rowid()
5544  } else {
5545  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
5546  }
5547  } finally {
5548  closeResultSet(resultSet);
5550  }
5551  }
5552 
5570  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5571  if (transaction == null) {
5572  throw new TskCoreException("Passed null CaseDbTransaction");
5573  }
5574 
5575  ResultSet resultSet = null;
5576  try {
5577  // Get the parent path.
5578  CaseDbConnection connection = transaction.getConnection();
5579 
5580  String parentPath;
5581  Content parent = this.getAbstractFileById(parentId, connection);
5582  if (parent instanceof AbstractFile) {
5583  if (isRootDirectory((AbstractFile) parent, transaction)) {
5584  parentPath = "/";
5585  } else {
5586  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
5587  }
5588  } else {
5589  // The parent was either null or not an abstract file
5590  parentPath = "/";
5591  }
5592 
5593  // Insert a row for the virtual directory into the tsk_objects table.
5594  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5595 
5596  // Insert a row for the virtual directory into the tsk_files table.
5597  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5598  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension)
5599  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5600  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5601  statement.clearParameters();
5602  statement.setLong(1, newObjId);
5603 
5604  // If the parent is part of a file system, grab its file system ID
5605  if (0 != parentId) {
5606  long parentFs = this.getFileSystemId(parentId, connection);
5607  if (parentFs != -1) {
5608  statement.setLong(2, parentFs);
5609  } else {
5610  statement.setNull(2, java.sql.Types.BIGINT);
5611  }
5612  } else {
5613  statement.setNull(2, java.sql.Types.BIGINT);
5614  }
5615 
5616  // name
5617  statement.setString(3, directoryName);
5618 
5619  //type
5620  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5621  statement.setShort(5, (short) 1);
5622 
5623  //flags
5625  statement.setShort(6, dirType.getValue());
5627  statement.setShort(7, metaType.getValue());
5628 
5629  //allocated
5631  statement.setShort(8, dirFlag.getValue());
5632  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5633  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5634  statement.setShort(9, metaFlags);
5635 
5636  //size
5637  statement.setLong(10, 0);
5638 
5639  // nulls for params 11-14
5640  statement.setNull(11, java.sql.Types.BIGINT);
5641  statement.setNull(12, java.sql.Types.BIGINT);
5642  statement.setNull(13, java.sql.Types.BIGINT);
5643  statement.setNull(14, java.sql.Types.BIGINT);
5644 
5645  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5646  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5647  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5648 
5649  // parent path
5650  statement.setString(18, parentPath);
5651 
5652  // data source object id (same as object id if this is a data source)
5653  long dataSourceObjectId;
5654  if (0 == parentId) {
5655  dataSourceObjectId = newObjId;
5656  } else {
5657  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5658  }
5659  statement.setLong(19, dataSourceObjectId);
5660 
5661  //extension, since this is not really file we just set it to null
5662  statement.setString(20, null);
5663  connection.executeUpdate(statement);
5664 
5665  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5666  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5667  parentPath);
5668  } catch (SQLException e) {
5669  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
5670  } finally {
5671  closeResultSet(resultSet);
5672  }
5673  }
5674 
5687  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
5688  CaseDbTransaction localTrans = beginTransaction();
5689  try {
5690  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
5691  localTrans.commit();
5692  return newLD;
5693  } catch (TskCoreException ex) {
5694  try {
5695  localTrans.rollback();
5696  } catch (TskCoreException ex2) {
5697  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
5698  }
5699  throw ex;
5700  }
5701  }
5702 
5720  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
5721  if (transaction == null) {
5722  throw new TskCoreException("Passed null CaseDbTransaction");
5723  }
5724 
5725  ResultSet resultSet = null;
5726  try {
5727  // Get the parent path.
5728  CaseDbConnection connection = transaction.getConnection();
5729  AbstractFile parent = getAbstractFileById(parentId, connection);
5730  String parentPath;
5731  if ((parent == null) || isRootDirectory(parent, transaction)) {
5732  parentPath = "/";
5733  } else {
5734  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
5735  }
5736 
5737  // Insert a row for the local directory into the tsk_objects table.
5738  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5739 
5740  // Insert a row for the local directory into the tsk_files table.
5741  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
5742  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id)
5743  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5744  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5745  statement.clearParameters();
5746  statement.setLong(1, newObjId);
5747 
5748  // The parent of a local directory will never be a file system
5749  statement.setNull(2, java.sql.Types.BIGINT);
5750 
5751  // name
5752  statement.setString(3, directoryName);
5753 
5754  //type
5755  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
5756  statement.setShort(5, (short) 1);
5757 
5758  //flags
5760  statement.setShort(6, dirType.getValue());
5762  statement.setShort(7, metaType.getValue());
5763 
5764  //allocated
5766  statement.setShort(8, dirFlag.getValue());
5767  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5768  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5769  statement.setShort(9, metaFlags);
5770 
5771  //size
5772  statement.setLong(10, 0);
5773 
5774  // nulls for params 11-14
5775  statement.setNull(11, java.sql.Types.BIGINT);
5776  statement.setNull(12, java.sql.Types.BIGINT);
5777  statement.setNull(13, java.sql.Types.BIGINT);
5778  statement.setNull(14, java.sql.Types.BIGINT);
5779 
5780  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
5781  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5782  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5783 
5784  // parent path
5785  statement.setString(18, parentPath);
5786 
5787  // data source object id
5788  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
5789  statement.setLong(19, dataSourceObjectId);
5790 
5791  //extension, since this is a directory we just set it to null
5792  statement.setString(20, null);
5793 
5794  connection.executeUpdate(statement);
5795 
5796  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
5797  metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN,
5798  parentPath);
5799  } catch (SQLException e) {
5800  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
5801  } finally {
5802  closeResultSet(resultSet);
5803  }
5804  }
5805 
5825  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
5827  Statement statement = null;
5828  try {
5829  // Insert a row for the root virtual directory of the data source
5830  // into the tsk_objects table.
5831  CaseDbConnection connection = transaction.getConnection();
5832  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
5833 
5834  // Insert a row for the virtual directory of the data source into
5835  // the data_source_info table.
5836  statement = connection.createStatement();
5837  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
5838  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');");
5839 
5840  // Insert a row for the root virtual directory of the data source
5841  // into the tsk_files table. Note that its data source object id is
5842  // its own object id.
5843  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
5844  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
5845  // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension)
5846  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
5847  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
5848  preparedStatement.clearParameters();
5849  preparedStatement.setLong(1, newObjId);
5850  preparedStatement.setNull(2, java.sql.Types.BIGINT);
5851  preparedStatement.setString(3, rootDirectoryName);
5852  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
5853  preparedStatement.setShort(5, (short) 1);
5855  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
5857  preparedStatement.setShort(7, metaType.getValue());
5859  preparedStatement.setShort(8, dirFlag.getValue());
5860  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
5861  | TSK_FS_META_FLAG_ENUM.USED.getValue());
5862  preparedStatement.setShort(9, metaFlags);
5863  preparedStatement.setLong(10, 0);
5864  preparedStatement.setNull(11, java.sql.Types.BIGINT);
5865  preparedStatement.setNull(12, java.sql.Types.BIGINT);
5866  preparedStatement.setNull(13, java.sql.Types.BIGINT);
5867  preparedStatement.setNull(14, java.sql.Types.BIGINT);
5868  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
5869  preparedStatement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
5870  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // MIME type
5871  String parentPath = "/"; //NON-NLS
5872  preparedStatement.setString(18, parentPath);
5873  preparedStatement.setLong(19, newObjId);
5874  preparedStatement.setString(20, null); //extension, just set it to null
5875  connection.executeUpdate(preparedStatement);
5876 
5877  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, FileKnown.UNKNOWN, parentPath);
5878 
5879  } catch (SQLException ex) {
5880  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
5881  } finally {
5882  closeStatement(statement);
5884  }
5885  }
5886 
5906  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
5907  String timezone, String md5, String sha1, String sha256,
5908  String deviceId,
5909  CaseDbTransaction transaction) throws TskCoreException {
5911  Statement statement = null;
5912  try {
5913  // Insert a row for the Image into the tsk_objects table.
5914  CaseDbConnection connection = transaction.getConnection();
5915  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
5916 
5917  // Add a row to tsk_image_info
5918  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
5919  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
5920  preparedStatement.clearParameters();
5921  preparedStatement.setLong(1, newObjId);
5922  preparedStatement.setShort(2, (short) type.getValue());
5923  preparedStatement.setLong(3, sectorSize);
5924  preparedStatement.setString(4, timezone);
5925  //prevent negative size
5926  long savedSize = size < 0 ? 0 : size;
5927  preparedStatement.setLong(5, savedSize);
5928  preparedStatement.setString(6, md5);
5929  preparedStatement.setString(7, sha1);
5930  preparedStatement.setString(8, sha256);
5931  preparedStatement.setString(9, displayName);
5932  connection.executeUpdate(preparedStatement);
5933 
5934  // If there are paths, add them to tsk_image_names
5935  for (int i = 0; i < imagePaths.size(); i++) {
5936  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
5937  preparedStatement.clearParameters();
5938  preparedStatement.setLong(1, newObjId);
5939  preparedStatement.setString(2, imagePaths.get(i));
5940  preparedStatement.setLong(3, i);
5941  connection.executeUpdate(preparedStatement);
5942  }
5943 
5944  // Add a row to data_source_info
5945  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
5946  statement = connection.createStatement();
5947  preparedStatement.setLong(1, newObjId);
5948  preparedStatement.setString(2, deviceId);
5949  preparedStatement.setString(3, timezone);
5950  connection.executeUpdate(preparedStatement);
5951 
5952  // Create the new Image object
5953  String name = displayName;
5954  if (name == null || name.isEmpty()) {
5955  if (imagePaths.size() > 0) {
5956  String path = imagePaths.get(0);
5957  name = (new java.io.File(path)).getName();
5958  } else {
5959  name = "";
5960  }
5961  }
5962  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
5963  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
5964  } catch (SQLException ex) {
5965  if (!imagePaths.isEmpty()) {
5966  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
5967  } else {
5968  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
5969  }
5970  } finally {
5971  closeStatement(statement);
5973  }
5974  }
5975 
5989  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
5990  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
5992  try {
5993  // Insert a row for the VolumeSystem into the tsk_objects table.
5994  CaseDbConnection connection = transaction.getConnection();
5995  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
5996 
5997  // Add a row to tsk_vs_info
5998  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
5999  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
6000  preparedStatement.clearParameters();
6001  preparedStatement.setLong(1, newObjId);
6002  preparedStatement.setShort(2, (short) type.getVsType());
6003  preparedStatement.setLong(3, imgOffset);
6004  preparedStatement.setLong(4, blockSize);
6005  connection.executeUpdate(preparedStatement);
6006 
6007  // Create the new VolumeSystem object
6008  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
6009  } catch (SQLException ex) {
6010  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
6011  parentObjId, imgOffset), ex);
6012  } finally {
6014  }
6015  }
6016 
6032  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
6033  long flags, CaseDbTransaction transaction) throws TskCoreException {
6035  Statement statement = null;
6036  try {
6037  // Insert a row for the Volume into the tsk_objects table.
6038  CaseDbConnection connection = transaction.getConnection();
6039  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
6040 
6041  // Add a row to tsk_vs_parts
6042  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
6043  PreparedStatement preparedStatement;
6044  if (this.dbType == DbType.POSTGRESQL) {
6045  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
6046  } else {
6047  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
6048  }
6049  preparedStatement.clearParameters();
6050  preparedStatement.setLong(1, newObjId);
6051  preparedStatement.setLong(2, addr);
6052  preparedStatement.setLong(3, start);
6053  preparedStatement.setLong(4, length);
6054  preparedStatement.setString(5, desc);
6055  preparedStatement.setShort(6, (short) flags);
6056  connection.executeUpdate(preparedStatement);
6057 
6058  // Create the new Volume object
6059  return new Volume(this, newObjId, addr, start, length, flags, desc);
6060  } catch (SQLException ex) {
6061  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
6062  } finally {
6063  closeStatement(statement);
6065  }
6066  }
6067 
6079  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
6081  Statement statement = null;
6082  try {
6083  // Insert a row for the Pool into the tsk_objects table.
6084  CaseDbConnection connection = transaction.getConnection();
6085  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
6086 
6087  // Add a row to tsk_pool_info
6088  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
6089  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
6090  preparedStatement.clearParameters();
6091  preparedStatement.setLong(1, newObjId);
6092  preparedStatement.setShort(2, type.getValue());
6093  connection.executeUpdate(preparedStatement);
6094 
6095  // Create the new Pool object
6096  return new Pool(this, newObjId, type.getName(), type.getValue());
6097  } catch (SQLException ex) {
6098  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
6099  } finally {
6100  closeStatement(statement);
6102  }
6103  }
6104 
6123  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
6124  long rootInum, long firstInum, long lastInum, String displayName,
6125  CaseDbTransaction transaction) throws TskCoreException {
6127  Statement statement = null;
6128  try {
6129  // Insert a row for the FileSystem into the tsk_objects table.
6130  CaseDbConnection connection = transaction.getConnection();
6131  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
6132 
6133  // Get the data source object ID
6134  long dataSourceId = getDataSourceObjectId(connection, newObjId);
6135 
6136  // Add a row to tsk_fs_info
6137  // INSERT INTO tsk_fs_info (obj_id, data_source_obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)
6138  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
6139  preparedStatement.clearParameters();
6140  preparedStatement.setLong(1, newObjId);
6141  preparedStatement.setLong(2, dataSourceId);
6142  preparedStatement.setLong(3, imgOffset);
6143  preparedStatement.setInt(4, type.getValue());
6144  preparedStatement.setLong(5, blockSize);
6145  preparedStatement.setLong(6, blockCount);
6146  preparedStatement.setLong(7, rootInum);
6147  preparedStatement.setLong(8, firstInum);
6148  preparedStatement.setLong(9, lastInum);
6149  preparedStatement.setString(10, displayName);
6150  connection.executeUpdate(preparedStatement);
6151 
6152  // Create the new FileSystem object
6153  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
6154  firstInum, lastInum);
6155  } catch (SQLException ex) {
6156  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
6157  imgOffset, parentObjId), ex);
6158  } finally {
6159  closeStatement(statement);
6161  }
6162  }
6163 
6189  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
6190  String fileName,
6191  long metaAddr, int metaSeq,
6192  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
6193  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
6194  long ctime, long crtime, long atime, long mtime,
6195  boolean isFile, Content parent) throws TskCoreException {
6196 
6197  TimelineManager timelineManager = getTimelineManager();
6198 
6199  CaseDbTransaction transaction = beginTransaction();
6200  Statement queryStatement = null;
6201  try {
6202  CaseDbConnection connection = transaction.getConnection();
6203 
6204  // Insert a row for the local/logical file into the tsk_objects table.
6205  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6206  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6207 
6208  String parentPath;
6209 
6210  if (parent instanceof AbstractFile) {
6211  AbstractFile parentFile = (AbstractFile) parent;
6212  if (isRootDirectory(parentFile, transaction)) {
6213  parentPath = "/";
6214  } else {
6215  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
6216  }
6217  } else {
6218  parentPath = "/";
6219  }
6220 
6221  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
6222  statement.clearParameters();
6223  statement.setLong(1, objectId); // obj_is
6224  statement.setLong(2, fsObjId); // fs_obj_id
6225  statement.setLong(3, dataSourceObjId); // data_source_obj_id
6226  statement.setShort(4, (short) attrType.getValue()); // attr_type
6227  statement.setInt(5, attrId); // attr_id
6228  statement.setString(6, fileName); // name
6229  statement.setLong(7, metaAddr); // meta_addr
6230  statement.setInt(8, metaSeq); // meta_addr
6231  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
6232  statement.setShort(10, (short) 1); // has_path
6234  statement.setShort(11, dirType.getValue()); // dir_type
6236  statement.setShort(12, metaType.getValue()); // meta_type
6237  statement.setShort(13, dirFlag.getValue()); // dir_flags
6238  statement.setShort(14, metaFlags); // meta_flags
6239  statement.setLong(15, size < 0 ? 0 : size);
6240  statement.setLong(16, ctime);
6241  statement.setLong(17, crtime);
6242  statement.setLong(18, atime);
6243  statement.setLong(19, mtime);
6244  statement.setString(20, parentPath);
6245  final String extension = extractExtension(fileName);
6246  statement.setString(21, extension);
6247 
6248  connection.executeUpdate(statement);
6249 
6250  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
6251  size, ctime, crtime, atime, mtime, null, null, parentPath, null, parent.getId(), null, null, extension);
6252 
6253  timelineManager.addEventsForNewFile(derivedFile, connection);
6254 
6255  transaction.commit();
6256  transaction = null;
6257 
6258  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
6259  attrType, attrId, fileName, metaAddr, metaSeq,
6260  dirType, metaType, dirFlag, metaFlags,
6261  size, ctime, crtime, atime, mtime,
6262  (short) 0, 0, 0, null, null, parentPath, null,
6263  extension);
6264 
6265  } catch (SQLException ex) {
6266  logger.log(Level.WARNING, "Failed to add file system file", ex);
6267  } finally {
6268  closeStatement(queryStatement);
6269  if (null != transaction) {
6270  try {
6271  transaction.rollback();
6272  } catch (TskCoreException ex2) {
6273  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6274  }
6275  }
6276  }
6277  return null;
6278  }
6279 
6288  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
6289  CaseDbConnection connection = connections.getConnection();
6291  Statement s = null;
6292  ResultSet rs = null;
6293  try {
6294  s = connection.createStatement();
6295  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
6296  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
6297  + " AND obj_id = data_source_obj_id"
6298  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
6299  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
6300  while (rs.next()) {
6301  virtDirRootIds.add(virtualDirectory(rs, connection));
6302  }
6303  return virtDirRootIds;
6304  } catch (SQLException ex) {
6305  throw new TskCoreException("Error getting local files virtual folder id", ex);
6306  } finally {
6307  closeResultSet(rs);
6308  closeStatement(s);
6309  connection.close();
6311  }
6312  }
6313 
6326  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
6327  assert (null != fileRanges);
6328  if (null == fileRanges) {
6329  throw new TskCoreException("TskFileRange object is null");
6330  }
6331 
6332  assert (null != parent);
6333  if (null == parent) {
6334  throw new TskCoreException("Conent is null");
6335  }
6336 
6337  CaseDbTransaction transaction = null;
6338  Statement statement = null;
6339  ResultSet resultSet = null;
6340 
6341  try {
6342  transaction = beginTransaction();
6343  CaseDbConnection connection = transaction.getConnection();
6344 
6345  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
6346  for (TskFileRange fileRange : fileRanges) {
6347  /*
6348  * Insert a row for the Tsk file range into the tsk_objects
6349  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
6350  * ?)
6351  */
6352  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6353  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
6354  /*
6355  * Insert a row for the Tsk file range into the tsk_files table:
6356  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6357  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6358  * ctime, crtime, atime, mtime, md5, known, mime_type,
6359  * parent_path, data_source_obj_id,extension) VALUES (?, ?, ?,
6360  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6361  */
6362  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6363  prepStmt.clearParameters();
6364  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
6365  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6366  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]
6367  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
6368  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
6369  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6370  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6371  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6372  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6373  prepStmt.setLong(10, fileRange.getByteLen()); // size
6374  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6375  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6376  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6377  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6378  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6379  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6380  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6381  prepStmt.setNull(18, java.sql.Types.VARCHAR); // parent path
6382  prepStmt.setLong(19, parent.getId()); // data_source_obj_id
6383 
6384  //extension, since this is not a FS file we just set it to null
6385  prepStmt.setString(20, null);
6386  connection.executeUpdate(prepStmt);
6387 
6388  /*
6389  * Insert a row in the tsk_layout_file table for each chunk of
6390  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6391  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6392  */
6393  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6394  prepStmt.clearParameters();
6395  prepStmt.setLong(1, fileRangeId); // obj_id
6396  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
6397  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
6398  prepStmt.setLong(4, fileRange.getSequence()); // sequence
6399  connection.executeUpdate(prepStmt);
6400 
6401  /*
6402  * Create a layout file representation of the carved file.
6403  */
6404  fileRangeLayoutFiles.add(new LayoutFile(this,
6405  fileRangeId,
6406  parent.getId(),
6407  Long.toString(fileRange.getSequence()),
6412  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6413  fileRange.getByteLen(),
6414  0L, 0L, 0L, 0L,
6415  null,
6417  parent.getUniquePath(),
6418  null));
6419  }
6420 
6421  transaction.commit();
6422  transaction = null;
6423  return fileRangeLayoutFiles;
6424 
6425  } catch (SQLException ex) {
6426  throw new TskCoreException("Failed to add layout files to case database", ex);
6427  } finally {
6428  closeResultSet(resultSet);
6429  closeStatement(statement);
6430 
6431  if (null != transaction) {
6432  try {
6433  transaction.rollback();
6434  } catch (TskCoreException ex2) {
6435  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6436  }
6437  }
6438  }
6439  }
6440 
6452  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
6453  assert (null != carvingResult);
6454  if (null == carvingResult) {
6455  throw new TskCoreException("Carving is null");
6456  }
6457  assert (null != carvingResult.getParent());
6458  if (null == carvingResult.getParent()) {
6459  throw new TskCoreException("Carving result has null parent");
6460  }
6461  assert (null != carvingResult.getCarvedFiles());
6462  if (null == carvingResult.getCarvedFiles()) {
6463  throw new TskCoreException("Carving result has null carved files");
6464  }
6465  CaseDbTransaction transaction = null;
6466  Statement statement = null;
6467  ResultSet resultSet = null;
6468  long newCacheKey = 0; // Used to roll back cache if transaction is rolled back.
6469  try {
6470  transaction = beginTransaction();
6471  CaseDbConnection connection = transaction.getConnection();
6472 
6473  /*
6474  * Carved files are "re-parented" as children of the $CarvedFiles
6475  * virtual directory of the root file system, volume, or image
6476  * ancestor of the carved files parent, but if no such ancestor is
6477  * found, then the parent specified in the carving result is used.
6478  */
6479  Content root = carvingResult.getParent();
6480  while (null != root) {
6481  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
6482  break;
6483  }
6484  root = root.getParent();
6485  }
6486  if (null == root) {
6487  root = carvingResult.getParent();
6488  }
6489 
6490  /*
6491  * Get or create the $CarvedFiles virtual directory for the root
6492  * ancestor.
6493  */
6494  VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
6495  if (null == carvedFilesDir) {
6496  List<Content> rootChildren;
6497  if (root instanceof FileSystem) {
6498  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
6499  } else {
6500  rootChildren = root.getChildren();
6501  }
6502  for (Content child : rootChildren) {
6503  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
6504  carvedFilesDir = (VirtualDirectory) child;
6505  break;
6506  }
6507  }
6508  if (null == carvedFilesDir) {
6509  long parId = root.getId();
6510  // $CarvedFiles should be a child of the root directory, not the file system
6511  if (root instanceof FileSystem) {
6512  Content rootDir = ((FileSystem) root).getRootDirectory();
6513  parId = rootDir.getId();
6514  }
6515  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED, transaction);
6516  }
6517  newCacheKey = root.getId();
6518  rootIdsToCarvedFileDirs.put(newCacheKey, carvedFilesDir);
6519  }
6520 
6521  /*
6522  * Add the carved files to the database as children of the
6523  * $CarvedFile directory of the root ancestor.
6524  */
6525  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
6526  List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>();
6527  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
6528  /*
6529  * Insert a row for the carved file into the tsk_objects table:
6530  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6531  */
6532  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6533 
6534  /*
6535  * Insert a row for the carved file into the tsk_files table:
6536  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
6537  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
6538  * ctime, crtime, atime, mtime, md5, known, mime_type,
6539  * parent_path, data_source_obj_id,extenion) VALUES (?, ?, ?, ?,
6540  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6541  */
6542  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6543  prepStmt.clearParameters();
6544  prepStmt.setLong(1, carvedFileId); // obj_id
6545  if (root instanceof FileSystem) {
6546  prepStmt.setLong(2, root.getId()); // fs_obj_id
6547  } else {
6548  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
6549  }
6550  prepStmt.setString(3, carvedFile.getName()); // name
6551  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
6552  prepStmt.setShort(5, (short) 1); // has_path
6553  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
6554  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
6555  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
6556  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
6557  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
6558  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
6559  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
6560  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
6561  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
6562  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
6563  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6564  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
6565  prepStmt.setString(18, parentPath); // parent path
6566  prepStmt.setLong(19, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
6567  prepStmt.setString(20, extractExtension(carvedFile.getName())); //extension
6568  connection.executeUpdate(prepStmt);
6569 
6570  /*
6571  * Insert a row in the tsk_layout_file table for each chunk of
6572  * the carved file. INSERT INTO tsk_file_layout (obj_id,
6573  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
6574  */
6575  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
6576  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
6577  prepStmt.clearParameters();
6578  prepStmt.setLong(1, carvedFileId); // obj_id
6579  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
6580  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
6581  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
6582  connection.executeUpdate(prepStmt);
6583  }
6584 
6585  /*
6586  * Create a layout file representation of the carved file.
6587  */
6588  carvedFiles.add(new LayoutFile(this,
6589  carvedFileId,
6590  carvedFilesDir.getDataSourceObjectId(),
6591  carvedFile.getName(),
6596  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
6597  carvedFile.getSizeInBytes(),
6598  0L, 0L, 0L, 0L,
6599  null,
6601  parentPath,
6602  null));
6603  }
6604 
6605  transaction.commit();
6606  transaction = null;
6607  return carvedFiles;
6608 
6609  } catch (SQLException ex) {
6610  throw new TskCoreException("Failed to add carved files to case database", ex);
6611  } finally {
6612  closeResultSet(resultSet);
6613  closeStatement(statement);
6614 
6615  if (null != transaction) {
6616  try {
6617  transaction.rollback();
6618  } catch (TskCoreException ex2) {
6619  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6620  }
6621  if (0 != newCacheKey) {
6622  rootIdsToCarvedFileDirs.remove(newCacheKey);
6623  }
6624  }
6625  }
6626  }
6627 
6658  public DerivedFile addDerivedFile(String fileName, String localPath,
6659  long size, long ctime, long crtime, long atime, long mtime,
6660  boolean isFile, Content parentObj,
6661  String rederiveDetails, String toolName, String toolVersion,
6662  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6663  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6664  localPath = localPath.replaceAll("^[/\\\\]+", "");
6665 
6666  TimelineManager timelineManager = getTimelineManager();
6667 
6668  CaseDbTransaction transaction = beginTransaction();
6669  CaseDbConnection connection = transaction.getConnection();
6670  try {
6671  final long parentId = parentObj.getId();
6672  String parentPath = "";
6673  if (parentObj instanceof BlackboardArtifact) {
6674  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6675  } else if (parentObj instanceof AbstractFile) {
6676  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6677  }
6678 
6679  // Insert a row for the derived file into the tsk_objects table.
6680  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6681  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6682 
6683  // Insert a row for the virtual directory into the tsk_files table.
6684  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6685  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6686  // parent_path, data_source_obj_id, extension)
6687  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6688  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6689  statement.clearParameters();
6690  statement.setLong(1, newObjId);
6691 
6692  // If the parentFile is part of a file system, use its file system object ID.
6693  long fsObjId = this.getFileSystemId(parentId, connection);
6694  if (fsObjId != -1) {
6695  statement.setLong(2, fsObjId);
6696  } else {
6697  statement.setNull(2, java.sql.Types.BIGINT);
6698  }
6699  statement.setString(3, fileName);
6700 
6701  //type, has_path
6702  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6703  statement.setShort(5, (short) 1);
6704 
6705  //flags
6707  statement.setShort(6, dirType.getValue());
6709  statement.setShort(7, metaType.getValue());
6710 
6711  //note: using alloc under assumption that derived files derive from alloc files
6713  statement.setShort(8, dirFlag.getValue());
6714  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6715  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6716  statement.setShort(9, metaFlags);
6717 
6718  //size
6719  //prevent negative size
6720  long savedSize = size < 0 ? 0 : size;
6721  statement.setLong(10, savedSize);
6722 
6723  //mactimes
6724  //long ctime, long crtime, long atime, long mtime,
6725  statement.setLong(11, ctime);
6726  statement.setLong(12, crtime);
6727  statement.setLong(13, atime);
6728  statement.setLong(14, mtime);
6729 
6730  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6731  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6732  statement.setNull(17, java.sql.Types.VARCHAR); // MIME type
6733 
6734  //parent path
6735  statement.setString(18, parentPath);
6736 
6737  // root data source object id
6738  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6739  statement.setLong(19, dataSourceObjId);
6740  final String extension = extractExtension(fileName);
6741  //extension
6742  statement.setString(20, extension);
6743 
6744  connection.executeUpdate(statement);
6745 
6746  //add localPath
6747  addFilePath(connection, newObjId, localPath, encodingType);
6748 
6749  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
6750  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6751 
6752  timelineManager.addEventsForNewFile(derivedFile, connection);
6753  transaction.commit();
6754  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
6755  return derivedFile;
6756  } catch (SQLException ex) {
6757  connection.rollbackTransaction();
6758  throw new TskCoreException("Failed to add derived file to case database", ex);
6759  } finally {
6760  connection.close();
6761  }
6762  }
6763 
6794  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
6795  long size, long ctime, long crtime, long atime, long mtime,
6796  boolean isFile, String mimeType,
6797  String rederiveDetails, String toolName, String toolVersion,
6798  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
6799 
6800  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
6801  localPath = localPath.replaceAll("^[/\\\\]+", "");
6802 
6803  CaseDbConnection connection = connections.getConnection();
6805  ResultSet rs = null;
6806  try {
6807  Content parentObj = derivedFile.getParent();
6808  connection.beginTransaction();
6809  final long parentId = parentObj.getId();
6810  String parentPath = "";
6811  if (parentObj instanceof BlackboardArtifact) {
6812  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
6813  } else if (parentObj instanceof AbstractFile) {
6814  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
6815  }
6816  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
6817  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
6818  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
6819  statement.clearParameters();
6820 
6821  //type
6822  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
6823 
6824  //flags
6826  statement.setShort(2, dirType.getValue());
6828  statement.setShort(3, metaType.getValue());
6829 
6830  //note: using alloc under assumption that derived files derive from alloc files
6832  statement.setShort(4, dirFlag.getValue());
6833  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6834  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6835  statement.setShort(5, metaFlags);
6836 
6837  //size
6838  //prevent negative size
6839  long savedSize = size < 0 ? 0 : size;
6840  statement.setLong(6, savedSize);
6841 
6842  //mactimes
6843  //long ctime, long crtime, long atime, long mtime,
6844  statement.setLong(7, ctime);
6845  statement.setLong(8, crtime);
6846  statement.setLong(9, atime);
6847  statement.setLong(10, mtime);
6848  statement.setString(11, mimeType);
6849  statement.setString(12, String.valueOf(derivedFile.getId()));
6850  connection.executeUpdate(statement);
6851 
6852  //add localPath
6853  updateFilePath(connection, derivedFile.getId(), localPath, encodingType);
6854 
6855  connection.commitTransaction();
6856 
6857  long dataSourceObjId = getDataSourceObjectId(connection, parentId);
6858  final String extension = extractExtension(derivedFile.getName());
6859  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
6860  savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension);
6861  } catch (SQLException ex) {
6862  connection.rollbackTransaction();
6863  throw new TskCoreException("Failed to add derived file to case database", ex);
6864  } finally {
6865  closeResultSet(rs);
6866  connection.close();
6868  }
6869  }
6870 
6890  public LocalFile addLocalFile(String fileName, String localPath,
6891  long size, long ctime, long crtime, long atime, long mtime,
6892  boolean isFile, TskData.EncodingType encodingType,
6893  AbstractFile parent) throws TskCoreException {
6894 
6895  CaseDbTransaction localTrans = beginTransaction();
6896  try {
6897  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
6898  localTrans.commit();
6899  localTrans = null;
6900  return created;
6901  } finally {
6902  if (null != localTrans) {
6903  try {
6904  localTrans.rollback();
6905  } catch (TskCoreException ex2) {
6906  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6907  }
6908  }
6909  }
6910  }
6911 
6936  public LocalFile addLocalFile(String fileName, String localPath,
6937  long size, long ctime, long crtime, long atime, long mtime,
6938  boolean isFile, TskData.EncodingType encodingType,
6939  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6940 
6941  return addLocalFile(fileName, localPath,
6942  size, ctime, crtime, atime, mtime,
6943  null, null, null,
6944  isFile, encodingType,
6945  parent, transaction);
6946  }
6947 
6975  public LocalFile addLocalFile(String fileName, String localPath,
6976  long size, long ctime, long crtime, long atime, long mtime,
6977  String md5, FileKnown known, String mimeType,
6978  boolean isFile, TskData.EncodingType encodingType,
6979  Content parent, CaseDbTransaction transaction) throws TskCoreException {
6980  CaseDbConnection connection = transaction.getConnection();
6981  Statement queryStatement = null;
6982  try {
6983 
6984  // Insert a row for the local/logical file into the tsk_objects table.
6985  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6986  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6987 
6988  // Insert a row for the local/logical file into the tsk_files table.
6989  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6990  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
6991  // parent_path, data_source_obj_id,extension)
6992  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
6993  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6994  statement.clearParameters();
6995  statement.setLong(1, objectId);
6996  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
6997  statement.setString(3, fileName);
6998  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
6999  statement.setShort(5, (short) 1);
7001  statement.setShort(6, dirType.getValue());
7003  statement.setShort(7, metaType.getValue());
7005  statement.setShort(8, dirFlag.getValue());
7006  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
7007  statement.setShort(9, metaFlags);
7008  //prevent negative size
7009  long savedSize = size < 0 ? 0 : size;
7010  statement.setLong(10, savedSize);
7011  statement.setLong(11, ctime);
7012  statement.setLong(12, crtime);
7013  statement.setLong(13, atime);
7014  statement.setLong(14, mtime);
7015  statement.setString(15, md5);
7016  if (known != null) {
7017  statement.setByte(16, known.getFileKnownValue());
7018  } else {
7019  statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue());
7020  }
7021  statement.setString(17, mimeType);
7022  String parentPath;
7023  long dataSourceObjId;
7024 
7025  if (parent instanceof AbstractFile) {
7026  AbstractFile parentFile = (AbstractFile) parent;
7027  if (isRootDirectory(parentFile, transaction)) {
7028  parentPath = "/";
7029  } else {
7030  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7031  }
7032  dataSourceObjId = parentFile.getDataSourceObjectId();
7033  } else {
7034  parentPath = "/";
7035  dataSourceObjId = getDataSourceObjectId(connection, parent.getId());
7036  }
7037  statement.setString(18, parentPath);
7038  statement.setLong(19, dataSourceObjId);
7039  final String extension = extractExtension(fileName);
7040  statement.setString(20, extension);
7041 
7042  connection.executeUpdate(statement);
7043  addFilePath(connection, objectId, localPath, encodingType);
7044  LocalFile localFile = new LocalFile(this,
7045  objectId,
7046  fileName,
7048  dirType,
7049  metaType,
7050  dirFlag,
7051  metaFlags,
7052  savedSize,
7053  ctime, crtime, atime, mtime,
7054  mimeType, md5, known,
7055  parent.getId(), parentPath,
7056  dataSourceObjId,
7057  localPath,
7058  encodingType, extension);
7059  getTimelineManager().addEventsForNewFile(localFile, connection);
7060  return localFile;
7061 
7062  } catch (SQLException ex) {
7063  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);
7064  } finally {
7065  closeStatement(queryStatement);
7066  }
7067  }
7068 
7081  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
7082  CaseDbConnection connection = transaction.getConnection();
7083  Statement statement = null;
7084  ResultSet resultSet = null;
7085 
7086  try {
7087  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
7088  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
7089  + "WHERE ChildRow.obj_id = %s;", file.getId());
7090 
7091  statement = connection.createStatement();
7092  resultSet = statement.executeQuery(query);
7093  if (resultSet.next()) {
7094  long parentId = resultSet.getLong("parent_object_id");
7095  if (parentId == 0) {
7096  return true;
7097  }
7098  int type = resultSet.getInt("parent_type");
7099  return (type == TskData.ObjectType.IMG.getObjectType()
7100  || type == TskData.ObjectType.VS.getObjectType()
7101  || type == TskData.ObjectType.VOL.getObjectType()
7102  || type == TskData.ObjectType.FS.getObjectType());
7103 
7104  } else {
7105  return true; // The file has no parent
7106  }
7107  } catch (SQLException ex) {
7108  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
7109  } finally {
7110  closeResultSet(resultSet);
7111  closeStatement(statement);
7112  }
7113  }
7114 
7134  public LayoutFile addLayoutFile(String fileName,
7135  long size,
7136  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
7137  long ctime, long crtime, long atime, long mtime,
7138  List<TskFileRange> fileRanges,
7139  Content parent) throws TskCoreException {
7140 
7141  if (null == parent) {
7142  throw new TskCoreException("Parent can not be null");
7143  }
7144 
7145  String parentPath;
7146  if (parent instanceof AbstractFile) {
7147  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7148  } else {
7149  parentPath = "/";
7150  }
7151 
7152  CaseDbTransaction transaction = null;
7153  Statement statement = null;
7154  ResultSet resultSet = null;
7155  try {
7156  transaction = beginTransaction();
7157  CaseDbConnection connection = transaction.getConnection();
7158 
7159  /*
7160  * Insert a row for the layout file into the tsk_objects table:
7161  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7162  */
7163  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7164 
7165  /*
7166  * Insert a row for the file into the tsk_files table: INSERT INTO
7167  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
7168  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
7169  * mtime, md5, known, mime_type, parent_path,
7170  * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,
7171  * ?, ?, ?, ?, ?, ?, ?,?)
7172  */
7173  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7174  prepStmt.clearParameters();
7175  prepStmt.setLong(1, newFileId); // obj_id
7176 
7177  // If the parent is part of a file system, grab its file system ID
7178  if (0 != parent.getId()) {
7179  long parentFs = this.getFileSystemId(parent.getId(), connection);
7180  if (parentFs != -1) {
7181  prepStmt.setLong(2, parentFs);
7182  } else {
7183  prepStmt.setNull(2, java.sql.Types.BIGINT);
7184  }
7185  } else {
7186  prepStmt.setNull(2, java.sql.Types.BIGINT);
7187  }
7188  prepStmt.setString(3, fileName); // name
7189  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
7190  prepStmt.setShort(5, (short) 0); // has_path
7191  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7192  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7193  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
7194  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
7195  //prevent negative size
7196  long savedSize = size < 0 ? 0 : size;
7197  prepStmt.setLong(10, savedSize); // size
7198  prepStmt.setLong(11, ctime); // ctime
7199  prepStmt.setLong(12, crtime); // crtime
7200  prepStmt.setLong(13, atime); // atime
7201  prepStmt.setLong(14, mtime); // mtime
7202  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7203  prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7204  prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type
7205  prepStmt.setString(18, parentPath); // parent path
7206  prepStmt.setLong(19, parent.getDataSource().getId()); // data_source_obj_id
7207 
7208  prepStmt.setString(20, extractExtension(fileName)); //extension
7209  connection.executeUpdate(prepStmt);
7210 
7211  /*
7212  * Insert a row in the tsk_layout_file table for each chunk of the
7213  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
7214  * byte_len, sequence) VALUES (?, ?, ?, ?)
7215  */
7216  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7217  for (TskFileRange tskFileRange : fileRanges) {
7218  prepStmt.clearParameters();
7219  prepStmt.setLong(1, newFileId); // obj_id
7220  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7221  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7222  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7223  connection.executeUpdate(prepStmt);
7224  }
7225 
7226  /*
7227  * Create a layout file representation of the carved file.
7228  */
7229  LayoutFile layoutFile = new LayoutFile(this,
7230  newFileId,
7231  parent.getDataSource().getId(),
7232  fileName,
7236  dirFlag,
7237  metaFlag.getValue(),
7238  savedSize,
7239  ctime, crtime, atime, mtime,
7240  null,
7242  parentPath,
7243  null);
7244 
7245  transaction.commit();
7246  transaction = null;
7247  return layoutFile;
7248 
7249  } catch (SQLException ex) {
7250  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
7251  } finally {
7252  closeResultSet(resultSet);
7253  closeStatement(statement);
7254 
7255  if (null != transaction) {
7256  try {
7257  transaction.rollback();
7258  } catch (TskCoreException ex2) {
7259  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7260  }
7261  }
7262  }
7263  }
7264 
7277  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
7279  Statement statement = null;
7280  ResultSet resultSet = null;
7281  try {
7282  statement = connection.createStatement();
7283  long dataSourceObjId;
7284  long ancestorId = objectId;
7285  do {
7286  dataSourceObjId = ancestorId;
7287  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
7288  resultSet = statement.executeQuery(query);
7289  if (resultSet.next()) {
7290  ancestorId = resultSet.getLong("par_obj_id");
7291  } else {
7292  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
7293  }
7294  resultSet.close();
7295  resultSet = null;
7296  } while (0 != ancestorId); // Not NULL
7297  return dataSourceObjId;
7298  } catch (SQLException ex) {
7299  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
7300  } finally {
7301  closeResultSet(resultSet);
7302  closeStatement(statement);
7304  }
7305  }
7306 
7318  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7319  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
7320  statement.clearParameters();
7321  statement.setLong(1, objId);
7322  statement.setString(2, path);
7323  statement.setInt(3, type.getType());
7324  connection.executeUpdate(statement);
7325  }
7326 
7338  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
7339  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
7340  statement.clearParameters();
7341  statement.setString(1, path);
7342  statement.setInt(2, type.getType());
7343  statement.setLong(3, objId);
7344  connection.executeUpdate(statement);
7345  }
7346 
7362  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
7363  return findFiles(dataSource, fileName, parentFile.getName());
7364  }
7365 
7377  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
7378  CaseDbConnection connection = connections.getConnection();
7380  Statement s = null;
7381  ResultSet rs = null;
7382  try {
7383  s = connection.createStatement();
7384  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7385  rs.next();
7386  return rs.getLong("count");
7387  } catch (SQLException e) {
7388  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
7389  } finally {
7390  closeResultSet(rs);
7391  closeStatement(s);
7392  connection.close();
7394  }
7395  }
7396 
7414  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
7415  CaseDbConnection connection = connections.getConnection();
7417  Statement s = null;
7418  ResultSet rs = null;
7419  try {
7420  s = connection.createStatement();
7421  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7422  return resultSetToAbstractFiles(rs, connection);
7423  } catch (SQLException e) {
7424  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
7425  } finally {
7426  closeResultSet(rs);
7427  closeStatement(s);
7428  connection.close();
7430  }
7431  }
7432 
7451  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException{
7452  String queryTemplate = "SELECT tsk_files.* FROM tsk_files JOIN tsk_objects ON tsk_objects.obj_id = tsk_files.obj_id WHERE par_obj_id = %d AND %s";
7453 
7454  try(CaseDbConnection connection = connections.getConnection()) {
7456 
7457  String query = String.format(queryTemplate, parentId, sqlWhereClause);
7458  try(Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
7459  return resultSetToAbstractFiles(rs, connection);
7460  } catch(SQLException ex) {
7461  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
7462  }
7463  }finally {
7465  }
7466  }
7467 
7480  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
7481  CaseDbConnection connection = connections.getConnection();
7483  Statement s = null;
7484  ResultSet rs = null;
7485  try {
7486  s = connection.createStatement();
7487  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
7488  List<Long> ret = new ArrayList<Long>();
7489  while (rs.next()) {
7490  ret.add(rs.getLong("obj_id"));
7491  }
7492  return ret;
7493  } catch (SQLException e) {
7494  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
7495  } finally {
7496  closeResultSet(rs);
7497  closeStatement(s);
7498  connection.close();
7500  }
7501  }
7502 
7514  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
7515 
7516  // get the non-unique path (strip of image and volume path segments, if
7517  // the exist.
7518  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
7519 
7520  // split the file name from the parent path
7521  int lastSlash = path.lastIndexOf('/'); //NON-NLS
7522 
7523  // if the last slash is at the end, strip it off
7524  if (lastSlash == path.length()) {
7525  path = path.substring(0, lastSlash - 1);
7526  lastSlash = path.lastIndexOf('/'); //NON-NLS
7527  }
7528 
7529  String parentPath = path.substring(0, lastSlash);
7530  String fileName = path.substring(lastSlash);
7531 
7532  return findFiles(dataSource, fileName, parentPath);
7533  }
7534 
7545  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
7546  CaseDbConnection connection = connections.getConnection();
7548  Statement s = null;
7549  ResultSet rs = null;
7550  try {
7551  s = connection.createStatement();
7552  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
7553  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
7554  while (rs.next()) {
7555  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
7556  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
7557  ranges.add(range);
7558  }
7559  return ranges;
7560  } catch (SQLException ex) {
7561  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
7562  } finally {
7563  closeResultSet(rs);
7564  closeStatement(s);
7565  connection.close();
7567  }
7568  }
7569 
7580  public Image getImageById(long id) throws TskCoreException {
7581  CaseDbConnection connection = connections.getConnection();
7583  Statement s1 = null;
7584  ResultSet rs1 = null;
7585  Statement s2 = null;
7586  ResultSet rs2 = null;
7587  try {
7588  s1 = connection.createStatement();
7589  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 "
7590  + "FROM tsk_image_info "
7591  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
7592  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
7593  if (rs1.next()) {
7594  s2 = connection.createStatement();
7595  rs2 = connection.executeQuery(s2, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + id); //NON-NLS
7596  List<String> imagePaths = new ArrayList<String>();
7597  while (rs2.next()) {
7598  imagePaths.add(rs2.getString("name"));
7599  }
7600  long type = rs1.getLong("type"); //NON-NLS
7601  long ssize = rs1.getLong("ssize"); //NON-NLS
7602  String tzone = rs1.getString("tzone"); //NON-NLS
7603  long size = rs1.getLong("size"); //NON-NLS
7604  String md5 = rs1.getString("md5"); //NON-NLS
7605  String sha1 = rs1.getString("sha1"); //NON-NLS
7606  String sha256 = rs1.getString("sha256"); //NON-NLS
7607  String name = rs1.getString("display_name");
7608  if (name == null) {
7609  if (imagePaths.size() > 0) {
7610  String path = imagePaths.get(0);
7611  name = (new java.io.File(path)).getName();
7612  } else {
7613  name = "";
7614  }
7615  }
7616  String device_id = rs1.getString("device_id");
7617 
7618  return new Image(this, id, type, device_id, ssize, name,
7619  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
7620  } else {
7621  throw new TskCoreException("No image found for id: " + id);
7622  }
7623  } catch (SQLException ex) {
7624  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
7625  } finally {
7626  closeResultSet(rs2);
7627  closeStatement(s2);
7628  closeResultSet(rs1);
7629  closeStatement(s1);
7630  connection.close();
7632  }
7633  }
7634 
7646  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
7647  CaseDbConnection connection = connections.getConnection();
7649  Statement s = null;
7650  ResultSet rs = null;
7651  try {
7652  s = connection.createStatement();
7653  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
7654  + "where obj_id = " + id); //NON-NLS
7655  if (rs.next()) {
7656  long type = rs.getLong("vs_type"); //NON-NLS
7657  long imgOffset = rs.getLong("img_offset"); //NON-NLS
7658  long blockSize = rs.getLong("block_size"); //NON-NLS
7659  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
7660  vs.setParent(parent);
7661  return vs;
7662  } else {
7663  throw new TskCoreException("No volume system found for id:" + id);
7664  }
7665  } catch (SQLException ex) {
7666  throw new TskCoreException("Error getting Volume System by ID.", ex);
7667  } finally {
7668  closeResultSet(rs);
7669  closeStatement(s);
7670  connection.close();
7672  }
7673  }
7674 
7683  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
7684  VolumeSystem vs = getVolumeSystemById(id, null);
7685  vs.setParentId(parentId);
7686  return vs;
7687  }
7688 
7700  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
7701  return getFileSystemByIdHelper(id, parent);
7702  }
7703 
7712  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
7713  Volume vol = null;
7714  FileSystem fs = getFileSystemById(id, vol);
7715  fs.setParentId(parentId);
7716  return fs;
7717  }
7718 
7730  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
7731  return getFileSystemByIdHelper(id, parent);
7732  }
7733 
7745  Pool getPoolById(long id, Content parent) throws TskCoreException {
7746  return getPoolByIdHelper(id, parent);
7747  }
7748 
7757  Pool getPoolById(long id, long parentId) throws TskCoreException {
7758  Pool pool = getPoolById(id, null);
7759  pool.setParentId(parentId);
7760  return pool;
7761  }
7762 
7774  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
7775 
7777  try (CaseDbConnection connection = connections.getConnection();
7778  Statement s = connection.createStatement();
7779  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
7780  + "where obj_id = " + id);) { //NON-NLS
7781  if (rs.next()) {
7782  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
7783  pool.setParent(parent);
7784 
7785  return pool;
7786  } else {
7787  throw new TskCoreException("No pool found for ID:" + id);
7788  }
7789  } catch (SQLException ex) {
7790  throw new TskCoreException("Error getting Pool by ID", ex);
7791  } finally {
7793  }
7794  }
7795 
7807  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
7808  // see if we already have it
7809  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
7810  // but it should be the same...
7811  synchronized (fileSystemIdMap) {
7812  if (fileSystemIdMap.containsKey(id)) {
7813  return fileSystemIdMap.get(id);
7814  }
7815  }
7816  CaseDbConnection connection = connections.getConnection();
7818  Statement s = null;
7819  ResultSet rs = null;
7820  try {
7821  s = connection.createStatement();
7822  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
7823  + "where obj_id = " + id); //NON-NLS
7824  if (rs.next()) {
7825  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7826  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7827  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7828  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7829  fs.setParent(parent);
7830  // save it for the next call
7831  synchronized (fileSystemIdMap) {
7832  fileSystemIdMap.put(id, fs);
7833  }
7834  return fs;
7835  } else {
7836  throw new TskCoreException("No file system found for id:" + id);
7837  }
7838  } catch (SQLException ex) {
7839  throw new TskCoreException("Error getting File System by ID", ex);
7840  } finally {
7841  closeResultSet(rs);
7842  closeStatement(s);
7843  connection.close();
7845  }
7846  }
7847 
7859  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
7860  CaseDbConnection connection = connections.getConnection();
7862  Statement s = null;
7863  ResultSet rs = null;
7864  try {
7865  s = connection.createStatement();
7866  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
7867  + "where obj_id = " + id); //NON-NLS
7868  if (rs.next()) {
7876  String description;
7877  try {
7878  description = rs.getString("desc");
7879  } catch (Exception ex) {
7880  description = rs.getString("descr");
7881  }
7882  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
7883  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
7884  description);
7885  vol.setParent(parent);
7886  return vol;
7887  } else {
7888  throw new TskCoreException("No volume found for id:" + id);
7889  }
7890  } catch (SQLException ex) {
7891  throw new TskCoreException("Error getting Volume by ID", ex);
7892  } finally {
7893  closeResultSet(rs);
7894  closeStatement(s);
7895  connection.close();
7897  }
7898  }
7899 
7908  Volume getVolumeById(long id, long parentId) throws TskCoreException {
7909  Volume vol = getVolumeById(id, null);
7910  vol.setParentId(parentId);
7911  return vol;
7912  }
7913 
7925  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
7926  CaseDbConnection connection = connections.getConnection();
7928  Statement s = null;
7929  ResultSet rs = null;
7930  try {
7931  s = connection.createStatement();
7932  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
7933  + "WHERE obj_id = " + id);
7934  Directory temp = null; //NON-NLS
7935  if (rs.next()) {
7936  final short type = rs.getShort("type"); //NON-NLS
7937  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
7938  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
7939  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
7940  temp = directory(rs, parentFs);
7941  }
7942  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
7943  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
7944  }
7945  } else {
7946  throw new TskCoreException("No Directory found for id:" + id);
7947  }
7948  return temp;
7949  } catch (SQLException ex) {
7950  throw new TskCoreException("Error getting Directory by ID", ex);
7951  } finally {
7952  closeResultSet(rs);
7953  closeStatement(s);
7954  connection.close();
7956  }
7957  }
7958 
7968  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
7969  List<FileSystem> fileSystems = new ArrayList<>();
7970  CaseDbConnection connection = connections.getConnection();
7971 
7973  Statement s = null;
7974  ResultSet rs = null;
7975  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
7976  try {
7977  s = connection.createStatement();
7978  rs = connection.executeQuery(s, queryStr); //NON-NLS
7979  while (rs.next()) {
7980  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
7981  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
7982  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
7983  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
7984  fs.setParent(null);
7985  fileSystems.add(fs);
7986  }
7987  } catch (SQLException ex) {
7988  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
7989  } finally {
7990  closeResultSet(rs);
7991  closeStatement(s);
7992  connection.close();
7994  }
7995  return fileSystems;
7996  }
7997 
8008  List<Content> getImageChildren(Image img) throws TskCoreException {
8009  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
8010  List<Content> children = new ArrayList<Content>();
8011  for (ObjectInfo info : childInfos) {
8012  if (null != info.type) {
8013  switch (info.type) {
8014  case VS:
8015  children.add(getVolumeSystemById(info.id, img));
8016  break;
8017  case POOL:
8018  children.add(getPoolById(info.id, img));
8019  break;
8020  case FS:
8021  children.add(getFileSystemById(info.id, img));
8022  break;
8023  case ABSTRACTFILE:
8024  AbstractFile f = getAbstractFileById(info.id);
8025  if (f != null) {
8026  children.add(f);
8027  }
8028  break;
8029  case ARTIFACT:
8030  BlackboardArtifact art = getArtifactById(info.id);
8031  if (art != null) {
8032  children.add(art);
8033  }
8034  break;
8035  case REPORT:
8036  // Do nothing for now - see JIRA-3673
8037  break;
8038  default:
8039  throw new TskCoreException("Image has child of invalid type: " + info.type);
8040  }
8041  }
8042  }
8043  return children;
8044  }
8045 
8056  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
8057  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
8058  List<Long> children = new ArrayList<Long>();
8059  for (ObjectInfo info : childInfos) {
8060  if (info.type == ObjectType.VS
8061  || info.type == ObjectType.POOL
8062  || info.type == ObjectType.FS
8063  || info.type == ObjectType.ABSTRACTFILE
8064  || info.type == ObjectType.ARTIFACT) {
8065  children.add(info.id);
8066  } else if (info.type == ObjectType.REPORT) {
8067  // Do nothing for now - see JIRA-3673
8068  } else {
8069  throw new TskCoreException("Image has child of invalid type: " + info.type);
8070  }
8071  }
8072  return children;
8073  }
8074 
8085  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
8086  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
8087  List<Content> children = new ArrayList<Content>();
8088  for (ObjectInfo info : childInfos) {
8089  if (null != info.type) {
8090  switch (info.type) {
8091  case VS:
8092  children.add(getVolumeSystemById(info.id, pool));
8093  break;
8094  case ABSTRACTFILE:
8095  AbstractFile f = getAbstractFileById(info.id);
8096  if (f != null) {
8097  children.add(f);
8098  }
8099  break;
8100  case ARTIFACT:
8101  BlackboardArtifact art = getArtifactById(info.id);
8102  if (art != null) {
8103  children.add(art);
8104  }
8105  break;
8106  default:
8107  throw new TskCoreException("Pool has child of invalid type: " + info.type);
8108  }
8109  }
8110  }
8111  return children;
8112  }
8113 
8124  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
8125  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
8126  List<Long> children = new ArrayList<Long>();
8127  for (ObjectInfo info : childInfos) {
8128  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8129  children.add(info.id);
8130  } else {
8131  throw new TskCoreException("Pool has child of invalid type: " + info.type);
8132  }
8133  }
8134  return children;
8135  }
8136 
8147  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
8148  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
8149  List<Content> children = new ArrayList<Content>();
8150  for (ObjectInfo info : childInfos) {
8151  if (null != info.type) {
8152  switch (info.type) {
8153  case VOL:
8154  children.add(getVolumeById(info.id, vs));
8155  break;
8156  case ABSTRACTFILE:
8157  AbstractFile f = getAbstractFileById(info.id);
8158  if (f != null) {
8159  children.add(f);
8160  }
8161  break;
8162  case ARTIFACT:
8163  BlackboardArtifact art = getArtifactById(info.id);
8164  if (art != null) {
8165  children.add(art);
8166  }
8167  break;
8168  default:
8169  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8170  }
8171  }
8172  }
8173  return children;
8174  }
8175 
8186  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
8187  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
8188  List<Long> children = new ArrayList<Long>();
8189  for (ObjectInfo info : childInfos) {
8190  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8191  children.add(info.id);
8192  } else {
8193  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
8194  }
8195  }
8196  return children;
8197  }
8198 
8209  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
8210  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8211  List<Content> children = new ArrayList<Content>();
8212  for (ObjectInfo info : childInfos) {
8213  if (null != info.type) {
8214  switch (info.type) {
8215  case POOL:
8216  children.add(getPoolById(info.id, vol));
8217  break;
8218  case FS:
8219  children.add(getFileSystemById(info.id, vol));
8220  break;
8221  case ABSTRACTFILE:
8222  AbstractFile f = getAbstractFileById(info.id);
8223  if (f != null) {
8224  children.add(f);
8225  }
8226  break;
8227  case ARTIFACT:
8228  BlackboardArtifact art = getArtifactById(info.id);
8229  if (art != null) {
8230  children.add(art);
8231  }
8232  break;
8233  default:
8234  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8235  }
8236  }
8237  }
8238  return children;
8239  }
8240 
8251  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
8252  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
8253  final List<Long> children = new ArrayList<Long>();
8254  for (ObjectInfo info : childInfos) {
8255  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
8256  children.add(info.id);
8257  } else {
8258  throw new TskCoreException("Volume has child of invalid type: " + info.type);
8259  }
8260  }
8261  return children;
8262  }
8263 
8277  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
8278  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, this);
8279  return getImageById(imageId);
8280  }
8281 
8291  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
8292  CaseDbConnection connection = connections.getConnection();
8294  Statement s1 = null;
8295  Statement s2 = null;
8296  ResultSet rs1 = null;
8297  ResultSet rs2 = null;
8298  try {
8299  s1 = connection.createStatement();
8300  rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8301  s2 = connection.createStatement();
8302  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
8303  while (rs1.next()) {
8304  long obj_id = rs1.getLong("obj_id"); //NON-NLS
8305  rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS
8306  List<String> paths = new ArrayList<String>();
8307  while (rs2.next()) {
8308  paths.add(rs2.getString("name"));
8309  }
8310  rs2.close();
8311  rs2 = null;
8312  imgPaths.put(obj_id, paths);
8313  }
8314  return imgPaths;
8315  } catch (SQLException ex) {
8316  throw new TskCoreException("Error getting image paths.", ex);
8317  } finally {
8318  closeResultSet(rs2);
8319  closeStatement(s2);
8320  closeResultSet(rs1);
8321  closeStatement(s1);
8322  connection.close();
8324  }
8325  }
8326 
8337  private List<String> getImagePathsById(long objectId) throws TskCoreException {
8338  List<String> imagePaths = new ArrayList<String>();
8339  CaseDbConnection connection = connections.getConnection();
8341  Statement statement = null;
8342  ResultSet resultSet = null;
8343  try {
8344  statement = connection.createStatement();
8345  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
8346  while (resultSet.next()) {
8347  imagePaths.add(resultSet.getString("name"));
8348  }
8349  } catch (SQLException ex) {
8350  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
8351  } finally {
8352  closeResultSet(resultSet);
8353  closeStatement(statement);
8354  connection.close();
8356  }
8357 
8358  return imagePaths;
8359  }
8360 
8367  public List<Image> getImages() throws TskCoreException {
8368  CaseDbConnection connection = connections.getConnection();
8370  Statement s = null;
8371  ResultSet rs = null;
8372  try {
8373  s = connection.createStatement();
8374  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
8375  Collection<Long> imageIDs = new ArrayList<Long>();
8376  while (rs.next()) {
8377  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
8378  }
8379  List<Image> images = new ArrayList<Image>();
8380  for (long id : imageIDs) {
8381  images.add(getImageById(id));
8382  }
8383  return images;
8384  } catch (SQLException ex) {
8385  throw new TskCoreException("Error retrieving images.", ex);
8386  } finally {
8387  closeResultSet(rs);
8388  closeStatement(s);
8389  connection.close();
8391  }
8392  }
8393 
8404  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
8405  CaseDbConnection connection = connections.getConnection();
8407  PreparedStatement statement = null;
8408  try {
8409  connection.beginTransaction();
8410  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
8411  statement.clearParameters();
8412  statement.setLong(1, obj_id);
8413  connection.executeUpdate(statement);
8414  for (int i = 0; i < paths.size(); i++) {
8415  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
8416  statement.clearParameters();
8417  statement.setLong(1, obj_id);
8418  statement.setString(2, paths.get(i));
8419  statement.setLong(3, i);
8420  connection.executeUpdate(statement);
8421  }
8422  connection.commitTransaction();
8423  } catch (SQLException ex) {
8424  connection.rollbackTransaction();
8425  throw new TskCoreException("Error updating image paths.", ex);
8426  } finally {
8427  connection.close();
8429  }
8430  }
8431 
8443  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
8444  CaseDbConnection connection = connections.getConnection();
8445  Statement statement = null;
8447  try {
8448  statement = connection.createStatement();
8449  connection.beginTransaction();
8450  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
8451  // all associated rows from tsk_object and its children. For large data sources this may take some time.
8452  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
8453  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
8454  // associated rows from accounts table and its children.
8455  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
8456  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
8457  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
8458  statement.execute(accountSql);
8459  connection.commitTransaction();
8460  } catch (SQLException ex) {
8461  connection.rollbackTransaction();
8462  throw new TskCoreException("Error deleting data source.", ex);
8463  } finally {
8464  connection.close();
8466  }
8467  }
8468 
8494  private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
8495  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
8496  try {
8497  while (rs.next()) {
8498  final short type = rs.getShort("type"); //NON-NLS
8499  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
8500  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
8501  FsContent result;
8502  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
8503  result = directory(rs, null);
8504  } else {
8505  result = file(rs, null);
8506  }
8507  results.add(result);
8508  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
8509  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
8510  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
8511  results.add(virtDir);
8512  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
8513  final LocalDirectory localDir = localDirectory(rs);
8514  results.add(localDir);
8515  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
8516  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
8517  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
8518  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
8519  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
8520  String parentPath = rs.getString("parent_path"); //NON-NLS
8521  if (parentPath == null) {
8522  parentPath = "/"; //NON-NLS
8523  }
8524  LayoutFile lf = new LayoutFile(this,
8525  rs.getLong("obj_id"), //NON-NLS
8526  rs.getLong("data_source_obj_id"),
8527  rs.getString("name"), //NON-NLS
8528  atype,
8529  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8530  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8531  rs.getLong("size"), //NON-NLS
8532  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8533  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS
8534  results.add(lf);
8535  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
8536  final DerivedFile df;
8537  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
8538  results.add(df);
8539  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
8540  final LocalFile lf;
8541  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
8542  results.add(lf);
8543  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
8544  final SlackFile sf = slackFile(rs, null);
8545  results.add(sf);
8546  }
8547  } //end for each resultSet
8548  } catch (SQLException e) {
8549  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
8550  }
8551 
8552  return results;
8553  }
8554 
8555  // This following methods generate AbstractFile objects from a ResultSet
8567  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
8568  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
8569  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8570  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8571  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8572  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8573  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8574  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8575  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8576  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8577  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8578  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8579  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8580  f.setFileSystem(fs);
8581  return f;
8582  }
8583 
8595  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
8596  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8597  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8598  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8599  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8600  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8601  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8602  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8603  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8604  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8605  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8606  rs.getString("parent_path")); //NON-NLS
8607  dir.setFileSystem(fs);
8608  return dir;
8609  }
8610 
8621  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
8622  String parentPath = rs.getString("parent_path"); //NON-NLS
8623  if (parentPath == null) {
8624  parentPath = "";
8625  }
8626 
8627  long objId = rs.getLong("obj_id");
8628  long dsObjId = rs.getLong("data_source_obj_id");
8629  if (objId == dsObjId) { // virtual directory is a data source
8630 
8631  String deviceId = "";
8632  String timeZone = "";
8633  Statement s = null;
8634  ResultSet rsDataSourceInfo = null;
8635 
8637  try {
8638  s = connection.createStatement();
8639  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
8640  if (rsDataSourceInfo.next()) {
8641  deviceId = rsDataSourceInfo.getString("device_id");
8642  timeZone = rsDataSourceInfo.getString("time_zone");
8643  }
8644  } catch (SQLException ex) {
8645  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
8646  } finally {
8647  closeResultSet(rsDataSourceInfo);
8648  closeStatement(s);
8650  }
8651 
8652  return new LocalFilesDataSource(this,
8653  objId, dsObjId,
8654  deviceId,
8655  rs.getString("name"),
8656  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8657  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8658  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
8659  rs.getShort("meta_flags"),
8660  timeZone,
8661  rs.getString("md5"),
8662  FileKnown.valueOf(rs.getByte("known")),
8663  parentPath);
8664  } else {
8665  final VirtualDirectory vd = new VirtualDirectory(this,
8666  objId, dsObjId,
8667  rs.getString("name"), //NON-NLS
8668  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8669  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8670  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8671  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8672  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8673  return vd;
8674  }
8675  }
8676 
8686  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
8687  String parentPath = rs.getString("parent_path"); //NON-NLS
8688  if (parentPath == null) {
8689  parentPath = "";
8690  }
8691  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
8692  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
8693  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8694  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8695  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8696  rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS
8697  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
8698  return ld;
8699  }
8700 
8714  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8715  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
8716  long objId = rs.getLong("obj_id"); //NON-NLS
8717  String localPath = null;
8718  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8719  if (hasLocalPath) {
8720  ResultSet rsFilePath = null;
8722  try {
8723  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8724  statement.clearParameters();
8725  statement.setLong(1, objId);
8726  rsFilePath = connection.executeQuery(statement);
8727  if (rsFilePath.next()) {
8728  localPath = rsFilePath.getString("path");
8729  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8730  }
8731  } catch (SQLException ex) {
8732  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8733  } finally {
8734  closeResultSet(rsFilePath);
8736  }
8737  }
8738  String parentPath = rs.getString("parent_path"); //NON-NLS
8739  if (parentPath == null) {
8740  parentPath = "";
8741  }
8742  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
8743  rs.getString("name"), //NON-NLS
8744  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8745  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8746  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8747  rs.getLong("size"), //NON-NLS
8748  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8749  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8750  parentPath, localPath, parentId, rs.getString("mime_type"),
8751  encodingType, rs.getString("extension"));
8752  return df;
8753  }
8754 
8768  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8769  long objId = rs.getLong("obj_id"); //NON-NLS
8770  String localPath = null;
8771  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
8772  if (rs.getBoolean("has_path")) {
8773  ResultSet rsFilePath = null;
8775  try {
8776  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
8777  statement.clearParameters();
8778  statement.setLong(1, objId);
8779  rsFilePath = connection.executeQuery(statement);
8780  if (rsFilePath.next()) {
8781  localPath = rsFilePath.getString("path");
8782  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
8783  }
8784  } catch (SQLException ex) {
8785  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
8786  } finally {
8787  closeResultSet(rsFilePath);
8789  }
8790  }
8791  String parentPath = rs.getString("parent_path"); //NON-NLS
8792  if (null == parentPath) {
8793  parentPath = "";
8794  }
8795  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
8796  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
8797  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8798  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8799  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
8800  rs.getLong("size"), //NON-NLS
8801  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8802  rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8803  parentId, parentPath, rs.getLong("data_source_obj_id"),
8804  localPath, encodingType, rs.getString("extension"));
8805  return file;
8806  }
8807 
8819  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
8820  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
8821  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
8822  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
8823  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
8824  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
8825  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
8826  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
8827  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
8828  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
8829  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
8830  rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
8831  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS
8832  f.setFileSystem(fs);
8833  return f;
8834  }
8835 
8847  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
8848  List<Content> children = new ArrayList<Content>();
8849 
8850  while (rs.next()) {
8851  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
8852 
8853  if (null != type) {
8854  switch (type) {
8855  case FS:
8856  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
8857  FsContent result;
8858  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
8859  result = directory(rs, null);
8860  } else {
8861  result = file(rs, null);
8862  }
8863  children.add(result);
8864  } else {
8865  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8866  children.add(virtDir);
8867  }
8868  break;
8869  case VIRTUAL_DIR:
8870  VirtualDirectory virtDir = virtualDirectory(rs, connection);
8871  children.add(virtDir);
8872  break;
8873  case LOCAL_DIR:
8874  LocalDirectory localDir = localDirectory(rs);
8875  children.add(localDir);
8876  break;
8877  case UNALLOC_BLOCKS:
8878  case UNUSED_BLOCKS:
8879  case CARVED:
8880  case LAYOUT_FILE: {
8881  String parentPath = rs.getString("parent_path");
8882  if (parentPath == null) {
8883  parentPath = "";
8884  }
8885  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
8886  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
8887  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
8888  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
8889  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
8890  rs.getLong("size"),
8891  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
8892  rs.getString("md5"),
8893  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"));
8894  children.add(lf);
8895  break;
8896  }
8897  case DERIVED:
8898  final DerivedFile df = derivedFile(rs, connection, parentId);
8899  children.add(df);
8900  break;
8901  case LOCAL: {
8902  final LocalFile lf = localFile(rs, connection, parentId);
8903  children.add(lf);
8904  break;
8905  }
8906  case SLACK: {
8907  final SlackFile sf = slackFile(rs, null);
8908  children.add(sf);
8909  break;
8910  }
8911  default:
8912  break;
8913  }
8914  }
8915  }
8916  return children;
8917  }
8918 
8934  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException, TskCoreException {
8935  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
8936  try {
8937  while (rs.next()) {
8938  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
8939  if (artifactType != null) {
8940  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
8941  rs.getInt("artifact_type_id"), artifactType.getTypeName(), artifactType.getDisplayName(),
8942  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
8943  } else {
8944  throw new TskCoreException("Error looking up artifact type ID " + rs.getInt("artifact_type_id") + " from artifact " + rs.getLong("artifact_id"));
8945  }
8946  } //end for each resultSet
8947  } catch (SQLException e) {
8948  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
8949  }
8950 
8951  return artifacts;
8952  }
8953 
8975  public CaseDbQuery executeQuery(String query) throws TskCoreException {
8976  return new CaseDbQuery(query);
8977  }
8978 
9000  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
9001  return new CaseDbQuery(query, true);
9002  }
9003 
9011  CaseDbConnection getConnection() throws TskCoreException {
9012  return connections.getConnection();
9013  }
9014 
9021  String getCaseHandleIdentifier() {
9022  return caseHandleIdentifier;
9023  }
9024 
9025  @Override
9026  protected void finalize() throws Throwable {
9027  try {
9028  close();
9029  } finally {
9030  super.finalize();
9031  }
9032  }
9033 
9037  public synchronized void close() {
9039 
9040  try {
9041  connections.close();
9042  } catch (TskCoreException ex) {
9043  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
9044  }
9045 
9046  fileSystemIdMap.clear();
9047 
9048  try {
9049  if (this.caseHandle != null) {
9050  this.caseHandle.free();
9051  this.caseHandle = null;
9052  }
9053  } catch (TskCoreException ex) {
9054  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
9055  } finally {
9057  }
9058  }
9059 
9072  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
9073  long id = file.getId();
9074  FileKnown currentKnown = file.getKnown();
9075  if (currentKnown.compareTo(fileKnown) > 0) {
9076  return false;
9077  }
9078  CaseDbConnection connection = connections.getConnection();
9080  Statement statement = null;
9081  try {
9082  statement = connection.createStatement();
9083  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
9084  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
9085  + "WHERE obj_id=" + id); //NON-NLS
9086 
9087  file.setKnown(fileKnown);
9088  } catch (SQLException ex) {
9089  throw new TskCoreException("Error setting Known status.", ex);
9090  } finally {
9091  closeStatement(statement);
9092  connection.close();
9094  }
9095  return true;
9096  }
9097 
9106  void setFileName(String name, long objId) throws TskCoreException {
9107 
9108  CaseDbConnection connection = connections.getConnection();
9110  try {
9111  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
9112  preparedStatement.clearParameters();
9113  preparedStatement.setString(1, name);
9114  preparedStatement.setLong(2, objId);
9115  connection.executeUpdate(preparedStatement);
9116  } catch (SQLException ex) {
9117  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
9118  } finally {
9119  connection.close();
9121  }
9122  }
9123 
9132  void setImageName(String name, long objId) throws TskCoreException {
9133 
9134  CaseDbConnection connection = connections.getConnection();
9136  try {
9137  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
9138  preparedStatement.clearParameters();
9139  preparedStatement.setString(1, name);
9140  preparedStatement.setLong(2, objId);
9141  connection.executeUpdate(preparedStatement);
9142  } catch (SQLException ex) {
9143  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
9144  } finally {
9145  connection.close();
9147  }
9148  }
9149 
9159  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
9160  CaseDbConnection connection = connections.getConnection();
9161  Statement statement = null;
9162  ResultSet rs = null;
9164  try {
9165  statement = connection.createStatement();
9166  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
9167  file.setMIMEType(mimeType);
9168  } catch (SQLException ex) {
9169  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
9170  } finally {
9171  closeResultSet(rs);
9172  closeStatement(statement);
9173  connection.close();
9175  }
9176  }
9177 
9187  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
9188  if (md5Hash == null) {
9189  return;
9190  }
9191  long id = file.getId();
9192  CaseDbConnection connection = connections.getConnection();
9194  try {
9195  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
9196  statement.clearParameters();
9197  statement.setString(1, md5Hash.toLowerCase());
9198  statement.setLong(2, id);
9199  connection.executeUpdate(statement);
9200  file.setMd5Hash(md5Hash.toLowerCase());
9201  } catch (SQLException ex) {
9202  throw new TskCoreException("Error setting MD5 hash", ex);
9203  } finally {
9204  connection.close();
9206  }
9207  }
9208 
9218  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
9219  if (md5Hash == null) {
9220  return;
9221  }
9222  long id = img.getId();
9223  CaseDbConnection connection = connections.getConnection();
9225  try {
9226  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
9227  statement.clearParameters();
9228  statement.setString(1, md5Hash.toLowerCase());
9229  statement.setLong(2, id);
9230  connection.executeUpdate(statement);
9231  } catch (SQLException ex) {
9232  throw new TskCoreException("Error setting MD5 hash", ex);
9233  } finally {
9234  connection.close();
9236  }
9237  }
9238 
9249  String getMd5ImageHash(Image img) throws TskCoreException {
9250  long id = img.getId();
9251  CaseDbConnection connection = connections.getConnection();
9253  ResultSet rs = null;
9254  String hash = "";
9255  try {
9256  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
9257  statement.clearParameters();
9258  statement.setLong(1, id);
9259  rs = connection.executeQuery(statement);
9260  if (rs.next()) {
9261  hash = rs.getString("md5");
9262  }
9263  return hash;
9264  } catch (SQLException ex) {
9265  throw new TskCoreException("Error getting MD5 hash", ex);
9266  } finally {
9267  closeResultSet(rs);
9268  connection.close();
9270  }
9271  }
9272 
9282  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
9283  if (sha1Hash == null) {
9284  return;
9285  }
9286  long id = img.getId();
9287  CaseDbConnection connection = connections.getConnection();
9289  try {
9290  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
9291  statement.clearParameters();
9292  statement.setString(1, sha1Hash.toLowerCase());
9293  statement.setLong(2, id);
9294  connection.executeUpdate(statement);
9295  } catch (SQLException ex) {
9296  throw new TskCoreException("Error setting SHA1 hash", ex);
9297  } finally {
9298  connection.close();
9300  }
9301  }
9302 
9313  String getSha1ImageHash(Image img) throws TskCoreException {
9314  long id = img.getId();
9315  CaseDbConnection connection = connections.getConnection();
9317  ResultSet rs = null;
9318  String hash = "";
9319  try {
9320  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
9321  statement.clearParameters();
9322  statement.setLong(1, id);
9323  rs = connection.executeQuery(statement);
9324  if (rs.next()) {
9325  hash = rs.getString("sha1");
9326  }
9327  return hash;
9328  } catch (SQLException ex) {
9329  throw new TskCoreException("Error getting SHA1 hash", ex);
9330  } finally {
9331  closeResultSet(rs);
9332  connection.close();
9334  }
9335  }
9336 
9346  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
9347  if (sha256Hash == null) {
9348  return;
9349  }
9350  long id = img.getId();
9351  CaseDbConnection connection = connections.getConnection();
9353  try {
9354  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
9355  statement.clearParameters();
9356  statement.setString(1, sha256Hash.toLowerCase());
9357  statement.setLong(2, id);
9358  connection.executeUpdate(statement);
9359  } catch (SQLException ex) {
9360  throw new TskCoreException("Error setting SHA256 hash", ex);
9361  } finally {
9362  connection.close();
9364  }
9365  }
9366 
9377  String getSha256ImageHash(Image img) throws TskCoreException {
9378  long id = img.getId();
9379  CaseDbConnection connection = connections.getConnection();
9381  ResultSet rs = null;
9382  String hash = "";
9383  try {
9384  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
9385  statement.clearParameters();
9386  statement.setLong(1, id);
9387  rs = connection.executeQuery(statement);
9388  if (rs.next()) {
9389  hash = rs.getString("sha256");
9390  }
9391  return hash;
9392  } catch (SQLException ex) {
9393  throw new TskCoreException("Error setting SHA256 hash", ex);
9394  } finally {
9395  closeResultSet(rs);
9396  connection.close();
9398  }
9399  }
9400 
9409  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
9410 
9411  long id = datasource.getId();
9412  CaseDbConnection connection = connections.getConnection();
9414  try {
9415  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
9416  statement.clearParameters();
9417  statement.setString(1, details);
9418  statement.setLong(2, id);
9419  connection.executeUpdate(statement);
9420  } catch (SQLException ex) {
9421  throw new TskCoreException("Error setting acquisition details", ex);
9422  } finally {
9423  connection.close();
9425  }
9426  }
9427 
9437  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
9439  try {
9440  CaseDbConnection connection = trans.getConnection();
9441  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
9442  statement.clearParameters();
9443  statement.setString(1, details);
9444  statement.setLong(2, dataSourceId);
9445  connection.executeUpdate(statement);
9446  } catch (SQLException ex) {
9447  throw new TskCoreException("Error setting acquisition details", ex);
9448  } finally {
9450  }
9451  }
9452 
9462  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
9463  long id = datasource.getId();
9464  CaseDbConnection connection = connections.getConnection();
9466  ResultSet rs = null;
9467  String hash = "";
9468  try {
9469  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
9470  statement.clearParameters();
9471  statement.setLong(1, id);
9472  rs = connection.executeQuery(statement);
9473  if (rs.next()) {
9474  hash = rs.getString("acquisition_details");
9475  }
9476  return hash;
9477  } catch (SQLException ex) {
9478  throw new TskCoreException("Error setting acquisition details", ex);
9479  } finally {
9480  closeResultSet(rs);
9481  connection.close();
9483  }
9484  }
9485 
9496  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
9497  if (newStatus == null) {
9498  return;
9499  }
9500  CaseDbConnection connection = connections.getConnection();
9502  Statement statement = null;
9503  try {
9504  statement = connection.createStatement();
9505  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
9506  + " SET review_status_id=" + newStatus.getID()
9507  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
9508  } catch (SQLException ex) {
9509  throw new TskCoreException("Error setting review status", ex);
9510  } finally {
9511  closeStatement(statement);
9512  connection.close();
9514  }
9515  }
9516 
9527  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
9528  CaseDbConnection connection = connections.getConnection();
9530  Statement s = null;
9531  ResultSet rs = null;
9532  try {
9533  s = connection.createStatement();
9534  Short contentShort = contentType.getValue();
9535  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
9536  int count = 0;
9537  if (rs.next()) {
9538  count = rs.getInt("count");
9539  }
9540  return count;
9541  } catch (SQLException ex) {
9542  throw new TskCoreException("Error getting number of objects.", ex);
9543  } finally {
9544  closeResultSet(rs);
9545  closeStatement(s);
9546  connection.close();
9548  }
9549  }
9550 
9559  public static String escapeSingleQuotes(String text) {
9560  String escapedText = null;
9561  if (text != null) {
9562  escapedText = text.replaceAll("'", "''");
9563  }
9564  return escapedText;
9565  }
9566 
9574  public List<AbstractFile> findFilesByMd5(String md5Hash) {
9575  if (md5Hash == null) {
9576  return Collections.<AbstractFile>emptyList();
9577  }
9578  CaseDbConnection connection;
9579  try {
9580  connection = connections.getConnection();
9581  } catch (TskCoreException ex) {
9582  logger.log(Level.SEVERE, "Error finding files by md5 hash " + md5Hash, ex); //NON-NLS
9583  return Collections.<AbstractFile>emptyList();
9584  }
9586  Statement s = null;
9587  ResultSet rs = null;
9588  try {
9589  s = connection.createStatement();
9590  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
9591  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
9592  + "AND size > 0"); //NON-NLS
9593  return resultSetToAbstractFiles(rs, connection);
9594  } catch (SQLException ex) {
9595  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
9596  return Collections.<AbstractFile>emptyList();
9597  } finally {
9598  closeResultSet(rs);
9599  closeStatement(s);
9600  connection.close();
9602  }
9603  }
9604 
9611  public boolean allFilesMd5Hashed() {
9612  CaseDbConnection connection;
9613  try {
9614  connection = connections.getConnection();
9615  } catch (TskCoreException ex) {
9616  logger.log(Level.SEVERE, "Error checking md5 hashing status", ex); //NON-NLS
9617  return false;
9618  }
9619  boolean allFilesAreHashed = false;
9621  Statement s = null;
9622  ResultSet rs = null;
9623  try {
9624  s = connection.createStatement();
9625  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9626  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
9627  + "AND md5 IS NULL " //NON-NLS
9628  + "AND size > '0'"); //NON-NLS
9629  if (rs.next() && rs.getInt("count") == 0) {
9630  allFilesAreHashed = true;
9631  }
9632  } catch (SQLException ex) {
9633  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
9634  } finally {
9635  closeResultSet(rs);
9636  closeStatement(s);
9637  connection.close();
9639  }
9640  return allFilesAreHashed;
9641  }
9642 
9648  public int countFilesMd5Hashed() {
9649  CaseDbConnection connection;
9650  try {
9651  connection = connections.getConnection();
9652  } catch (TskCoreException ex) {
9653  logger.log(Level.SEVERE, "Error getting database connection for hashed files count", ex); //NON-NLS
9654  return 0;
9655  }
9656  int count = 0;
9658  Statement s = null;
9659  ResultSet rs = null;
9660  try {
9661  s = connection.createStatement();
9662  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
9663  + "WHERE md5 IS NOT NULL " //NON-NLS
9664  + "AND size > '0'"); //NON-NLS
9665  if (rs.next()) {
9666  count = rs.getInt("count");
9667  }
9668  } catch (SQLException ex) {
9669  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
9670  } finally {
9671  closeResultSet(rs);
9672  closeStatement(s);
9673  connection.close();
9675  }
9676  return count;
9677 
9678  }
9679 
9688  public List<TagName> getAllTagNames() throws TskCoreException {
9689  CaseDbConnection connection = connections.getConnection();
9691  ResultSet resultSet = null;
9692  try {
9693  // SELECT * FROM tag_names
9694  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
9695  resultSet = connection.executeQuery(statement);
9696  ArrayList<TagName> tagNames = new ArrayList<>();
9697  while (resultSet.next()) {
9698  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9699  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9700  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
9701  }
9702  return tagNames;
9703  } catch (SQLException ex) {
9704  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9705  } finally {
9706  closeResultSet(resultSet);
9707  connection.close();
9709  }
9710  }
9711 
9722  public List<TagName> getTagNamesInUse() throws TskCoreException {
9723  CaseDbConnection connection = connections.getConnection();
9725  ResultSet resultSet = null;
9726  try {
9727  // 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)
9728  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
9729  resultSet = connection.executeQuery(statement);
9730  ArrayList<TagName> tagNames = new ArrayList<>();
9731  while (resultSet.next()) {
9732  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9733  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9734  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
9735  }
9736  return tagNames;
9737  } catch (SQLException ex) {
9738  throw new TskCoreException("Error selecting rows from tag_names table", ex);
9739  } finally {
9740  closeResultSet(resultSet);
9741  connection.close();
9743  }
9744  }
9745 
9758  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
9759 
9760  ArrayList<TagName> tagNames = new ArrayList<TagName>();
9761  // SELECT * FROM tag_names WHERE tag_name_id IN
9762  // ( 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 = ? "
9763  // UNION
9764  // 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 = ? )
9765  // )
9766  CaseDbConnection connection = connections.getConnection();
9768  ResultSet resultSet = null;
9769 
9770  try {
9771  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
9772  statement.setLong(1, dsObjId);
9773  statement.setLong(2, dsObjId);
9774  resultSet = connection.executeQuery(statement); //NON-NLS
9775  while (resultSet.next()) {
9776  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9777  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9778  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
9779  }
9780  return tagNames;
9781  } catch (SQLException ex) {
9782  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
9783  } finally {
9784  closeResultSet(resultSet);
9785  connection.close();
9787  }
9788  }
9789 
9803  @Deprecated
9804  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
9805  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
9806  }
9807 
9822  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
9823  CaseDbConnection connection = connections.getConnection();
9825  ResultSet resultSet = null;
9826  try {
9827  PreparedStatement statement;
9828  // INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?
9829  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME, Statement.RETURN_GENERATED_KEYS);
9830  statement.clearParameters();
9831  statement.setString(5, description);
9832  statement.setString(6, color.getName());
9833  statement.setByte(7, knownStatus.getFileKnownValue());
9834  statement.setString(1, displayName);
9835  statement.setString(2, description);
9836  statement.setString(3, color.getName());
9837  statement.setByte(4, knownStatus.getFileKnownValue());
9838  connection.executeUpdate(statement);
9839 
9840  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAME_BY_NAME);
9841  statement.clearParameters();
9842  statement.setString(1, displayName);
9843  resultSet = connection.executeQuery(statement);
9844  resultSet.next();
9845 
9846  return new TagName(resultSet.getLong("tag_name_id"), displayName, description, color, knownStatus, resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
9847 
9848  } catch (SQLException ex) {
9849  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
9850  } finally {
9851  closeResultSet(resultSet);
9852  connection.close();
9854  }
9855  }
9856 
9871  @Deprecated
9872  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
9873  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
9874  }
9875 
9876  /*
9877  * Deletes a row from the content_tags table in the case database. @param
9878  * tag A ContentTag data transfer object (DTO) for the row to delete.
9879  * @throws TskCoreException
9880  */
9881  public void deleteContentTag(ContentTag tag) throws TskCoreException {
9882  CaseDbConnection connection = connections.getConnection();
9884  try {
9885  // DELETE FROM content_tags WHERE tag_id = ?
9886  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
9887  statement.clearParameters();
9888  statement.setLong(1, tag.getId());
9889  connection.executeUpdate(statement);
9890  } catch (SQLException ex) {
9891  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
9892  } finally {
9893  connection.close();
9895  }
9896  }
9897 
9906  public List<ContentTag> getAllContentTags() throws TskCoreException {
9907  CaseDbConnection connection = connections.getConnection();
9909  ResultSet resultSet = null;
9910  try {
9911  // SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name
9912  // FROM content_tags
9913  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
9914  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
9915  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
9916  resultSet = connection.executeQuery(statement);
9917  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
9918  while (resultSet.next()) {
9919  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
9920  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
9921  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
9922  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
9923  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
9924  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
9925  }
9926  return tags;
9927  } catch (SQLException ex) {
9928  throw new TskCoreException("Error selecting rows from content_tags table", ex);
9929  } finally {
9930  closeResultSet(resultSet);
9931  connection.close();
9933  }
9934  }
9935 
9946  public long getContentTagsCountByTagName(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 COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
9955  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
9956  statement.clearParameters();
9957  statement.setLong(1, tagName.getId());
9958  resultSet = connection.executeQuery(statement);
9959  if (resultSet.next()) {
9960  return resultSet.getLong("count");
9961  } else {
9962  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
9963  }
9964  } catch (SQLException ex) {
9965  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
9966  } finally {
9967  closeResultSet(resultSet);
9968  connection.close();
9970  }
9971  }
9972 
9988  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
9989 
9990  if (tagName.getId() == Tag.ID_NOT_SET) {
9991  throw new TskCoreException("TagName object is invalid, id not set");
9992  }
9993 
9994  CaseDbConnection connection = connections.getConnection();
9996  ResultSet resultSet = null;
9997  try {
9998  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
9999  // + " AND content_tags.tag_name_id = ? "
10000  // + " AND tsk_files.data_source_obj_id = ? "
10001  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10002  statement.clearParameters();
10003  statement.setLong(1, tagName.getId());
10004  statement.setLong(2, dsObjId);
10005 
10006  resultSet = connection.executeQuery(statement);
10007  if (resultSet.next()) {
10008  return resultSet.getLong("count");
10009  } else {
10010  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
10011  }
10012  } catch (SQLException ex) {
10013  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10014  } finally {
10015  closeResultSet(resultSet);
10016  connection.close();
10018  }
10019  }
10020 
10031  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
10032 
10033  CaseDbConnection connection = connections.getConnection();
10035  ResultSet resultSet = null;
10036  ContentTag tag = null;
10037  try {
10038  // 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
10039  // FROM content_tags
10040  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
10041  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10042  // WHERE tag_id = ?
10043  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
10044  statement.clearParameters();
10045  statement.setLong(1, contentTagID);
10046  resultSet = connection.executeQuery(statement);
10047 
10048  while (resultSet.next()) {
10049  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10050  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10051  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
10052  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
10053  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
10054  }
10055  resultSet.close();
10056 
10057  } catch (SQLException ex) {
10058  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
10059  } finally {
10060  closeResultSet(resultSet);
10061  connection.close();
10063  }
10064  return tag;
10065  }
10066 
10078  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
10079  if (tagName.getId() == Tag.ID_NOT_SET) {
10080  throw new TskCoreException("TagName object is invalid, id not set");
10081  }
10082  CaseDbConnection connection = connections.getConnection();
10084  ResultSet resultSet = null;
10085  try {
10086  // 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
10087  // FROM content_tags
10088  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10089  // WHERE tag_name_id = ?
10090  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
10091  statement.clearParameters();
10092  statement.setLong(1, tagName.getId());
10093  resultSet = connection.executeQuery(statement);
10094  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10095  while (resultSet.next()) {
10096  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
10097  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10098  tags.add(tag);
10099  }
10100  resultSet.close();
10101  return tags;
10102  } catch (SQLException ex) {
10103  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
10104  } finally {
10105  closeResultSet(resultSet);
10106  connection.close();
10108  }
10109  }
10110 
10123  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10124 
10125  CaseDbConnection connection = connections.getConnection();
10127  ResultSet resultSet = null;
10128  try {
10129 
10130  // 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
10131  // FROM content_tags as content_tags, tsk_files as tsk_files
10132  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10133  // WHERE content_tags.obj_id = tsk_files.obj_id
10134  // AND content_tags.tag_name_id = ?
10135  // AND tsk_files.data_source_obj_id = ?
10136  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10137  statement.clearParameters();
10138  statement.setLong(1, tagName.getId());
10139  statement.setLong(2, dsObjId);
10140  resultSet = connection.executeQuery(statement);
10141  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10142  while (resultSet.next()) {
10143  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
10144  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10145  tags.add(tag);
10146  }
10147  resultSet.close();
10148  return tags;
10149  } catch (SQLException ex) {
10150  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
10151  } finally {
10152  closeResultSet(resultSet);
10153  connection.close();
10155  }
10156  }
10157 
10169  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
10170  CaseDbConnection connection = connections.getConnection();
10172  ResultSet resultSet = null;
10173  try {
10174  // 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
10175  // FROM content_tags
10176  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
10177  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
10178  // WHERE content_tags.obj_id = ?
10179  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
10180  statement.clearParameters();
10181  statement.setLong(1, content.getId());
10182  resultSet = connection.executeQuery(statement);
10183  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
10184  while (resultSet.next()) {
10185  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10186  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10187  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
10188  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
10189  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
10190  tags.add(tag);
10191  }
10192  return tags;
10193  } catch (SQLException ex) {
10194  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
10195  } finally {
10196  closeResultSet(resultSet);
10197  connection.close();
10199  }
10200  }
10201 
10216  @Deprecated
10217  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
10218  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
10219  }
10220 
10221  /*
10222  * Deletes a row from the blackboard_artifact_tags table in the case
10223  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
10224  * representing the row to delete. @throws TskCoreException
10225  */
10226  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
10227  CaseDbConnection connection = connections.getConnection();
10229  try {
10230  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
10231  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
10232  statement.clearParameters();
10233  statement.setLong(1, tag.getId());
10234  connection.executeUpdate(statement);
10235  } catch (SQLException ex) {
10236  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
10237  } finally {
10238  connection.close();
10240  }
10241  }
10242 
10252  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
10253  CaseDbConnection connection = connections.getConnection();
10255  ResultSet resultSet = null;
10256  try {
10257  // 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
10258  // FROM blackboard_artifact_tags
10259  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10260  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10261  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
10262  resultSet = connection.executeQuery(statement);
10263  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
10264  while (resultSet.next()) {
10265  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10266  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10267  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
10268  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10269  Content content = getContentById(artifact.getObjectID());
10270  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10271  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10272  tags.add(tag);
10273  }
10274  return tags;
10275  } catch (SQLException ex) {
10276  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
10277  } finally {
10278  closeResultSet(resultSet);
10279  connection.close();
10281  }
10282  }
10283 
10294  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
10295  if (tagName.getId() == Tag.ID_NOT_SET) {
10296  throw new TskCoreException("TagName object is invalid, id not set");
10297  }
10298  CaseDbConnection connection = connections.getConnection();
10300  ResultSet resultSet = null;
10301  try {
10302  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
10303  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
10304  statement.clearParameters();
10305  statement.setLong(1, tagName.getId());
10306  resultSet = connection.executeQuery(statement);
10307  if (resultSet.next()) {
10308  return resultSet.getLong("count");
10309  } else {
10310  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
10311  }
10312  } catch (SQLException ex) {
10313  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
10314  } finally {
10315  closeResultSet(resultSet);
10316  connection.close();
10318  }
10319  }
10320 
10335  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10336 
10337  if (tagName.getId() == Tag.ID_NOT_SET) {
10338  throw new TskCoreException("TagName object is invalid, id not set");
10339  }
10340 
10341  CaseDbConnection connection = connections.getConnection();
10343  ResultSet resultSet = null;
10344  try {
10345  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
10346  // + " AND artifact_tags.tag_name_id = ?"
10347  // + " AND arts.data_source_obj_id = ? "
10348  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
10349  statement.clearParameters();
10350  statement.setLong(1, tagName.getId());
10351  statement.setLong(2, dsObjId);
10352  resultSet = connection.executeQuery(statement);
10353  if (resultSet.next()) {
10354  return resultSet.getLong("count");
10355  } else {
10356  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
10357  }
10358  } catch (SQLException ex) {
10359  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10360  } finally {
10361  closeResultSet(resultSet);
10362  connection.close();
10364  }
10365  }
10366 
10378  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
10379  if (tagName.getId() == Tag.ID_NOT_SET) {
10380  throw new TskCoreException("TagName object is invalid, id not set");
10381  }
10382  CaseDbConnection connection = connections.getConnection();
10384  ResultSet resultSet = null;
10385  try {
10386  // 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
10387  // FROM blackboard_artifact_tags
10388  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10389  // WHERE tag_name_id = ?
10390  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
10391  statement.clearParameters();
10392  statement.setLong(1, tagName.getId());
10393  resultSet = connection.executeQuery(statement);
10394  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10395  while (resultSet.next()) {
10396  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10397  Content content = getContentById(artifact.getObjectID());
10398  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10399  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10400  tags.add(tag);
10401  }
10402  return tags;
10403  } catch (SQLException ex) {
10404  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
10405  } finally {
10406  closeResultSet(resultSet);
10407  connection.close();
10409  }
10410  }
10411 
10426  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
10427 
10428  if (tagName.getId() == Tag.ID_NOT_SET) {
10429  throw new TskCoreException("TagName object is invalid, id not set");
10430  }
10431 
10432  CaseDbConnection connection = connections.getConnection();
10434  ResultSet resultSet = null;
10435  try {
10436  // 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
10437  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
10438  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
10439  // WHERE artifact_tags.artifact_id = arts.artifact_id
10440  // AND artifact_tags.tag_name_id = ?
10441  // AND arts.data_source_obj_id = ?
10442  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
10443  statement.clearParameters();
10444  statement.setLong(1, tagName.getId());
10445  statement.setLong(2, dsObjId);
10446  resultSet = connection.executeQuery(statement);
10447  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
10448  while (resultSet.next()) {
10449  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10450  Content content = getContentById(artifact.getObjectID());
10451  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10452  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10453  tags.add(tag);
10454  }
10455  return tags;
10456  } catch (SQLException ex) {
10457  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
10458  } finally {
10459  closeResultSet(resultSet);
10460  connection.close();
10462  }
10463 
10464  }
10465 
10477  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
10478 
10479  CaseDbConnection connection = connections.getConnection();
10481  ResultSet resultSet = null;
10482  BlackboardArtifactTag tag = null;
10483  try {
10484  //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
10485  // FROM blackboard_artifact_tags
10486  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10487  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10488  // WHERE blackboard_artifact_tags.tag_id = ?
10489  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
10490  statement.clearParameters();
10491  statement.setLong(1, artifactTagID);
10492  resultSet = connection.executeQuery(statement);
10493 
10494  while (resultSet.next()) {
10495  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10496  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10497  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
10498  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
10499  Content content = getContentById(artifact.getObjectID());
10500  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10501  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
10502  }
10503  resultSet.close();
10504 
10505  } catch (SQLException ex) {
10506  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
10507  } finally {
10508  closeResultSet(resultSet);
10509  connection.close();
10511  }
10512  return tag;
10513  }
10514 
10527  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
10528  CaseDbConnection connection = connections.getConnection();
10530  ResultSet resultSet = null;
10531  try {
10532  // 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
10533  // FROM blackboard_artifact_tags
10534  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
10535  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
10536  // WHERE blackboard_artifact_tags.artifact_id = ?
10537  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
10538  statement.clearParameters();
10539  statement.setLong(1, artifact.getArtifactID());
10540  resultSet = connection.executeQuery(statement);
10541  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
10542  while (resultSet.next()) {
10543  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
10544  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
10545  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
10546  Content content = getContentById(artifact.getObjectID());
10547  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
10548  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
10549  tags.add(tag);
10550  }
10551  return tags;
10552  } catch (SQLException ex) {
10553  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
10554  } finally {
10555  closeResultSet(resultSet);
10556  connection.close();
10558  }
10559  }
10560 
10569  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
10570  CaseDbConnection connection = connections.getConnection();
10572  try {
10573  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
10574  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
10575  statement.clearParameters();
10576  statement.setString(1, newPath);
10577  statement.setLong(2, objectId);
10578  connection.executeUpdate(statement);
10579  } catch (SQLException ex) {
10580  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
10581  } finally {
10582  connection.close();
10584  }
10585  }
10586 
10600  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
10601  return addReport(localPath, sourceModuleName, reportName, null);
10602  }
10603 
10619  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
10620  // Make sure the local path of the report is in the database directory
10621  // or one of its subdirectories.
10622  String relativePath = ""; //NON-NLS
10623  long createTime = 0;
10624  String localPathLower = localPath.toLowerCase();
10625 
10626  if (localPathLower.startsWith("http")) {
10627  relativePath = localPathLower;
10628  createTime = System.currentTimeMillis() / 1000;
10629  } else {
10630  /*
10631  * Note: The following call to .relativize() may be dangerous in
10632  * case-sensitive operating systems and should be looked at. For
10633  * now, we are simply relativizing the paths as all lower case, then
10634  * using the length of the result to pull out the appropriate number
10635  * of characters from the localPath String.
10636  */
10637  try {
10638  String casePathLower = getDbDirPath().toLowerCase();
10639  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
10640  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
10641  } catch (IllegalArgumentException ex) {
10642  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
10643  throw new TskCoreException(errorMessage, ex);
10644  }
10645  try {
10646  // get its file time
10647  java.io.File tempFile = new java.io.File(localPath);
10648  // Convert to UNIX epoch (seconds, not milliseconds).
10649  createTime = tempFile.lastModified() / 1000;
10650  } catch (Exception ex) {
10651  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
10652  }
10653  }
10654 
10655  // Write the report data to the database.
10656  CaseDbConnection connection = connections.getConnection();
10658  ResultSet resultSet = null;
10659  try {
10660  // Insert a row for the report into the tsk_objects table.
10661  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
10662  long parentObjId = 0;
10663  if (parent != null) {
10664  parentObjId = parent.getId();
10665  }
10666  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
10667 
10668  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
10669  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
10670  statement.clearParameters();
10671  statement.setLong(1, objectId);
10672  statement.setString(2, relativePath);
10673  statement.setLong(3, createTime);
10674  statement.setString(4, sourceModuleName);
10675  statement.setString(5, reportName);
10676  connection.executeUpdate(statement);
10677  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
10678  } catch (SQLException ex) {
10679  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
10680  } finally {
10681  closeResultSet(resultSet);
10682  connection.close();
10684  }
10685  }
10686 
10695  public List<Report> getAllReports() throws TskCoreException {
10696  CaseDbConnection connection = connections.getConnection();
10698  ResultSet resultSet = null;
10699  ResultSet parentResultSet = null;
10700  PreparedStatement statement = null;
10701  Statement parentStatement = null;
10702  try {
10703  // SELECT * FROM reports
10704  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
10705  parentStatement = connection.createStatement();
10706  resultSet = connection.executeQuery(statement);
10707  ArrayList<Report> reports = new ArrayList<Report>();
10708  while (resultSet.next()) {
10709  String localpath = resultSet.getString("path");
10710  if (localpath.toLowerCase().startsWith("http") == false) {
10711  // make path absolute
10712  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
10713  }
10714 
10715  // get the report parent
10716  Content parent = null;
10717  long reportId = resultSet.getLong("obj_id"); // NON-NLS
10718  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
10719  parentResultSet = parentStatement.executeQuery(parentQuery);
10720  if (parentResultSet.next()) {
10721  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10722  parent = this.getContentById(parentId);
10723  }
10724  parentResultSet.close();
10725 
10726  reports.add(new Report(this,
10727  reportId,
10728  localpath,
10729  resultSet.getLong("crtime"), //NON-NLS
10730  resultSet.getString("src_module_name"), //NON-NLS
10731  resultSet.getString("report_name"),
10732  parent)); //NON-NLS
10733  }
10734  return reports;
10735  } catch (SQLException ex) {
10736  throw new TskCoreException("Error querying reports table", ex);
10737  } finally {
10738  closeResultSet(resultSet);
10739  closeResultSet(parentResultSet);
10740  closeStatement(statement);
10741  closeStatement(parentStatement);
10742 
10743  connection.close();
10745  }
10746  }
10747 
10757  public Report getReportById(long id) throws TskCoreException {
10758  CaseDbConnection connection = connections.getConnection();
10760  PreparedStatement statement = null;
10761  Statement parentStatement = null;
10762  ResultSet resultSet = null;
10763  ResultSet parentResultSet = null;
10764  Report report = null;
10765  try {
10766  // SELECT * FROM reports WHERE obj_id = ?
10767  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
10768  parentStatement = connection.createStatement();
10769  statement.clearParameters();
10770  statement.setLong(1, id);
10771  resultSet = connection.executeQuery(statement);
10772 
10773  if (resultSet.next()) {
10774  // get the report parent
10775  Content parent = null;
10776  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
10777  parentResultSet = parentStatement.executeQuery(parentQuery);
10778  if (parentResultSet.next()) {
10779  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
10780  parent = this.getContentById(parentId);
10781  }
10782 
10783  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
10784  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
10785  resultSet.getLong("crtime"), //NON-NLS
10786  resultSet.getString("src_module_name"), //NON-NLS
10787  resultSet.getString("report_name"),
10788  parent); //NON-NLS
10789  } else {
10790  throw new TskCoreException("No report found for id: " + id);
10791  }
10792  } catch (SQLException ex) {
10793  throw new TskCoreException("Error querying reports table for id: " + id, ex);
10794  } finally {
10795  closeResultSet(resultSet);
10796  closeResultSet(parentResultSet);
10797  closeStatement(statement);
10798  closeStatement(parentStatement);
10799  connection.close();
10801  }
10802 
10803  return report;
10804  }
10805 
10813  public void deleteReport(Report report) throws TskCoreException {
10814  CaseDbConnection connection = connections.getConnection();
10816  try {
10817  // DELETE FROM reports WHERE reports.obj_id = ?
10818  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
10819  statement.setLong(1, report.getId());
10820  connection.executeUpdate(statement);
10821  } catch (SQLException ex) {
10822  throw new TskCoreException("Error querying reports table", ex);
10823  } finally {
10824  connection.close();
10826  }
10827  }
10828 
10829  static void closeResultSet(ResultSet resultSet) {
10830  if (resultSet != null) {
10831  try {
10832  resultSet.close();
10833  } catch (SQLException ex) {
10834  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
10835  }
10836  }
10837  }
10838 
10839  static void closeStatement(Statement statement) {
10840  if (statement != null) {
10841  try {
10842  statement.close();
10843  } catch (SQLException ex) {
10844  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
10845 
10846  }
10847  }
10848  }
10849 
10858  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
10859  CaseDbConnection connection = connections.getConnection();
10861  try {
10862  Statement statement = connection.createStatement();
10863  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
10864  } catch (SQLException ex) {
10865  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
10866  } finally {
10867  connection.close();
10869  }
10870  }
10871 
10872  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
10873  CaseDbConnection connection = connections.getConnection();
10875  try {
10876  Statement statement = connection.createStatement();
10877  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
10878  } catch (SQLException ex) {
10879  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
10880  } finally {
10881  connection.close();
10883  }
10884  }
10885 
10902  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
10903  CaseDbConnection connection = connections.getConnection();
10905  ResultSet resultSet = null;
10906  Statement statement;
10907  try {
10908  connection.beginTransaction();
10909  statement = connection.createStatement();
10910  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
10911  insertStatement.setLong(1, dataSource.getId());
10912  insertStatement.setString(2, hostName);
10913  insertStatement.setLong(3, jobStart.getTime());
10914  insertStatement.setLong(4, jobEnd.getTime());
10915  insertStatement.setInt(5, status.ordinal());
10916  insertStatement.setString(6, settingsDir);
10917  connection.executeUpdate(insertStatement);
10918  resultSet = insertStatement.getGeneratedKeys();
10919  resultSet.next();
10920  long id = resultSet.getLong(1); //last_insert_rowid()
10921  for (int i = 0; i < ingestModules.size(); i++) {
10922  IngestModuleInfo ingestModule = ingestModules.get(i);
10923  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
10924  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
10925  }
10926  resultSet.close();
10927  resultSet = null;
10928  connection.commitTransaction();
10929  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
10930  } catch (SQLException ex) {
10931  connection.rollbackTransaction();
10932  throw new TskCoreException("Error adding the ingest job.", ex);
10933  } finally {
10934  closeResultSet(resultSet);
10935  connection.close();
10937  }
10938  }
10939 
10953  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
10954  CaseDbConnection connection = connections.getConnection();
10955  ResultSet resultSet = null;
10956  Statement statement = null;
10957  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
10959  try {
10960  statement = connection.createStatement();
10961  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10962  if (!resultSet.next()) {
10963  resultSet.close();
10964  resultSet = null;
10965  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
10966  insertStatement.setString(1, displayName);
10967  insertStatement.setString(2, uniqueName);
10968  insertStatement.setInt(3, type.ordinal());
10969  insertStatement.setString(4, version);
10970  connection.executeUpdate(insertStatement);
10971  resultSet = statement.getGeneratedKeys();
10972  resultSet.next();
10973  long id = resultSet.getLong(1); //last_insert_rowid()
10974  resultSet.close();
10975  resultSet = null;
10976  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
10977  } else {
10978  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10979  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10980  }
10981  } catch (SQLException ex) {
10982  try {
10983  closeStatement(statement);
10984  statement = connection.createStatement();
10985  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
10986  if (resultSet.next()) {
10987  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
10988  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
10989  } else {
10990  throw new TskCoreException("Couldn't add new module to database.", ex);
10991  }
10992  } catch (SQLException ex1) {
10993  throw new TskCoreException("Couldn't add new module to database.", ex1);
10994  }
10995  } finally {
10996  closeResultSet(resultSet);
10997  closeStatement(statement);
10998  connection.close();
11000  }
11001  }
11002 
11010  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
11011  CaseDbConnection connection = connections.getConnection();
11012  ResultSet resultSet = null;
11013  Statement statement = null;
11014  List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>();
11016  try {
11017  statement = connection.createStatement();
11018  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
11019  while (resultSet.next()) {
11020  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
11021  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
11022  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
11023  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
11024  }
11025  return ingestJobs;
11026  } catch (SQLException ex) {
11027  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
11028  } finally {
11029  closeResultSet(resultSet);
11030  closeStatement(statement);
11031  connection.close();
11033  }
11034  }
11035 
11046  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
11047  ResultSet resultSet = null;
11048  Statement statement = null;
11049  List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>();
11051  try {
11052  statement = connection.createStatement();
11053  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
11054  + "ingest_job_modules.pipeline_position AS pipeline_position, "
11055  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
11056  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
11057  + "FROM ingest_job_modules, ingest_modules "
11058  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
11059  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
11060  + "ORDER BY (ingest_job_modules.pipeline_position);");
11061  while (resultSet.next()) {
11062  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
11063  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
11064  }
11065  return ingestModules;
11066  } finally {
11067  closeResultSet(resultSet);
11068  closeStatement(statement);
11070 
11071  }
11072  }
11073 
11077  static class ObjectInfo {
11078 
11079  private long id;
11080  private TskData.ObjectType type;
11081 
11082  ObjectInfo(long id, ObjectType type) {
11083  this.id = id;
11084  this.type = type;
11085  }
11086 
11087  long getId() {
11088  return id;
11089  }
11090 
11091  TskData.ObjectType getType() {
11092  return type;
11093  }
11094  }
11095 
11096  private interface DbCommand {
11097 
11098  void execute() throws SQLException;
11099  }
11100 
11101  private enum PREPARED_STATEMENT {
11102 
11103  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
11104  + "WHERE artifact_type_id = ?"), //NON-NLS
11105  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
11106  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
11107  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
11108  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
11109  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
11110  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11111  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11112  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
11113  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
11114  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
11115  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11116  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11117  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
11118  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
11119  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
11120  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11121  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11122  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
11123  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
11124  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
11125  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
11126  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
11127  + "AND tsk_files.type = ? )"), //NON-NLS
11128  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
11129  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
11130  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
11131  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
11132  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
11133  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
11134  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
11135  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
11136  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11137  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
11138  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11139  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
11140  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11141  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
11142  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11143  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
11144  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
11145  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
11146  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
11147  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
11148  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
11149  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
11150  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
11151  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11152  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11153  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
11154  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
11155  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
11156  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
11157  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
11158  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
11159  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11160  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
11161  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
11162  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
11163  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
11164  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
11165  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
11166  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
11167  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)"
11168  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
11169  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
11170  + "WHERE obj_id = ?"), //NON-NLS
11171  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
11172  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11173  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
11174  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
11175  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
11176  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
11177  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
11178  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
11179  + "WHERE tag_name_id IN " //NON-NLS
11180  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
11181  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
11182  + "WHERE tag_name_id IN "
11183  + "( SELECT content_tags.tag_name_id as tag_name_id "
11184  + "FROM content_tags as content_tags, tsk_files as tsk_files"
11185  + " WHERE content_tags.obj_id = tsk_files.obj_id"
11186  + " AND tsk_files.data_source_obj_id = ?"
11187  + " UNION "
11188  + "SELECT artifact_tags.tag_name_id as tag_name_id "
11189  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
11190  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
11191  + " AND arts.data_source_obj_id = ?"
11192  + " )"),
11193  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
11194  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11195  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
11196  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
11197  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
11198  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11199  + " AND content_tags.tag_name_id = ? "
11200  + " AND tsk_files.data_source_obj_id = ? "
11201  ),
11202  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, tag_names.tag_set_id, tag_names.rank "
11203  + "FROM content_tags "
11204  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11205  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11206  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 "
11207  + "FROM content_tags "
11208  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11209  + "WHERE tag_name_id = ?"), //NON-NLS
11210  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, tag_names.tag_set_id "
11211  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
11212  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
11213  + " AND content_tags.obj_id = tsk_files.obj_id"
11214  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
11215  + " AND content_tags.tag_name_id = ?"
11216  + " AND tsk_files.data_source_obj_id = ? "),
11217  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, tag_names.tag_set_id, tag_names.rank "
11218  + "FROM content_tags "
11219  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11220  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11221  + "WHERE tag_id = ?"), //NON-NLS
11222  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, tag_names.tag_set_id, tag_names.rank "
11223  + "FROM content_tags "
11224  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
11225  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
11226  + "WHERE content_tags.obj_id = ?"), //NON-NLS
11227  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
11228  + "VALUES (?, ?, ?, ?)"), //NON-NLS
11229  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
11230  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, tag_names.tag_set_id, tsk_examiners.login_name, tag_names.rank "
11231  + "FROM blackboard_artifact_tags "
11232  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11233  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
11234  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
11235  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"
11236  + " AND artifact_tags.tag_name_id = ?"
11237  + " AND arts.data_source_obj_id = ? "),
11238  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 "
11239  + "FROM blackboard_artifact_tags "
11240  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11241  + "WHERE tag_name_id = ?"), //NON-NLS
11242  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 "
11243  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
11244  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
11245  + " AND artifact_tags.artifact_id = arts.artifact_id"
11246  + " AND artifact_tags.tag_name_id = ? "
11247  + " AND arts.data_source_obj_id = ? "),
11248  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, tag_names.tag_set_id, tag_names.rank "
11249  + "FROM blackboard_artifact_tags "
11250  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11251  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11252  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
11253  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, tag_names.tag_set_id, tag_names.rank "
11254  + "FROM blackboard_artifact_tags "
11255  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
11256  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
11257  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
11258  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
11259  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
11260  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
11261  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
11262  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
11263  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
11264  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
11265  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
11266  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
11267  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
11268  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
11269  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
11270  + "WHERE (tsk_objects.par_obj_id = ?)"),
11271  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 = ?"),
11272  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
11273  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
11274  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
11275  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
11276  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
11277  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
11278  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
11279  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
11280  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
11281  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
11282  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone) VALUES (?, ?, ?)"),
11283  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
11284  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11285  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
11286  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
11287  INSERT_FS_INFO("INSERT INTO tsk_fs_info (obj_id, data_source_obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)"
11288  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
11289  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?"),
11290  SELECT_TAG_NAME_BY_NAME("SELECT * FROM tag_names where display_name = ?");
11291 
11292  private final String sql;
11293 
11294  private PREPARED_STATEMENT(String sql) {
11295  this.sql = sql;
11296  }
11297 
11298  String getSQL() {
11299  return sql;
11300  }
11301  }
11302 
11308  abstract private class ConnectionPool {
11309 
11310  private PooledDataSource pooledDataSource;
11311 
11312  public ConnectionPool() {
11313  pooledDataSource = null;
11314  }
11315 
11316  CaseDbConnection getConnection() throws TskCoreException {
11317  if (pooledDataSource == null) {
11318  throw new TskCoreException("Error getting case database connection - case is closed");
11319  }
11320  try {
11321  return getPooledConnection();
11322  } catch (SQLException exp) {
11323  throw new TskCoreException(exp.getMessage());
11324  }
11325  }
11326 
11327  void close() throws TskCoreException {
11328  if (pooledDataSource != null) {
11329  try {
11330  pooledDataSource.close();
11331  } catch (SQLException exp) {
11332  throw new TskCoreException(exp.getMessage());
11333  } finally {
11334  pooledDataSource = null;
11335  }
11336  }
11337  }
11338 
11339  abstract CaseDbConnection getPooledConnection() throws SQLException;
11340 
11341  public PooledDataSource getPooledDataSource() {
11342  return pooledDataSource;
11343  }
11344 
11345  public void setPooledDataSource(PooledDataSource pooledDataSource) {
11346  this.pooledDataSource = pooledDataSource;
11347  }
11348  }
11349 
11354  private final class SQLiteConnections extends ConnectionPool {
11355 
11356  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
11357 
11358  SQLiteConnections(String dbPath) throws SQLException {
11359  configurationOverrides.put("acquireIncrement", "2");
11360  configurationOverrides.put("initialPoolSize", "5");
11361  configurationOverrides.put("minPoolSize", "5");
11362  /*
11363  * NOTE: max pool size and max statements are related. If you
11364  * increase max pool size, then also increase statements.
11365  */
11366  configurationOverrides.put("maxPoolSize", "20");
11367  configurationOverrides.put("maxStatements", "200");
11368  configurationOverrides.put("maxStatementsPerConnection", "20");
11369 
11370  SQLiteConfig config = new SQLiteConfig();
11371  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
11372  config.setReadUncommited(true);
11373  config.enforceForeignKeys(true); // Enforce foreign key constraints.
11374  SQLiteDataSource unpooled = new SQLiteDataSource(config);
11375  unpooled.setUrl("jdbc:sqlite:" + dbPath);
11376  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
11377  }
11378 
11379  @Override
11380  public CaseDbConnection getPooledConnection() throws SQLException {
11381  return new SQLiteConnection(getPooledDataSource().getConnection());
11382  }
11383  }
11384 
11389  private final class PostgreSQLConnections extends ConnectionPool {
11390 
11391  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
11392  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
11393  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
11394  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
11395  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
11396  comboPooledDataSource.setUser(userName);
11397  comboPooledDataSource.setPassword(password);
11398  comboPooledDataSource.setAcquireIncrement(2);
11399  comboPooledDataSource.setInitialPoolSize(5);
11400  comboPooledDataSource.setMinPoolSize(5);
11401  /*
11402  * NOTE: max pool size and max statements are related. If you
11403  * increase max pool size, then also increase statements.
11404  */
11405  comboPooledDataSource.setMaxPoolSize(20);
11406  comboPooledDataSource.setMaxStatements(200);
11407  comboPooledDataSource.setMaxStatementsPerConnection(20);
11408  setPooledDataSource(comboPooledDataSource);
11409  }
11410 
11411  @Override
11412  public CaseDbConnection getPooledConnection() throws SQLException {
11413  return new PostgreSQLConnection(getPooledDataSource().getConnection());
11414  }
11415  }
11416 
11420  abstract class CaseDbConnection implements AutoCloseable {
11421 
11422  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
11423  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
11424 
11425  private class CreateStatement implements DbCommand {
11426 
11427  private final Connection connection;
11428  private Statement statement = null;
11429 
11430  CreateStatement(Connection connection) {
11431  this.connection = connection;
11432  }
11433 
11434  Statement getStatement() {
11435  return statement;
11436  }
11437 
11438  @Override
11439  public void execute() throws SQLException {
11440  statement = connection.createStatement();
11441  }
11442  }
11443 
11444  private class SetAutoCommit implements DbCommand {
11445 
11446  private final Connection connection;
11447  private final boolean mode;
11448 
11449  SetAutoCommit(Connection connection, boolean mode) {
11450  this.connection = connection;
11451  this.mode = mode;
11452  }
11453 
11454  @Override
11455  public void execute() throws SQLException {
11456  connection.setAutoCommit(mode);
11457  }
11458  }
11459 
11460  private class Commit implements DbCommand {
11461 
11462  private final Connection connection;
11463 
11464  Commit(Connection connection) {
11465  this.connection = connection;
11466  }
11467 
11468  @Override
11469  public void execute() throws SQLException {
11470  connection.commit();
11471  }
11472  }
11473 
11474  private class ExecuteQuery implements DbCommand {
11475 
11476  private final Statement statement;
11477  private final String query;
11478  private ResultSet resultSet;
11479 
11480  ExecuteQuery(Statement statement, String query) {
11481  this.statement = statement;
11482  this.query = query;
11483  }
11484 
11485  ResultSet getResultSet() {
11486  return resultSet;
11487  }
11488 
11489  @Override
11490  public void execute() throws SQLException {
11491  resultSet = statement.executeQuery(query);
11492  }
11493  }
11494 
11495  private class ExecutePreparedStatementQuery implements DbCommand {
11496 
11497  private final PreparedStatement preparedStatement;
11498  private ResultSet resultSet;
11499 
11500  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
11501  this.preparedStatement = preparedStatement;
11502  }
11503 
11504  ResultSet getResultSet() {
11505  return resultSet;
11506  }
11507 
11508  @Override
11509  public void execute() throws SQLException {
11510  resultSet = preparedStatement.executeQuery();
11511  }
11512  }
11513 
11514  private class ExecutePreparedStatementUpdate implements DbCommand {
11515 
11516  private final PreparedStatement preparedStatement;
11517 
11518  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
11519  this.preparedStatement = preparedStatement;
11520  }
11521 
11522  @Override
11523  public void execute() throws SQLException {
11524  preparedStatement.executeUpdate();
11525  }
11526  }
11527 
11528  private class ExecuteStatementUpdate implements DbCommand {
11529 
11530  private final Statement statement;
11531  private final String updateCommand;
11532 
11533  ExecuteStatementUpdate(Statement statement, String updateCommand) {
11534  this.statement = statement;
11535  this.updateCommand = updateCommand;
11536  }
11537 
11538  @Override
11539  public void execute() throws SQLException {
11540  statement.executeUpdate(updateCommand);
11541  }
11542  }
11543 
11544  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
11545 
11546  private final Statement statement;
11547  private final int generateKeys;
11548  private final String updateCommand;
11549 
11550  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
11551  this.statement = statement;
11552  this.generateKeys = generateKeys;
11553  this.updateCommand = updateCommand;
11554  }
11555 
11556  @Override
11557  public void execute() throws SQLException {
11558  statement.executeUpdate(updateCommand, generateKeys);
11559  }
11560  }
11561 
11562  private class PrepareStatement implements DbCommand {
11563 
11564  private final Connection connection;
11565  private final String input;
11566  private PreparedStatement preparedStatement = null;
11567 
11568  PrepareStatement(Connection connection, String input) {
11569  this.connection = connection;
11570  this.input = input;
11571  }
11572 
11573  PreparedStatement getPreparedStatement() {
11574  return preparedStatement;
11575  }
11576 
11577  @Override
11578  public void execute() throws SQLException {
11579  preparedStatement = connection.prepareStatement(input);
11580  }
11581  }
11582 
11583  private class PrepareStatementGenerateKeys implements DbCommand {
11584 
11585  private final Connection connection;
11586  private final String input;
11587  private final int generateKeys;
11588  private PreparedStatement preparedStatement = null;
11589 
11590  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
11591  this.connection = connection;
11592  this.input = input;
11593  this.generateKeys = generateKeysInput;
11594  }
11595 
11596  PreparedStatement getPreparedStatement() {
11597  return preparedStatement;
11598  }
11599 
11600  @Override
11601  public void execute() throws SQLException {
11602  preparedStatement = connection.prepareStatement(input, generateKeys);
11603  }
11604  }
11605 
11606  abstract void executeCommand(DbCommand command) throws SQLException;
11607 
11608  private final Connection connection;
11609  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
11610  private final Map<String, PreparedStatement> adHocPreparedStatements;
11611 
11612  CaseDbConnection(Connection connection) {
11613  this.connection = connection;
11614  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
11615  adHocPreparedStatements = new HashMap<>();
11616  }
11617 
11618  boolean isOpen() {
11619  return this.connection != null;
11620  }
11621 
11622  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
11623  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
11624  }
11625 
11626  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
11627  // Lazy statement preparation.
11628  PreparedStatement statement;
11629  if (this.preparedStatements.containsKey(statementKey)) {
11630  statement = this.preparedStatements.get(statementKey);
11631  } else {
11632  statement = prepareStatement(statementKey.getSQL(), generateKeys);
11633  this.preparedStatements.put(statementKey, statement);
11634  }
11635  return statement;
11636  }
11637 
11649  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
11650  PreparedStatement statement;
11651  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
11652  if (adHocPreparedStatements.containsKey(statementKey)) {
11653  statement = this.adHocPreparedStatements.get(statementKey);
11654  } else {
11655  statement = prepareStatement(sqlStatement, generateKeys);
11656  this.adHocPreparedStatements.put(statementKey, statement);
11657  }
11658  return statement;
11659  }
11660 
11661  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11662  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
11663  executeCommand(prepareStatement);
11664  return prepareStatement.getPreparedStatement();
11665  }
11666 
11667  Statement createStatement() throws SQLException {
11668  CreateStatement createStatement = new CreateStatement(this.connection);
11669  executeCommand(createStatement);
11670  return createStatement.getStatement();
11671  }
11672 
11673  void beginTransaction() throws SQLException {
11674  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
11675  executeCommand(setAutoCommit);
11676  }
11677 
11678  void commitTransaction() throws SQLException {
11679  Commit commit = new Commit(connection);
11680  executeCommand(commit);
11681  // You must turn auto commit back on when done with the transaction.
11682  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
11683  executeCommand(setAutoCommit);
11684  }
11685 
11691  void rollbackTransaction() {
11692  try {
11693  connection.rollback();
11694  } catch (SQLException e) {
11695  logger.log(Level.SEVERE, "Error rolling back transaction", e);
11696  }
11697  try {
11698  connection.setAutoCommit(true);
11699  } catch (SQLException e) {
11700  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
11701  }
11702  }
11703 
11711  void rollbackTransactionWithThrow() throws SQLException {
11712  try {
11713  connection.rollback();
11714  } finally {
11715  connection.setAutoCommit(true);
11716  }
11717  }
11718 
11719  ResultSet executeQuery(Statement statement, String query) throws SQLException {
11720  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
11721  executeCommand(queryCommand);
11722  return queryCommand.getResultSet();
11723  }
11724 
11734  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
11735  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
11736  executeCommand(executePreparedStatementQuery);
11737  return executePreparedStatementQuery.getResultSet();
11738  }
11739 
11740  void executeUpdate(Statement statement, String update) throws SQLException {
11741  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
11742  }
11743 
11744  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11745  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
11746  executeCommand(executeStatementUpdate);
11747  }
11748 
11749  void executeUpdate(PreparedStatement statement) throws SQLException {
11750  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
11751  executeCommand(executePreparedStatementUpdate);
11752  }
11753 
11757  @Override
11758  public void close() {
11759  try {
11760  for (PreparedStatement stmt:preparedStatements.values()) {
11761  closeStatement(stmt);
11762  }
11763  for (PreparedStatement stmt:adHocPreparedStatements.values()) {
11764  closeStatement(stmt);
11765  }
11766  connection.close();
11767  } catch (SQLException ex) {
11768  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
11769  }
11770  }
11771 
11772  Connection getConnection() {
11773  return this.connection;
11774  }
11775  }
11776 
11780  private final class SQLiteConnection extends CaseDbConnection {
11781 
11782  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
11783  private static final int SQLITE_BUSY_ERROR = 5;
11784 
11785  SQLiteConnection(Connection conn) {
11786  super(conn);
11787  }
11788 
11789  @Override
11790  void executeCommand(DbCommand command) throws SQLException {
11791  int retryCounter = 0;
11792  while (true) {
11793  try {
11794  command.execute(); // Perform the operation
11795  break;
11796  } catch (SQLException ex) {
11797  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
11798  try {
11799 
11800  // We do not notify of error here, as this is not an
11801  // error condition. It is likely a temporary busy or
11802  // locked issue and we will retry.
11803  retryCounter++;
11804  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11805  } catch (InterruptedException exp) {
11806  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11807  }
11808  } else {
11809  throw ex;
11810  }
11811  }
11812  }
11813  }
11814  }
11815 
11819  private final class PostgreSQLConnection extends CaseDbConnection {
11820 
11821  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
11822  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
11823  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
11824  private static final int MAX_RETRIES = 3;
11825 
11826  PostgreSQLConnection(Connection conn) {
11827  super(conn);
11828  }
11829 
11830  @Override
11831  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
11832  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
11833  executeCommand(executeStatementUpdateGenerateKeys);
11834  }
11835 
11836  @Override
11837  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
11838  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
11839  executeCommand(prepareStatementGenerateKeys);
11840  return prepareStatementGenerateKeys.getPreparedStatement();
11841  }
11842 
11843  @Override
11844  void executeCommand(DbCommand command) throws SQLException {
11845  SQLException lastException = null;
11846  for (int retries = 0; retries < MAX_RETRIES; retries++) {
11847  try {
11848  command.execute();
11849  lastException = null; // reset since we had a successful execution
11850  break;
11851  } catch (SQLException ex) {
11852  lastException = ex;
11853  String sqlState = ex.getSQLState();
11854  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
11855  try {
11856  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
11857  } catch (InterruptedException exp) {
11858  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
11859  }
11860  } else {
11861  throw ex;
11862  }
11863  }
11864  }
11865 
11866  // rethrow the exception if we bailed because of too many retries
11867  if (lastException != null) {
11868  throw lastException;
11869  }
11870  }
11871  }
11872 
11887  public static final class CaseDbTransaction {
11888 
11889  private final CaseDbConnection connection;
11890  private SleuthkitCase sleuthkitCase;
11891 
11892  private CaseDbTransaction(SleuthkitCase sleuthkitCase, CaseDbConnection connection) throws TskCoreException {
11893  this.connection = connection;
11894  this.sleuthkitCase = sleuthkitCase;
11895  try {
11896  this.connection.beginTransaction();
11897  } catch (SQLException ex) {
11898  throw new TskCoreException("Failed to create transaction on case database", ex);
11899  }
11900  sleuthkitCase.acquireSingleUserCaseWriteLock();
11901  }
11902 
11910  CaseDbConnection getConnection() {
11911  return this.connection;
11912  }
11913 
11920  public void commit() throws TskCoreException {
11921  try {
11922  this.connection.commitTransaction();
11923  } catch (SQLException ex) {
11924  throw new TskCoreException("Failed to commit transaction on case database", ex);
11925  } finally {
11926  close();
11927  }
11928  }
11929 
11936  public void rollback() throws TskCoreException {
11937  try {
11938  this.connection.rollbackTransactionWithThrow();
11939  } catch (SQLException ex) {
11940  throw new TskCoreException("Case database transaction rollback failed", ex);
11941  } finally {
11942  close();
11943  }
11944  }
11945 
11950  void close() {
11951  this.connection.close();
11952  sleuthkitCase.releaseSingleUserCaseWriteLock();
11953  }
11954  }
11955 
11965  public final class CaseDbQuery implements AutoCloseable {
11966 
11967  private ResultSet resultSet;
11968  private CaseDbConnection connection;
11969 
11970  private CaseDbQuery(String query) throws TskCoreException {
11971  this(query, false);
11972  }
11973 
11974  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
11975  if (!allowWriteQuery) {
11976  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
11977  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
11978  }
11979  }
11980  try {
11981  connection = connections.getConnection();
11982  } catch (TskCoreException ex) {
11983  throw new TskCoreException("Error getting connection for query: ", ex);
11984  }
11985 
11986  try {
11988  resultSet = connection.executeQuery(connection.createStatement(), query);
11989  } catch (SQLException ex) {
11991  throw new TskCoreException("Error executing query: ", ex);
11992  }
11993  }
11994 
12000  public ResultSet getResultSet() {
12001  return resultSet;
12002  }
12003 
12004  @Override
12005  public void close() throws TskCoreException {
12006  try {
12007  if (resultSet != null) {
12008  final Statement statement = resultSet.getStatement();
12009  if (statement != null) {
12010  statement.close();
12011  }
12012  resultSet.close();
12013  }
12014  connection.close();
12015  } catch (SQLException ex) {
12016  throw new TskCoreException("Error closing query: ", ex);
12017  } finally {
12019  }
12020  }
12021  }
12022 
12030  @Deprecated
12031  public void addErrorObserver(ErrorObserver observer) {
12032  sleuthkitCaseErrorObservers.add(observer);
12033  }
12034 
12042  @Deprecated
12043  public void removeErrorObserver(ErrorObserver observer) {
12044  int i = sleuthkitCaseErrorObservers.indexOf(observer);
12045  if (i >= 0) {
12046  sleuthkitCaseErrorObservers.remove(i);
12047  }
12048  }
12049 
12058  @Deprecated
12059  public void submitError(String context, String errorMessage) {
12060  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
12061  if (observer != null) {
12062  try {
12063  observer.receiveError(context, errorMessage);
12064  } catch (Exception ex) {
12065  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
12066 
12067  }
12068  }
12069  }
12070  }
12071 
12077  @Deprecated
12078  public interface ErrorObserver {
12079 
12086  public enum Context {
12087 
12091  IMAGE_READ_ERROR("Image File Read Error"),
12095  DATABASE_READ_ERROR("Database Read Error");
12096 
12097  private final String contextString;
12098 
12099  private Context(String context) {
12100  this.contextString = context;
12101  }
12102 
12103  public String getContextString() {
12104  return contextString;
12105  }
12106  };
12107 
12108  void receiveError(String context, String errorMessage);
12109  }
12110 
12121  @Deprecated
12122  long getDataSourceObjectId(long objectId) {
12123  try {
12124  CaseDbConnection connection = connections.getConnection();
12125  try {
12126  return getDataSourceObjectId(connection, objectId);
12127  } finally {
12128  connection.close();
12129  }
12130  } catch (TskCoreException ex) {
12131  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
12132  return 0;
12133  }
12134  }
12135 
12145  @Deprecated
12146  public long getLastObjectId() throws TskCoreException {
12147  CaseDbConnection connection = connections.getConnection();
12149  ResultSet rs = null;
12150  try {
12151  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
12152  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
12153  rs = connection.executeQuery(statement);
12154  long id = -1;
12155  if (rs.next()) {
12156  id = rs.getLong("max_obj_id");
12157  }
12158  return id;
12159  } catch (SQLException e) {
12160  throw new TskCoreException("Error getting last object id", e);
12161  } finally {
12162  closeResultSet(rs);
12163  connection.close();
12165  }
12166  }
12167 
12181  @Deprecated
12182  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
12183  CaseDbConnection connection = connections.getConnection();
12185  Statement s = null;
12186  ResultSet rs = null;
12187  try {
12188  s = connection.createStatement();
12189  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
12190  List<FsContent> results = new ArrayList<FsContent>();
12191  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
12192  for (AbstractFile f : temp) {
12193  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
12194  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
12195  results.add((FsContent) f);
12196  }
12197  }
12198  return results;
12199  } catch (SQLException e) {
12200  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
12201  } finally {
12202  closeResultSet(rs);
12203  closeStatement(s);
12204  connection.close();
12206  }
12207  }
12208 
12220  @Deprecated
12221  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
12222  CaseDbConnection connection = connections.getConnection();
12224  Statement s = null;
12225  ResultSet rs = null;
12226  try {
12227  s = connection.createStatement();
12228  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
12229  int typeId = -1;
12230  if (rs.next()) {
12231  typeId = rs.getInt("artifact_type_id");
12232  }
12233  return typeId;
12234  } catch (SQLException ex) {
12235  throw new TskCoreException("Error getting artifact type id", ex);
12236  } finally {
12237  closeResultSet(rs);
12238  closeStatement(s);
12239  connection.close();
12241  }
12242  }
12243 
12253  @Deprecated
12254  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
12255  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
12256  }
12257 
12271  @Deprecated
12272  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
12273  try {
12274  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
12275  } catch (TskDataException ex) {
12276  throw new TskCoreException("Failed to add artifact type.", ex);
12277  }
12278  }
12279 
12293  @Deprecated
12294  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
12295  try {
12296  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
12297  } catch (TskDataException ex) {
12298  throw new TskCoreException("Couldn't add new attribute type");
12299  }
12300  }
12301 
12312  @Deprecated
12313  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
12314  CaseDbConnection connection = connections.getConnection();
12316  Statement s = null;
12317  ResultSet rs = null;
12318  try {
12319  s = connection.createStatement();
12320  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
12321  int typeId = -1;
12322  if (rs.next()) {
12323  typeId = rs.getInt("attribute_type_id");
12324  }
12325  return typeId;
12326  } catch (SQLException ex) {
12327  throw new TskCoreException("Error getting attribute type id", ex);
12328  } finally {
12329  closeResultSet(rs);
12330  closeStatement(s);
12331  connection.close();
12333  }
12334  }
12335 
12348  @Deprecated
12349  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
12350  CaseDbConnection connection = connections.getConnection();
12352  Statement s = null;
12353  ResultSet rs = null;
12354  try {
12355  s = connection.createStatement();
12356  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12357  if (rs.next()) {
12358  return rs.getString("type_name");
12359  } else {
12360  throw new TskCoreException("No type with that id");
12361  }
12362  } catch (SQLException ex) {
12363  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12364  } finally {
12365  closeResultSet(rs);
12366  closeStatement(s);
12367  connection.close();
12369  }
12370  }
12371 
12384  @Deprecated
12385  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
12386  CaseDbConnection connection = connections.getConnection();
12388  Statement s = null;
12389  ResultSet rs = null;
12390  try {
12391  s = connection.createStatement();
12392  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
12393  if (rs.next()) {
12394  return rs.getString("display_name");
12395  } else {
12396  throw new TskCoreException("No type with that id");
12397  }
12398  } catch (SQLException ex) {
12399  throw new TskCoreException("Error getting or creating a attribute type name", ex);
12400  } finally {
12401  closeResultSet(rs);
12402  closeStatement(s);
12403  connection.close();
12405  }
12406  }
12407 
12417  @Deprecated
12418  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
12419  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
12420  }
12421 
12437  @Deprecated
12438  public ResultSet runQuery(String query) throws SQLException {
12439  CaseDbConnection connection;
12440  try {
12441  connection = connections.getConnection();
12442  } catch (TskCoreException ex) {
12443  throw new SQLException("Error getting connection for ad hoc query", ex);
12444  }
12446  try {
12447  return connection.executeQuery(connection.createStatement(), query);
12448  } finally {
12449  //TODO unlock should be done in closeRunQuery()
12450  //but currently not all code calls closeRunQuery - need to fix this
12451  connection.close();
12453  }
12454  }
12455 
12465  @Deprecated
12466  public void closeRunQuery(ResultSet resultSet) throws SQLException {
12467  final Statement statement = resultSet.getStatement();
12468  resultSet.close();
12469  if (statement != null) {
12470  statement.close();
12471  }
12472  }
12473 
12490  @Deprecated
12491  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
12492  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
12493  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
12494  files.add(carvedFile);
12495  CarvingResult carvingResult;
12496  Content parent = getContentById(containerId);
12497  if (parent instanceof FileSystem
12498  || parent instanceof Volume
12499  || parent instanceof Image) {
12500  carvingResult = new CarvingResult(parent, files);
12501  } else {
12502  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
12503  }
12504  return addCarvedFiles(carvingResult).get(0);
12505  }
12506 
12520  @Deprecated
12521  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
12522  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
12523  for (CarvedFileContainer container : filesToAdd) {
12524  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
12525  carvedFiles.add(carvedFile);
12526  }
12527  CarvingResult carvingResult;
12528  Content parent = getContentById(filesToAdd.get(0).getId());
12529  if (parent instanceof FileSystem
12530  || parent instanceof Volume
12531  || parent instanceof Image) {
12532  carvingResult = new CarvingResult(parent, carvedFiles);
12533  } else {
12534  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
12535  }
12536  return addCarvedFiles(carvingResult);
12537  }
12538 
12568  @Deprecated
12569  public DerivedFile addDerivedFile(String fileName, String localPath,
12570  long size, long ctime, long crtime, long atime, long mtime,
12571  boolean isFile, AbstractFile parentFile,
12572  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
12573  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12574  isFile, parentFile, rederiveDetails, toolName, toolVersion,
12575  otherDetails, TskData.EncodingType.NONE);
12576  }
12577 
12602  @Deprecated
12603  public LocalFile addLocalFile(String fileName, String localPath,
12604  long size, long ctime, long crtime, long atime, long mtime,
12605  boolean isFile,
12606  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
12607  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
12608  TskData.EncodingType.NONE, parent, transaction);
12609  }
12610 
12630  @Deprecated
12631  public LocalFile addLocalFile(String fileName, String localPath,
12632  long size, long ctime, long crtime, long atime, long mtime,
12633  boolean isFile,
12634  AbstractFile parent) throws TskCoreException {
12635  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
12636  isFile, TskData.EncodingType.NONE, parent);
12637  }
12638 
12655  @Deprecated
12656  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
12657  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
12658  }
12659 
12670  @Deprecated
12671  public Collection<FileSystem> getFileSystems(Image image) {
12672  try {
12673  return getImageFileSystems(image);
12674  } catch (TskCoreException ex) {
12675  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
12676  return new ArrayList<>();
12677  }
12678  }
12679 
12687  @Deprecated
12688  public void acquireExclusiveLock() {
12690  }
12691 
12699  @Deprecated
12700  public void releaseExclusiveLock() {
12702  }
12703 
12711  @Deprecated
12712  public void acquireSharedLock() {
12714  }
12715 
12723  @Deprecated
12724  public void releaseSharedLock() {
12726  }
12727 };
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)
BlackboardArtifactTagChange addArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
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
List< AbstractFile > findAllFilesInFolderWhere(long parentId, String sqlWhereClause)
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)
synchronized TaggingManager getTaggingManager()
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:76
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)
ContentTagChange addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
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)
Collection< FileSystem > getImageFileSystems(Image image)
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.