Sleuth Kit Java Bindings (JNI)  4.12.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-2021 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.annotations.Beta;
22 import com.google.common.cache.Cache;
23 import com.google.common.cache.CacheBuilder;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.eventbus.EventBus;
26 import com.mchange.v2.c3p0.ComboPooledDataSource;
27 import com.mchange.v2.c3p0.DataSources;
28 import com.mchange.v2.c3p0.PooledDataSource;
29 import com.zaxxer.sparsebits.SparseBitSet;
30 import java.beans.PropertyVetoException;
31 import java.io.BufferedInputStream;
32 import java.io.BufferedOutputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.io.UnsupportedEncodingException;
40 import java.net.InetAddress;
41 import java.net.URLEncoder;
42 import java.nio.charset.StandardCharsets;
43 import java.nio.file.Paths;
44 import java.sql.Connection;
45 import java.sql.DriverManager;
46 import java.sql.PreparedStatement;
47 import java.sql.ResultSet;
48 import java.sql.SQLException;
49 import java.sql.Statement;
50 import java.text.SimpleDateFormat;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.Collections;
55 import java.util.concurrent.atomic.AtomicBoolean;
56 import java.util.concurrent.atomic.AtomicInteger;
57 import java.util.Date;
58 import java.util.EnumMap;
59 import java.util.HashMap;
60 import java.util.HashSet;
61 import java.util.LinkedHashMap;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.MissingResourceException;
65 import java.util.Objects;
66 import java.util.Properties;
67 import java.util.ResourceBundle;
68 import java.util.Set;
69 import java.util.UUID;
70 import java.util.concurrent.TimeUnit;
71 import java.util.concurrent.locks.ReentrantReadWriteLock;
72 import java.util.logging.Level;
73 import java.util.logging.Logger;
74 import java.util.stream.Collectors;
75 import org.apache.commons.lang3.StringUtils;
76 import org.postgresql.util.PSQLState;
95 import org.sqlite.SQLiteConfig;
96 import org.sqlite.SQLiteDataSource;
97 import org.sqlite.SQLiteJDBCLoader;
98 
103 public class SleuthkitCase {
104 
105  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
106 
107  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
108  = new CaseDbSchemaVersionNumber(9, 4);
109 
110  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
111  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
112  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
113  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
114  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
115  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
116  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
117  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
118  private static final String SQL_ERROR_LIMIT_GROUP = "54";
119  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
120 
121  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
122  "tsk_events",
123  "tsk_event_descriptions",
124  "tsk_event_types",
125  "tsk_db_info",
126  "tsk_objects",
127  "tsk_image_info",
128  "tsk_image_names",
129  "tsk_vs_info",
130  "tsk_vs_parts",
131  "tsk_fs_info",
132  "tsk_file_layout",
133  "tsk_files",
134  "tsk_files_path",
135  "tsk_files_derived",
136  "tsk_files_derived_method",
137  "tag_names",
138  "content_tags",
139  "blackboard_artifact_tags",
140  "blackboard_artifacts",
141  "blackboard_attributes",
142  "blackboard_artifact_types",
143  "blackboard_attribute_types",
144  "data_source_info",
145  "file_encoding_types",
146  "file_collection_status_types",
147  "ingest_module_types",
148  "ingest_job_status_types",
149  "ingest_modules",
150  "ingest_jobs",
151  "ingest_job_modules",
152  "account_types",
153  "accounts",
154  "account_relationships",
155  "review_statuses",
156  "reports,");
157 
158  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
159  "parObjId",
160  "layout_objID",
161  "artifact_objID",
162  "artifact_artifact_objID",
163  "artifact_typeID",
164  "attrsArtifactID",
165  "mime_type",
166  "file_extension",
167  "relationships_account1",
168  "relationships_account2",
169  "relationships_relationship_source_obj_id",
170  "relationships_date_time",
171  "relationships_relationship_type",
172  "relationships_data_source_obj_id",
173  "events_time",
174  "events_type",
175  "events_data_source_obj_id",
176  "events_file_obj_id",
177  "events_artifact_id");
178 
179  private static final String TSK_VERSION_KEY = "TSK_VER";
180  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
181  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
182  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
183  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
184 
185  private final ConnectionPool connections;
186  private final Object carvedFileDirsLock = new Object();
187  private final static int MAX_CARVED_FILES_PER_FOLDER = 2000;
188  private final Map<Long, CarvedFileDirInfo> rootIdsToCarvedFileDirs = new HashMap<>();
189  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
190  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
191  private final String databaseName;
192  private final String dbPath;
193  private final DbType dbType;
194  private final String caseDirPath;
195  private SleuthkitJNI.CaseDbHandle caseHandle;
196  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
197  private String dbBackupPath;
198  private AtomicBoolean timelineEventsDisabled = new AtomicBoolean(false);
199 
200  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
201 
202  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
203  private final Object rootDirectoryMapLock = new Object();
204  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
205  private final Cache<Long, Boolean> isRootDirectoryCache
206  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
207  // custom provider for file bytes (can be null)
208  private final ContentStreamProvider contentProvider;
209 
210  /*
211  * First parameter is used to specify the SparseBitSet to use, as object IDs
212  * can be larger than the max size of a SparseBitSet
213  */
214  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
215 
216  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
217  // This read/write lock is used to implement a layer of locking on top of
218  // the locking protocol provided by the underlying SQLite database. The Java
219  // locking protocol improves performance for reasons that are not currently
220  // understood. Note that the lock is contructed to use a fairness policy.
221  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
222 
223  private CommunicationsManager communicationsMgr;
224  private TimelineManager timelineMgr;
225  private Blackboard blackboard;
226  private CaseDbAccessManager dbAccessManager;
227  private FileManager fileManager;
228  private TaggingManager taggingMgr;
229  private ScoringManager scoringManager;
230  private OsAccountRealmManager osAccountRealmManager;
231  private OsAccountManager osAccountManager;
232  private HostManager hostManager;
233  private PersonManager personManager;
234  private HostAddressManager hostAddressManager;
235 
236  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
237 
238  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
239 
240  public void registerForEvents(Object listener) {
241  eventBus.register(listener);
242  }
243 
244  public void unregisterForEvents(Object listener) {
245  eventBus.unregister(listener);
246  }
247 
248  void fireTSKEvent(Object event) {
249  eventBus.post(event);
250  }
251 
252  // Cache of frequently used content objects (e.g. data source, file system).
253  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
254 
255  private Examiner cachedCurrentExaminer = null;
256 
257  static {
258  Properties p = new Properties(System.getProperties());
259  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
260  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
261  System.setProperties(p);
262  }
263 
278  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
279  // Check if we can talk to the database.
280  if (info.getHost() == null || info.getHost().isEmpty()) {
281  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
282  } else if (info.getPort() == null || info.getPort().isEmpty()) {
283  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
284  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
285  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
286  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
287  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
288  }
289 
290  try {
291  Class.forName("org.postgresql.Driver"); //NON-NLS
292  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
293  if (conn != null) {
294  conn.close();
295  }
296  } catch (SQLException ex) {
297  String result;
298  String sqlState = ex.getSQLState().toLowerCase();
299  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
300  try {
301  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
302  // if we can reach the host, then it's probably port problem
303  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
304  } else {
305  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
306  }
307  } catch (IOException | MissingResourceException any) {
308  // it may be anything
309  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
310  }
311  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
312  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
313  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
314  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
315  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
316  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
317  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
318  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
319  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
320  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
321  } else {
322  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
323  }
324  throw new TskCoreException(result);
325  } catch (ClassNotFoundException ex) {
326  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
327  }
328  }
329 
342  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType, ContentStreamProvider contentProvider) throws Exception {
343  Class.forName("org.sqlite.JDBC");
344  this.dbPath = dbPath;
345  this.dbType = dbType;
346  File dbFile = new File(dbPath);
347  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
348  this.databaseName = dbFile.getName();
349  this.connections = new SQLiteConnections(dbPath);
350  this.caseHandle = caseHandle;
351  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
352  this.contentProvider = contentProvider;
353  init();
354  logSQLiteJDBCDriverInfo();
355  }
356 
375  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType, ContentStreamProvider contentProvider) throws Exception {
376  this.dbPath = "";
377  this.databaseName = dbName;
378  this.dbType = dbType;
379  this.caseDirPath = caseDirPath;
380  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
381  this.caseHandle = caseHandle;
382  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
383  this.contentProvider = contentProvider;
384  init();
385  }
386 
387  private void init() throws Exception {
388  blackboard = new Blackboard(this);
389  updateDatabaseSchema(null);
390  try (CaseDbConnection connection = connections.getConnection()) {
391  blackboard.initBlackboardArtifactTypes(connection);
392  blackboard.initBlackboardAttributeTypes(connection);
393  initNextArtifactId(connection);
394  initIngestModuleTypes(connection);
395  initIngestStatusTypes(connection);
396  initReviewStatuses(connection);
397  initEncodingTypes(connection);
398  initCollectedStatusTypes(connection);
399  populateHasChildrenMap(connection);
400  updateExaminers(connection);
401  initDBSchemaCreationVersion(connection);
402  }
403 
404  fileManager = new FileManager(this);
405  communicationsMgr = new CommunicationsManager(this);
406  timelineMgr = new TimelineManager(this);
407  dbAccessManager = new CaseDbAccessManager(this);
408  taggingMgr = new TaggingManager(this);
409  scoringManager = new ScoringManager(this);
410  osAccountRealmManager = new OsAccountRealmManager(this);
411  osAccountManager = new OsAccountManager(this);
412  hostManager = new HostManager(this);
413  personManager = new PersonManager(this);
414  hostAddressManager = new HostAddressManager(this);
415  }
416 
424  ContentStreamProvider getContentProvider() {
425  return this.contentProvider;
426  }
427 
433  static Set<String> getCoreTableNames() {
434  return Collections.unmodifiableSet(CORE_TABLE_NAMES);
435  }
436 
442  static Set<String> getCoreIndexNames() {
443  return Collections.unmodifiableSet(CORE_INDEX_NAMES);
444  }
445 
454  boolean getHasChildren(Content content) {
455  long objId = content.getId();
456  long mapIndex = objId / Integer.MAX_VALUE;
457  int mapValue = (int) (objId % Integer.MAX_VALUE);
458 
459  synchronized (hasChildrenBitSetMap) {
460  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
461  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
462  }
463  return false;
464  }
465  }
466 
472  private void setHasChildren(Long objId) {
473  long mapIndex = objId / Integer.MAX_VALUE;
474  int mapValue = (int) (objId % Integer.MAX_VALUE);
475 
476  synchronized (hasChildrenBitSetMap) {
477  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
478  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
479  } else {
480  SparseBitSet bitSet = new SparseBitSet();
481  bitSet.set(mapValue);
482  hasChildrenBitSetMap.put(mapIndex, bitSet);
483  }
484  }
485  }
486 
495  return communicationsMgr;
496  }
497 
504  return blackboard;
505  }
506 
513  return fileManager;
514  }
515 
524  return timelineMgr;
525  }
526 
527  /*
528  * Gets the case database access manager for this case.
529  *
530  * @return The per case CaseDbAccessManager object.
531  *
532  * @throws org.sleuthkit.datamodel.TskCoreException
533  */
535  return dbAccessManager;
536  }
537 
543  public synchronized TaggingManager getTaggingManager() {
544  return taggingMgr;
545  }
546 
555  return scoringManager;
556  }
557 
566  return osAccountRealmManager;
567  }
568 
577  return osAccountManager;
578  }
579 
588  return hostManager;
589  }
590 
599  return personManager;
600  }
601 
610  return hostAddressManager;
611  }
612 
622  private void initNextArtifactId(CaseDbConnection connection) throws SQLException {
624  try (Statement statement = connection.createStatement()) {
625  ResultSet resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
626  resultSet.next();
627  nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
628  if (nextArtifactId == 1) {
629  nextArtifactId = BASE_ARTIFACT_ID;
630  }
631  } finally {
633  }
634  }
635 
643  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
644  Statement statement = null;
645  ResultSet resultSet = null;
647  try {
648  statement = connection.createStatement();
649  for (IngestModuleType type : IngestModuleType.values()) {
650  try {
651  String query = "INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
652  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
653  query += " ON CONFLICT ON CONSTRAINT ingest_module_types_pkey DO NOTHING"; // NON-NLS
654  }
655  statement.execute(query);
656  } catch (SQLException ex) {
657  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
658  resultSet.next();
659  if (resultSet.getLong("count") == 0) {
660  throw ex;
661  }
662  resultSet.close();
663  resultSet = null;
664  }
665  }
666  } finally {
667  closeResultSet(resultSet);
668  closeStatement(statement);
670  }
671  }
672 
680  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
681  Statement statement = null;
682  ResultSet resultSet = null;
684  try {
685  statement = connection.createStatement();
686  for (IngestJobStatusType type : IngestJobStatusType.values()) {
687  try {
688  String query = "INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
689  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
690  query += " ON CONFLICT ON CONSTRAINT ingest_job_status_types_pkey DO NOTHING"; // NON-NLS
691  }
692  statement.execute(query);
693  } catch (SQLException ex) {
694  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
695  resultSet.next();
696  if (resultSet.getLong("count") == 0) {
697  throw ex;
698  }
699  resultSet.close();
700  resultSet = null;
701  }
702  }
703  } finally {
704  closeResultSet(resultSet);
705  closeStatement(statement);
707  }
708  }
709 
716  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
717  Statement statement = null;
718  ResultSet resultSet = null;
720  try {
721  statement = connection.createStatement();
722  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
723  try {
724  String query = "INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
725  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')";
726  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
727  query += " ON CONFLICT ON CONSTRAINT review_statuses_pkey DO NOTHING"; // NON-NLS
728  }
729  statement.execute(query);
730  } catch (SQLException ex) {
731  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
732  resultSet.next();
733  if (resultSet.getLong("count") == 0) {
734  throw ex;
735  }
736  resultSet.close();
737  resultSet = null;
738  }
739  }
740  } finally {
741  closeResultSet(resultSet);
742  closeStatement(statement);
744  }
745  }
746 
754  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
755  Statement statement = null;
756  ResultSet resultSet = null;
758  try {
759  statement = connection.createStatement();
760  for (TskData.EncodingType type : TskData.EncodingType.values()) {
761  try {
762  String query = "INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
763  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
764  query += " ON CONFLICT ON CONSTRAINT file_encoding_types_pkey DO NOTHING"; // NON-NLS
765  }
766  statement.execute(query);
767  } catch (SQLException ex) {
768  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
769  resultSet.next();
770  if (resultSet.getLong("count") == 0) {
771  throw ex;
772  }
773  resultSet.close();
774  resultSet = null;
775  }
776  }
777  } finally {
778  closeResultSet(resultSet);
779  closeStatement(statement);
781  }
782  }
783 
791  private void initCollectedStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
792  Statement statement = null;
793  ResultSet resultSet = null;
795  try {
796  statement = connection.createStatement();
797  for (TskData.CollectedStatus type : TskData.CollectedStatus.values()) {
798  try {
799  String query = "INSERT INTO file_collection_status_types (collection_status_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
800  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
801  query += " ON CONFLICT ON CONSTRAINT file_collection_status_types_pkey DO NOTHING"; // NON-NLS
802  }
803  statement.execute(query);
804  } catch (SQLException ex) {
805  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_collection_status_types WHERE collection_status_type = " + type.getType()); //NON-NLS
806  resultSet.next();
807  if (resultSet.getLong("count") == 0) {
808  throw ex;
809  }
810  resultSet.close();
811  resultSet = null;
812  }
813  }
814  } finally {
815  closeResultSet(resultSet);
816  closeStatement(statement);
818  }
819  }
820 
829  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
830 
831  String loginName = System.getProperty("user.name");
832  if (loginName.isEmpty()) {
833  logger.log(Level.SEVERE, "Cannot determine logged in user name");
834  return;
835  }
836 
838  try {
839  PreparedStatement statement;
840  switch (getDatabaseType()) {
841  case POSTGRESQL:
842  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
843  break;
844  case SQLITE:
845  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
846  break;
847  default:
848  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
849  }
850  statement.clearParameters();
851  statement.setString(1, loginName);
852  connection.executeUpdate(statement);
853  } catch (SQLException ex) {
854  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
855  } finally {
857  }
858  }
859 
867  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
868  long timestamp = System.currentTimeMillis();
869 
870  Statement statement = null;
871  ResultSet resultSet = null;
873  try {
874  statement = connection.createStatement();
875  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
876 
877  synchronized (hasChildrenBitSetMap) {
878  while (resultSet.next()) {
879  setHasChildren(resultSet.getLong("par_obj_id"));
880  }
881  }
882  long delay = System.currentTimeMillis() - timestamp;
883  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
884  } catch (SQLException ex) {
885  throw new TskCoreException("Error populating parent node cache", ex);
886  } finally {
887  closeResultSet(resultSet);
888  closeStatement(statement);
890  }
891  }
892 
899  void addDataSourceToHasChildrenMap() throws TskCoreException {
900 
901  CaseDbConnection connection = connections.getConnection();
902  try {
903  populateHasChildrenMap(connection);
904  } finally {
905  closeConnection(connection);
906  }
907  }
908 
918  private void updateDatabaseSchema(String dbPath) throws Exception {
919  CaseDbConnection connection = null;
920  ResultSet resultSet = null;
921  Statement statement = null;
923  try {
924  connection = connections.getConnection();
925  connection.beginTransaction();
926 
927  boolean hasMinorVersion = false;
928  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
929  while (columns.next()) {
930  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
931  hasMinorVersion = true;
932  }
933  }
934 
935  // Get the schema version number of the case database from the tsk_db_info table.
936  int dbSchemaMajorVersion;
937  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
938 
939  statement = connection.createStatement();
940  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
941  + (hasMinorVersion ? ", schema_minor_ver" : "")
942  + " FROM tsk_db_info"); //NON-NLS
943  if (resultSet.next()) {
944  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
945  if (hasMinorVersion) {
946  //if there is a minor version column, use it, else default to zero.
947  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
948  }
949  } else {
950  throw new TskCoreException();
951  }
952  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
953 
954  resultSet.close();
955  resultSet = null;
956  statement.close();
957  statement = null;
958  //check schema compatibility
959  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
960  //we cannot open a db with a major schema version higher than the current one.
961  throw new TskUnsupportedSchemaVersionException(
962  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
963  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
964  //The schema version is compatible,possibly after upgrades.
965 
966  if (null != dbPath) {
967  // Make a backup copy of the database. Client code can get the path of the backup
968  // using the getBackupDatabasePath() method.
969  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
970  copyCaseDB(backupFilePath);
971  dbBackupPath = backupFilePath;
972  }
973 
974  // ***CALL SCHEMA UPDATE METHODS HERE***
975  // Each method should examine the schema version passed to it and either:
976  // a. do nothing and return the schema version unchanged, or
977  // b. upgrade the database and return the schema version that the db was upgraded to.
978  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
979  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
980  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
981  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
982  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
983  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
984  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
985  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
986  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
987  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
988  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
989  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
990  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
991  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
992  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
993  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
994  dbSchemaVersion = updateFromSchema9dot1toSchema9dot2(dbSchemaVersion, connection);
995  dbSchemaVersion = updateFromSchema9dot2toSchema9dot3(dbSchemaVersion, connection);
996  dbSchemaVersion = updateFromSchema9dot3toSchema9dot4(dbSchemaVersion, connection);
997 
998 
999 
1000  statement = connection.createStatement();
1001  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
1002  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
1003  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
1004  statement.close();
1005  statement = null;
1006  }
1007 
1008  connection.commitTransaction();
1009  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
1010  rollbackTransaction(connection);
1011  throw ex;
1012  } finally {
1013  closeResultSet(resultSet);
1014  closeStatement(statement);
1015  closeConnection(connection);
1017  }
1018  }
1019 
1027  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
1028 
1029  Statement statement = null;
1030  ResultSet resultSet = null;
1031  String createdSchemaMajorVersion = "0";
1032  String createdSchemaMinorVersion = "0";
1034  try {
1035  statement = connection.createStatement();
1036  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
1037  while (resultSet.next()) {
1038  String name = resultSet.getString("name");
1039  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
1040  createdSchemaMajorVersion = resultSet.getString("value");
1041  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
1042  createdSchemaMinorVersion = resultSet.getString("value");
1043  }
1044  }
1045 
1046  } finally {
1047  closeResultSet(resultSet);
1048  closeStatement(statement);
1050  }
1051 
1052  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
1053  }
1054 
1064  public void copyCaseDB(String newDBPath) throws IOException {
1065  if (dbPath.isEmpty()) {
1066  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1067  }
1068  InputStream in = null;
1069  OutputStream out = null;
1071  try {
1072  InputStream inFile = new FileInputStream(dbPath);
1073  in = new BufferedInputStream(inFile);
1074  OutputStream outFile = new FileOutputStream(newDBPath);
1075  out = new BufferedOutputStream(outFile);
1076  int bytesRead = in.read();
1077  while (bytesRead != -1) {
1078  out.write(bytesRead);
1079  bytesRead = in.read();
1080  }
1081  } finally {
1082  try {
1083  if (in != null) {
1084  in.close();
1085  }
1086  if (out != null) {
1087  out.flush();
1088  out.close();
1089  }
1090  } catch (IOException e) {
1091  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1092  }
1094  }
1095  }
1096 
1100  private void logSQLiteJDBCDriverInfo() {
1101  try {
1102  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1103  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1104  ? "native" : "pure-java")); //NON-NLS
1105  } catch (Exception ex) {
1106  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1107  }
1108  }
1109 
1123  @SuppressWarnings("deprecation")
1124  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1125  if (schemaVersion.getMajor() != 2) {
1126  return schemaVersion;
1127  }
1128  Statement statement = null;
1129  Statement statement2 = null;
1130  Statement updateStatement = null;
1131  ResultSet resultSet = null;
1133  try {
1134  statement = connection.createStatement();
1135  statement2 = connection.createStatement();
1136 
1137  // Add new tables for tags.
1138  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
1139  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
1140  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
1141 
1142  // Add a new table for reports.
1143  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
1144 
1145  // Add new columns to the image info table.
1146  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1147  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1148  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1149 
1150  // Add a new column to the file system info table.
1151  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1152 
1153  // Add a new column to the file table.
1154  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1155 
1156  // Add new columns and indexes to the attributes table and populate the
1157  // new column. Note that addition of the new column is a denormalization
1158  // to optimize attribute queries.
1159  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1160  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1161  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1162  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1163  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1164  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1165  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1166  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1167  + "FROM blackboard_attributes AS attrs " //NON-NLS
1168  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1169  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1170  updateStatement = connection.createStatement();
1171  while (resultSet.next()) {
1172  long artifactId = resultSet.getLong("artifact_id");
1173  int artifactTypeId = resultSet.getInt("artifact_type_id");
1174  updateStatement.executeUpdate(
1175  "UPDATE blackboard_attributes " //NON-NLS
1176  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1177  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1178  }
1179  resultSet.close();
1180 
1181  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1182  Map<String, Long> tagNames = new HashMap<>();
1183  long tagNameCounter = 1;
1184 
1185  // Convert file tags.
1186  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1187  resultSet = statement.executeQuery("SELECT * FROM \n"
1188  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1189  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1190  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1191  + "WHERE blackboard_artifacts.artifact_type_id = "
1192  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1193  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1194  + ") AS tagNames \n"
1195  + "INNER JOIN \n"
1196  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1197  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1198  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1199  + "ON tagNames.objId = fileData.objId2 \n"
1200  + "LEFT JOIN \n"
1201  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1202  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1203  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1204 
1205  while (resultSet.next()) {
1206  long objId = resultSet.getLong("objId");
1207  long fileSize = resultSet.getLong("fileSize");
1208  String tagName = resultSet.getString("name");
1209  String tagComment = resultSet.getString("comment");
1210  if (tagComment == null) {
1211  tagComment = "";
1212  }
1213 
1214  if (tagName != null && !tagName.isEmpty()) {
1215  // Get the index for the tag name, adding it to the database if needed.
1216  long tagNameIndex;
1217  if (tagNames.containsKey(tagName)) {
1218  tagNameIndex = tagNames.get(tagName);
1219  } else {
1220  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1221  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1222  tagNames.put(tagName, tagNameCounter);
1223  tagNameIndex = tagNameCounter;
1224  tagNameCounter++;
1225  }
1226 
1227  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1228  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1229  }
1230  }
1231  resultSet.close();
1232 
1233  // Convert artifact tags.
1234  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1235  resultSet = statement.executeQuery("SELECT * FROM \n"
1236  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1237  + "blackboard_attributes.value_text AS name\n"
1238  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1239  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1240  + "WHERE blackboard_artifacts.artifact_type_id = "
1241  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1242  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1243  + ") AS tagNames \n"
1244  + "INNER JOIN \n"
1245  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1246  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1247  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1248  + "LEFT JOIN \n"
1249  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1250  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1251  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1252 
1253  while (resultSet.next()) {
1254  long artifactId = resultSet.getLong("taggedArtifactId");
1255  String tagName = resultSet.getString("name");
1256  String tagComment = resultSet.getString("comment");
1257  if (tagComment == null) {
1258  tagComment = "";
1259  }
1260  if (tagName != null && !tagName.isEmpty()) {
1261  // Get the index for the tag name, adding it to the database if needed.
1262  long tagNameIndex;
1263  if (tagNames.containsKey(tagName)) {
1264  tagNameIndex = tagNames.get(tagName);
1265  } else {
1266  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1267  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1268  tagNames.put(tagName, tagNameCounter);
1269  tagNameIndex = tagNameCounter;
1270  tagNameCounter++;
1271  }
1272 
1273  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1274  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1275  }
1276  }
1277  resultSet.close();
1278 
1279  statement.execute(
1280  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1281  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1282  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1283  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1284  statement.execute(
1285  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1286  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1287  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1288 
1289  return new CaseDbSchemaVersionNumber(3, 0);
1290  } finally {
1291  closeStatement(updateStatement);
1292  closeResultSet(resultSet);
1293  closeStatement(statement);
1294  closeStatement(statement2);
1296  }
1297  }
1298 
1312  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1313  if (schemaVersion.getMajor() != 3) {
1314  return schemaVersion;
1315  }
1316 
1317  Statement statement = null;
1318  ResultSet resultSet = null;
1319  Statement queryStatement = null;
1320  ResultSet queryResultSet = null;
1321  Statement updateStatement = null;
1323  try {
1324  // Add mime_type column to tsk_files table. Populate with general
1325  // info artifact file signature data.
1326  statement = connection.createStatement();
1327  updateStatement = connection.createStatement();
1328  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1329  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1330  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1331  + "WHERE files.obj_id = arts.obj_id AND "
1332  + "arts.artifact_id = attrs.artifact_id AND "
1333  + "arts.artifact_type_id = 1 AND "
1334  + "attrs.attribute_type_id = 62");
1335  while (resultSet.next()) {
1336  updateStatement.executeUpdate(
1337  "UPDATE tsk_files " //NON-NLS
1338  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1339  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1340  }
1341  resultSet.close();
1342 
1343  // Add value_type column to blackboard_attribute_types table.
1344  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1345  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1346  while (resultSet.next()) {
1347  int attributeTypeId = resultSet.getInt("attribute_type_id");
1348  String attributeLabel = resultSet.getString("type_name");
1349  if (attributeTypeId < Blackboard.MIN_USER_DEFINED_TYPE_ID) {
1350  updateStatement.executeUpdate(
1351  "UPDATE blackboard_attribute_types " //NON-NLS
1352  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1353  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1354  }
1355  }
1356  resultSet.close();
1357 
1358  // Add a data_sources_info table.
1359  queryStatement = connection.createStatement();
1360  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));");
1361  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1362  while (resultSet.next()) {
1363  long objectId = resultSet.getLong("obj_id");
1364  String timeZone = "";
1365  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1366  if (queryResultSet.next()) {
1367  timeZone = queryResultSet.getString("tzone");
1368  }
1369  queryResultSet.close();
1370  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1371  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1372  }
1373  resultSet.close();
1374 
1375  // Add data_source_obj_id column to the tsk_files table.
1376  //
1377  // NOTE: A new case database will have the following FK constraint:
1378  //
1379  // REFERENCES data_source_info (obj_id)
1380  //
1381  // The constraint is sacrificed here to avoid having to create and
1382  // populate a new tsk_files table.
1383  //
1384  // TODO: Do this right.
1385  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1386  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");
1387  while (resultSet.next()) {
1388  long fileId = resultSet.getLong("obj_id");
1389  long dataSourceId = getDataSourceObjectId(connection, fileId);
1390  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1391  }
1392  resultSet.close();
1393  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1394  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1395  if (this.dbType.equals(DbType.SQLITE)) {
1396  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
1397  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
1398  } else {
1399  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
1400  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
1401  }
1402 
1403  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
1404  initIngestModuleTypes(connection);
1405  initIngestStatusTypes(connection);
1406 
1407  return new CaseDbSchemaVersionNumber(4, 0);
1408 
1409  } finally {
1410  closeResultSet(queryResultSet);
1411  closeStatement(queryStatement);
1412  closeStatement(updateStatement);
1413  closeResultSet(resultSet);
1414  closeStatement(statement);
1416  }
1417  }
1418 
1432  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1433  if (schemaVersion.getMajor() != 4) {
1434  return schemaVersion;
1435  }
1436 
1437  Statement statement = null;
1439  try {
1440  // Add the review_statuses lookup table.
1441  statement = connection.createStatement();
1442  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1443 
1444  /*
1445  * Add review_status_id column to artifacts table.
1446  *
1447  * NOTE: For DBs created with schema 5 we define a foreign key
1448  * constraint on the review_status_column. We don't bother with this
1449  * for DBs updated to schema 5 because of limitations of the SQLite
1450  * ALTER TABLE command.
1451  */
1452  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1453 
1454  // Add the encoding table
1455  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1456  initEncodingTypes(connection);
1457 
1458  /*
1459  * This needs to be done due to a Autopsy/TSK out of synch problem.
1460  * Without this, it is possible to upgrade from version 4 to 5 and
1461  * then 5 to 6, but not from 4 to 6.
1462  */
1463  initReviewStatuses(connection);
1464 
1465  // Add encoding type column to tsk_files_path
1466  // This should really have the FOREIGN KEY constraint but there are problems
1467  // getting that to work, so we don't add it on this upgrade path.
1468  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1469 
1470  return new CaseDbSchemaVersionNumber(5, 0);
1471 
1472  } finally {
1473  closeStatement(statement);
1475  }
1476  }
1477 
1491  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1492  if (schemaVersion.getMajor() != 5) {
1493  return schemaVersion;
1494  }
1495 
1496  /*
1497  * This upgrade fixes a bug where some releases had artifact review
1498  * status support in the case database and others did not.
1499  */
1500  Statement statement = null;
1501  ResultSet resultSet = null;
1503  try {
1504  /*
1505  * Add the review_statuses lookup table, if missing.
1506  */
1507  statement = connection.createStatement();
1508  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)");
1509 
1510  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1511  resultSet.next();
1512  if (resultSet.getLong("count") == 0) {
1513  /*
1514  * Add review_status_id column to artifacts table.
1515  *
1516  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1517  * key constraint on the review_status_column. We don't bother
1518  * with this for DBs updated to schema 5 or 6 because of
1519  * limitations of the SQLite ALTER TABLE command.
1520  */
1521  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1522  }
1523 
1524  return new CaseDbSchemaVersionNumber(6, 0);
1525 
1526  } finally {
1527  closeResultSet(resultSet);
1528  closeStatement(statement);
1530  }
1531  }
1532 
1546  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1547  if (schemaVersion.getMajor() != 6) {
1548  return schemaVersion;
1549  }
1550 
1551  /*
1552  * This upgrade adds an indexed extension column to the tsk_files table.
1553  */
1554  Statement statement = null;
1555  Statement updstatement = null;
1556  ResultSet resultSet = null;
1558  try {
1559  statement = connection.createStatement();
1560  updstatement = connection.createStatement();
1561  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1562 
1563  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1564  while (resultSet.next()) {
1565  long objID = resultSet.getLong("obj_id");
1566  String name = resultSet.getString("name");
1567  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1568  + "WHERE obj_id = " + objID);
1569  }
1570 
1571  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1572 
1573  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1574  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1575 
1576  return new CaseDbSchemaVersionNumber(7, 0);
1577 
1578  } finally {
1579  closeResultSet(resultSet);
1580  closeStatement(statement);
1581  closeStatement(updstatement);
1583  }
1584  }
1585 
1599  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1600  if (schemaVersion.getMajor() != 7) {
1601  return schemaVersion;
1602  }
1603 
1604  if (schemaVersion.getMinor() != 0) {
1605  return schemaVersion;
1606  }
1607 
1608  /*
1609  * This upgrade adds a minor version number column.
1610  */
1611  Statement statement = null;
1612  ResultSet resultSet = null;
1614  try {
1615  statement = connection.createStatement();
1616 
1617  //add the schema minor version number column.
1618  if (schemaVersion.getMinor() == 0) {
1619  //add the schema minor version number column.
1620  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1621  }
1622  return new CaseDbSchemaVersionNumber(7, 1);
1623 
1624  } finally {
1625  closeResultSet(resultSet);
1626  closeStatement(statement);
1628  }
1629  }
1630 
1644  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1645  if (schemaVersion.getMajor() != 7) {
1646  return schemaVersion;
1647  }
1648 
1649  if (schemaVersion.getMinor() != 1) {
1650  return schemaVersion;
1651  }
1652 
1653  Statement statement = null;
1654  Statement updstatement = null;
1655  ResultSet resultSet = null;
1657  try {
1658  //add the data_source_obj_id column to blackboard_artifacts.
1659  statement = connection.createStatement();
1660  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1661 
1662  // populate data_source_obj_id for each artifact
1663  updstatement = connection.createStatement();
1664  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1665  while (resultSet.next()) {
1666  long artifact_id = resultSet.getLong("artifact_id");
1667  long obj_id = resultSet.getLong("obj_id");
1668  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1669  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1670  + "WHERE artifact_id = " + artifact_id);
1671  }
1672  closeResultSet(resultSet);
1673  closeStatement(statement);
1674  closeStatement(updstatement);
1675 
1676  /*
1677  * Add a knownStatus column to the tag_names table.
1678  */
1679  statement = connection.createStatement();
1680  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1681 
1682  // Create account_types, accounts, and account_relationships table
1683  if (this.dbType.equals(DbType.SQLITE)) {
1684  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1685  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))");
1686  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))");
1687  } else {
1688  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1689  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))");
1690  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))");
1691  }
1692 
1693  // Create indexes
1694  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1695  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1696  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1697  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1698  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1699  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1700  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1701 
1702  return new CaseDbSchemaVersionNumber(7, 2);
1703  } finally {
1704  closeResultSet(resultSet);
1705  closeStatement(statement);
1706  closeStatement(updstatement);
1708  }
1709  }
1710 
1724  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1725  if (schemaVersion.getMajor() != 7) {
1726  return schemaVersion;
1727  }
1728 
1729  if (schemaVersion.getMinor() != 2) {
1730  return schemaVersion;
1731  }
1732 
1733  Statement updateSchemaStatement = connection.createStatement();
1734  Statement getExistingReportsStatement = connection.createStatement();
1735  ResultSet resultSet = null;
1736  ResultSet existingReports = null;
1737 
1739  try {
1740  // Update the schema to turn report_id into an object id.
1741 
1742  // Unfortunately, SQLite doesn't support adding a constraint
1743  // to an existing table so we have to rename the old...
1744  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1745 
1746  // ...create the new...
1747  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))");
1748 
1749  // ...add the existing report records back...
1750  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1751  while (existingReports.next()) {
1752  String path = existingReports.getString(2);
1753  long crtime = existingReports.getInt(3);
1754  String sourceModule = existingReports.getString(4);
1755  String reportName = existingReports.getString(5);
1756 
1757  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1758  insertObjectStatement.clearParameters();
1759  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1760  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1761  connection.executeUpdate(insertObjectStatement);
1762  resultSet = insertObjectStatement.getGeneratedKeys();
1763  if (!resultSet.next()) {
1764  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1765  }
1766  long objectId = resultSet.getLong(1); //last_insert_rowid()
1767 
1768  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1769  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1770  insertReportStatement.clearParameters();
1771  insertReportStatement.setLong(1, objectId);
1772  insertReportStatement.setString(2, path);
1773  insertReportStatement.setLong(3, crtime);
1774  insertReportStatement.setString(4, sourceModule);
1775  insertReportStatement.setString(5, reportName);
1776  connection.executeUpdate(insertReportStatement);
1777  }
1778 
1779  // ...and drop the old table.
1780  updateSchemaStatement.execute("DROP TABLE old_reports");
1781 
1782  return new CaseDbSchemaVersionNumber(8, 0);
1783  } finally {
1784  closeResultSet(resultSet);
1785  closeResultSet(existingReports);
1786  closeStatement(updateSchemaStatement);
1787  closeStatement(getExistingReportsStatement);
1789  }
1790  }
1791 
1805  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1806  if (schemaVersion.getMajor() != 8) {
1807  return schemaVersion;
1808  }
1809 
1810  if (schemaVersion.getMinor() != 0) {
1811  return schemaVersion;
1812  }
1813 
1815 
1816  try (Statement statement = connection.createStatement();) {
1817  // create examiners table
1818  if (this.dbType.equals(DbType.SQLITE)) {
1819  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1820  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1821  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1822  } else {
1823  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1824  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1825  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1826  }
1827 
1828  return new CaseDbSchemaVersionNumber(8, 1);
1829  } finally {
1831  }
1832  }
1833 
1847  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1848  if (schemaVersion.getMajor() != 8) {
1849  return schemaVersion;
1850  }
1851 
1852  if (schemaVersion.getMinor() != 1) {
1853  return schemaVersion;
1854  }
1855 
1857 
1858  try (Statement statement = connection.createStatement();) {
1859  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1860  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1861 
1862  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1863 
1864  /*
1865  * Add new tsk_db_extended_info table with TSK version, creation
1866  * time schema and schema version numbers as the initial data. The
1867  * creation time schema version is set to 0, 0 to indicate that it
1868  * is not known.
1869  */
1870  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1871  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1872  result.next();
1873  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1874  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1875  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1876  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1877  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1878 
1879  String primaryKeyType;
1880  switch (getDatabaseType()) {
1881  case POSTGRESQL:
1882  primaryKeyType = "BIGSERIAL";
1883  break;
1884  case SQLITE:
1885  primaryKeyType = "INTEGER";
1886  break;
1887  default:
1888  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1889  }
1890 
1891  //create and initialize tsk_event_types tables
1892  statement.execute("CREATE TABLE tsk_event_types ("
1893  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1894  + " display_name TEXT UNIQUE NOT NULL, "
1895  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1896  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1897  + " values( 0, 'Event Types', null)");
1898  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1899  + " values(1, 'File System', 0)");
1900  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1901  + " values(2, 'Web Activity', 0)");
1902  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1903  + " values(3, 'Misc Types', 0)");
1904  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1905  + " values(4, 'Modified', 1)");
1906  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1907  + " values(5, 'Accessed', 1)");
1908  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1909  + " values(6, 'Created', 1)");
1910  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1911  + " values(7, 'Changed', 1)");
1912 
1913  //create tsk_events tables
1914  statement.execute("CREATE TABLE tsk_event_descriptions ("
1915  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1916  + " full_description TEXT NOT NULL, "
1917  + " med_description TEXT, "
1918  + " short_description TEXT,"
1919  + " data_source_obj_id BIGINT NOT NULL, "
1920  + " file_obj_id BIGINT NOT NULL, "
1921  + " artifact_id BIGINT, "
1922  + " hash_hit INTEGER NOT NULL, " //boolean
1923  + " tagged INTEGER NOT NULL, " //boolean
1924  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1925  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1926  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1927  );
1928 
1929  statement.execute("CREATE TABLE tsk_events ( "
1930  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1931  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1932  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1933  + " time INTEGER NOT NULL) "
1934  );
1935 
1936  //create tsk_events indices
1937  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1938  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1939  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1940  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1941  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1942  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1943  return new CaseDbSchemaVersionNumber(8, 2);
1944 
1945  } finally {
1947  }
1948  }
1949 
1963  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1964  if (schemaVersion.getMajor() != 8) {
1965  return schemaVersion;
1966  }
1967 
1968  if (schemaVersion.getMinor() != 2) {
1969  return schemaVersion;
1970  }
1971 
1973 
1974  ResultSet resultSet = null;
1975 
1976  try (Statement statement = connection.createStatement();) {
1977 
1978  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1979  // Unfortunately, SQLite doesn't support adding a constraint
1980  // to an existing table so we have to rename the old...
1981  String primaryKeyType;
1982  switch (getDatabaseType()) {
1983  case POSTGRESQL:
1984  primaryKeyType = "BIGSERIAL";
1985  break;
1986  case SQLITE:
1987  primaryKeyType = "INTEGER";
1988  break;
1989  default:
1990  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1991  }
1992 
1993  //create and initialize tsk_event_types tables which may or may not exist
1994  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
1995  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1996  + " display_name TEXT UNIQUE NOT NULL, "
1997  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1998 
1999  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
2000 
2001  // If there is something in resultSet then the table must have previously
2002  // existing therefore there is not need to populate
2003  if (!resultSet.next()) {
2004 
2005  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2006  + " values( 0, 'Event Types', null)");
2007  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2008  + " values(1, 'File System', 0)");
2009  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2010  + " values(2, 'Web Activity', 0)");
2011  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2012  + " values(3, 'Misc Types', 0)");
2013  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2014  + " values(4, 'Modified', 1)");
2015  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2016  + " values(5, 'Accessed', 1)");
2017  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2018  + " values(6, 'Created', 1)");
2019  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2020  + " values(7, 'Changed', 1)");
2021  }
2022 
2023  // Delete the old table that may have been created with the upgrade
2024  // from 8.1 to 8.2.
2025  statement.execute("DROP TABLE IF EXISTS tsk_events");
2026 
2027  // Delete the old table that may have been created with the upgrade
2028  // from 8.1 to 8.2
2029  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
2030 
2031  //create new tsk_event_description table
2032  statement.execute("CREATE TABLE tsk_event_descriptions ("
2033  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2034  + " full_description TEXT NOT NULL, "
2035  + " med_description TEXT, "
2036  + " short_description TEXT,"
2037  + " data_source_obj_id BIGINT NOT NULL, "
2038  + " file_obj_id BIGINT NOT NULL, "
2039  + " artifact_id BIGINT, "
2040  + " hash_hit INTEGER NOT NULL, " //boolean
2041  + " tagged INTEGER NOT NULL, " //boolean
2042  + " UNIQUE(full_description, file_obj_id, artifact_id), "
2043  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2044  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2045  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2046  );
2047 
2048  // create a new table
2049  statement.execute("CREATE TABLE tsk_events ( "
2050  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2051  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2052  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2053  + " time INTEGER NOT NULL, "
2054  + " UNIQUE (event_type_id, event_description_id, time))"
2055  );
2056 
2057  // Fix mistakenly set names in tsk_db_info_extended
2058  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2059  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2060 
2061  return new CaseDbSchemaVersionNumber(8, 3);
2062  } finally {
2063  closeResultSet(resultSet);
2065  }
2066  }
2067 
2089  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2090  if (schemaVersion.getMajor() != 8) {
2091  return schemaVersion;
2092  }
2093 
2094  if (schemaVersion.getMinor() != 3) {
2095  return schemaVersion;
2096  }
2097 
2098  Statement statement = connection.createStatement();
2099  ResultSet results = null;
2100 
2102  try {
2103  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2104  // the previous update code.
2105  if (null == getDatabaseType()) {
2106  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2107  }
2108 
2109  switch (getDatabaseType()) {
2110  case POSTGRESQL:
2111  // Check if the misnamed column is present
2112  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2113  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2114  if (results.next()) {
2115  // In PostgreSQL we can rename the column if it exists
2116  statement.execute("ALTER TABLE tsk_event_descriptions "
2117  + "RENAME COLUMN file_obj_id TO content_obj_id");
2118 
2119  // 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
2120  // Fix the schema, preserving any data if exists.
2121  statement.execute("CREATE TABLE temp_tsk_events ( "
2122  + " event_id BIGSERIAL PRIMARY KEY, "
2123  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2124  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2125  + " time BIGINT NOT NULL, "
2126  + " UNIQUE (event_type_id, event_description_id, time))"
2127  );
2128 
2129  // Copy the data
2130  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2131  + "event_description_id, time) SELECT * FROM tsk_events");
2132 
2133  // Drop the old table
2134  statement.execute("DROP TABLE tsk_events");
2135 
2136  // Rename the new table
2137  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2138 
2139  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2140  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2141  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2142  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2143  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2144  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2145  }
2146  break;
2147  case SQLITE:
2148  boolean hasMisnamedColumn = false;
2149  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2150  while (results.next()) {
2151  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2152  hasMisnamedColumn = true;
2153  break;
2154  }
2155  }
2156 
2157  if (hasMisnamedColumn) {
2158  // Since we can't rename the column we'll need to make new tables and copy the data
2159  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2160  + " event_description_id INTEGER PRIMARY KEY, "
2161  + " full_description TEXT NOT NULL, "
2162  + " med_description TEXT, "
2163  + " short_description TEXT,"
2164  + " data_source_obj_id BIGINT NOT NULL, "
2165  + " content_obj_id BIGINT NOT NULL, "
2166  + " artifact_id BIGINT, "
2167  + " hash_hit INTEGER NOT NULL, " //boolean
2168  + " tagged INTEGER NOT NULL, " //boolean
2169  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2170  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2171  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2172  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2173  );
2174 
2175  statement.execute("CREATE TABLE temp_tsk_events ( "
2176  + " event_id INTEGER PRIMARY KEY, "
2177  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2178  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2179  + " time INTEGER NOT NULL, "
2180  + " UNIQUE (event_type_id, event_description_id, time))"
2181  );
2182 
2183  // Copy the data
2184  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2185  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2186  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2187 
2188  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2189  + "event_description_id, time) SELECT * FROM tsk_events");
2190 
2191  // Drop the old tables
2192  statement.execute("DROP TABLE tsk_events");
2193  statement.execute("DROP TABLE tsk_event_descriptions");
2194 
2195  // Rename the new tables
2196  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2197  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2198 
2199  //create tsk_events indices
2200  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2201  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2202  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2203  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2204  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2205  }
2206  break;
2207  default:
2208  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2209  }
2210 
2211  // create pool info table
2212  if (this.dbType.equals(DbType.SQLITE)) {
2213  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)");
2214  } else {
2215  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)");
2216  }
2217 
2218  // Add new account types for newly supported messaging applications, if they dont exists already.
2219  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2220  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2221  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2222  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2223  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2224  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2225  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2226  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2227  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2228  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2229 
2230  return new CaseDbSchemaVersionNumber(8, 4);
2231  } finally {
2232  closeResultSet(results);
2233  closeStatement(statement);
2235  }
2236  }
2237 
2238  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2239  if (schemaVersion.getMajor() != 8) {
2240  return schemaVersion;
2241  }
2242 
2243  if (schemaVersion.getMinor() != 4) {
2244  return schemaVersion;
2245  }
2246 
2247  Statement statement = connection.createStatement();
2249  try {
2250  switch (getDatabaseType()) {
2251  case POSTGRESQL:
2252  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2253  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2254  break;
2255  case SQLITE:
2256  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2257  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2258  break;
2259  }
2260 
2261  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2262 
2263  /*
2264  * Update existing Project Vic tag names (from Image Gallery in
2265  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2266  * date and will not work with the Project VIC Report module. New
2267  * cases will get the new names from Image Gallery.
2268  */
2269  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2270  if (getDatabaseType() == DbType.POSTGRESQL) {
2271  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2272  } else {
2273  statement.execute(insertStmt);
2274  }
2275  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2276  if (resultSet != null && resultSet.next()) {
2277  int tagSetId = resultSet.getInt(1);
2278 
2279  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2280  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2281  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2282  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2283  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2284  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2285 
2286  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')";
2287  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')";
2288  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2289  statement.executeUpdate(deleteContentTag);
2290  statement.executeUpdate(deleteArtifactTag);
2291  statement.executeUpdate(deleteCat0);
2292 
2293  } else {
2294  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2295  }
2296  }
2297 
2298  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2299  // this column will have a foreign key constraint on the data_source_info table.
2300  // There does not seem to be a reasonable way to do this in an upgrade,
2301  // so upgraded cases will be missing the foreign key.
2302  switch (getDatabaseType()) {
2303  case POSTGRESQL:
2304  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2305  break;
2306  case SQLITE:
2307  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2308  break;
2309  }
2310  Statement updateStatement = connection.createStatement();
2311  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2312  while (resultSet.next()) {
2313  long fsId = resultSet.getLong("obj_id");
2314  long dataSourceId = getDataSourceObjectId(connection, fsId);
2315  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2316  }
2317  } finally {
2318  closeStatement(updateStatement);
2319  }
2320 
2321  return new CaseDbSchemaVersionNumber(8, 5);
2322 
2323  } finally {
2324  closeStatement(statement);
2326  }
2327  }
2328 
2329  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2330  if (schemaVersion.getMajor() != 8) {
2331  return schemaVersion;
2332  }
2333 
2334  if (schemaVersion.getMinor() != 5) {
2335  return schemaVersion;
2336  }
2337 
2338  Statement statement = connection.createStatement();
2340  try {
2341  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2342 
2343  return new CaseDbSchemaVersionNumber(8, 6);
2344 
2345  } finally {
2346  closeStatement(statement);
2348  }
2349  }
2350 
2351  @SuppressWarnings("deprecation")
2352  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2353  if (schemaVersion.getMajor() != 8) {
2354  return schemaVersion;
2355  }
2356 
2357  if (schemaVersion.getMinor() != 6) {
2358  return schemaVersion;
2359  }
2360 
2361  Statement statement = connection.createStatement();
2363  try {
2364  String dateDataType = "BIGINT";
2365  String bigIntDataType = "BIGINT";
2366  String blobDataType = "BYTEA";
2367  String primaryKeyType = "BIGSERIAL";
2368 
2369  if (this.dbType.equals(DbType.SQLITE)) {
2370  dateDataType = "INTEGER";
2371  bigIntDataType = "INTEGER";
2372  blobDataType = "BLOB";
2373  primaryKeyType = "INTEGER";
2374  }
2375  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2376  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2377  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2378  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2379 
2380  // Add category type and initialize the types. We use the list of artifact types that
2381  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2382  // case the built-in types change in a later release.
2383  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2384  String analysisTypeObjIdList
2385  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2386  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2387  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2388  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2389  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2390  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2391  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2392  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2393  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2394  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2395  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2396  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2397  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2398  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2399  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2400  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2401  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2402  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2403  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2404 
2405  // Create tsk file attributes table
2406  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2407  + "obj_id " + bigIntDataType + " NOT NULL, "
2408  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2409  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2410  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2411  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2412  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2413 
2414  // create analysis results tables
2415  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2416  + "conclusion TEXT, "
2417  + "significance INTEGER NOT NULL, "
2418  /*
2419  * method_category was a column in a little distributed
2420  * version of 9.0. It was renamed to priority before public
2421  * release. The 9.1 upgrade code will add the priority
2422  * column. This is commented out since it was never used.
2423  */
2424  // + "method_category INTEGER NOT NULL, "
2425  + "configuration TEXT, justification TEXT, "
2426  + "ignore_score INTEGER DEFAULT 0 " // boolean
2427  + ")");
2428 
2429  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2430  + "data_source_obj_id " + bigIntDataType + ", "
2431  + "significance INTEGER NOT NULL, "
2432  // See comment above on why this is commented out
2433  // + "method_category INTEGER NOT NULL, "
2434  + "UNIQUE (obj_id),"
2435  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2436  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2437  + ")");
2438 
2439  // Create person table.
2440  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2441  + "name TEXT NOT NULL, " // person name
2442  + "UNIQUE(name)) ");
2443 
2444  // Create host table.
2445  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2446  + "name TEXT NOT NULL, " // host name
2447  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2448  + "person_id INTEGER, "
2449  + "merged_into " + bigIntDataType + ", "
2450  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2451  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2452  + "UNIQUE(name)) ");
2453 
2454  // Create OS Account and related tables
2455  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2456  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2457  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2458  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2459  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2460  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2461  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2462  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2463  + "UNIQUE(realm_signature), "
2464  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2465  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2466 
2467  // Add host column and create a host for each existing data source.
2468  // We will create a host for each device id so that related data sources will
2469  // be associated with the same host.
2470  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2471  Statement updateStatement = connection.createStatement();
2472  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2473  Map<String, Long> hostMap = new HashMap<>();
2474  long hostIndex = 1;
2475  while (resultSet.next()) {
2476  long objId = resultSet.getLong("obj_id");
2477  String deviceId = resultSet.getString("device_id");
2478 
2479  if (!hostMap.containsKey(deviceId)) {
2480  String hostName = "Host " + hostIndex;
2481  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2482  hostMap.put(deviceId, hostIndex);
2483  hostIndex++;
2484  }
2485  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2486  }
2487  } finally {
2488  closeStatement(updateStatement);
2489  }
2490 
2491  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2492  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2493  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2494  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2495  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2496  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2497  + "status INTEGER, " // enabled/disabled/deleted
2498  + "type INTEGER, " // service/interactive
2499  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2500  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2501  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2502  + "UNIQUE(signature, realm_id), "
2503  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2504  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2505  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2506 
2507  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2508  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2509  + "host_id " + bigIntDataType + ", "
2510  + "source_obj_id " + bigIntDataType + ", "
2511  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2512  + "value_type INTEGER NOT NULL, "
2513  + "value_byte " + bigIntDataType + ", "
2514  + "value_text TEXT, "
2515  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2516  + "value_double NUMERIC(20, 10), "
2517  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2518  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2519  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2520  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2521 
2522  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2523  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2524  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2525  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2526  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2527  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2528  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2529 
2530  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2531  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2532  + "os_account_obj_id " + bigIntDataType + ", "
2533  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2534 
2535  // add owner_uid & os_account_obj_id columns to tsk_files
2536  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2537  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2538 
2539  // create host address tables
2540  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2541  + "address_type INTEGER NOT NULL, "
2542  + "address TEXT NOT NULL, "
2543  + "UNIQUE(address_type, address)) ");
2544 
2545  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2546  + "host_id " + bigIntDataType + " NOT NULL, "
2547  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2548  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2549  + "time " + bigIntDataType + ", " // time at which the mapping existed
2550  + "UNIQUE(host_id, addr_obj_id, time), "
2551  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2552  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2553  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2554 
2555  // stores associations between DNS name and IP address
2556  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2557  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2558  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2559  + "source_obj_id " + bigIntDataType + ", "
2560  + "time " + bigIntDataType + ", " // time at which the mapping existed
2561  + "UNIQUE(dns_address_id, ip_address_id, time), "
2562  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2563  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2564  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2565 
2566  // maps an address to an artifact using it
2567  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2568  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2569  + "obj_id " + bigIntDataType + " NOT NULL, "
2570  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2571  + "UNIQUE(addr_obj_id, obj_id), "
2572  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2573  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2574 
2575  return new CaseDbSchemaVersionNumber(9, 0);
2576 
2577  } finally {
2578  closeStatement(statement);
2580  }
2581  }
2582 
2583  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2584  if (schemaVersion.getMajor() != 9) {
2585  return schemaVersion;
2586  }
2587 
2588  if (schemaVersion.getMinor() != 0) {
2589  return schemaVersion;
2590  }
2591 
2592  Statement statement = connection.createStatement();
2593  ResultSet results = null;
2595  try {
2596  // The 9.0 schema contained method_category columns that were renamed to priority.
2597  switch (getDatabaseType()) {
2598  case POSTGRESQL:
2599  // Check if the misnamed column is present. We'll assume here that the column will exist
2600  // in both tables if present in one.
2601  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2602  + "WHERE table_name='tsk_analysis_results' and column_name='method_category'");
2603  if (results.next()) {
2604  // In PostgreSQL we can delete the column
2605  statement.execute("ALTER TABLE tsk_analysis_results "
2606  + "DROP COLUMN method_category");
2607  statement.execute("ALTER TABLE tsk_aggregate_score "
2608  + "DROP COLUMN method_category");
2609  }
2610  break;
2611  case SQLITE:
2612  // Check if the misnamed column is present. We'll assume here that the column will exist
2613  // in both tables if present in one.
2614  boolean hasMisnamedColumn = false;
2615  results = statement.executeQuery("pragma table_info('tsk_analysis_results')");
2616  while (results.next()) {
2617  if (results.getString("name") != null && results.getString("name").equals("method_category")) {
2618  hasMisnamedColumn = true;
2619  break;
2620  }
2621  }
2622 
2623  if (hasMisnamedColumn) {
2624  // Since we can't rename the column we'll need to make a new table and copy the data.
2625  // We'll add the priority column later.
2626  statement.execute("CREATE TABLE temp_tsk_analysis_results (artifact_obj_id INTEGER PRIMARY KEY, "
2627  + "conclusion TEXT, "
2628  + "significance INTEGER NOT NULL, "
2629  + "configuration TEXT, justification TEXT, "
2630  + "ignore_score INTEGER DEFAULT 0 " // boolean
2631  + ")");
2632  statement.execute("CREATE TABLE temp_tsk_aggregate_score( obj_id INTEGER PRIMARY KEY, "
2633  + "data_source_obj_id INTEGER, "
2634  + "significance INTEGER NOT NULL, "
2635  + "UNIQUE (obj_id),"
2636  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2637  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2638  + ")");
2639 
2640  // Copy the data
2641  statement.execute("INSERT INTO temp_tsk_analysis_results(artifact_obj_id, "
2642  + "conclusion, justification, significance, configuration, ignore_score) "
2643  + "SELECT artifact_obj_id, conclusion, justification, significance, configuration, ignore_score FROM tsk_analysis_results");
2644  statement.execute("INSERT INTO temp_tsk_aggregate_score(obj_id, "
2645  + "data_source_obj_id, significance) "
2646  + "SELECT obj_id, data_source_obj_id, significance FROM tsk_aggregate_score");
2647 
2648  // Drop the old tables
2649  statement.execute("DROP TABLE tsk_analysis_results");
2650  statement.execute("DROP TABLE tsk_aggregate_score");
2651 
2652  // Rename the new tables
2653  statement.execute("ALTER TABLE temp_tsk_analysis_results RENAME TO tsk_analysis_results");
2654  statement.execute("ALTER TABLE temp_tsk_aggregate_score RENAME TO tsk_aggregate_score");
2655 
2656  }
2657  break;
2658  default:
2659  throw new TskCoreException("Unsupported database type: " + getDatabaseType().toString());
2660  }
2661 
2662  // add an index on tsk_file_attributes table.
2663  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2664 
2665  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2666  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2667 
2668  statement.execute("UPDATE blackboard_artifact_types SET category_type = 1 WHERE artifact_type_id = 16");
2669 
2670  return new CaseDbSchemaVersionNumber(9, 1);
2671  } finally {
2672  closeResultSet(results);
2673  closeStatement(statement);
2675  }
2676  }
2677 
2691  private CaseDbSchemaVersionNumber updateFromSchema9dot1toSchema9dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2692  if (schemaVersion.getMajor() != 9) {
2693  return schemaVersion;
2694  }
2695 
2696  if (schemaVersion.getMinor() != 1) {
2697  return schemaVersion;
2698  }
2699 
2700  Statement updateSchemaStatement = connection.createStatement();
2701  ResultSet results = null;
2703  try {
2704 
2705  String bigIntDataType = "BIGINT";
2706  String primaryKeyType = "BIGSERIAL";
2707 
2708  if (this.dbType.equals(DbType.SQLITE)) {
2709  bigIntDataType = "INTEGER";
2710  primaryKeyType = "INTEGER";
2711  }
2712 
2713  // In 9.2 we modified the UNIQUE constraint on tsk_os_account_instances to include instance_type column.
2714  // Since SQLite does not allow to drop or alter constraints, we will create a new table, copy the data and delete the old table.
2715  // Rename existing table
2716  updateSchemaStatement.execute("ALTER TABLE tsk_os_account_instances RENAME TO old_tsk_os_account_instances");
2717 
2718  // New table
2719  updateSchemaStatement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2720  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2721  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2722  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2723  + "UNIQUE(os_account_obj_id, data_source_obj_id, instance_type), "
2724  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id) ON DELETE CASCADE, "
2725  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE ) ");
2726 
2727  // Copy the data from old table, order by id preserves the primary key.
2728  updateSchemaStatement.execute("INSERT INTO tsk_os_account_instances(os_account_obj_id, "
2729  + "data_source_obj_id, instance_type) SELECT os_account_obj_id, data_source_obj_id, instance_type FROM old_tsk_os_account_instances ORDER BY id ASC");
2730 
2731  // delete old table
2732  updateSchemaStatement.execute("DROP TABLE old_tsk_os_account_instances");
2733 
2734  return new CaseDbSchemaVersionNumber(9, 2);
2735  } finally {
2736  closeResultSet(results);
2737  closeStatement(updateSchemaStatement);
2739  }
2740  }
2741 
2742  private CaseDbSchemaVersionNumber updateFromSchema9dot2toSchema9dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2743  if (schemaVersion.getMajor() != 9) {
2744  return schemaVersion;
2745  }
2746 
2747  if (schemaVersion.getMinor() != 2) {
2748  return schemaVersion;
2749  }
2750 
2751  Statement statement = connection.createStatement();
2753  try {
2754  // add a new column 'sha1' to tsk_files
2755  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha1 TEXT");
2756 
2757 
2758  return new CaseDbSchemaVersionNumber(9, 3);
2759 
2760  } finally {
2761  closeStatement(statement);
2763  }
2764  }
2765 
2766  private CaseDbSchemaVersionNumber updateFromSchema9dot3toSchema9dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2767  if (schemaVersion.getMajor() != 9) {
2768  return schemaVersion;
2769  }
2770 
2771  if (schemaVersion.getMinor() != 3) {
2772  return schemaVersion;
2773  }
2774 
2775  Statement statement = connection.createStatement();
2777  try {
2778  // Add file_collection_status_types table
2779  statement.execute("CREATE TABLE file_collection_status_types (collection_status_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
2780  initCollectedStatusTypes(connection);
2781 
2782  // add a new column 'collected' to tsk_files
2783  statement.execute("ALTER TABLE tsk_files ADD COLUMN collected INTEGER NOT NULL DEFAULT " +
2784  TskData.CollectedStatus.UNKNOWN.getType() + ";");
2785 
2786  return new CaseDbSchemaVersionNumber(9, 4);
2787 
2788  } finally {
2789  closeStatement(statement);
2791  }
2792  }
2793 
2805  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2806 
2807  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2808  switch (getDatabaseType()) {
2809  case POSTGRESQL:
2810  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2811  break;
2812  case SQLITE:
2813  insertSQL = "INSERT OR IGNORE " + insertSQL;
2814  break;
2815  default:
2816  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2817  }
2818  statement.execute(insertSQL); //NON-NLS
2819  }
2820 
2828  static String extractExtension(final String fileName) {
2829  String ext;
2830  int i = fileName.lastIndexOf(".");
2831  // > 0 because we assume it's not an extension if period is the first character
2832  if ((i > 0) && ((i + 1) < fileName.length())) {
2833  ext = fileName.substring(i + 1);
2834  } else {
2835  return "";
2836  }
2837  // we added this at one point to deal with files that had crazy names based on URLs
2838  // it's too hard though to clean those up and not mess up basic extensions though.
2839  // We need to add '-' to the below if we use it again
2840  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2841  // if (findNonAlphanumeric.length > 1) {
2842  // ext = findNonAlphanumeric[0];
2843  // }
2844  return ext.toLowerCase();
2845  }
2846 
2857  @Deprecated
2858  public int getSchemaVersion() {
2859  return getDBSchemaVersion().getMajor();
2860  }
2861 
2868  return CURRENT_DB_SCHEMA_VERSION;
2869  }
2870 
2878  return caseDBSchemaCreationVersion;
2879  }
2880 
2887  return this.dbType;
2888  }
2889 
2896  public String getBackupDatabasePath() {
2897  return dbBackupPath;
2898  }
2899 
2914  public CaseDbTransaction beginTransaction() throws TskCoreException {
2915  return new CaseDbTransaction(this);
2916  }
2917 
2923  public String getDatabaseName() {
2924  return databaseName;
2925  }
2926 
2933  public String getDbDirPath() {
2934  return caseDirPath;
2935  }
2936 
2943  if (dbType == DbType.SQLITE) {
2944  rwLock.writeLock().lock();
2945  }
2946  }
2947 
2954  if (dbType == DbType.SQLITE) {
2955  rwLock.writeLock().unlock();
2956  }
2957  }
2958 
2965  if (dbType == DbType.SQLITE) {
2966  rwLock.readLock().lock();
2967  }
2968  }
2969 
2976  if (dbType == DbType.SQLITE) {
2977  rwLock.readLock().unlock();
2978  }
2979  }
2980 
2990  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2991  return openCase(dbPath, null);
2992  }
2993 
3004  @Beta
3005  public static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider) throws TskCoreException {
3006  try {
3007  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3008  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, provider);
3010  //don't wrap in new TskCoreException
3011  throw ex;
3012  } catch (Exception ex) {
3013  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
3014  }
3015  }
3016 
3028  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
3029  return openCase(databaseName, info, caseDir, null);
3030  }
3031 
3044  @Beta
3045  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentStreamProvider contentProvider) throws TskCoreException {
3046  try {
3047  /*
3048  * The flow of this method involves trying to open case and if
3049  * successful, return that case. If unsuccessful, an exception is
3050  * thrown. We catch any exceptions, and use tryConnect() to attempt
3051  * to obtain further information about the error. If tryConnect() is
3052  * unable to successfully connect, tryConnect() will throw a
3053  * TskCoreException with a message containing user-level error
3054  * reporting. If tryConnect() is able to connect, flow continues and
3055  * we rethrow the original exception obtained from trying to create
3056  * the case. In this way, we obtain more detailed information if we
3057  * are able, but do not lose any information if unable.
3058  */
3059  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3060  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType(), contentProvider);
3061  } catch (PropertyVetoException exp) {
3062  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3063  throw new TskCoreException(exp.getMessage(), exp);
3065  //don't wrap in new TskCoreException
3066  throw ex;
3067  } catch (Exception exp) {
3068  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3069  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3070  }
3071  }
3072 
3082  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
3083  return newCase(dbPath, null);
3084  }
3085 
3096  @Beta
3097  public static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider) throws TskCoreException {
3098  try {
3099  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
3100  factory.createCaseDatabase();
3101 
3102  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3103  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, contentProvider);
3104  } catch (Exception ex) {
3105  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
3106  }
3107  }
3108 
3124  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
3125  return newCase(caseName, info, caseDirPath, null);
3126  }
3127 
3128 
3145  @Beta
3146  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentStreamProvider contentProvider) throws TskCoreException {
3147  String databaseName = createCaseDataBaseName(caseName);
3148  try {
3161  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
3162  factory.createCaseDatabase();
3163 
3164  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3165  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
3166  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType(), contentProvider);
3167  } catch (PropertyVetoException exp) {
3168  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3169  throw new TskCoreException(exp.getMessage(), exp);
3170  } catch (Exception exp) {
3171  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3172  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3173  }
3174  }
3175 
3185  private static String createCaseDataBaseName(String candidateDbName) {
3186  String dbName;
3187  if (!candidateDbName.isEmpty()) {
3188  /*
3189  * Replace all non-ASCII characters.
3190  */
3191  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
3192 
3193  /*
3194  * Replace all control characters.
3195  */
3196  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
3197 
3198  /*
3199  * Replace /, \, :, ?, space, ' ".
3200  */
3201  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
3202 
3203  /*
3204  * Make it all lowercase.
3205  */
3206  dbName = dbName.toLowerCase();
3207 
3208  /*
3209  * Must start with letter or underscore. If not, prepend an
3210  * underscore.
3211  */
3212  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
3213  dbName = "_" + dbName;
3214  }
3215 
3216  /*
3217  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
3218  * uniqueness.
3219  */
3220  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
3221  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
3222  }
3223 
3224  } else {
3225  /*
3226  * Must start with letter or underscore.
3227  */
3228  dbName = "_";
3229  }
3230  /*
3231  * Add the time stmap.
3232  */
3233  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
3234  Date date = new Date();
3235  dbName = dbName + "_" + dateFormat.format(date);
3236 
3237  return dbName;
3238  }
3239 
3245  @Beta
3247  timelineEventsDisabled.set(true);
3248  }
3249 
3257  public Examiner getCurrentExaminer() throws TskCoreException {
3258 
3259  // return cached value if there's one
3260  if (cachedCurrentExaminer != null) {
3261  return cachedCurrentExaminer;
3262  }
3263  String loginName = System.getProperty("user.name");
3264  if (loginName == null || loginName.isEmpty()) {
3265  throw new TskCoreException("Failed to determine logged in user name.");
3266  }
3267 
3268  ResultSet resultSet = null;
3269  CaseDbConnection connection = null;
3271  try {
3272  connection = connections.getConnection();
3273  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3274  statement.clearParameters();
3275  statement.setString(1, loginName);
3276  resultSet = connection.executeQuery(statement);
3277  if (resultSet.next()) {
3278  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3279  return cachedCurrentExaminer;
3280  } else {
3281  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3282  }
3283 
3284  } catch (SQLException ex) {
3285  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3286  } finally {
3287  closeResultSet(resultSet);
3288  closeConnection(connection);
3290  }
3291 
3292  }
3293 
3303  Examiner getExaminerById(long id) throws TskCoreException {
3304 
3305  CaseDbConnection connection = null;
3306  ResultSet resultSet = null;
3308  try {
3309  connection = connections.getConnection();
3310  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3311  statement.clearParameters();
3312  statement.setLong(1, id);
3313  resultSet = connection.executeQuery(statement);
3314  if (resultSet.next()) {
3315  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3316  } else {
3317  throw new TskCoreException("Error getting examaminer for id = " + id);
3318  }
3319  } catch (SQLException ex) {
3320  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3321  } finally {
3322  closeResultSet(resultSet);
3323  closeConnection(connection);
3325  }
3326  }
3327 
3345  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3346  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
3347  }
3348 
3357  public List<Content> getRootObjects() throws TskCoreException {
3358  CaseDbConnection connection = null;
3359  Statement s = null;
3360  ResultSet rs = null;
3362  try {
3363  connection = connections.getConnection();
3364  s = connection.createStatement();
3365  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
3366  + "WHERE par_obj_id IS NULL"); //NON-NLS
3367  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3368  while (rs.next()) {
3369  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3370  }
3371 
3372  List<Content> rootObjs = new ArrayList<Content>();
3373  for (ObjectInfo i : infos) {
3374  if (null != i.type) {
3375  switch (i.type) {
3376  case IMG:
3377  rootObjs.add(getImageById(i.id));
3378  break;
3379  case ABSTRACTFILE:
3380  // Check if virtual dir for local files.
3381  AbstractFile af = getAbstractFileById(i.id);
3382  if (af instanceof VirtualDirectory) {
3383  rootObjs.add(af);
3384  } else {
3385  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3386  }
3387  break;
3388  case REPORT:
3389  break;
3390  case OS_ACCOUNT:
3391  break;
3392  case HOST_ADDRESS:
3393  break;
3394  case UNSUPPORTED:
3395  break;
3396  default:
3397  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3398  }
3399  }
3400  }
3401  return rootObjs;
3402  } catch (SQLException ex) {
3403  throw new TskCoreException("Error getting root objects", ex);
3404  } finally {
3405  closeResultSet(rs);
3406  closeStatement(s);
3407  closeConnection(connection);
3409  }
3410  }
3411 
3423  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3424 
3425  // check cached map first
3426  synchronized (deviceIdToDatasourceObjIdMap) {
3427  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3428  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3429  }
3430 
3431  CaseDbConnection connection = null;
3432  Statement s = null;
3433  ResultSet rs = null;
3435  try {
3436  connection = connections.getConnection();
3437  s = connection.createStatement();
3438  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3439  List<Long> dataSourceObjIds = new ArrayList<Long>();
3440  while (rs.next()) {
3441  dataSourceObjIds.add(rs.getLong("obj_id"));
3442 
3443  // Add to map of deviceID to data_source_obj_id.
3444  long ds_obj_id = rs.getLong("obj_id");
3445  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3446  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3447  } else {
3448  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3449  }
3450  }
3451  return dataSourceObjIds;
3452  } catch (SQLException ex) {
3453  throw new TskCoreException("Error getting data sources", ex);
3454  } finally {
3455  closeResultSet(rs);
3456  closeStatement(s);
3457  closeConnection(connection);
3459  }
3460  }
3461  }
3462 
3479  public List<DataSource> getDataSources() throws TskCoreException {
3480  CaseDbConnection connection = null;
3481  Statement statement = null;
3482  ResultSet resultSet = null;
3483  Statement statement2 = null;
3484  ResultSet resultSet2 = null;
3486  try {
3487  connection = connections.getConnection();
3488  statement = connection.createStatement();
3489  statement2 = connection.createStatement();
3490  resultSet = connection.executeQuery(statement,
3491  "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 "
3492  + "FROM data_source_info AS ds "
3493  + "LEFT JOIN tsk_image_info AS img "
3494  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3495 
3496  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3497  Map<Long, List<String>> imagePathsMap = getImagePaths();
3498 
3499  while (resultSet.next()) {
3500  DataSource dataSource;
3501  Long objectId = resultSet.getLong("obj_id");
3502  String deviceId = resultSet.getString("device_id");
3503  String timezone = resultSet.getString("time_zone");
3504  String type = resultSet.getString("type");
3505 
3506  if (type == null) {
3507  /*
3508  * No data found in 'tsk_image_info', so we build a
3509  * LocalFilesDataSource.
3510  */
3511 
3512  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3513  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3514  resultSet2.close();
3515 
3519  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3520  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3521  String parentPath = "/"; //NON-NLS
3522  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3523  } else {
3524  /*
3525  * Data found in 'tsk_image_info', so we build an Image.
3526  */
3527  Long ssize = resultSet.getLong("ssize");
3528  Long size = resultSet.getLong("size");
3529  String md5 = resultSet.getString("md5");
3530  String sha1 = resultSet.getString("sha1");
3531  String sha256 = resultSet.getString("sha256");
3532  String name = resultSet.getString("display_name");
3533 
3534  List<String> imagePaths = imagePathsMap.get(objectId);
3535  if (name == null) {
3536  if (imagePaths.size() > 0) {
3537  String path = imagePaths.get(0);
3538  name = (new java.io.File(path)).getName();
3539  } else {
3540  name = "";
3541  }
3542  }
3543 
3544  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3545  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3546  }
3547 
3548  dataSourceList.add(dataSource);
3549  }
3550 
3551  return dataSourceList;
3552 
3553  } catch (SQLException ex) {
3554  throw new TskCoreException("Error getting data sources", ex);
3555  } finally {
3556  closeResultSet(resultSet);
3557  closeStatement(statement);
3558  closeResultSet(resultSet2);
3559  closeStatement(statement2);
3560  closeConnection(connection);
3562  }
3563  }
3564 
3584  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3585  DataSource dataSource = null;
3586  CaseDbConnection connection = null;
3587  Statement statement = null;
3588  ResultSet resultSet = null;
3589  Statement statement2 = null;
3590  ResultSet resultSet2 = null;
3592  try {
3593  connection = connections.getConnection();
3594  statement = connection.createStatement();
3595  statement2 = connection.createStatement();
3596  resultSet = connection.executeQuery(statement,
3597  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3598  + "FROM data_source_info AS ds "
3599  + "LEFT JOIN tsk_image_info AS img "
3600  + "ON ds.obj_id = img.obj_id "
3601  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3602  if (resultSet.next()) {
3603  String deviceId = resultSet.getString("device_id");
3604  String timezone = resultSet.getString("time_zone");
3605  String type = resultSet.getString("type");
3606 
3607  if (type == null) {
3608  /*
3609  * No data found in 'tsk_image_info', so we build an
3610  * LocalFilesDataSource.
3611  */
3612 
3613  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3614  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3615 
3619  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3620  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3621  String parentPath = "/"; //NON-NLS
3622  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3623  } else {
3624  /*
3625  * Data found in 'tsk_image_info', so we build an Image.
3626  */
3627  Long ssize = resultSet.getLong("ssize");
3628  Long size = resultSet.getLong("size");
3629  String md5 = resultSet.getString("md5");
3630  String sha1 = resultSet.getString("sha1");
3631  String sha256 = resultSet.getString("sha256");
3632  String name = resultSet.getString("display_name");
3633 
3634  List<String> imagePaths = getImagePathsById(objectId, connection);
3635  if (name == null) {
3636  if (imagePaths.size() > 0) {
3637  String path = imagePaths.get(0);
3638  name = (new java.io.File(path)).getName();
3639  } else {
3640  name = "";
3641  }
3642  }
3643 
3644  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3645  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3646  }
3647  } else {
3648  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3649  }
3650  } catch (SQLException ex) {
3651  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3652  } finally {
3653  closeResultSet(resultSet);
3654  closeStatement(statement);
3655  closeResultSet(resultSet2);
3656  closeStatement(statement2);
3657  closeConnection(connection);
3659  }
3660 
3661  return dataSource;
3662  }
3663 
3676  @Deprecated
3677  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3678  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3679  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactTypeID)));
3680  return artifacts;
3681  }
3682 
3693  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3694  CaseDbConnection connection = null;
3695  ResultSet rs = null;
3697  try {
3698  connection = connections.getConnection();
3699 
3700  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3701  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3702  statement.clearParameters();
3703  statement.setLong(1, objId);
3704  rs = connection.executeQuery(statement);
3705  long count = 0;
3706  if (rs.next()) {
3707  count = rs.getLong("count");
3708  }
3709  return count;
3710  } catch (SQLException ex) {
3711  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3712  } finally {
3713  closeResultSet(rs);
3714  closeConnection(connection);
3716  }
3717  }
3718 
3729  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3730  CaseDbConnection connection = null;
3731  ResultSet rs = null;
3733  try {
3734  connection = connections.getConnection();
3735 
3736  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3737  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3738  statement.clearParameters();
3739  statement.setInt(1, artifactTypeID);
3740  rs = connection.executeQuery(statement);
3741  long count = 0;
3742  if (rs.next()) {
3743  count = rs.getLong("count");
3744  }
3745  return count;
3746  } catch (SQLException ex) {
3747  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3748  } finally {
3749  closeResultSet(rs);
3750  closeConnection(connection);
3752  }
3753  }
3754 
3766  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3767  CaseDbConnection connection = null;
3768  ResultSet rs = null;
3770  try {
3771  connection = connections.getConnection();
3772 
3773  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3774  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3775  statement.clearParameters();
3776  statement.setInt(2, artifactTypeID);
3777  statement.setLong(1, dataSourceID);
3778  rs = connection.executeQuery(statement);
3779  long count = 0;
3780  if (rs.next()) {
3781  count = rs.getLong("count");
3782  }
3783  return count;
3784  } catch (SQLException ex) {
3785  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3786  } finally {
3787  closeResultSet(rs);
3788  closeConnection(connection);
3790  }
3791  }
3792 
3809  @Deprecated
3810  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3812  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3813  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3814  + "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, "
3815  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3816  + " arts.review_status_id AS review_status_id " //NON-NLS
3817  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3818  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3819  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3820  + " AND attrs.value_text = '" + value + "'"
3821  + " AND types.artifact_type_id=arts.artifact_type_id"
3822  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) { //NON-NLS
3823 
3824  List<Long> analysisArtifactObjIds = new ArrayList<>();
3825  List<Long> dataArtifactObjIds = new ArrayList<>();
3826  while (resultSet.next()) {
3827  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3828  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3829  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3830  } else {
3831  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3832  }
3833  }
3834 
3835  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3836  if (!analysisArtifactObjIds.isEmpty()) {
3837  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3838  }
3839 
3840  if (!dataArtifactObjIds.isEmpty()) {
3841  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3842  }
3843  return artifacts;
3844  } catch (SQLException ex) {
3845  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3846  } finally {
3848  }
3849  }
3850 
3869  @Deprecated
3870  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3871  String valSubStr = "%" + subString; //NON-NLS
3872  if (startsWith == false) {
3873  valSubStr += "%"; //NON-NLS
3874  }
3875 
3877  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3878  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3879  + " 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
3880  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3881  + " arts.review_status_id AS review_status_id " //NON-NLS
3882  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3883  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3884  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3885  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3886  + " AND types.artifact_type_id=arts.artifact_type_id "
3887  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3888  List<Long> analysisArtifactObjIds = new ArrayList<>();
3889  List<Long> dataArtifactObjIds = new ArrayList<>();
3890  while (resultSet.next()) {
3891  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3892  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3893  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3894  } else {
3895  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3896  }
3897  }
3898 
3899  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3900  if (!analysisArtifactObjIds.isEmpty()) {
3901  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3902  }
3903 
3904  if (!dataArtifactObjIds.isEmpty()) {
3905  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3906  }
3907  return artifacts;
3908  } catch (SQLException ex) {
3909  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3910  } finally {
3912  }
3913  }
3914 
3930  @Deprecated
3931  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3933  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3934  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3935  + " 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, "
3936  + " types.type_name AS type_name, types.display_name AS display_name, "
3937  + " arts.review_status_id AS review_status_id "//NON-NLS
3938  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3939  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3940  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3941  + " AND attrs.value_int32 = " + value //NON-NLS
3942  + " AND types.artifact_type_id=arts.artifact_type_id "
3943  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3944  List<Long> analysisArtifactObjIds = new ArrayList<>();
3945  List<Long> dataArtifactObjIds = new ArrayList<>();
3946  while (resultSet.next()) {
3947  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3948  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3949  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3950  } else {
3951  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3952  }
3953  }
3954 
3955  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3956  if (!analysisArtifactObjIds.isEmpty()) {
3957  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3958  }
3959 
3960  if (!dataArtifactObjIds.isEmpty()) {
3961  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3962  }
3963  return artifacts;
3964  } catch (SQLException ex) {
3965  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3966  } finally {
3968  }
3969  }
3970 
3987  @Deprecated
3988  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3990  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3991  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3992  + " 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, "
3993  + " types.type_name AS type_name, types.display_name AS display_name, "
3994  + " arts.review_status_id AS review_status_id "//NON-NLS
3995  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3996  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3997  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3998  + " AND attrs.value_int64 = " + value //NON-NLS
3999  + " AND types.artifact_type_id=arts.artifact_type_id "
4000  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4001  List<Long> analysisArtifactObjIds = new ArrayList<>();
4002  List<Long> dataArtifactObjIds = new ArrayList<>();
4003  while (resultSet.next()) {
4004  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4005  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4006  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4007  } else {
4008  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4009  }
4010  }
4011 
4012  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4013  if (!analysisArtifactObjIds.isEmpty()) {
4014  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4015  }
4016 
4017  if (!dataArtifactObjIds.isEmpty()) {
4018  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4019  }
4020  return artifacts;
4021  } catch (SQLException ex) {
4022  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
4023  } finally {
4025  }
4026  }
4027 
4044  @Deprecated
4045  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
4047  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4048  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4049  + " 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, "
4050  + " types.type_name AS type_name, types.display_name AS display_name, "
4051  + " arts.review_status_id AS review_status_id "//NON-NLS
4052  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4053  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4054  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4055  + " AND attrs.value_double = " + value //NON-NLS
4056  + " AND types.artifact_type_id=arts.artifact_type_id "
4057  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4058  List<Long> analysisArtifactObjIds = new ArrayList<>();
4059  List<Long> dataArtifactObjIds = new ArrayList<>();
4060  while (resultSet.next()) {
4061  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4062  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4063  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4064  } else {
4065  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4066  }
4067  }
4068 
4069  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4070  if (!analysisArtifactObjIds.isEmpty()) {
4071  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4072  }
4073 
4074  if (!dataArtifactObjIds.isEmpty()) {
4075  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4076  }
4077  return artifacts;
4078  } catch (SQLException ex) {
4079  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4080  } finally {
4082  }
4083  }
4084 
4101  @Deprecated
4102  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
4103 
4105  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4106  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4107  + " 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, "
4108  + " types.type_name AS type_name, types.display_name AS display_name, "
4109  + " arts.review_status_id AS review_status_id "//NON-NLS
4110  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4111  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4112  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4113  + " AND attrs.value_byte = " + value //NON-NLS
4114  + " AND types.artifact_type_id=arts.artifact_type_id "
4115  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4116  List<Long> analysisArtifactObjIds = new ArrayList<>();
4117  List<Long> dataArtifactObjIds = new ArrayList<>();
4118  while (resultSet.next()) {
4119  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4120  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4121  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4122  } else {
4123  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4124  }
4125  }
4126 
4127  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4128  if (!analysisArtifactObjIds.isEmpty()) {
4129  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4130  }
4131 
4132  if (!dataArtifactObjIds.isEmpty()) {
4133  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4134  }
4135  return artifacts;
4136  } catch (SQLException ex) {
4137  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4138  } finally {
4140  }
4141  }
4142 
4150  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
4151  CaseDbConnection connection = null;
4152  Statement s = null;
4153  ResultSet rs = null;
4155  try {
4156  connection = connections.getConnection();
4157  s = connection.createStatement();
4158  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
4159  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
4160  while (rs.next()) {
4161  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4162  rs.getString("type_name"), rs.getString("display_name"),
4163  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4164  }
4165  return artifactTypes;
4166  } catch (SQLException ex) {
4167  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
4168  } finally {
4169  closeResultSet(rs);
4170  closeStatement(s);
4171  closeConnection(connection);
4173  }
4174  }
4175 
4184  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
4185  String typeIdList = "";
4186  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
4187  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
4188  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
4189  typeIdList += ", ";
4190  }
4191  }
4192  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
4193  + "WHERE artifact_type_id IN (" + typeIdList + ")";
4194  CaseDbConnection connection = null;
4195  Statement s = null;
4196  ResultSet rs = null;
4198  try {
4199  connection = connections.getConnection();
4200  s = connection.createStatement();
4201  rs = connection.executeQuery(s, query);
4202  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
4203  while (rs.next()) {
4204  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
4205  }
4206  return usedArts;
4207  } catch (SQLException ex) {
4208  throw new TskCoreException("Error getting artifact types in use", ex);
4209  } finally {
4210  closeResultSet(rs);
4211  closeStatement(s);
4212  closeConnection(connection);
4214  }
4215  }
4216 
4227  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
4228  CaseDbConnection connection = null;
4229  Statement s = null;
4230  ResultSet rs = null;
4232  try {
4233  connection = connections.getConnection();
4234  s = connection.createStatement();
4235  rs = connection.executeQuery(s,
4236  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
4237  + "types.type_name AS type_name, "
4238  + "types.display_name AS display_name, "
4239  + "types.category_type AS category_type "
4240  + "FROM blackboard_artifact_types AS types "
4241  + "INNER JOIN blackboard_artifacts AS arts "
4242  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
4243  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
4244  while (rs.next()) {
4245  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4246  rs.getString("type_name"), rs.getString("display_name"),
4247  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4248  }
4249  return uniqueArtifactTypes;
4250  } catch (SQLException ex) {
4251  throw new TskCoreException("Error getting attribute types", ex);
4252  } finally {
4253  closeResultSet(rs);
4254  closeStatement(s);
4255  closeConnection(connection);
4257  }
4258  }
4259 
4267  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
4268  CaseDbConnection connection = null;
4269  Statement s = null;
4270  ResultSet rs = null;
4272  try {
4273  connection = connections.getConnection();
4274  s = connection.createStatement();
4275  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
4276  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
4277  while (rs.next()) {
4278  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4279  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
4280  }
4281  return attribute_types;
4282  } catch (SQLException ex) {
4283  throw new TskCoreException("Error getting attribute types", ex);
4284  } finally {
4285  closeResultSet(rs);
4286  closeStatement(s);
4287  closeConnection(connection);
4289  }
4290  }
4291 
4303  public int getBlackboardAttributeTypesCount() throws TskCoreException {
4304  CaseDbConnection connection = null;
4305  Statement s = null;
4306  ResultSet rs = null;
4308  try {
4309  connection = connections.getConnection();
4310  s = connection.createStatement();
4311  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4312  int count = 0;
4313  if (rs.next()) {
4314  count = rs.getInt("count");
4315  }
4316  return count;
4317  } catch (SQLException ex) {
4318  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4319  } finally {
4320  closeResultSet(rs);
4321  closeStatement(s);
4322  closeConnection(connection);
4324  }
4325  }
4326 
4339  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4340  CaseDbConnection connection = null;
4341  ResultSet rs = null;
4343  try {
4344  connection = connections.getConnection();
4345 
4346  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4347  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4348  statement.clearParameters();
4349  statement.setLong(1, obj_id);
4350  statement.setInt(2, artifactTypeID);
4351  rs = connection.executeQuery(statement);
4352  long count = 0;
4353  if (rs.next()) {
4354  count = rs.getLong("count");
4355  }
4356  return count;
4357  } catch (SQLException ex) {
4358  throw new TskCoreException("Error getting blackboard artifact count", ex);
4359  } finally {
4360  closeResultSet(rs);
4361  closeConnection(connection);
4363  }
4364  }
4365 
4378  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4379  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4380  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeName), obj_id));
4381  return artifacts;
4382  }
4383 
4396  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4397  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4398  artifacts.addAll(blackboard.getArtifactsBySourceId(blackboard.getArtifactType(artifactTypeID), obj_id));
4399  return artifacts;
4400  }
4401 
4414  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4415  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4416  }
4417 
4430  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4431  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4432  if (artifactTypeID == -1) {
4433  return 0;
4434  }
4435  return getArtifactsCountHelper(artifactTypeID, obj_id);
4436  }
4437 
4450  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4451  return getArtifactsCountHelper(artifactTypeID, obj_id);
4452  }
4453 
4466  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4467  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4468  }
4469 
4481  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4482  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4483  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeName)));
4484  return artifacts;
4485  }
4486 
4498  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4499  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4500  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactType.getTypeID())));
4501  return artifacts;
4502  }
4503 
4519  @Deprecated
4520  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4521 
4522  String dataArtifactJoin = "tsk_data_artifacts AS datarts ON datarts.artifact_obj_id = arts.artifact_obj_id";
4523  String analysisResultJoin = "tsk_analysis_results AS anresult ON anresult.artifact_obj_id = arts.artifact_obj_id";
4524  String dataArtifactColumns = ", datarts.os_account_obj_id AS os_account_obj_id";
4525  String analysResultColumns = ", anresult.conclusion AS conclusion, anresult.significance AS significance, anresult.priority AS priority, anresult.configuration AS configuration, anresult.justification AS justification ";
4526 
4527  String formatQuery = "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4528  + "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, "
4529  + "types.type_name AS type_name, types.display_name AS display_name,"
4530  + "arts.review_status_id AS review_status_id %s "//NON-NLS
4531  + "FROM blackboard_artifacts AS arts "
4532  + "JOIN blackboard_attributes AS attrs ON arts.artifact_id = attrs.artifact_id "
4533  + "JOIN blackboard_artifact_types AS types ON types.artifact_type_id = arts.artifact_type_id " //NON-NLS
4534  + "LEFT JOIN %s "
4535  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4536  + "AND attrs.attribute_type_id = %d "
4537  + " AND arts.artifact_type_id = %d "
4538  + " AND attrs.value_text = '%s' " //NON-NLS
4539  + " AND types.artifact_type_id=arts.artifact_type_id "
4540  + " AND arts.review_status_id != %d";
4541 
4542  String query = String.format(formatQuery,
4543  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysResultColumns : dataArtifactColumns),
4544  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysisResultJoin : dataArtifactJoin),
4545  attrType.getTypeID(),
4546  artifactType.getTypeID(),
4547  value,
4549 
4551  try (CaseDbConnection connection = connections.getConnection(); Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
4552  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4553  while (rs.next()) {
4554  if (artifactType.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
4555  Long osAccountObjId = rs.getLong("os_account_obj_id");
4556  if (rs.wasNull()) {
4557  osAccountObjId = null;
4558  }
4559 
4560  artifacts.add(new DataArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4561  rs.getLong("artifact_obj_id"),
4562  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4563  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4564  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")), osAccountObjId, false));
4565  } else {
4566  artifacts.add(new AnalysisResult(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4567  rs.getLong("artifact_obj_id"),
4568  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4569  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4570  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")),
4571  new Score(Score.Significance.fromID(rs.getInt("significance")), Score.Priority.fromID(rs.getInt("priority"))),
4572  rs.getString("conclusion"), rs.getString("configuration"), rs.getString("justification")));
4573  }
4574  }
4575  return artifacts;
4576  } catch (SQLException ex) {
4577  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4578  } finally {
4580  }
4581  }
4582 
4594  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4595  List<DataArtifact> dataArtifacts = blackboard.getDataArtifactsWhere("artifacts.artifact_id = " + artifactID);
4596  if (!dataArtifacts.isEmpty()) {
4597  return dataArtifacts.get(0);
4598  }
4599 
4600  List<AnalysisResult> analysisResults = blackboard.getAnalysisResultsWhere("artifacts.artifact_id = " + artifactID);
4601  if (!analysisResults.isEmpty()) {
4602  return analysisResults.get(0);
4603  }
4604 
4605  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4606  }
4607 
4616  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4618  try (CaseDbConnection connection = connections.getConnection();) {
4619  addBlackBoardAttribute(attr, artifactTypeId, connection);
4620  } catch (SQLException ex) {
4621  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4622  } finally {
4624  }
4625  }
4626 
4636  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4637  CaseDbConnection connection = null;
4639  try {
4640  connection = connections.getConnection();
4641  connection.beginTransaction();
4642  for (final BlackboardAttribute attr : attributes) {
4643  addBlackBoardAttribute(attr, artifactTypeId, connection);
4644  }
4645  connection.commitTransaction();
4646  } catch (SQLException ex) {
4647  rollbackTransaction(connection);
4648  throw new TskCoreException("Error adding blackboard attributes", ex);
4649  } finally {
4650  closeConnection(connection);
4652  }
4653  }
4654 
4655  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4656  PreparedStatement statement;
4657  switch (attr.getAttributeType().getValueType()) {
4658  case STRING:
4659  case JSON:
4660  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4661  statement.clearParameters();
4662  statement.setString(7, attr.getValueString());
4663  break;
4664  case BYTE:
4665  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4666  statement.clearParameters();
4667  statement.setBytes(7, attr.getValueBytes());
4668  break;
4669  case INTEGER:
4670  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4671  statement.clearParameters();
4672  statement.setInt(7, attr.getValueInt());
4673  break;
4674  case LONG:
4675  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4676  statement.clearParameters();
4677  statement.setLong(7, attr.getValueLong());
4678  break;
4679  case DOUBLE:
4680  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4681  statement.clearParameters();
4682  statement.setDouble(7, attr.getValueDouble());
4683  break;
4684  case DATETIME:
4685  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4686  statement.clearParameters();
4687  statement.setLong(7, attr.getValueLong());
4688  break;
4689  default:
4690  throw new TskCoreException("Unrecognized artifact attribute value type");
4691  }
4692  statement.setLong(1, attr.getArtifactID());
4693  statement.setInt(2, artifactTypeId);
4694  statement.setString(3, attr.getSourcesCSV());
4695  statement.setString(4, "");
4696  statement.setInt(5, attr.getAttributeType().getTypeID());
4697  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4698  connection.executeUpdate(statement);
4699  }
4700 
4701  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4702  PreparedStatement statement;
4703  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4704  statement.clearParameters();
4705 
4706  statement.setLong(1, attr.getAttributeParentId());
4707  statement.setInt(2, attr.getAttributeType().getTypeID());
4708  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4709 
4710  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4711  statement.setBytes(4, attr.getValueBytes());
4712  } else {
4713  statement.setBytes(4, null);
4714  }
4715 
4716  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4717  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4718  statement.setString(5, attr.getValueString());
4719  } else {
4720  statement.setString(5, null);
4721  }
4722  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4723  statement.setInt(6, attr.getValueInt());
4724  } else {
4725  statement.setNull(6, java.sql.Types.INTEGER);
4726  }
4727 
4728  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4729  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4730  statement.setLong(7, attr.getValueLong());
4731  } else {
4732  statement.setNull(7, java.sql.Types.BIGINT);
4733  }
4734 
4735  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4736  statement.setDouble(8, attr.getValueDouble());
4737  } else {
4738  statement.setNull(8, java.sql.Types.DOUBLE);
4739  }
4740 
4741  connection.executeUpdate(statement);
4742  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4743  if (!resultSet.next()) {
4744  throw new TskCoreException(String.format("Failed to insert file attribute "
4745  + "with id=%d. The expected key was not generated", attr.getId()));
4746  }
4747 
4748  attr.setId(resultSet.getLong(1));
4749  }
4750  }
4751 
4762  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
4763  /*
4764  * WARNING: This is a temporary implementation that is not safe and
4765  * denormalizes the case datbase.
4766  *
4767  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
4768  * the sources of artifact attributes.
4769  */
4770  if (null == source || source.isEmpty()) {
4771  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
4772  }
4773  CaseDbConnection connection = null;
4775  Statement queryStmt = null;
4776  Statement updateStmt = null;
4777  ResultSet result = null;
4778  String newSources = "";
4779  try {
4780  connection = connections.getConnection();
4781  connection.beginTransaction();
4782  String valueClause = "";
4783  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
4784  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4785  switch (valueType) {
4786  case STRING:
4787  case JSON:
4788  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
4789  break;
4790  case INTEGER:
4791  valueClause = " value_int32 = " + attr.getValueInt();
4792  break;
4793  case LONG:
4794  case DATETIME:
4795  valueClause = " value_int64 = " + attr.getValueLong();
4796  break;
4797  case DOUBLE:
4798  valueClause = " value_double = " + attr.getValueDouble();
4799  break;
4800  default:
4801  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4802  }
4803  String query = "SELECT source FROM blackboard_attributes WHERE"
4804  + " artifact_id = " + attr.getArtifactID()
4805  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4806  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4807  + " AND " + valueClause + ";";
4808  queryStmt = connection.createStatement();
4809  updateStmt = connection.createStatement();
4810  result = connection.executeQuery(queryStmt, query);
4811  } else {
4812  /*
4813  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4814  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4815  * = ?
4816  */
4817  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4818  statement.clearParameters();
4819  statement.setLong(1, attr.getArtifactID());
4820  statement.setLong(2, attr.getAttributeType().getTypeID());
4821  statement.setBytes(3, attr.getValueBytes());
4822  result = connection.executeQuery(statement);
4823  }
4824  while (result.next()) {
4825  String oldSources = result.getString("source");
4826  if (null != oldSources && !oldSources.isEmpty()) {
4827  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4828  if (!uniqueSources.contains(source)) {
4829  newSources = oldSources + "," + source;
4830  } else {
4831  newSources = oldSources;
4832  }
4833  } else {
4834  newSources = source;
4835  }
4836  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4837  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4838  + " artifact_id = " + attr.getArtifactID()
4839  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4840  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4841  + " AND " + valueClause + ";";
4842  connection.executeUpdate(updateStmt, update);
4843  } else {
4844  /*
4845  * UPDATE blackboard_attributes SET source = ? WHERE
4846  * artifact_id = ? AND attribute_type_id = ? AND value_type
4847  * = 4 AND value_byte = ?
4848  */
4849  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4850  statement.clearParameters();
4851  statement.setString(1, newSources);
4852  statement.setLong(2, attr.getArtifactID());
4853  statement.setLong(3, attr.getAttributeType().getTypeID());
4854  statement.setBytes(4, attr.getValueBytes());
4855  connection.executeUpdate(statement);
4856  }
4857  }
4858  connection.commitTransaction();
4859  return newSources;
4860  } catch (SQLException ex) {
4861  rollbackTransaction(connection);
4862  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4863  } finally {
4864  closeResultSet(result);
4865  closeStatement(updateStmt);
4866  closeStatement(queryStmt);
4867  closeConnection(connection);
4869  }
4870  }
4871 
4886  @Deprecated
4887  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4888  try {
4889  return blackboard.getOrAddAttributeType(attrTypeString, valueType, displayName);
4890  } catch (BlackboardException ex) {
4891  throw new TskCoreException("Error adding artifact type: " + attrTypeString, ex);
4892  }
4893  }
4894 
4906  @Deprecated
4907  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4908  return blackboard.getAttributeType(attrTypeName);
4909  }
4910 
4922  @Deprecated
4923  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4924  return blackboard.getArtifactType(artTypeName);
4925  }
4926 
4943  @Deprecated
4944  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4945  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
4946  }
4947 
4963  @Deprecated
4964  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
4965  try {
4966  return blackboard.getOrAddArtifactType(displayName, displayName, category);
4967  } catch (BlackboardException ex) {
4968  throw new TskCoreException("Error getting or adding artifact type with name: " + artifactTypeName, ex);
4969  }
4970  }
4971 
4983  @Deprecated
4984  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4985  return blackboard.getBlackboardAttributes(artifact);
4986  }
4987 
4988 
5001  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
5002  CaseDbConnection connection = null;
5003  Statement s = null;
5004  ResultSet rs = null;
5006  try {
5007  connection = connections.getConnection();
5008  s = connection.createStatement();
5009  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
5010  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
5011  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
5012  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
5013  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
5014  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
5015  + "FROM blackboard_attributes " + whereClause); //NON-NLS
5016  ArrayList<BlackboardAttribute> matches = new ArrayList<>();
5017  while (rs.next()) {
5019  // attribute type is cached, so this does not necessarily call to the db
5020  type = blackboard.getAttributeType(rs.getInt("attribute_type_id"));
5022  rs.getLong("artifact_id"),
5023  type,
5024  rs.getString("source"),
5025  rs.getString("context"),
5026  rs.getInt("value_int32"),
5027  rs.getLong("value_int64"),
5028  rs.getDouble("value_double"),
5029  rs.getString("value_text"),
5030  rs.getBytes("value_byte"), this
5031  );
5032  matches.add(attr);
5033  }
5034  return matches;
5035  } catch (SQLException ex) {
5036  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5037  } finally {
5038  closeResultSet(rs);
5039  closeStatement(s);
5040  closeConnection(connection);
5042  }
5043  }
5044 
5056  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
5057  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
5058  + "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, "
5059  + "blackboard_artifacts.review_status_id AS review_status_id "
5060  + "FROM blackboard_artifacts " + whereClause;
5062  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
5063 
5064  List<Long> analysisArtifactObjIds = new ArrayList<>();
5065  List<Long> dataArtifactObjIds = new ArrayList<>();
5066  while (resultSet.next()) {
5067  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
5068  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5069  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5070  } else {
5071  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5072  }
5073  }
5074 
5075  ArrayList<BlackboardArtifact> matches = new ArrayList<>();
5076  if (!analysisArtifactObjIds.isEmpty()) {
5077  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
5078  }
5079 
5080  if (!dataArtifactObjIds.isEmpty()) {
5081  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
5082  }
5083 
5084  return matches;
5085  } catch (SQLException ex) {
5086  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5087  } finally {
5089  }
5090  }
5091 
5106  @Deprecated
5107  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
5108  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5109  if (type == null) {
5110  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
5111  }
5112 
5113  Category category = type.getCategory();
5114  if (category == null) {
5115  throw new TskCoreException(String.format("No category for %s (id: %d)",
5116  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
5117  type.getTypeID()));
5118  }
5119 
5120  Content content = getContentById(obj_id);
5121  if (content == null) {
5122  throw new TskCoreException("No content found for object id: " + obj_id);
5123  }
5124 
5125  switch (category) {
5126  case ANALYSIS_RESULT:
5127  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
5128  .getAnalysisResult();
5129  case DATA_ARTIFACT:
5130  return content.newDataArtifact(type, Collections.emptyList());
5131  default:
5132  throw new TskCoreException("Unknown category type: " + category.getName());
5133  }
5134  }
5135 
5148  @Deprecated
5149  @SuppressWarnings("deprecation")
5150  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
5151  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
5152  }
5153 
5169  @Deprecated
5170  @SuppressWarnings("deprecation")
5171  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5172  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5173  try (CaseDbConnection connection = connections.getConnection()) {
5174  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5175  }
5176  }
5177 
5178  @Deprecated
5179  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5180  try (CaseDbConnection connection = connections.getConnection()) {
5181  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5182  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5183  }
5184  }
5185 
5186  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5187 
5188  PreparedStatement statement;
5189  if (dbType == DbType.POSTGRESQL) {
5190  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5191  statement.clearParameters();
5192  statement.setLong(1, obj_id);
5193  statement.setLong(2, artifact_obj_id);
5194  statement.setLong(3, data_source_obj_id);
5195  statement.setInt(4, artifact_type_id);
5196  } else {
5197  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5198  statement.clearParameters();
5199  this.nextArtifactId++;
5200  statement.setLong(1, this.nextArtifactId);
5201  statement.setLong(2, obj_id);
5202  statement.setLong(3, artifact_obj_id);
5203  statement.setLong(4, data_source_obj_id);
5204  statement.setInt(5, artifact_type_id);
5205  }
5206 
5207  return statement;
5208  }
5209 
5226  @Deprecated
5227  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5228  BlackboardArtifact.Type type = blackboard.getArtifactType(artifact_type_id);
5229  try {
5230  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5231  return blackboard.newAnalysisResult(type, obj_id, data_source_obj_id, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList()).getAnalysisResult();
5232  } else {
5233  return blackboard.newDataArtifact(type, obj_id, data_source_obj_id, Collections.emptyList(), null);
5234  }
5235  } catch (BlackboardException ex) {
5236  throw new TskCoreException("Error creating a blackboard artifact", ex);
5237  }
5238  }
5239 
5258  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5259 
5260  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5261  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5262  }
5263 
5264  long artifactID;
5266  try {
5267  // add a row in tsk_objects
5268  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5269 
5270  // add a row in blackboard_artifacts table
5271  PreparedStatement insertArtifactstatement;
5272  ResultSet resultSet = null;
5273  try {
5274  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5275  connection.executeUpdate(insertArtifactstatement);
5276  resultSet = insertArtifactstatement.getGeneratedKeys();
5277  resultSet.next();
5278  artifactID = resultSet.getLong(1); //last_insert_rowid()
5279 
5280  // add a row in tsk_analysis_results if any data for it is set
5281  if (score.getSignificance() != Score.Significance.UNKNOWN
5282  || !StringUtils.isBlank(conclusion)
5283  || !StringUtils.isBlank(configuration)
5284  || !StringUtils.isBlank(justification)) {
5285 
5286  PreparedStatement analysisResultsStatement;
5287 
5288  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5289  analysisResultsStatement.clearParameters();
5290 
5291  analysisResultsStatement.setLong(1, artifactObjId);
5292  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5293  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5294  analysisResultsStatement.setInt(4, score.getPriority().getId());
5295  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5296  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5297 
5298  connection.executeUpdate(analysisResultsStatement);
5299  }
5300 
5301  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5302  artifactType.getTypeName(), artifactType.getDisplayName(),
5303  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5304  score, (conclusion != null) ? conclusion : "",
5305  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5306 
5307  } finally {
5308  closeResultSet(resultSet);
5309  }
5310 
5311  } catch (SQLException ex) {
5312  throw new TskCoreException("Error creating a analysis result", ex);
5313  } finally {
5315  }
5316  }
5317 
5330  boolean getContentHasChildren(Content content) throws TskCoreException {
5331  CaseDbConnection connection = null;
5332  ResultSet rs = null;
5334  try {
5335  connection = connections.getConnection();
5336 
5337  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5338  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5339  statement.clearParameters();
5340  statement.setLong(1, content.getId());
5341  rs = connection.executeQuery(statement);
5342  boolean hasChildren = false;
5343  if (rs.next()) {
5344  hasChildren = rs.getInt("count") > 0;
5345  }
5346  return hasChildren;
5347  } catch (SQLException e) {
5348  throw new TskCoreException("Error checking for children of parent " + content, e);
5349  } finally {
5350  closeResultSet(rs);
5351  closeConnection(connection);
5353  }
5354  }
5355 
5368  int getContentChildrenCount(Content content) throws TskCoreException {
5369 
5370  if (!this.getHasChildren(content)) {
5371  return 0;
5372  }
5373 
5374  CaseDbConnection connection = null;
5375  ResultSet rs = null;
5377  try {
5378  connection = connections.getConnection();
5379 
5380  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5381  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5382  statement.clearParameters();
5383  statement.setLong(1, content.getId());
5384  rs = connection.executeQuery(statement);
5385  int countChildren = -1;
5386  if (rs.next()) {
5387  countChildren = rs.getInt("count");
5388  }
5389  return countChildren;
5390  } catch (SQLException e) {
5391  throw new TskCoreException("Error checking for children of parent " + content, e);
5392  } finally {
5393  closeResultSet(rs);
5394  closeConnection(connection);
5396  }
5397  }
5398 
5410  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5411  CaseDbConnection connection = null;
5412  ResultSet rs = null;
5414  try {
5415  connection = connections.getConnection();
5416 
5417  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5418  statement.clearParameters();
5419  long parentId = parent.getId();
5420  statement.setLong(1, parentId);
5421  statement.setShort(2, type.getFileType());
5422  rs = connection.executeQuery(statement);
5423  return fileChildren(rs, connection, parentId);
5424  } catch (SQLException ex) {
5425  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5426  } finally {
5427  closeResultSet(rs);
5428  closeConnection(connection);
5430  }
5431  }
5432 
5442  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5443  CaseDbConnection connection = null;
5444  ResultSet rs = null;
5446  try {
5447  connection = connections.getConnection();
5448 
5449  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5450  statement.clearParameters();
5451  long parentId = parent.getId();
5452  statement.setLong(1, parentId);
5453  rs = connection.executeQuery(statement);
5454  return fileChildren(rs, connection, parentId);
5455  } catch (SQLException ex) {
5456  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5457  } finally {
5458  closeResultSet(rs);
5459  closeConnection(connection);
5461  }
5462  }
5463 
5475  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5476  CaseDbConnection connection = null;
5477  ResultSet rs = null;
5479  try {
5480  connection = connections.getConnection();
5481 
5482  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5483  statement.clearParameters();
5484  statement.setLong(1, parent.getId());
5485  statement.setShort(2, type.getFileType());
5486  rs = connection.executeQuery(statement);
5487  List<Long> children = new ArrayList<Long>();
5488  while (rs.next()) {
5489  children.add(rs.getLong("obj_id"));
5490  }
5491  return children;
5492  } catch (SQLException ex) {
5493  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5494  } finally {
5495  closeResultSet(rs);
5496  closeConnection(connection);
5498  }
5499  }
5500 
5510  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5511  CaseDbConnection connection = null;
5512  ResultSet rs = null;
5514  try {
5515  connection = connections.getConnection();
5516 
5517  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5518  statement.clearParameters();
5519  statement.setLong(1, parent.getId());
5520  rs = connection.executeQuery(statement);
5521  List<Long> children = new ArrayList<Long>();
5522  while (rs.next()) {
5523  children.add(rs.getLong("obj_id"));
5524  }
5525  return children;
5526  } catch (SQLException ex) {
5527  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5528  } finally {
5529  closeResultSet(rs);
5530  closeConnection(connection);
5532  }
5533  }
5534 
5545  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5546  CaseDbConnection connection = null;
5547  ResultSet rs = null;
5549  try {
5550  connection = connections.getConnection();
5551 
5552  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5553  statement.clearParameters();
5554  statement.setLong(1, parent.getId());
5555  rs = connection.executeQuery(statement);
5556  List<Long> children = new ArrayList<Long>();
5557  while (rs.next()) {
5558  children.add(rs.getLong("obj_id"));
5559  }
5560  return children;
5561  } catch (SQLException ex) {
5562  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5563  } finally {
5564  closeResultSet(rs);
5565  closeConnection(connection);
5567  }
5568  }
5569 
5579  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5580  long parentId = parent.getId();
5581  List<Content> lc = new ArrayList<>();
5582  lc.addAll(blackboard.getAnalysisResults(parentId));
5583  lc.addAll(blackboard.getDataArtifactsBySource(parentId));
5584  return lc;
5585  }
5586 
5595  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5596  CaseDbConnection connection = null;
5597  Statement s = null;
5598  ResultSet rs = null;
5600  try {
5601  connection = connections.getConnection();
5602  s = connection.createStatement();
5603  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5604  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5605  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5606  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5607  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5608  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5609  while (rs.next()) {
5610  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5611  }
5612  return infos;
5613  } catch (SQLException ex) {
5614  throw new TskCoreException("Error getting Children Info for Content", ex);
5615  } finally {
5616  closeResultSet(rs);
5617  closeStatement(s);
5618  closeConnection(connection);
5620  }
5621  }
5622 
5633  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5634  return getParentInfo(c.getId());
5635  }
5636 
5647  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5649  CaseDbConnection connection = null;
5650  Statement s = null;
5651  ResultSet rs = null;
5652  try {
5653  connection = connections.getConnection();
5654  s = connection.createStatement();
5655  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5656  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5657  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5658  + "WHERE child.obj_id = " + contentId); //NON-NLS
5659  if (rs.next()) {
5660  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5661  } else {
5662  return null;
5663  }
5664  } catch (SQLException ex) {
5665  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5666  } finally {
5667  closeResultSet(rs);
5668  closeStatement(s);
5669  closeConnection(connection);
5671  }
5672  }
5673 
5684  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5685  if (fsc.isRoot()) {
5686  // Given FsContent is a root object and can't have parent directory
5687  return null;
5688  } else {
5689  ObjectInfo parentInfo = getParentInfo(fsc);
5690  if (parentInfo == null) {
5691  return null;
5692  }
5693  Directory parent = null;
5694  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
5695  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
5696  } else {
5697  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
5698  }
5699  return parent;
5700  }
5701  }
5702 
5714  public Content getContentById(long id) throws TskCoreException {
5715  // First check to see if this exists in our frequently used content cache.
5716  Content content = frequentlyUsedContentMap.get(id);
5717  if (null != content) {
5718  return content;
5719  }
5720 
5721  long parentId;
5722  TskData.ObjectType type;
5723 
5724  CaseDbConnection connection = null;
5725  Statement s = null;
5726  ResultSet rs = null;
5728  try {
5729  connection = connections.getConnection();
5730  s = connection.createStatement();
5731  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
5732  if (!rs.next()) {
5733  return null;
5734  }
5735  parentId = rs.getLong("par_obj_id"); //NON-NLS
5736  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
5737  } catch (SQLException ex) {
5738  throw new TskCoreException("Error getting Content by ID.", ex);
5739  } finally {
5740  closeResultSet(rs);
5741  closeStatement(s);
5742  closeConnection(connection);
5744  }
5745 
5746  // Construct the object
5747  switch (type) {
5748  case IMG:
5749  content = getImageById(id);
5750  frequentlyUsedContentMap.put(id, content);
5751  break;
5752  case VS:
5753  content = getVolumeSystemById(id, parentId);
5754  break;
5755  case VOL:
5756  content = getVolumeById(id, parentId);
5757  frequentlyUsedContentMap.put(id, content);
5758  break;
5759  case POOL:
5760  content = getPoolById(id, parentId);
5761  break;
5762  case FS:
5763  content = getFileSystemById(id, parentId);
5764  frequentlyUsedContentMap.put(id, content);
5765  break;
5766  case ABSTRACTFILE:
5767  content = getAbstractFileById(id);
5768 
5769  // Add virtual and root directories to frequently used map.
5770  // Calling isRoot() on local directories goes up the entire directory structure
5771  // and they can only be the root of portable cases, so skip trying to add
5772  // them to the cache.
5773  if (((AbstractFile) content).isVirtual()
5774  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5775  frequentlyUsedContentMap.put(id, content);
5776  }
5777  break;
5778  case ARTIFACT:
5779  content = getArtifactById(id);
5780  break;
5781  case REPORT:
5782  content = getReportById(id);
5783  break;
5784  case OS_ACCOUNT:
5785  content = this.osAccountManager.getOsAccountByObjectId(id);
5786  break;
5787  case HOST_ADDRESS:
5788  content = hostAddressManager.getHostAddress(id);
5789  break;
5790  default:
5791  content = new UnsupportedContent(this, id);
5792  }
5793 
5794  return content;
5795  }
5796 
5804  String getFilePath(long id) {
5805 
5806  String filePath = null;
5807  CaseDbConnection connection = null;
5808  ResultSet rs = null;
5810  try {
5811  connection = connections.getConnection();
5812 
5813  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5814  statement.clearParameters();
5815  statement.setLong(1, id);
5816  rs = connection.executeQuery(statement);
5817  if (rs.next()) {
5818  filePath = rs.getString("path");
5819  }
5820  } catch (SQLException | TskCoreException ex) {
5821  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5822  } finally {
5823  closeResultSet(rs);
5824  closeConnection(connection);
5826  }
5827  return filePath;
5828  }
5829 
5837  TskData.EncodingType getEncodingType(long id) {
5838 
5839  TskData.EncodingType type = TskData.EncodingType.NONE;
5840  CaseDbConnection connection = null;
5841  ResultSet rs = null;
5843  try {
5844  connection = connections.getConnection();
5845  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5846  statement.clearParameters();
5847  statement.setLong(1, id);
5848  rs = connection.executeQuery(statement);
5849  if (rs.next()) {
5850  type = TskData.EncodingType.valueOf(rs.getInt(1));
5851  }
5852  } catch (SQLException | TskCoreException ex) {
5853  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5854  } finally {
5855  closeResultSet(rs);
5856  closeConnection(connection);
5858  }
5859  return type;
5860  }
5861 
5870  String getFileParentPath(long objectId, CaseDbConnection connection) {
5871  String parentPath = null;
5873  ResultSet rs = null;
5874  try {
5875  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5876  statement.clearParameters();
5877  statement.setLong(1, objectId);
5878  rs = connection.executeQuery(statement);
5879  if (rs.next()) {
5880  parentPath = rs.getString("parent_path");
5881  }
5882  } catch (SQLException ex) {
5883  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5884  } finally {
5885  closeResultSet(rs);
5887  }
5888  return parentPath;
5889  }
5890 
5899  String getFileName(long objectId, CaseDbConnection connection) {
5900  String fileName = null;
5902  ResultSet rs = null;
5903  try {
5904  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5905  statement.clearParameters();
5906  statement.setLong(1, objectId);
5907  rs = connection.executeQuery(statement);
5908  if (rs.next()) {
5909  fileName = rs.getString("name");
5910  }
5911  } catch (SQLException ex) {
5912  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5913  } finally {
5914  closeResultSet(rs);
5916  }
5917  return fileName;
5918  }
5919 
5930  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5931 
5932  DerivedFile.DerivedMethod method = null;
5933  CaseDbConnection connection = null;
5934  ResultSet rs1 = null;
5935  ResultSet rs2 = null;
5937  try {
5938  connection = connections.getConnection();
5939 
5940  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5941  statement.clearParameters();
5942  statement.setLong(1, id);
5943  rs1 = connection.executeQuery(statement);
5944  if (rs1.next()) {
5945  int method_id = rs1.getInt("derived_id");
5946  String rederive = rs1.getString("rederive");
5947  method = new DerivedFile.DerivedMethod(method_id, rederive);
5948  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5949  statement.clearParameters();
5950  statement.setInt(1, method_id);
5951  rs2 = connection.executeQuery(statement);
5952  if (rs2.next()) {
5953  method.setToolName(rs2.getString("tool_name"));
5954  method.setToolVersion(rs2.getString("tool_version"));
5955  method.setOther(rs2.getString("other"));
5956  }
5957  }
5958  } catch (SQLException e) {
5959  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5960  } finally {
5961  closeResultSet(rs2);
5962  closeResultSet(rs1);
5963  closeConnection(connection);
5965  }
5966  return method;
5967  }
5968 
5979  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5980  CaseDbConnection connection = connections.getConnection();
5981  try {
5982  return getAbstractFileById(id, connection);
5983  } finally {
5984  closeConnection(connection);
5985  }
5986  }
5987 
6000  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
6002  ResultSet rs = null;
6003  try {
6004  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
6005  statement.clearParameters();
6006  statement.setLong(1, objectId);
6007  rs = connection.executeQuery(statement);
6008  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
6009  if (files.size() > 0) {
6010  return files.get(0);
6011  } else {
6012  return null;
6013  }
6014  } catch (SQLException ex) {
6015  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
6016  } finally {
6017  closeResultSet(rs);
6019  }
6020  }
6021 
6033  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
6034 
6035  CaseDbConnection connection = null;
6036  ResultSet rs = null;
6038  try {
6039  connection = connections.getConnection();
6040 
6041  // get the artifact type.
6042  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
6043  statement.clearParameters();
6044  statement.setLong(1, id);
6045 
6046  rs = connection.executeQuery(statement);
6047  if (!rs.next()) {
6048  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
6049  }
6050 
6051  // based on the artifact type category, get the analysis result or the data artifact
6052  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(rs.getInt("artifact_type_id"));
6053  switch (artifactType.getCategory()) {
6054  case ANALYSIS_RESULT:
6055  return blackboard.getAnalysisResultById(id);
6056  case DATA_ARTIFACT:
6057  return blackboard.getDataArtifactById(id);
6058  default:
6059  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
6060  }
6061 
6062  } catch (SQLException ex) {
6063  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
6064  } finally {
6065  closeResultSet(rs);
6066  closeConnection(connection);
6068  }
6069  }
6070 
6084  @Deprecated
6085  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
6086  String query = "SELECT artifact_type_id, artifact_obj_id FROM blackboard_artifacts WHERE artifact_id = " + id;
6088 
6089  try (CaseDbConnection connection = connections.getConnection();
6090  Statement statement = connection.createStatement();
6091  ResultSet resultSet = statement.executeQuery(query);) {
6092  if (resultSet != null && resultSet.next()) {
6093  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
6094  long artifactObjId = resultSet.getLong("artifact_obj_id");
6095  switch (artifactType.getCategory()) {
6096  case ANALYSIS_RESULT:
6097  return blackboard.getAnalysisResultById(artifactObjId);
6098  case DATA_ARTIFACT:
6099  return blackboard.getDataArtifactById(artifactObjId);
6100  }
6101  }
6102  return null;
6103  } catch (SQLException ex) {
6104  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
6105  } finally {
6107  }
6108  }
6109 
6122  private long getFileSystemId(long fileId, CaseDbConnection connection) {
6124  ResultSet rs = null;
6125  long ret = -1;
6126  try {
6127  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
6128  statement.clearParameters();
6129  statement.setLong(1, fileId);
6130  rs = connection.executeQuery(statement);
6131  if (rs.next()) {
6132  ret = rs.getLong("fs_obj_id");
6133  if (ret == 0) {
6134  ret = -1;
6135  }
6136  }
6137  } catch (SQLException e) {
6138  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
6139  } finally {
6140  closeResultSet(rs);
6142  }
6143  return ret;
6144  }
6145 
6157  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6158  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
6159  CaseDbConnection connection = null;
6160  Statement statement = null;
6161  ResultSet resultSet = null;
6163  try {
6164  connection = connections.getConnection();
6165  statement = connection.createStatement();
6166  resultSet = connection.executeQuery(statement, query);
6167  resultSet.next();
6168  return (resultSet.getLong("count") > 0L);
6169  } catch (SQLException ex) {
6170  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6171  } finally {
6172  closeResultSet(resultSet);
6173  closeStatement(statement);
6174  closeConnection(connection);
6176  }
6177  }
6178 
6188  private static boolean containsLikeWildcard(String str) {
6189  if (str == null) {
6190  return false;
6191  } else {
6192  return str.contains("%") || str.contains("_");
6193  }
6194  }
6195 
6207  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6208  String ext = "";
6209  if (!containsLikeWildcard(fileName)) {
6210  ext = SleuthkitCase.extractExtension(fileName);
6211  }
6212 
6213  List<AbstractFile> files = new ArrayList<>();
6214  CaseDbConnection connection = null;
6215  ResultSet resultSet = null;
6217  try {
6218  connection = connections.getConnection();
6219 
6220  PreparedStatement statement;
6221  if (ext.isEmpty()) {
6222  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6223  statement.clearParameters();
6224  statement.setString(1, fileName.toLowerCase());
6225  statement.setLong(2, dataSource.getId());
6226  } else {
6227  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6228  statement.clearParameters();
6229  statement.setString(1, ext);
6230  statement.setString(2, fileName.toLowerCase());
6231  statement.setLong(3, dataSource.getId());
6232  }
6233 
6234  resultSet = connection.executeQuery(statement);
6235  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6236  } catch (SQLException e) {
6237  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6238  } finally {
6239  closeResultSet(resultSet);
6240  closeConnection(connection);
6242  }
6243  return files;
6244  }
6245 
6259  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6260  String ext = "";
6261  if (!containsLikeWildcard(fileName)) {
6262  ext = SleuthkitCase.extractExtension(fileName);
6263  }
6264 
6265  List<AbstractFile> files = new ArrayList<>();
6266  CaseDbConnection connection = null;
6267  ResultSet resultSet = null;
6269  try {
6270  connection = connections.getConnection();
6271  PreparedStatement statement;
6272  if (ext.isEmpty()) {
6273  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6274  statement.clearParameters();
6275  statement.setString(1, fileName.toLowerCase());
6276  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6277  statement.setLong(3, dataSource.getId());
6278  } else {
6279  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6280  statement.clearParameters();
6281  statement.setString(1, ext);
6282  statement.setString(2, fileName.toLowerCase());
6283  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6284  statement.setLong(4, dataSource.getId());
6285  }
6286 
6287  resultSet = connection.executeQuery(statement);
6288  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6289  } catch (SQLException e) {
6290  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6291  } finally {
6292  closeResultSet(resultSet);
6293  closeConnection(connection);
6295  }
6296  return files;
6297  }
6298 
6310  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6311  CaseDbTransaction localTrans = beginTransaction();
6312  try {
6313  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6314  localTrans.commit();
6315  localTrans = null;
6316  return newVD;
6317  } finally {
6318  if (null != localTrans) {
6319  try {
6320  localTrans.rollback();
6321  } catch (TskCoreException ex2) {
6322  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6323  }
6324  }
6325  }
6326  }
6327 
6340  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6341  ResultSet resultSet = null;
6343  try {
6344  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6345  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6346  statement.clearParameters();
6347  if (parentId != 0) {
6348  statement.setLong(1, parentId);
6349  } else {
6350  statement.setNull(1, java.sql.Types.BIGINT);
6351  }
6352  statement.setInt(2, objectType);
6353  connection.executeUpdate(statement);
6354  resultSet = statement.getGeneratedKeys();
6355 
6356  if (resultSet.next()) {
6357  if (parentId != 0) {
6358  setHasChildren(parentId);
6359  }
6360  return resultSet.getLong(1); //last_insert_rowid()
6361  } else {
6362  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6363  }
6364  } finally {
6365  closeResultSet(resultSet);
6367  }
6368  }
6369 
6387  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6388  if (transaction == null) {
6389  throw new TskCoreException("Passed null CaseDbTransaction");
6390  }
6391 
6392  ResultSet resultSet = null;
6393  try {
6394  // Get the parent path.
6395  CaseDbConnection connection = transaction.getConnection();
6396 
6397  String parentPath;
6398  Content parent = this.getAbstractFileById(parentId, connection);
6399  if (parent instanceof AbstractFile) {
6400  if (isRootDirectory((AbstractFile) parent, transaction)) {
6401  if (parent.getName().isEmpty()) {
6402  parentPath = "/";
6403  } else {
6404  parentPath = "/" + parent.getName() + "/";
6405  }
6406  } else {
6407  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6408  }
6409  } else {
6410  // The parent was either null or not an abstract file
6411  parentPath = "/";
6412  }
6413 
6414  // Insert a row for the virtual directory into the tsk_objects table.
6415  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6416 
6417  // Insert a row for the virtual directory into the tsk_files table.
6418  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6419  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id,extension,owner_uid, os_account_obj_id)
6420  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)
6421  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6422  statement.clearParameters();
6423  statement.setLong(1, newObjId);
6424 
6425  // If the parent is part of a file system, grab its file system ID
6426  Long fileSystemObjectId = null;
6427  if (0 != parentId) {
6428  fileSystemObjectId = this.getFileSystemId(parentId, connection);
6429  if (fileSystemObjectId != -1) {
6430  statement.setLong(2, fileSystemObjectId);
6431  } else {
6432  statement.setNull(2, java.sql.Types.BIGINT);
6433  fileSystemObjectId = null;
6434  }
6435  } else {
6436  statement.setNull(2, java.sql.Types.BIGINT);
6437  }
6438 
6439  // name
6440  statement.setString(3, directoryName);
6441 
6442  //type
6443  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6444  statement.setShort(5, (short) 1);
6445 
6446  //flags
6448  statement.setShort(6, dirType.getValue());
6450  statement.setShort(7, metaType.getValue());
6451 
6452  //allocated
6454  statement.setShort(8, dirFlag.getValue());
6455  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6456  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6457  statement.setShort(9, metaFlags);
6458 
6459  //size
6460  statement.setLong(10, 0);
6461 
6462  // nulls for params 11-14
6463  statement.setNull(11, java.sql.Types.BIGINT);
6464  statement.setNull(12, java.sql.Types.BIGINT);
6465  statement.setNull(13, java.sql.Types.BIGINT);
6466  statement.setNull(14, java.sql.Types.BIGINT);
6467 
6468  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6469  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6470  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6471 
6472  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6473  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6474 
6475  // parent path
6476  statement.setString(20, parentPath);
6477 
6478  // data source object id (same as object id if this is a data source)
6479  long dataSourceObjectId;
6480  if (0 == parentId) {
6481  dataSourceObjectId = newObjId;
6482  } else {
6483  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6484  }
6485  statement.setLong(21, dataSourceObjectId);
6486 
6487  //extension, since this is not really file we just set it to null
6488  statement.setString(22, null);
6489 
6490  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6491  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6492  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6493 
6494  connection.executeUpdate(statement);
6495 
6496  return new VirtualDirectory(this, newObjId, dataSourceObjectId, fileSystemObjectId, directoryName, dirType,
6497  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6498  parentPath);
6499  } catch (SQLException e) {
6500  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6501  } finally {
6502  closeResultSet(resultSet);
6503  }
6504  }
6505 
6518  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6519  CaseDbTransaction localTrans = beginTransaction();
6520  try {
6521  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6522  localTrans.commit();
6523  return newLD;
6524  } catch (TskCoreException ex) {
6525  try {
6526  localTrans.rollback();
6527  } catch (TskCoreException ex2) {
6528  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6529  }
6530  throw ex;
6531  }
6532  }
6533 
6551  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6552  if (transaction == null) {
6553  throw new TskCoreException("Passed null CaseDbTransaction");
6554  }
6555 
6556  ResultSet resultSet = null;
6557  try {
6558  // Get the parent path.
6559  CaseDbConnection connection = transaction.getConnection();
6560  AbstractFile parent = getAbstractFileById(parentId, connection);
6561  String parentPath;
6562  if ((parent == null) || isRootDirectory(parent, transaction)) {
6563  parentPath = "/";
6564  } else {
6565  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6566  }
6567 
6568  // Insert a row for the local directory into the tsk_objects table.
6569  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6570 
6571  // Insert a row for the local directory into the tsk_files table.
6572  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6573  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6574  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6575  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6576  statement.clearParameters();
6577  statement.setLong(1, newObjId);
6578 
6579  // The parent of a local directory will never be a file system
6580  statement.setNull(2, java.sql.Types.BIGINT);
6581 
6582  // name
6583  statement.setString(3, directoryName);
6584 
6585  //type
6586  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6587  statement.setShort(5, (short) 1);
6588 
6589  //flags
6591  statement.setShort(6, dirType.getValue());
6593  statement.setShort(7, metaType.getValue());
6594 
6595  //allocated
6597  statement.setShort(8, dirFlag.getValue());
6598  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6599  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6600  statement.setShort(9, metaFlags);
6601 
6602  //size
6603  statement.setLong(10, 0);
6604 
6605  // nulls for params 11-14
6606  statement.setNull(11, java.sql.Types.BIGINT);
6607  statement.setNull(12, java.sql.Types.BIGINT);
6608  statement.setNull(13, java.sql.Types.BIGINT);
6609  statement.setNull(14, java.sql.Types.BIGINT);
6610 
6611  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6612  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6613  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6614 
6615  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6616  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6617 
6618  // parent path
6619  statement.setString(20, parentPath);
6620 
6621  // data source object id
6622  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6623  statement.setLong(21, dataSourceObjectId);
6624 
6625  //extension, since this is a directory we just set it to null
6626  statement.setString(22, null);
6627 
6628  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6629  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6630  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6631 
6632  connection.executeUpdate(statement);
6633 
6634  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6635  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6636  parentPath);
6637  } catch (SQLException e) {
6638  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6639  } finally {
6640  closeResultSet(resultSet);
6641  }
6642  }
6643 
6663  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6664  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6665  }
6666 
6687  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6688 
6689  Statement statement = null;
6690  try {
6691  CaseDbConnection connection = transaction.getConnection();
6692 
6693  // Insert a row for the root virtual directory of the data source
6694  // into the tsk_objects table.
6695  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6696 
6697  // If no host was supplied, make one
6698  if (host == null) {
6699  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
6700  }
6701 
6702  // Insert a row for the virtual directory of the data source into
6703  // the data_source_info table.
6704  statement = connection.createStatement();
6705  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
6706  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
6707 
6708  // Insert a row for the root virtual directory of the data source
6709  // into the tsk_files table. Note that its data source object id is
6710  // its own object id.
6711  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
6712  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
6713  // atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6714  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
6715  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6716  preparedStatement.clearParameters();
6717  preparedStatement.setLong(1, newObjId);
6718  preparedStatement.setNull(2, java.sql.Types.BIGINT);
6719  preparedStatement.setString(3, rootDirectoryName);
6720  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6721  preparedStatement.setShort(5, (short) 1);
6723  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
6725  preparedStatement.setShort(7, metaType.getValue());
6727  preparedStatement.setShort(8, dirFlag.getValue());
6728  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6729  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6730  preparedStatement.setShort(9, metaFlags);
6731  preparedStatement.setLong(10, 0);
6732  preparedStatement.setNull(11, java.sql.Types.BIGINT);
6733  preparedStatement.setNull(12, java.sql.Types.BIGINT);
6734  preparedStatement.setNull(13, java.sql.Types.BIGINT);
6735  preparedStatement.setNull(14, java.sql.Types.BIGINT);
6736  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
6737  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6738  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6739  preparedStatement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6740  preparedStatement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6741  String parentPath = "/"; //NON-NLS
6742  preparedStatement.setString(20, parentPath);
6743  preparedStatement.setLong(21, newObjId);
6744  preparedStatement.setString(22, null); //extension, just set it to null
6745  preparedStatement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6746  preparedStatement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6747  preparedStatement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6748 
6749 
6750  connection.executeUpdate(preparedStatement);
6751 
6752  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, null, FileKnown.UNKNOWN, parentPath);
6753 
6754  } catch (SQLException ex) {
6755  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
6756  } finally {
6757  closeStatement(statement);
6758  }
6759  }
6760 
6780  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6781  String timezone, String md5, String sha1, String sha256,
6782  String deviceId,
6783  CaseDbTransaction transaction) throws TskCoreException {
6784  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
6785  }
6786 
6807  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6808  String timezone, String md5, String sha1, String sha256,
6809  String deviceId, Host host,
6810  CaseDbTransaction transaction) throws TskCoreException {
6811  Statement statement = null;
6812  try {
6813  // Insert a row for the Image into the tsk_objects table.
6814  CaseDbConnection connection = transaction.getConnection();
6815  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
6816 
6817  // Add a row to tsk_image_info
6818  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
6819  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
6820  preparedStatement.clearParameters();
6821  preparedStatement.setLong(1, newObjId);
6822  preparedStatement.setShort(2, (short) type.getValue());
6823  preparedStatement.setLong(3, sectorSize);
6824  preparedStatement.setString(4, timezone);
6825  //prevent negative size
6826  long savedSize = size < 0 ? 0 : size;
6827  preparedStatement.setLong(5, savedSize);
6828  preparedStatement.setString(6, md5);
6829  preparedStatement.setString(7, sha1);
6830  preparedStatement.setString(8, sha256);
6831  preparedStatement.setString(9, displayName);
6832  connection.executeUpdate(preparedStatement);
6833 
6834  // If there are paths, add them to tsk_image_names
6835  for (int i = 0; i < imagePaths.size(); i++) {
6836  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
6837  preparedStatement.clearParameters();
6838  preparedStatement.setLong(1, newObjId);
6839  preparedStatement.setString(2, imagePaths.get(i));
6840  preparedStatement.setLong(3, i);
6841  connection.executeUpdate(preparedStatement);
6842  }
6843 
6844  // Create the display name
6845  String name = displayName;
6846  if (name == null || name.isEmpty()) {
6847  if (imagePaths.size() > 0) {
6848  String path = imagePaths.get(0);
6849  name = (new java.io.File(path)).getName();
6850  } else {
6851  name = "";
6852  }
6853  }
6854 
6855  // Create a host if needed
6856  if (host == null) {
6857  if (name.isEmpty()) {
6858  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
6859  } else {
6860  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
6861  }
6862  }
6863 
6864  // Add a row to data_source_info
6865  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
6866  statement = connection.createStatement();
6867  preparedStatement.setLong(1, newObjId);
6868  preparedStatement.setString(2, deviceId);
6869  preparedStatement.setString(3, timezone);
6870  preparedStatement.setLong(4, new Date().getTime());
6871  preparedStatement.setLong(5, host.getHostId());
6872  connection.executeUpdate(preparedStatement);
6873 
6874  // Create the new Image object
6875  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
6876  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
6877  } catch (SQLException ex) {
6878  if (!imagePaths.isEmpty()) {
6879  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
6880  } else {
6881  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
6882  }
6883  } finally {
6884  closeStatement(statement);
6885  }
6886  }
6887 
6901  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
6902  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
6903  try {
6904  // Insert a row for the VolumeSystem into the tsk_objects table.
6905  CaseDbConnection connection = transaction.getConnection();
6906  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
6907 
6908  // Add a row to tsk_vs_info
6909  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
6910  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
6911  preparedStatement.clearParameters();
6912  preparedStatement.setLong(1, newObjId);
6913  preparedStatement.setShort(2, (short) type.getVsType());
6914  preparedStatement.setLong(3, imgOffset);
6915  preparedStatement.setLong(4, blockSize);
6916  connection.executeUpdate(preparedStatement);
6917 
6918  // Create the new VolumeSystem object
6919  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
6920  } catch (SQLException ex) {
6921  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
6922  parentObjId, imgOffset), ex);
6923  }
6924  }
6925 
6941  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
6942  long flags, CaseDbTransaction transaction) throws TskCoreException {
6943  try {
6944  // Insert a row for the Volume into the tsk_objects table.
6945  CaseDbConnection connection = transaction.getConnection();
6946  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
6947 
6948  // Add a row to tsk_vs_parts
6949  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
6950  PreparedStatement preparedStatement;
6951  if (this.dbType == DbType.POSTGRESQL) {
6952  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
6953  } else {
6954  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
6955  }
6956  preparedStatement.clearParameters();
6957  preparedStatement.setLong(1, newObjId);
6958  preparedStatement.setLong(2, addr);
6959  preparedStatement.setLong(3, start);
6960  preparedStatement.setLong(4, length);
6961  preparedStatement.setString(5, desc);
6962  preparedStatement.setShort(6, (short) flags);
6963  connection.executeUpdate(preparedStatement);
6964 
6965  // Create the new Volume object
6966  return new Volume(this, newObjId, addr, start, length, flags, desc);
6967  } catch (SQLException ex) {
6968  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
6969  }
6970  }
6971 
6983  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
6984  try {
6985  // Insert a row for the Pool into the tsk_objects table.
6986  CaseDbConnection connection = transaction.getConnection();
6987  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
6988 
6989  // Add a row to tsk_pool_info
6990  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
6991  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
6992  preparedStatement.clearParameters();
6993  preparedStatement.setLong(1, newObjId);
6994  preparedStatement.setShort(2, type.getValue());
6995  connection.executeUpdate(preparedStatement);
6996 
6997  // Create the new Pool object
6998  return new Pool(this, newObjId, type.getName(), type.getValue());
6999  } catch (SQLException ex) {
7000  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
7001  }
7002  }
7003 
7022  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
7023  long rootInum, long firstInum, long lastInum, String displayName,
7024  CaseDbTransaction transaction) throws TskCoreException {
7025  try {
7026  // Insert a row for the FileSystem into the tsk_objects table.
7027  CaseDbConnection connection = transaction.getConnection();
7028  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
7029 
7030  // Get the data source object ID
7031  long dataSourceId = getDataSourceObjectId(connection, newObjId);
7032 
7033  // Add a row to tsk_fs_info
7034  // 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)
7035  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
7036  preparedStatement.clearParameters();
7037  preparedStatement.setLong(1, newObjId);
7038  preparedStatement.setLong(2, dataSourceId);
7039  preparedStatement.setLong(3, imgOffset);
7040  preparedStatement.setInt(4, type.getValue());
7041  preparedStatement.setLong(5, blockSize);
7042  preparedStatement.setLong(6, blockCount);
7043  preparedStatement.setLong(7, rootInum);
7044  preparedStatement.setLong(8, firstInum);
7045  preparedStatement.setLong(9, lastInum);
7046  preparedStatement.setString(10, displayName);
7047  connection.executeUpdate(preparedStatement);
7048 
7049  // Create the new FileSystem object
7050  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
7051  firstInum, lastInum);
7052  } catch (SQLException ex) {
7053  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
7054  imgOffset, parentObjId), ex);
7055  }
7056  }
7057 
7083  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7084  String fileName,
7085  long metaAddr, int metaSeq,
7086  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7087  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7088  long ctime, long crtime, long atime, long mtime,
7089  boolean isFile, Content parent) throws TskCoreException {
7090 
7091  CaseDbTransaction transaction = beginTransaction();
7092  try {
7093 
7094  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
7095  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
7096  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
7097  OsAccount.NO_OWNER_ID, null,
7098  Collections.emptyList(), transaction);
7099 
7100  transaction.commit();
7101  transaction = null;
7102  return fileSystemFile;
7103  } finally {
7104  if (null != transaction) {
7105  try {
7106  transaction.rollback();
7107  } catch (TskCoreException ex2) {
7108  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7109  }
7110  }
7111  }
7112  }
7113 
7151  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7152  String fileName,
7153  long metaAddr, int metaSeq,
7154  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7155  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7156  long ctime, long crtime, long atime, long mtime,
7157  String md5Hash, String sha256Hash, String mimeType,
7158  boolean isFile, Content parent, String ownerUid,
7159  OsAccount osAccount, List<Attribute> fileAttributes,
7160  CaseDbTransaction transaction) throws TskCoreException {
7161 
7162  return addFileSystemFile(dataSourceObjId, fsObjId,
7163  fileName,
7164  metaAddr, metaSeq,
7165  attrType, attrId,
7166  dirFlag, metaFlags, size,
7167  ctime, crtime, atime, mtime,
7168  md5Hash, sha256Hash, null,
7169  mimeType,
7170  isFile, parent, ownerUid,
7171  osAccount, fileAttributes,
7172  transaction);
7173  }
7174 
7214  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7215  String fileName,
7216  long metaAddr, int metaSeq,
7217  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7218  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7219  long ctime, long crtime, long atime, long mtime,
7220  String md5Hash, String sha256Hash, String sha1Hash,
7221  String mimeType, boolean isFile,
7222  Content parent, String ownerUid,
7223  OsAccount osAccount, List<Attribute> fileAttributes,
7224  CaseDbTransaction transaction) throws TskCoreException {
7225  return addFileSystemFile(dataSourceObjId, fsObjId,
7226  fileName,
7227  metaAddr, metaSeq,
7228  attrType, attrId,
7229  dirFlag, metaFlags, size,
7230  ctime, crtime, atime, mtime,
7231  md5Hash, sha256Hash, sha1Hash,
7232  mimeType,
7233  isFile, parent, ownerUid,
7234  osAccount, TskData.CollectedStatus.UNKNOWN, fileAttributes,
7235  transaction);
7236  }
7237 
7278  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7279  String fileName,
7280  long metaAddr, int metaSeq,
7281  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7282  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7283  long ctime, long crtime, long atime, long mtime,
7284  String md5Hash, String sha256Hash, String sha1Hash,
7285  String mimeType, boolean isFile,
7286  Content parent, String ownerUid,
7287  OsAccount osAccount, TskData.CollectedStatus collected,
7288  List<Attribute> fileAttributes,
7289  CaseDbTransaction transaction) throws TskCoreException {
7290  TimelineManager timelineManager = getTimelineManager();
7291 
7292  Statement queryStatement = null;
7293  String parentPath = "/";
7294  try {
7295  CaseDbConnection connection = transaction.getConnection();
7296 
7297  // Insert a row for the local/logical file into the tsk_objects table.
7298  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7299  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7300 
7301  if (parent instanceof AbstractFile) {
7302  AbstractFile parentFile = (AbstractFile) parent;
7303  if (isRootDirectory(parentFile, transaction)) {
7304  parentPath = "/";
7305  } else {
7306  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7307  }
7308  } else {
7309  parentPath = "/";
7310  }
7311 
7312  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7313  statement.clearParameters();
7314  statement.setLong(1, objectId); // obj_is
7315  statement.setLong(2, fsObjId); // fs_obj_id
7316  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7317  statement.setShort(4, (short) attrType.getValue()); // attr_type
7318  statement.setInt(5, attrId); // attr_id
7319  statement.setString(6, fileName); // name
7320  statement.setLong(7, metaAddr); // meta_addr
7321  statement.setInt(8, metaSeq); // meta_addr
7322  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7323  statement.setShort(10, (short) 1); // has_path
7325  statement.setShort(11, dirType.getValue()); // dir_type
7327  statement.setShort(12, metaType.getValue()); // meta_type
7328  statement.setShort(13, dirFlag.getValue()); // dir_flags
7329  statement.setShort(14, metaFlags); // meta_flags
7330  statement.setLong(15, size < 0 ? 0 : size);
7331  statement.setLong(16, ctime);
7332  statement.setLong(17, crtime);
7333  statement.setLong(18, atime);
7334  statement.setLong(19, mtime);
7335  statement.setString(20, md5Hash);
7336  statement.setString(21, sha256Hash);
7337  statement.setString(22, sha1Hash);
7338  statement.setString(23, mimeType);
7339  statement.setString(24, parentPath);
7340  final String extension = extractExtension(fileName);
7341  statement.setString(25, extension);
7342  statement.setString(26, ownerUid);
7343  if (null != osAccount) {
7344  statement.setLong(27, osAccount.getId());
7345  } else {
7346  statement.setNull(27, java.sql.Types.BIGINT); // osAccountObjId
7347  }
7348  statement.setLong(28, collected.getType());
7349 
7350  connection.executeUpdate(statement);
7351 
7352  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7353  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7354  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, sha1Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7355 
7356  if (!timelineEventsDisabled.get()) {
7357  timelineManager.addEventsForNewFile(derivedFile, connection);
7358  }
7359 
7360  for (Attribute fileAttribute : fileAttributes) {
7361  fileAttribute.setAttributeParentId(objectId);
7362  fileAttribute.setCaseDatabase(this);
7363  addFileAttribute(fileAttribute, connection);
7364  }
7365 
7366  if (osAccount != null) {
7367  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
7368  }
7369 
7370  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7371  attrType, attrId, fileName, metaAddr, metaSeq,
7372  dirType, metaType, dirFlag, metaFlags,
7373  size, ctime, crtime, atime, mtime,
7374  (short) 0, 0, 0, md5Hash, sha256Hash, sha1Hash, null, parentPath, mimeType,
7375  extension, ownerUid, osAccountId, collected, fileAttributes);
7376 
7377  } catch (SQLException ex) {
7378  throw new TskCoreException(String.format("Failed to INSERT file system file %s (%s) with parent id %d in tsk_files table", fileName, parentPath, parent.getId()), ex);
7379  } finally {
7380  closeStatement(queryStatement);
7381  }
7382  }
7383 
7392  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7393  CaseDbConnection connection = null;
7394  Statement s = null;
7395  ResultSet rs = null;
7397  try {
7398  connection = connections.getConnection();
7399  s = connection.createStatement();
7400  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7401  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7402  + " AND obj_id = data_source_obj_id"
7403  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7404  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7405  while (rs.next()) {
7406  virtDirRootIds.add(virtualDirectory(rs, connection));
7407  }
7408  return virtDirRootIds;
7409  } catch (SQLException ex) {
7410  throw new TskCoreException("Error getting local files virtual folder id", ex);
7411  } finally {
7412  closeResultSet(rs);
7413  closeStatement(s);
7414  closeConnection(connection);
7416  }
7417  }
7418 
7431  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7432  assert (null != fileRanges);
7433  if (null == fileRanges) {
7434  throw new TskCoreException("TskFileRange object is null");
7435  }
7436 
7437  assert (null != parent);
7438  if (null == parent) {
7439  throw new TskCoreException("Conent is null");
7440  }
7441 
7442  String parentPath;
7443  if (parent instanceof AbstractFile) {
7444  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7445  } else {
7446  parentPath = "/";
7447  }
7448 
7449  CaseDbTransaction transaction = null;
7450  Statement statement = null;
7451  ResultSet resultSet = null;
7452 
7453  try {
7454  transaction = beginTransaction();
7455  CaseDbConnection connection = transaction.getConnection();
7456 
7457  // If the parent is part of a file system, grab its file system ID
7458  Long fileSystemObjectId;
7459  if (0 != parent.getId()) {
7460  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
7461  if (fileSystemObjectId == -1) {
7462  fileSystemObjectId = null;
7463  }
7464  } else {
7465  fileSystemObjectId = null;
7466  }
7467 
7468  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<>();
7469  for (TskFileRange fileRange : fileRanges) {
7470  /*
7471  * Insert a row for the Tsk file range into the tsk_objects
7472  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7473  * ?)
7474  */
7475  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7476  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7477  /*
7478  * Insert a row for the Tsk file range into the tsk_files table:
7479  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7480  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7481  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7482  * parent_path, data_source_obj_id,extension, owner_uid,
7483  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7484  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
7485  */
7486  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7487  prepStmt.clearParameters();
7488  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7489  if (fileSystemObjectId != null) {
7490  prepStmt.setLong(2, fileSystemObjectId);// fs_obj_id
7491  } else {
7492  prepStmt.setNull(2, java.sql.Types.BIGINT);
7493  }
7494  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]
7495  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7496  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7497  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7498  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7499  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7500  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7501  prepStmt.setLong(10, fileRange.getByteLen()); // size
7502  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7503  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7504  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7505  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7506  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7507  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7508  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7509 
7510  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7511  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7512  prepStmt.setString(20, parentPath); // parent path
7513  prepStmt.setLong(21, parent.getId()); // data_source_obj_id
7514 
7515  //extension, since this is not a FS file we just set it to null
7516  prepStmt.setString(22, null);
7517 
7518  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7519  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7520  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7521 
7522  connection.executeUpdate(prepStmt);
7523 
7524  /*
7525  * Insert a row in the tsk_layout_file table for each chunk of
7526  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7527  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7528  */
7529  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7530  prepStmt.clearParameters();
7531  prepStmt.setLong(1, fileRangeId); // obj_id
7532  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7533  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7534  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7535  connection.executeUpdate(prepStmt);
7536 
7537  /*
7538  * Create a layout file representation of the carved file.
7539  */
7540  fileRangeLayoutFiles.add(new LayoutFile(this,
7541  fileRangeId,
7542  parent.getId(),
7543  fileSystemObjectId,
7544  Long.toString(fileRange.getSequence()),
7549  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7550  fileRange.getByteLen(),
7551  0L, 0L, 0L, 0L,
7552  null, null, null,
7554  parent.getUniquePath(),
7555  null,
7556  OsAccount.NO_OWNER_ID,
7557  OsAccount.NO_ACCOUNT));
7558  }
7559 
7560  transaction.commit();
7561  transaction = null;
7562  return fileRangeLayoutFiles;
7563 
7564  } catch (SQLException ex) {
7565  throw new TskCoreException("Failed to add layout files to case database", ex);
7566  } finally {
7567  closeResultSet(resultSet);
7568  closeStatement(statement);
7569 
7570  if (null != transaction) {
7571  try {
7572  transaction.rollback();
7573  } catch (TskCoreException ex2) {
7574  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7575  }
7576  }
7577  }
7578  }
7579 
7586  private class CarvedFileDirInfo {
7587 
7588  final VirtualDirectory currentFolder;
7589  AtomicInteger count;
7590 
7591  CarvedFileDirInfo(VirtualDirectory currentFolder) {
7592  this.currentFolder = currentFolder;
7593  count = new AtomicInteger(0);
7594  }
7595 
7596  CarvedFileDirInfo(VirtualDirectory currentFolder, int count) {
7597  this.currentFolder = currentFolder;
7598  this.count = new AtomicInteger(count);
7599  }
7600 
7607  boolean isFull() {
7608  return count.get() >= MAX_CARVED_FILES_PER_FOLDER;
7609  }
7610 
7614  void incrementFileCounter() {
7615  count.incrementAndGet();
7616  }
7617  }
7618 
7628  private CarvedFileDirInfo getMostRecentCarvedDirInfo(VirtualDirectory carvedFilesBaseDir) throws TskCoreException {
7629  VirtualDirectory mostRecentDir = null;
7630  for (Content child : carvedFilesBaseDir.getChildren()) {
7631  if (isValidCarvedFileSubfolder(child)) {
7632  if (mostRecentDir == null
7633  || (mostRecentDir.getId() < child.getId())) {
7634  mostRecentDir = (VirtualDirectory) child;
7635  }
7636  }
7637  }
7638 
7639  if (mostRecentDir != null) {
7640  return new CarvedFileDirInfo(mostRecentDir, mostRecentDir.getChildrenCount());
7641  }
7642  return null;
7643  }
7644 
7653  private boolean isValidCarvedFileSubfolder(Content subfolder) {
7654  if (!(subfolder instanceof VirtualDirectory)) {
7655  return false;
7656  }
7657  return subfolder.getName().matches("^[0-9]+$");
7658  }
7659 
7673  private CarvedFileDirInfo createCarvedFilesSubfolder(Content carvedFilesBaseDir, CarvedFileDirInfo currentSubfolderInfo) throws TskCoreException {
7674  int nextIndex = 1;
7675  if (currentSubfolderInfo != null) {
7676  try {
7677  int currentIndex = Integer.parseInt(currentSubfolderInfo.currentFolder.getName());
7678  nextIndex = currentIndex + 1;
7679  } catch (NumberFormatException ex) {
7680  throw new TskCoreException("Unexpected name format for carved files subdirectory with ID: " + currentSubfolderInfo.currentFolder.getId() + " (" + currentSubfolderInfo.currentFolder.getName() + ")", ex);
7681  }
7682  }
7683 
7684  VirtualDirectory carvedFilesSubdir = addVirtualDirectory(carvedFilesBaseDir.getId(), Integer.toString(nextIndex));
7685  return new CarvedFileDirInfo(carvedFilesSubdir);
7686  }
7687 
7699  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
7700  assert (null != carvingResult);
7701  if (null == carvingResult) {
7702  throw new TskCoreException("Carving is null");
7703  }
7704  assert (null != carvingResult.getParent());
7705  if (null == carvingResult.getParent()) {
7706  throw new TskCoreException("Carving result has null parent");
7707  }
7708  assert (null != carvingResult.getCarvedFiles());
7709  if (null == carvingResult.getCarvedFiles()) {
7710  throw new TskCoreException("Carving result has null carved files");
7711  }
7712  CaseDbTransaction transaction = null;
7713  Statement statement = null;
7714  ResultSet resultSet = null;
7715  try {
7716 
7717  /*
7718  * Carved files are "re-parented" as children of the $CarvedFiles
7719  * virtual directory of the root file system, volume, or image
7720  * ancestor of the carved files parent, but if no such ancestor is
7721  * found, then the parent specified in the carving result is used.
7722  */
7723  Content root = carvingResult.getParent();
7724  while (null != root) {
7725  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
7726  break;
7727  }
7728  root = root.getParent();
7729  }
7730  if (null == root) {
7731  root = carvingResult.getParent();
7732  }
7733 
7734  /*
7735  * Get or create the $CarvedFiles virtual directory for the root
7736  * ancestor.
7737  */
7738  CarvedFileDirInfo carvedFilesDirInfo = null;
7739  synchronized (carvedFileDirsLock) {
7740  // Get the subfolder currently in use (if there is one)
7741  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7742  if (carvedFilesDirInfo != null) {
7743  carvedFilesDirInfo.incrementFileCounter();
7744 
7745  // If the current folder is full, create a new one.
7746  if (carvedFilesDirInfo.isFull()) {
7747  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesDirInfo.currentFolder.getParent(), carvedFilesDirInfo);
7748  }
7749  }
7750 
7751  if (null == carvedFilesDirInfo) {
7752  List<Content> rootChildren;
7753  if (root instanceof FileSystem) {
7754  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
7755  } else {
7756  rootChildren = root.getChildren();
7757  }
7758  for (Content child : rootChildren) {
7759  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
7760 
7761  VirtualDirectory baseDir = (VirtualDirectory) child;
7762 
7763  // Get the most recent subfolder in the carved files folder.
7764  carvedFilesDirInfo = getMostRecentCarvedDirInfo(baseDir);
7765 
7766  // If there are no subfolders, create one.
7767  if (carvedFilesDirInfo == null) {
7768  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, null);
7769  }
7770 
7771  // If there are already too many files in the subfolder, create a new one.
7772  if (carvedFilesDirInfo.isFull()) {
7773  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, carvedFilesDirInfo);
7774  }
7775 
7776  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7777  break;
7778  }
7779  }
7780  if (carvedFilesDirInfo == null) {
7781  // If we get here, we didn't have a carved files base folder in the case, so we need to make that and
7782  // the first subfolder.
7783 
7784  long parId = root.getId();
7785  // $CarvedFiles should be a child of the root directory, not the file system
7786  if (root instanceof FileSystem) {
7787  Content rootDir = ((FileSystem) root).getRootDirectory();
7788  parId = rootDir.getId();
7789  }
7790  VirtualDirectory carvedFilesBaseDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
7791  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, null);
7792  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7793  }
7794  }
7795  }
7796 
7797  /*
7798  * Add the carved files to the database as children of the
7799  * $CarvedFile directory of the root ancestor.
7800  */
7801  VirtualDirectory carvedFilesBaseDir = (VirtualDirectory) carvedFilesDirInfo.currentFolder.getParent();
7802  transaction = beginTransaction();
7803  CaseDbConnection connection = transaction.getConnection();
7804  String parentPath = getFileParentPath(carvedFilesDirInfo.currentFolder.getId(), connection) + carvedFilesDirInfo.currentFolder.getName() + "/";
7805  List<LayoutFile> carvedFiles = new ArrayList<>();
7806  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
7807 
7808  /*
7809  * Check if we need to change to a new subfolder.
7810  */
7811  VirtualDirectory carvedFilesDir = carvedFilesDirInfo.currentFolder;
7812  if (carvedFilesDirInfo.isFull()) {
7813  // To prevent deadlocks involving the case write lock and the carvedFileDirsLock,
7814  // commit the current transaction and then start a new one
7815  // after switching to the new folder.
7816  transaction.commit();
7817 
7818  synchronized (carvedFileDirsLock) {
7819  // Get the current copy from the map - another thread may have just created a new folder.
7820  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7821  if (carvedFilesDirInfo.isFull()) {
7822  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, carvedFilesDirInfo);
7823  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7824  carvedFilesDir = carvedFilesDirInfo.currentFolder;
7825  }
7826  }
7827 
7828  // Start a new transaction.
7829  transaction = beginTransaction();
7830  connection = transaction.getConnection();
7831  parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
7832 
7833  }
7834  carvedFilesDirInfo.incrementFileCounter();
7835 
7836  /*
7837  * Insert a row for the carved file into the tsk_objects table:
7838  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7839  */
7840  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7841 
7842 
7843  /*
7844  * Insert a row for the carved file into the tsk_files table:
7845  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7846  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7847  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7848  * parent_path, data_source_obj_id,extenion, owner_uid,
7849  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7850  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7851  */
7852  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7853  prepStmt.clearParameters();
7854  prepStmt.setLong(1, carvedFileId); // obj_id
7855  Long fileSystemObjectId;
7856  if (root instanceof FileSystem) {
7857  prepStmt.setLong(2, root.getId()); // fs_obj_id
7858  fileSystemObjectId = root.getId();
7859  } else {
7860  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7861  fileSystemObjectId = null;
7862  }
7863  prepStmt.setString(3, carvedFile.getName()); // name
7864  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
7865  prepStmt.setShort(5, (short) 1); // has_path
7866  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7867  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7868  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7869  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7870  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
7871  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7872  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7873  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7874  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7875  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7876  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7877  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7878 
7879  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7880  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7881  prepStmt.setString(20, parentPath); // parent path
7882  prepStmt.setLong(21, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
7883  prepStmt.setString(22, extractExtension(carvedFile.getName())); //extension
7884 
7885  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7886  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7887  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7888 
7889  connection.executeUpdate(prepStmt);
7890 
7891  /*
7892  * Insert a row in the tsk_layout_file table for each chunk of
7893  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7894  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7895  */
7896  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7897  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
7898  prepStmt.clearParameters();
7899  prepStmt.setLong(1, carvedFileId); // obj_id
7900  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7901  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7902  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7903  connection.executeUpdate(prepStmt);
7904  }
7905 
7906  /*
7907  * Create a layout file representation of the carved file.
7908  */
7909  carvedFiles.add(new LayoutFile(this,
7910  carvedFileId,
7911  carvedFilesDir.getDataSourceObjectId(),
7912  fileSystemObjectId,
7913  carvedFile.getName(),
7918  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7919  carvedFile.getSizeInBytes(),
7920  0L, 0L, 0L, 0L,
7921  null, null, null,
7923  parentPath,
7924  null,
7925  OsAccount.NO_OWNER_ID,
7926  OsAccount.NO_ACCOUNT));
7927  }
7928 
7929  transaction.commit();
7930  transaction = null;
7931  return carvedFiles;
7932 
7933  } catch (SQLException ex) {
7934  throw new TskCoreException("Failed to add carved files to case database", ex);
7935  } finally {
7936  closeResultSet(resultSet);
7937  closeStatement(statement);
7938 
7939  if (null != transaction) {
7940  try {
7941  transaction.rollback();
7942  } catch (TskCoreException ex2) {
7943  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7944  }
7945  }
7946  }
7947  }
7948 
7979  public DerivedFile addDerivedFile(String fileName, String localPath,
7980  long size, long ctime, long crtime, long atime, long mtime,
7981  boolean isFile, Content parentObj,
7982  String rederiveDetails, String toolName, String toolVersion,
7983  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7984  CaseDbTransaction transaction = beginTransaction();
7985  try {
7986  DerivedFile df = addDerivedFile(fileName, localPath,
7987  size, ctime, crtime, atime, mtime,
7988  isFile, parentObj,
7989  rederiveDetails, toolName, toolVersion,
7990  otherDetails, encodingType, transaction);
7991  transaction.commit();
7992  return df;
7993  } catch (TskCoreException ex) {
7994  transaction.rollback();
7995  throw ex;
7996  }
7997  }
7998 
7999  public DerivedFile addDerivedFile(String fileName, String localPath,
8000  long size, long ctime, long crtime, long atime, long mtime,
8001  boolean isFile, Content parentObj,
8002  String rederiveDetails, String toolName, String toolVersion,
8003  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
8004  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8005  localPath = localPath.replaceAll("^[/\\\\]+", "");
8006 
8007  TimelineManager timelineManager = getTimelineManager();
8008 
8009  CaseDbConnection connection = transaction.getConnection();
8010  try {
8011  final long parentId = parentObj.getId();
8012  String parentPath = "";
8013  if (parentObj instanceof BlackboardArtifact) {
8014  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8015  } else if (parentObj instanceof AbstractFile) {
8016  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8017  }
8018 
8019  // Insert a row for the derived file into the tsk_objects table.
8020  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8021  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8022 
8023  // Insert a row for the virtual directory into the tsk_files table.
8024  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8025  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
8026  // parent_path, data_source_obj_id, extension)
8027  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
8028  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8029  statement.clearParameters();
8030  statement.setLong(1, newObjId);
8031 
8032  // If the parentFile is part of a file system, use its file system object ID.
8033  Long fsObjId = this.getFileSystemId(parentId, connection);
8034  if (fsObjId != -1) {
8035  statement.setLong(2, fsObjId);
8036  } else {
8037  fsObjId = null;
8038  statement.setNull(2, java.sql.Types.BIGINT);
8039  }
8040  statement.setString(3, fileName);
8041 
8042  //type, has_path
8043  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8044  statement.setShort(5, (short) 1);
8045 
8046  //flags
8048  statement.setShort(6, dirType.getValue());
8050  statement.setShort(7, metaType.getValue());
8051 
8052  //note: using alloc under assumption that derived files derive from alloc files
8054  statement.setShort(8, dirFlag.getValue());
8055  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8056  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8057  statement.setShort(9, metaFlags);
8058 
8059  //size
8060  //prevent negative size
8061  long savedSize = size < 0 ? 0 : size;
8062  statement.setLong(10, savedSize);
8063 
8064  //mactimes
8065  //long ctime, long crtime, long atime, long mtime,
8066  statement.setLong(11, ctime);
8067  statement.setLong(12, crtime);
8068  statement.setLong(13, atime);
8069  statement.setLong(14, mtime);
8070 
8071  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
8072  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8073  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8074 
8075  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8076  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
8077 
8078  //parent path
8079  statement.setString(20, parentPath);
8080 
8081  // root data source object id
8082  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
8083  statement.setLong(21, dataSourceObjId);
8084  final String extension = extractExtension(fileName);
8085  //extension
8086  statement.setString(22, extension);
8087 
8088  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8089  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8090  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8091 
8092  connection.executeUpdate(statement);
8093 
8094  //add localPath
8095  addFilePath(connection, newObjId, localPath, encodingType);
8096 
8097  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
8098  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
8099 
8100  if (!timelineEventsDisabled.get()) {
8101  timelineManager.addEventsForNewFile(derivedFile, connection);
8102  }
8103 
8104  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
8105  return derivedFile;
8106  } catch (SQLException ex) {
8107  throw new TskCoreException("Failed to add derived file to case database", ex);
8108  }
8109  }
8110 
8141  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8142  long size, long ctime, long crtime, long atime, long mtime,
8143  boolean isFile, String mimeType,
8144  String rederiveDetails, String toolName, String toolVersion,
8145  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
8146 
8147  CaseDbTransaction trans = null;
8148  try {
8149  Content parentObj = derivedFile.getParent();
8150 
8151  trans = beginTransaction();
8152  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
8153  size, ctime, crtime, atime, mtime,
8154  isFile, mimeType,
8155  rederiveDetails, toolName, toolVersion,
8156  otherDetails, encodingType, parentObj, trans);
8157  trans.commit();
8158  return updatedFile;
8159  } catch (TskCoreException ex) {
8160  if (trans != null) {
8161  trans.rollback();
8162  }
8163  throw ex;
8164  }
8165  }
8166 
8167  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8168  long size, long ctime, long crtime, long atime, long mtime,
8169  boolean isFile, String mimeType,
8170  String rederiveDetails, String toolName, String toolVersion,
8171  String otherDetails, TskData.EncodingType encodingType,
8172  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
8173 
8174  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8175  localPath = localPath.replaceAll("^[/\\\\]+", "");
8176 
8177  ResultSet rs = null;
8178  try {
8179  final long parentId = parentObj.getId();
8180  String parentPath = "";
8181  if (parentObj instanceof BlackboardArtifact) {
8182  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8183  } else if (parentObj instanceof AbstractFile) {
8184  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8185  }
8186  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
8187  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
8188  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
8189  statement.clearParameters();
8190 
8191  //type
8192  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8193 
8194  //flags
8196  statement.setShort(2, dirType.getValue());
8198  statement.setShort(3, metaType.getValue());
8199 
8200  //note: using alloc under assumption that derived files derive from alloc files
8202  statement.setShort(4, dirFlag.getValue());
8203  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8204  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8205  statement.setShort(5, metaFlags);
8206 
8207  //size
8208  //prevent negative size
8209  long savedSize = size < 0 ? 0 : size;
8210  statement.setLong(6, savedSize);
8211 
8212  //mactimes
8213  //long ctime, long crtime, long atime, long mtime,
8214  statement.setLong(7, ctime);
8215  statement.setLong(8, crtime);
8216  statement.setLong(9, atime);
8217  statement.setLong(10, mtime);
8218  statement.setString(11, mimeType);
8219  statement.setString(12, String.valueOf(derivedFile.getId()));
8220  trans.getConnection().executeUpdate(statement);
8221 
8222  //add localPath
8223  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
8224 
8225  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
8226  Long fileSystemObjId = derivedFile.getFileSystemObjectId().orElse(null);
8227  final String extension = extractExtension(derivedFile.getName());
8228  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, fileSystemObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
8229  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension,
8230  derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
8231  } catch (SQLException ex) {
8232  throw new TskCoreException("Failed to add derived file to case database", ex);
8233  } finally {
8234  closeResultSet(rs);
8235  }
8236  }
8237 
8257  public LocalFile addLocalFile(String fileName, String localPath,
8258  long size, long ctime, long crtime, long atime, long mtime,
8259  boolean isFile, TskData.EncodingType encodingType,
8260  AbstractFile parent) throws TskCoreException {
8261 
8262  CaseDbTransaction localTrans = beginTransaction();
8263  try {
8264  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
8265  localTrans.commit();
8266  localTrans = null;
8267  return created;
8268  } finally {
8269  if (null != localTrans) {
8270  try {
8271  localTrans.rollback();
8272  } catch (TskCoreException ex2) {
8273  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8274  }
8275  }
8276  }
8277  }
8278 
8303  public LocalFile addLocalFile(String fileName, String localPath,
8304  long size, long ctime, long crtime, long atime, long mtime,
8305  boolean isFile, TskData.EncodingType encodingType,
8306  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8307 
8308  return addLocalFile(fileName, localPath,
8309  size, ctime, crtime, atime, mtime,
8310  null, null, null,
8311  isFile, encodingType,
8312  parent, transaction);
8313  }
8314 
8343  public LocalFile addLocalFile(String fileName, String localPath,
8344  long size, long ctime, long crtime, long atime, long mtime,
8345  String md5, String sha256, FileKnown known, String mimeType,
8346  boolean isFile, TskData.EncodingType encodingType,
8347  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8348 
8349  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8350  md5, sha256, known, mimeType, isFile, encodingType,
8351  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8352 
8353  }
8354 
8385  public LocalFile addLocalFile(String fileName, String localPath,
8386  long size, long ctime, long crtime, long atime, long mtime,
8387  String md5, String sha256, FileKnown known, String mimeType,
8388  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8389  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8390 
8391  return addLocalFile(fileName, localPath,
8392  size, ctime, crtime, atime, mtime,
8393  md5, sha256, null, known, mimeType,
8394  isFile, encodingType, osAccountId, ownerAccount,
8395  parent, transaction);
8396  }
8397 
8398 
8431  public LocalFile addLocalFile(String fileName, String localPath,
8432  long size, long ctime, long crtime, long atime, long mtime,
8433  String md5, String sha256, String sha1Hash, FileKnown known, String mimeType,
8434  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8435  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8436  CaseDbConnection connection = transaction.getConnection();
8437  Statement queryStatement = null;
8438  try {
8439 
8440  // Insert a row for the local/logical file into the tsk_objects table.
8441  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8442  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8443 
8444  // Insert a row for the local/logical file into the tsk_files table.
8445  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8446  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
8447  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8448  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
8449  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8450  statement.clearParameters();
8451  statement.setLong(1, objectId);
8452  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8453  statement.setString(3, fileName);
8454  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8455  statement.setShort(5, (short) 1);
8457  statement.setShort(6, dirType.getValue());
8459  statement.setShort(7, metaType.getValue());
8461  statement.setShort(8, dirFlag.getValue());
8462  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8463  statement.setShort(9, metaFlags);
8464  //prevent negative size
8465  long savedSize = size < 0 ? 0 : size;
8466  statement.setLong(10, savedSize);
8467  statement.setLong(11, ctime);
8468  statement.setLong(12, crtime);
8469  statement.setLong(13, atime);
8470  statement.setLong(14, mtime);
8471  statement.setString(15, md5);
8472  statement.setString(16, sha256);
8473  statement.setString(17, sha1Hash); // sha1
8474 
8475  if (known != null) {
8476  statement.setByte(18, known.getFileKnownValue());
8477  } else {
8478  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue());
8479  }
8480  statement.setString(19, mimeType);
8481  String parentPath;
8482  long dataSourceObjId;
8483 
8484  if (parent instanceof AbstractFile) {
8485  AbstractFile parentFile = (AbstractFile) parent;
8486  if (isRootDirectory(parentFile, transaction)) {
8487  parentPath = "/";
8488  } else {
8489  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8490  }
8491  dataSourceObjId = parentFile.getDataSourceObjectId();
8492  } else {
8493  parentPath = "/";
8494  dataSourceObjId = getDataSourceObjectId(connection, parent);
8495  }
8496  statement.setString(20, parentPath);
8497  statement.setLong(21, dataSourceObjId);
8498  final String extension = extractExtension(fileName);
8499  statement.setString(22, extension);
8500 
8501  if (ownerAccount != null) {
8502  statement.setString(23, ownerAccount); // ownerUid
8503  } else {
8504  statement.setNull(23, java.sql.Types.VARCHAR);
8505  }
8506 
8507  if (osAccountId != null) {
8508  statement.setLong(24, osAccountId); // osAccountObjId
8509  } else {
8510  statement.setNull(24, java.sql.Types.BIGINT);
8511  }
8512 
8513  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8514 
8515  connection.executeUpdate(statement);
8516  addFilePath(connection, objectId, localPath, encodingType);
8517  LocalFile localFile = new LocalFile(this,
8518  objectId,
8519  fileName,
8521  dirType,
8522  metaType,
8523  dirFlag,
8524  metaFlags,
8525  savedSize,
8526  ctime, crtime, atime, mtime,
8527  mimeType, md5, sha256, sha1Hash, known,
8528  parent.getId(), parentPath,
8529  dataSourceObjId,
8530  localPath,
8531  encodingType, extension,
8532  ownerAccount, osAccountId);
8533  if (!timelineEventsDisabled.get()) {
8534  getTimelineManager().addEventsForNewFile(localFile, connection);
8535  }
8536  return localFile;
8537 
8538  } catch (SQLException ex) {
8539  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);
8540  } finally {
8541  closeStatement(queryStatement);
8542  }
8543  }
8544 
8550  private class RootDirectoryKey {
8551 
8552  private long dataSourceId;
8553  private Long fileSystemId;
8554 
8555  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8556  this.dataSourceId = dataSourceId;
8557  this.fileSystemId = fileSystemId;
8558  }
8559 
8560  @Override
8561  public int hashCode() {
8562  int hash = 7;
8563  hash = 41 * hash + Objects.hashCode(dataSourceId);
8564  hash = 41 * hash + Objects.hashCode(fileSystemId);
8565  return hash;
8566  }
8567 
8568  @Override
8569  public boolean equals(Object obj) {
8570  if (this == obj) {
8571  return true;
8572  }
8573  if (obj == null) {
8574  return false;
8575  }
8576  if (getClass() != obj.getClass()) {
8577  return false;
8578  }
8579 
8580  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8581  if (dataSourceId != otherKey.dataSourceId) {
8582  return false;
8583  }
8584 
8585  if (fileSystemId != null) {
8586  return fileSystemId.equals(otherKey.fileSystemId);
8587  }
8588  return (otherKey.fileSystemId == null);
8589  }
8590  }
8591 
8604  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8605 
8606  // First check if we know the root directory for this data source and optionally
8607  // file system. There is only one root, so if we know it we can simply compare
8608  // this file ID to the known root directory.
8609  Long fsObjId = null;
8610  if (file instanceof FsContent) {
8611  fsObjId = ((FsContent) file).getFileSystemId();
8612  }
8613  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8614  synchronized (rootDirectoryMapLock) {
8615  if (rootDirectoryMap.containsKey(key)) {
8616  return rootDirectoryMap.get(key).equals(file.getId());
8617  }
8618  }
8619 
8620  // Fallback cache. We store the result of each database lookup
8621  // so it won't be done multiple times in a row. In practice, this will
8622  // only be used if this method was never called on the root directory.
8623  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8624  if (isRoot != null) {
8625  return isRoot;
8626  }
8627 
8628  CaseDbConnection connection = transaction.getConnection();
8629  Statement statement = null;
8630  ResultSet resultSet = null;
8631 
8632  try {
8633  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8634  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8635  + "WHERE ChildRow.obj_id = %s;", file.getId());
8636 
8637  statement = connection.createStatement();
8638  resultSet = statement.executeQuery(query);
8639  if (resultSet.next()) {
8640  long parentId = resultSet.getLong("parent_object_id");
8641  if (parentId == 0) {
8642  return true;
8643  }
8644  int type = resultSet.getInt("parent_type");
8645  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8646  || type == TskData.ObjectType.VS.getObjectType()
8647  || type == TskData.ObjectType.VOL.getObjectType()
8648  || type == TskData.ObjectType.FS.getObjectType();
8649  if (result == true) {
8650  synchronized (rootDirectoryMapLock) {
8651  // This is a root directory so save it
8652  rootDirectoryMap.put(key, file.getId());
8653  }
8654  }
8655  isRootDirectoryCache.put(file.getId(), result);
8656  return result;
8657 
8658  } else {
8659  // This is a root directory so save it
8660  synchronized (rootDirectoryMapLock) {
8661  rootDirectoryMap.put(key, file.getId());
8662  }
8663  isRootDirectoryCache.put(file.getId(), true);
8664 
8665  return true; // The file has no parent
8666 
8667  }
8668  } catch (SQLException ex) {
8669  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
8670  } finally {
8671  closeResultSet(resultSet);
8672  closeStatement(statement);
8673  }
8674  }
8675 
8695  public LayoutFile addLayoutFile(String fileName,
8696  long size,
8697  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
8698  long ctime, long crtime, long atime, long mtime,
8699  List<TskFileRange> fileRanges,
8700  Content parent) throws TskCoreException {
8701 
8702  if (null == parent) {
8703  throw new TskCoreException("Parent can not be null");
8704  }
8705 
8706  String parentPath;
8707  if (parent instanceof AbstractFile) {
8708  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
8709  } else {
8710  parentPath = "/";
8711  }
8712 
8713  CaseDbTransaction transaction = null;
8714  Statement statement = null;
8715  ResultSet resultSet = null;
8716  try {
8717  transaction = beginTransaction();
8718  CaseDbConnection connection = transaction.getConnection();
8719 
8720  /*
8721  * Insert a row for the layout file into the tsk_objects table:
8722  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8723  */
8724  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8725 
8726  /*
8727  * Insert a row for the file into the tsk_files table: INSERT INTO
8728  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
8729  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
8730  * mtime, md5, known, mime_type, parent_path,
8731  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
8732  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8733  */
8734  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8735  prepStmt.clearParameters();
8736  prepStmt.setLong(1, newFileId); // obj_id
8737 
8738  // If the parent is part of a file system, grab its file system ID
8739  Long fileSystemObjectId;
8740  if (0 != parent.getId()) {
8741  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
8742  if (fileSystemObjectId != -1) {
8743  prepStmt.setLong(2, fileSystemObjectId);
8744  } else {
8745  prepStmt.setNull(2, java.sql.Types.BIGINT);
8746  fileSystemObjectId = null;
8747  }
8748  } else {
8749  prepStmt.setNull(2, java.sql.Types.BIGINT);
8750  fileSystemObjectId = null;
8751  }
8752  prepStmt.setString(3, fileName); // name
8753  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
8754  prepStmt.setShort(5, (short) 0); // has_path
8755  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8756  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8757  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
8758  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
8759  //prevent negative size
8760  long savedSize = size < 0 ? 0 : size;
8761  prepStmt.setLong(10, savedSize); // size
8762  prepStmt.setLong(11, ctime); // ctime
8763  prepStmt.setLong(12, crtime); // crtime
8764  prepStmt.setLong(13, atime); // atime
8765  prepStmt.setLong(14, mtime); // mtime
8766  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8767  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8768  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8769 
8770  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8771  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
8772  prepStmt.setString(20, parentPath); // parent path
8773  prepStmt.setLong(21, parent.getDataSource().getId()); // data_source_obj_id
8774 
8775  prepStmt.setString(22, extractExtension(fileName)); //extension
8776 
8777  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8778  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8779  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8780 
8781  connection.executeUpdate(prepStmt);
8782 
8783  /*
8784  * Insert a row in the tsk_layout_file table for each chunk of the
8785  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
8786  * byte_len, sequence) VALUES (?, ?, ?, ?)
8787  */
8788  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8789  for (TskFileRange tskFileRange : fileRanges) {
8790  prepStmt.clearParameters();
8791  prepStmt.setLong(1, newFileId); // obj_id
8792  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8793  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8794  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8795  connection.executeUpdate(prepStmt);
8796  }
8797 
8798  /*
8799  * Create a layout file representation of the carved file.
8800  */
8801  LayoutFile layoutFile = new LayoutFile(this,
8802  newFileId,
8803  parent.getDataSource().getId(),
8804  fileSystemObjectId,
8805  fileName,
8809  dirFlag,
8810  metaFlag.getValue(),
8811  savedSize,
8812  ctime, crtime, atime, mtime,
8813  null, null, null,
8815  parentPath,
8816  null,
8817  OsAccount.NO_OWNER_ID,
8818  OsAccount.NO_ACCOUNT);
8819 
8820  transaction.commit();
8821  transaction = null;
8822  return layoutFile;
8823 
8824  } catch (SQLException ex) {
8825  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
8826  } finally {
8827  closeResultSet(resultSet);
8828  closeStatement(statement);
8829 
8830  if (null != transaction) {
8831  try {
8832  transaction.rollback();
8833  } catch (TskCoreException ex2) {
8834  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8835  }
8836  }
8837  }
8838  }
8839 
8849  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
8850  if (content == null) {
8851  throw new TskCoreException("Null Content parameter given");
8852  }
8853  if (content instanceof AbstractFile) {
8854  return ((AbstractFile) content).getDataSourceObjectId();
8855  } else {
8856  return getDataSourceObjectId(connection, content.getId());
8857  }
8858  }
8859 
8872  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
8874  Statement statement = null;
8875  ResultSet resultSet = null;
8876  try {
8877  statement = connection.createStatement();
8878  long dataSourceObjId;
8879  long ancestorId = objectId;
8880  do {
8881  dataSourceObjId = ancestorId;
8882  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
8883  resultSet = statement.executeQuery(query);
8884  if (resultSet.next()) {
8885  ancestorId = resultSet.getLong("par_obj_id");
8886  } else {
8887  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
8888  }
8889  resultSet.close();
8890  resultSet = null;
8891  } while (0 != ancestorId); // Not NULL
8892  return dataSourceObjId;
8893  } catch (SQLException ex) {
8894  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
8895  } finally {
8896  closeResultSet(resultSet);
8897  closeStatement(statement);
8899  }
8900  }
8901 
8913  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8914  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
8915  statement.clearParameters();
8916  statement.setLong(1, objId);
8917  statement.setString(2, path);
8918  statement.setInt(3, type.getType());
8919  connection.executeUpdate(statement);
8920  }
8921 
8933  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8934  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
8935  statement.clearParameters();
8936  statement.setString(1, path);
8937  statement.setInt(2, type.getType());
8938  statement.setLong(3, objId);
8939  connection.executeUpdate(statement);
8940  }
8941 
8955  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
8956  String ext = "";
8957  if (!containsLikeWildcard(fileName)) {
8958  ext = SleuthkitCase.extractExtension(fileName);
8959  }
8960 
8961  CaseDbConnection connection = null;
8962  ResultSet rs = null;
8963  long parentId = parentFile.getId();
8964 
8966  try {
8967  connection = connections.getConnection();
8968 
8969  PreparedStatement statement;
8970  if (ext.isEmpty()) {
8971  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
8972  statement.clearParameters();
8973  statement.setLong(1, parentId);
8974  statement.setString(2, fileName);
8975  } else {
8976  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
8977  statement.clearParameters();
8978  statement.setString(1, ext);
8979  statement.setLong(2, parentId);
8980  statement.setString(3, fileName);
8981  }
8982 
8983  rs = connection.executeQuery(statement);
8984  return resultSetToAbstractFiles(rs, connection);
8985  } catch (SQLException ex) {
8986  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
8987  } finally {
8988  closeResultSet(rs);
8989  closeConnection(connection);
8991  }
8992  }
8993 
9005  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
9006  CaseDbConnection connection = null;
9007  Statement s = null;
9008  ResultSet rs = null;
9010  try {
9011  connection = connections.getConnection();
9012  s = connection.createStatement();
9013  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9014  rs.next();
9015  return rs.getLong("count");
9016  } catch (SQLException e) {
9017  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
9018  } finally {
9019  closeResultSet(rs);
9020  closeStatement(s);
9021  closeConnection(connection);
9023  }
9024  }
9025 
9043  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
9044  CaseDbConnection connection = null;
9045  Statement s = null;
9046  ResultSet rs = null;
9048  try {
9049  connection = connections.getConnection();
9050  s = connection.createStatement();
9051  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9052  return resultSetToAbstractFiles(rs, connection);
9053  } catch (SQLException e) {
9054  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
9055  } finally {
9056  closeResultSet(rs);
9057  closeStatement(s);
9058  closeConnection(connection);
9060  }
9061  }
9062 
9081  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
9082  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";
9084  try (CaseDbConnection connection = connections.getConnection()) {
9085  String query = String.format(queryTemplate, parentId, sqlWhereClause);
9086  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
9087  return resultSetToAbstractFiles(rs, connection);
9088  } catch (SQLException ex) {
9089  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
9090  }
9091  } finally {
9093  }
9094  }
9095 
9108  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
9109  CaseDbConnection connection = null;
9110  Statement s = null;
9111  ResultSet rs = null;
9113  try {
9114  connection = connections.getConnection();
9115  s = connection.createStatement();
9116  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9117  List<Long> ret = new ArrayList<>();
9118  while (rs.next()) {
9119  ret.add(rs.getLong("obj_id"));
9120  }
9121  return ret;
9122  } catch (SQLException e) {
9123  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
9124  } finally {
9125  closeResultSet(rs);
9126  closeStatement(s);
9127  closeConnection(connection);
9129  }
9130  }
9131 
9143  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
9144 
9145  // get the non-unique path (strip of image and volume path segments, if
9146  // the exist.
9147  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
9148 
9149  // split the file name from the parent path
9150  int lastSlash = path.lastIndexOf('/'); //NON-NLS
9151 
9152  // if the last slash is at the end, strip it off
9153  if (lastSlash == path.length()) {
9154  path = path.substring(0, lastSlash - 1);
9155  lastSlash = path.lastIndexOf('/'); //NON-NLS
9156  }
9157 
9158  String parentPath = path.substring(0, lastSlash);
9159  String fileName = path.substring(lastSlash);
9160 
9161  return findFiles(dataSource, fileName, parentPath);
9162  }
9163 
9174  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
9175  CaseDbConnection connection = null;
9176  Statement s = null;
9177  ResultSet rs = null;
9179  try {
9180  connection = connections.getConnection();
9181  s = connection.createStatement();
9182  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
9183  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
9184  while (rs.next()) {
9185  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
9186  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
9187  ranges.add(range);
9188  }
9189  return ranges;
9190  } catch (SQLException ex) {
9191  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
9192  } finally {
9193  closeResultSet(rs);
9194  closeStatement(s);
9195  closeConnection(connection);
9197  }
9198  }
9199 
9210  public Image getImageById(long id) throws TskCoreException {
9211  CaseDbConnection connection = null;
9212  Statement s = null;
9213  ResultSet rs = null;
9215  try {
9216  connection = connections.getConnection();
9217  s = connection.createStatement();
9218  rs = connection.executeQuery(s, "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, tsk_image_names.name "
9219  + "FROM tsk_image_info "
9220  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
9221  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
9222  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
9223 
9224  List<String> imagePaths = new ArrayList<>();
9225  long type, ssize, size;
9226  String tzone, md5, sha1, sha256, name, device_id, imagePath;
9227 
9228  if (rs.next()) {
9229  imagePath = rs.getString("name");
9230  if (imagePath != null) {
9231  imagePaths.add(imagePath);
9232  }
9233  type = rs.getLong("type"); //NON-NLS
9234  ssize = rs.getLong("ssize"); //NON-NLS
9235  tzone = rs.getString("tzone"); //NON-NLS
9236  size = rs.getLong("size"); //NON-NLS
9237  md5 = rs.getString("md5"); //NON-NLS
9238  sha1 = rs.getString("sha1"); //NON-NLS
9239  sha256 = rs.getString("sha256"); //NON-NLS
9240  name = rs.getString("display_name");
9241  if (name == null) {
9242  if (imagePaths.size() > 0) {
9243  String path = imagePaths.get(0);
9244  name = (new java.io.File(path)).getName();
9245  } else {
9246  name = "";
9247  }
9248  }
9249  device_id = rs.getString("device_id");
9250  } else {
9251  throw new TskCoreException("No image found for id: " + id);
9252  }
9253 
9254  // image can have multiple paths, therefore there can be multiple rows in the result set
9255  while (rs.next()) {
9256  imagePath = rs.getString("name");
9257  if (imagePath != null) {
9258  imagePaths.add(imagePath);
9259  }
9260  }
9261 
9262  return new Image(this, id, type, device_id, ssize, name,
9263  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
9264  } catch (SQLException ex) {
9265  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
9266  } finally {
9267  closeResultSet(rs);
9268  closeStatement(s);
9269  closeConnection(connection);
9271  }
9272  }
9273 
9285  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
9286  CaseDbConnection connection = null;
9287  Statement s = null;
9288  ResultSet rs = null;
9290  try {
9291  connection = connections.getConnection();
9292  s = connection.createStatement();
9293  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
9294  + "where obj_id = " + id); //NON-NLS
9295  if (rs.next()) {
9296  long type = rs.getLong("vs_type"); //NON-NLS
9297  long imgOffset = rs.getLong("img_offset"); //NON-NLS
9298  long blockSize = rs.getLong("block_size"); //NON-NLS
9299  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
9300  vs.setParent(parent);
9301  return vs;
9302  } else {
9303  throw new TskCoreException("No volume system found for id:" + id);
9304  }
9305  } catch (SQLException ex) {
9306  throw new TskCoreException("Error getting Volume System by ID.", ex);
9307  } finally {
9308  closeResultSet(rs);
9309  closeStatement(s);
9310  closeConnection(connection);
9312  }
9313  }
9314 
9323  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
9324  VolumeSystem vs = getVolumeSystemById(id, null);
9325  vs.setParentId(parentId);
9326  return vs;
9327  }
9328 
9340  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
9341  return getFileSystemByIdHelper(id, parent);
9342  }
9343 
9352  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
9353  Volume vol = null;
9354  FileSystem fs = getFileSystemById(id, vol);
9355  fs.setParentId(parentId);
9356  return fs;
9357  }
9358 
9370  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
9371  return getFileSystemByIdHelper(id, parent);
9372  }
9373 
9385  Pool getPoolById(long id, Content parent) throws TskCoreException {
9386  return getPoolByIdHelper(id, parent);
9387  }
9388 
9397  Pool getPoolById(long id, long parentId) throws TskCoreException {
9398  Pool pool = getPoolById(id, null);
9399  pool.setParentId(parentId);
9400  return pool;
9401  }
9402 
9414  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9415 
9417  try (CaseDbConnection connection = connections.getConnection();
9418  Statement s = connection.createStatement();
9419  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9420  + "where obj_id = " + id);) { //NON-NLS
9421  if (rs.next()) {
9422  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9423  pool.setParent(parent);
9424 
9425  return pool;
9426  } else {
9427  throw new TskCoreException("No pool found for ID:" + id);
9428  }
9429  } catch (SQLException ex) {
9430  throw new TskCoreException("Error getting Pool by ID", ex);
9431  } finally {
9433  }
9434  }
9435 
9447  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9448  // see if we already have it
9449  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9450  // but it should be the same...
9451  synchronized (fileSystemIdMap) {
9452  if (fileSystemIdMap.containsKey(id)) {
9453  return fileSystemIdMap.get(id);
9454  }
9455  }
9456  CaseDbConnection connection = null;
9457  Statement s = null;
9458  ResultSet rs = null;
9460  try {
9461  connection = connections.getConnection();
9462  s = connection.createStatement();
9463  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9464  + "where obj_id = " + id); //NON-NLS
9465  if (rs.next()) {
9466  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9467  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9468  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9469  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9470  fs.setParent(parent);
9471  // save it for the next call
9472  synchronized (fileSystemIdMap) {
9473  fileSystemIdMap.put(id, fs);
9474  }
9475  return fs;
9476  } else {
9477  throw new TskCoreException("No file system found for id:" + id);
9478  }
9479  } catch (SQLException ex) {
9480  throw new TskCoreException("Error getting File System by ID", ex);
9481  } finally {
9482  closeResultSet(rs);
9483  closeStatement(s);
9484  closeConnection(connection);
9486  }
9487  }
9488 
9500  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9501  CaseDbConnection connection = null;
9502  Statement s = null;
9503  ResultSet rs = null;
9505  try {
9506  connection = connections.getConnection();
9507  s = connection.createStatement();
9508  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9509  + "where obj_id = " + id); //NON-NLS
9510  if (rs.next()) {
9518  String description;
9519  try {
9520  description = rs.getString("desc");
9521  } catch (Exception ex) {
9522  description = rs.getString("descr");
9523  }
9524  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9525  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9526  description);
9527  vol.setParent(parent);
9528  return vol;
9529  } else {
9530  throw new TskCoreException("No volume found for id:" + id);
9531  }
9532  } catch (SQLException ex) {
9533  throw new TskCoreException("Error getting Volume by ID", ex);
9534  } finally {
9535  closeResultSet(rs);
9536  closeStatement(s);
9537  closeConnection(connection);
9539  }
9540  }
9541 
9550  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9551  Volume vol = getVolumeById(id, null);
9552  vol.setParentId(parentId);
9553  return vol;
9554  }
9555 
9567  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9568  CaseDbConnection connection = null;
9569  Statement s = null;
9570  ResultSet rs = null;
9572  try {
9573  connection = connections.getConnection();
9574  s = connection.createStatement();
9575  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9576  + "WHERE obj_id = " + id);
9577  Directory temp = null; //NON-NLS
9578  if (rs.next()) {
9579  final short type = rs.getShort("type"); //NON-NLS
9580  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9581  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9582  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9583  temp = directory(rs, parentFs);
9584  }
9585  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9586  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9587  }
9588  } else {
9589  throw new TskCoreException("No Directory found for id:" + id);
9590  }
9591  return temp;
9592  } catch (SQLException ex) {
9593  throw new TskCoreException("Error getting Directory by ID", ex);
9594  } finally {
9595  closeResultSet(rs);
9596  closeStatement(s);
9597  closeConnection(connection);
9599  }
9600  }
9601 
9611  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9612  List<FileSystem> fileSystems = new ArrayList<>();
9613  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9614 
9615  CaseDbConnection connection = null;
9616  Statement s = null;
9617  ResultSet rs = null;
9619  try {
9620  connection = connections.getConnection();
9621  s = connection.createStatement();
9622  rs = connection.executeQuery(s, queryStr); //NON-NLS
9623  while (rs.next()) {
9624  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9625  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9626  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9627  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9628  fs.setParent(null);
9629  fileSystems.add(fs);
9630  }
9631  } catch (SQLException ex) {
9632  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9633  } finally {
9634  closeResultSet(rs);
9635  closeStatement(s);
9636  closeConnection(connection);
9638  }
9639  return fileSystems;
9640  }
9641 
9652  List<Content> getImageChildren(Image img) throws TskCoreException {
9653  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9654  List<Content> children = new ArrayList<Content>();
9655  for (ObjectInfo info : childInfos) {
9656  if (null != info.type) {
9657  switch (info.type) {
9658  case VS:
9659  children.add(getVolumeSystemById(info.id, img));
9660  break;
9661  case POOL:
9662  children.add(getPoolById(info.id, img));
9663  break;
9664  case FS:
9665  children.add(getFileSystemById(info.id, img));
9666  break;
9667  case ABSTRACTFILE:
9668  AbstractFile f = getAbstractFileById(info.id);
9669  if (f != null) {
9670  children.add(f);
9671  }
9672  break;
9673  case ARTIFACT:
9674  BlackboardArtifact art = getArtifactById(info.id);
9675  if (art != null) {
9676  children.add(art);
9677  }
9678  break;
9679  case REPORT:
9680  // Do nothing for now - see JIRA-3673
9681  break;
9682  default:
9683  throw new TskCoreException("Image has child of invalid type: " + info.type);
9684  }
9685  }
9686  }
9687  return children;
9688  }
9689 
9700  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
9701  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9702  List<Long> children = new ArrayList<Long>();
9703  for (ObjectInfo info : childInfos) {
9704  if (info.type == ObjectType.VS
9705  || info.type == ObjectType.POOL
9706  || info.type == ObjectType.FS
9707  || info.type == ObjectType.ABSTRACTFILE
9708  || info.type == ObjectType.ARTIFACT) {
9709  children.add(info.id);
9710  } else if (info.type == ObjectType.REPORT) {
9711  // Do nothing for now - see JIRA-3673
9712  } else {
9713  throw new TskCoreException("Image has child of invalid type: " + info.type);
9714  }
9715  }
9716  return children;
9717  }
9718 
9729  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
9730  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9731  List<Content> children = new ArrayList<Content>();
9732  for (ObjectInfo info : childInfos) {
9733  if (null != info.type) {
9734  switch (info.type) {
9735  case VS:
9736  children.add(getVolumeSystemById(info.id, pool));
9737  break;
9738  case ABSTRACTFILE:
9739  AbstractFile f = getAbstractFileById(info.id);
9740  if (f != null) {
9741  children.add(f);
9742  }
9743  break;
9744  case ARTIFACT:
9745  BlackboardArtifact art = getArtifactById(info.id);
9746  if (art != null) {
9747  children.add(art);
9748  }
9749  break;
9750  default:
9751  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9752  }
9753  }
9754  }
9755  return children;
9756  }
9757 
9768  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
9769  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9770  List<Long> children = new ArrayList<Long>();
9771  for (ObjectInfo info : childInfos) {
9772  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9773  children.add(info.id);
9774  } else {
9775  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9776  }
9777  }
9778  return children;
9779  }
9780 
9791  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
9792  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9793  List<Content> children = new ArrayList<Content>();
9794  for (ObjectInfo info : childInfos) {
9795  if (null != info.type) {
9796  switch (info.type) {
9797  case VOL:
9798  children.add(getVolumeById(info.id, vs));
9799  break;
9800  case ABSTRACTFILE:
9801  AbstractFile f = getAbstractFileById(info.id);
9802  if (f != null) {
9803  children.add(f);
9804  }
9805  break;
9806  case ARTIFACT:
9807  BlackboardArtifact art = getArtifactById(info.id);
9808  if (art != null) {
9809  children.add(art);
9810  }
9811  break;
9812  default:
9813  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9814  }
9815  }
9816  }
9817  return children;
9818  }
9819 
9830  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
9831  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9832  List<Long> children = new ArrayList<Long>();
9833  for (ObjectInfo info : childInfos) {
9834  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9835  children.add(info.id);
9836  } else {
9837  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9838  }
9839  }
9840  return children;
9841  }
9842 
9853  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
9854  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9855  List<Content> children = new ArrayList<Content>();
9856  for (ObjectInfo info : childInfos) {
9857  if (null != info.type) {
9858  switch (info.type) {
9859  case POOL:
9860  children.add(getPoolById(info.id, vol));
9861  break;
9862  case FS:
9863  children.add(getFileSystemById(info.id, vol));
9864  break;
9865  case ABSTRACTFILE:
9866  AbstractFile f = getAbstractFileById(info.id);
9867  if (f != null) {
9868  children.add(f);
9869  }
9870  break;
9871  case ARTIFACT:
9872  BlackboardArtifact art = getArtifactById(info.id);
9873  if (art != null) {
9874  children.add(art);
9875  }
9876  break;
9877  default:
9878  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9879  }
9880  }
9881  }
9882  return children;
9883  }
9884 
9895  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
9896  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9897  final List<Long> children = new ArrayList<Long>();
9898  for (ObjectInfo info : childInfos) {
9899  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9900  children.add(info.id);
9901  } else {
9902  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9903  }
9904  }
9905  return children;
9906  }
9907 
9921  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
9922  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
9923  }
9924 
9939  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
9940  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this);
9941  return getImageById(imageId);
9942  }
9943 
9953  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
9954  CaseDbConnection connection = null;
9955  Statement s1 = null;
9956  ResultSet rs1 = null;
9958  try {
9959  connection = connections.getConnection();
9960  s1 = connection.createStatement();
9961  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
9962  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
9963  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
9964  while (rs1.next()) {
9965  long obj_id = rs1.getLong("obj_id"); //NON-NLS
9966  String name = rs1.getString("name"); //NON-NLS
9967  List<String> imagePaths = imgPaths.get(obj_id);
9968  if (imagePaths == null) {
9969  List<String> paths = new ArrayList<String>();
9970  if (name != null) {
9971  paths.add(name);
9972  }
9973  imgPaths.put(obj_id, paths);
9974  } else {
9975  if (name != null) {
9976  imagePaths.add(name);
9977  }
9978  }
9979  }
9980  return imgPaths;
9981  } catch (SQLException ex) {
9982  throw new TskCoreException("Error getting image paths.", ex);
9983  } finally {
9984  closeResultSet(rs1);
9985  closeStatement(s1);
9986  closeConnection(connection);
9988  }
9989  }
9990 
10002  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
10003  List<String> imagePaths = new ArrayList<>();
10005  Statement statement = null;
10006  ResultSet resultSet = null;
10007  try {
10008  statement = connection.createStatement();
10009  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
10010  while (resultSet.next()) {
10011  imagePaths.add(resultSet.getString("name"));
10012  }
10013  } catch (SQLException ex) {
10014  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
10015  } finally {
10016  closeResultSet(resultSet);
10017  closeStatement(statement);
10019  }
10020 
10021  return imagePaths;
10022  }
10023 
10030  public List<Image> getImages() throws TskCoreException {
10031  CaseDbConnection connection = null;
10032  Statement s = null;
10033  ResultSet rs = null;
10035  try {
10036  connection = connections.getConnection();
10037  s = connection.createStatement();
10038  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
10039  Collection<Long> imageIDs = new ArrayList<Long>();
10040  while (rs.next()) {
10041  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
10042  }
10043  List<Image> images = new ArrayList<Image>();
10044  for (long id : imageIDs) {
10045  images.add(getImageById(id));
10046  }
10047  return images;
10048  } catch (SQLException ex) {
10049  throw new TskCoreException("Error retrieving images.", ex);
10050  } finally {
10051  closeResultSet(rs);
10052  closeStatement(s);
10053  closeConnection(connection);
10055  }
10056  }
10057 
10068  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
10069  CaseDbTransaction transaction = beginTransaction();
10070  try {
10071  setImagePaths(obj_id, paths, transaction);
10072  transaction.commit();
10073  transaction = null;
10074  } finally {
10075  if (transaction != null) {
10076  transaction.rollback();
10077  }
10078  }
10079  }
10080 
10092  @Beta
10093  public void setImagePaths(long objId, List<String> paths, CaseDbTransaction trans) throws TskCoreException {
10094  try {
10095  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
10096  statement.clearParameters();
10097  statement.setLong(1, objId);
10098  trans.getConnection().executeUpdate(statement);
10099  for (int i = 0; i < paths.size(); i++) {
10100  statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
10101  statement.clearParameters();
10102  statement.setLong(1, objId);
10103  statement.setString(2, paths.get(i));
10104  statement.setLong(3, i);
10105  trans.getConnection().executeUpdate(statement);
10106  }
10107  } catch (SQLException ex) {
10108  throw new TskCoreException("Error updating image paths.", ex);
10109  }
10110  }
10111 
10112 
10124  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
10125 
10126  // Check if this data source is the only one associated with its host. If so,
10127  // we will delete the host and other associated data.
10128  // Note that the cascading deletes were only added in schema 9.1, so we
10129  // would get an error trying to delete a host from older cases.
10130  Host hostToDelete = null;
10132  int major = version.getMajor();
10133  int minor = version.getMinor();
10134  if (major > 9 || (major == 9 && minor >= 1)) {
10135  hostToDelete = getHostManager().getHostByDataSource(dataSourceObjectId);
10136  if (getHostManager().getDataSourcesForHost(hostToDelete).size() != 1) {
10137  hostToDelete = null;
10138  }
10139  }
10140 
10141  CaseDbConnection connection = null;
10142  Statement statement;
10144  try {
10145  connection = connections.getConnection();
10146  statement = connection.createStatement();
10147  connection.beginTransaction();
10148  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
10149  // all associated rows from tsk_object and its children. For large data sources this may take some time.
10150  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
10151  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
10152  // associated rows from accounts table and its children.
10153  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
10154  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
10155  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
10156  statement.execute(accountSql);
10157 
10158  // Now delete any host that was only associated with this data source. This will cascade to delete
10159  // realms, os accounts, and os account attributes that were associated with the host.
10160  if (hostToDelete != null) {
10161  statement.execute("DELETE FROM tsk_hosts WHERE id = " + hostToDelete.getHostId());
10162 
10163  // Clean up any stray OS Account objects
10164  String deleteOsAcctObjectsQuery = "DELETE FROM tsk_objects "
10165  + "WHERE type=" + TskData.ObjectType.OS_ACCOUNT.getObjectType() + " "
10166  + "AND obj_id NOT IN (SELECT os_account_obj_id FROM tsk_os_accounts WHERE os_account_obj_id IS NOT NULL)";
10167  statement.execute(deleteOsAcctObjectsQuery);
10168  }
10169 
10170  connection.commitTransaction();
10171  } catch (SQLException ex) {
10172  rollbackTransaction(connection);
10173  throw new TskCoreException("Error deleting data source.", ex);
10174  } finally {
10175  closeConnection(connection);
10177  }
10178  }
10179 
10205  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
10206  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
10207  try {
10208  while (rs.next()) {
10209  final short type = rs.getShort("type"); //NON-NLS
10210  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
10211  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
10212  FsContent result;
10213  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
10214  result = directory(rs, null);
10215  } else {
10216  result = file(rs, null);
10217  }
10218  results.add(result);
10219  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
10220  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
10221  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
10222  results.add(virtDir);
10223  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
10224  final LocalDirectory localDir = localDirectory(rs);
10225  results.add(localDir);
10226  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
10227  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
10228  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
10229  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
10230  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
10231  String parentPath = rs.getString("parent_path"); //NON-NLS
10232  if (parentPath == null) {
10233  parentPath = "/"; //NON-NLS
10234  }
10235 
10236  Long osAccountObjId = rs.getLong("os_account_obj_id");
10237  if (rs.wasNull()) {
10238  osAccountObjId = null;
10239  }
10240 
10241  LayoutFile lf = new LayoutFile(this,
10242  rs.getLong("obj_id"), //NON-NLS
10243  rs.getLong("data_source_obj_id"),
10244  rs.getLong("fs_obj_id"),
10245  rs.getString("name"), //NON-NLS
10246  atype,
10247  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10248  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10249  rs.getLong("size"), //NON-NLS
10250  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10251  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10252  FileKnown.valueOf(rs.getByte("known")), parentPath,
10253  rs.getString("mime_type"),
10254  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10255  results.add(lf);
10256  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
10257  final DerivedFile df;
10258  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
10259  results.add(df);
10260  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
10261  final LocalFile lf;
10262  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
10263  results.add(lf);
10264  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
10265  final SlackFile sf = slackFile(rs, null);
10266  results.add(sf);
10267  }
10268  } //end for each resultSet
10269  } catch (SQLException e) {
10270  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
10271  }
10272 
10273  return results;
10274  }
10275 
10276  // This following methods generate AbstractFile objects from a ResultSet
10288  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
10289  Long osAccountObjId = rs.getLong("os_account_obj_id");
10290  if (rs.wasNull()) {
10291  osAccountObjId = null;
10292  }
10293 
10294  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
10295  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10296  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10297  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10298  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10299  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10300  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10301  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10302  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10303  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10304  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10305  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10306  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"),
10307  osAccountObjId, TskData.CollectedStatus.valueOf(rs.getInt("collected")), Collections.emptyList()); //NON-NLS
10308  f.setFileSystem(fs);
10309  return f;
10310  }
10311 
10323  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
10324  Long osAccountObjId = rs.getLong("os_account_obj_id");
10325  if (rs.wasNull()) {
10326  osAccountObjId = null;
10327  }
10328 
10329  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10330  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10331  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10332  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10333  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10334  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10335  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10336  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10337  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10338  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10339  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10340  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10341  dir.setFileSystem(fs);
10342  return dir;
10343  }
10344 
10355  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
10356  String parentPath = rs.getString("parent_path"); //NON-NLS
10357  if (parentPath == null) {
10358  parentPath = "";
10359  }
10360 
10361  long objId = rs.getLong("obj_id");
10362  long dsObjId = rs.getLong("data_source_obj_id");
10363  if (objId == dsObjId) { // virtual directory is a data source
10364 
10365  String deviceId = "";
10366  String timeZone = "";
10367  Statement s = null;
10368  ResultSet rsDataSourceInfo = null;
10369 
10371  try {
10372  s = connection.createStatement();
10373  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
10374  if (rsDataSourceInfo.next()) {
10375  deviceId = rsDataSourceInfo.getString("device_id");
10376  timeZone = rsDataSourceInfo.getString("time_zone");
10377  }
10378  } catch (SQLException ex) {
10379  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
10380  } finally {
10381  closeResultSet(rsDataSourceInfo);
10382  closeStatement(s);
10384  }
10385 
10386  return new LocalFilesDataSource(this,
10387  objId, dsObjId,
10388  deviceId,
10389  rs.getString("name"),
10390  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10391  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10392  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
10393  rs.getShort("meta_flags"),
10394  timeZone,
10395  rs.getString("md5"),
10396  rs.getString("sha256"),
10397  rs.getString("sha1"),
10398  FileKnown.valueOf(rs.getByte("known")),
10399  parentPath);
10400  } else {
10401  final VirtualDirectory vd = new VirtualDirectory(this,
10402  objId, dsObjId,
10403  rs.getLong("fs_obj_id"),
10404  rs.getString("name"), //NON-NLS
10405  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10406  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10407  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10408  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10409  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10410  return vd;
10411  }
10412  }
10413 
10423  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
10424  String parentPath = rs.getString("parent_path"); //NON-NLS
10425  if (parentPath == null) {
10426  parentPath = "";
10427  }
10428  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
10429  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
10430  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10431  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10432  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10433  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10434  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10435  return ld;
10436  }
10437 
10451  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10452  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10453  long objId = rs.getLong("obj_id"); //NON-NLS
10454  String localPath = null;
10455  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10456  if (hasLocalPath) {
10457  ResultSet rsFilePath = null;
10459  try {
10460  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10461  statement.clearParameters();
10462  statement.setLong(1, objId);
10463  rsFilePath = connection.executeQuery(statement);
10464  if (rsFilePath.next()) {
10465  localPath = rsFilePath.getString("path");
10466  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10467  }
10468  } catch (SQLException ex) {
10469  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10470  } finally {
10471  closeResultSet(rsFilePath);
10473  }
10474  }
10475  String parentPath = rs.getString("parent_path"); //NON-NLS
10476  if (parentPath == null) {
10477  parentPath = "";
10478  }
10479 
10480  Long osAccountObjId = rs.getLong("os_account_obj_id");
10481  if (rs.wasNull()) {
10482  osAccountObjId = null;
10483  }
10484 
10485  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10486  rs.getLong("fs_obj_id"),
10487  rs.getString("name"), //NON-NLS
10488  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10489  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10490  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10491  rs.getLong("size"), //NON-NLS
10492  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10493  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10494  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10495  parentPath, localPath, parentId, rs.getString("mime_type"),
10496  encodingType, rs.getString("extension"),
10497  rs.getString("owner_uid"), osAccountObjId);
10498  return df;
10499  }
10500 
10514  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10515  long objId = rs.getLong("obj_id"); //NON-NLS
10516  String localPath = null;
10517  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10518  if (rs.getBoolean("has_path")) {
10519  ResultSet rsFilePath = null;
10521  try {
10522  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10523  statement.clearParameters();
10524  statement.setLong(1, objId);
10525  rsFilePath = connection.executeQuery(statement);
10526  if (rsFilePath.next()) {
10527  localPath = rsFilePath.getString("path");
10528  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10529  }
10530  } catch (SQLException ex) {
10531  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10532  } finally {
10533  closeResultSet(rsFilePath);
10535  }
10536  }
10537  String parentPath = rs.getString("parent_path"); //NON-NLS
10538  if (null == parentPath) {
10539  parentPath = "";
10540  }
10541  Long osAccountObjId = rs.getLong("os_account_obj_id");
10542  if (rs.wasNull()) {
10543  osAccountObjId = null;
10544  }
10545 
10546  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10547  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10548  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10549  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10550  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10551  rs.getLong("size"), //NON-NLS
10552  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10553  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10554  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10555  parentId, parentPath, rs.getLong("data_source_obj_id"),
10556  localPath, encodingType, rs.getString("extension"),
10557  rs.getString("owner_uid"), osAccountObjId);
10558  return file;
10559  }
10560 
10572  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10573  Long osAccountObjId = rs.getLong("os_account_obj_id");
10574  if (rs.wasNull()) {
10575  osAccountObjId = null;
10576  }
10577  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10578  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10579  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10580  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10581  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10582  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10583  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10584  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10585  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10586  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10587  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10588  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10589  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10590  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10591  f.setFileSystem(fs);
10592  return f;
10593  }
10594 
10606  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10607  List<Content> children = new ArrayList<Content>();
10608 
10609  while (rs.next()) {
10610  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10611 
10612  if (null != type) {
10613  switch (type) {
10614  case FS:
10615  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10616  FsContent result;
10617  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10618  result = directory(rs, null);
10619  } else {
10620  result = file(rs, null);
10621  }
10622  children.add(result);
10623  } else {
10624  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10625  children.add(virtDir);
10626  }
10627  break;
10628  case VIRTUAL_DIR:
10629  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10630  children.add(virtDir);
10631  break;
10632  case LOCAL_DIR:
10633  LocalDirectory localDir = localDirectory(rs);
10634  children.add(localDir);
10635  break;
10636  case UNALLOC_BLOCKS:
10637  case UNUSED_BLOCKS:
10638  case CARVED:
10639  case LAYOUT_FILE: {
10640  String parentPath = rs.getString("parent_path");
10641  if (parentPath == null) {
10642  parentPath = "";
10643  }
10644  Long osAccountObjId = rs.getLong("os_account_obj_id");
10645  if (rs.wasNull()) {
10646  osAccountObjId = null;
10647  }
10648  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
10649  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"),
10650  rs.getString("name"), type,
10651  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
10652  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
10653  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
10654  rs.getLong("size"),
10655  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
10656  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10657  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
10658  rs.getString("owner_uid"), osAccountObjId);
10659  children.add(lf);
10660  break;
10661  }
10662  case DERIVED:
10663  final DerivedFile df = derivedFile(rs, connection, parentId);
10664  children.add(df);
10665  break;
10666  case LOCAL: {
10667  final LocalFile lf = localFile(rs, connection, parentId);
10668  children.add(lf);
10669  break;
10670  }
10671  case SLACK: {
10672  final SlackFile sf = slackFile(rs, null);
10673  children.add(sf);
10674  break;
10675  }
10676  default:
10677  break;
10678  }
10679  }
10680  }
10681  return children;
10682  }
10683 
10705  public CaseDbQuery executeQuery(String query) throws TskCoreException {
10706  return new CaseDbQuery(query);
10707  }
10708 
10730  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
10731  return new CaseDbQuery(query, true);
10732  }
10733 
10741  CaseDbConnection getConnection() throws TskCoreException {
10742  return connections.getConnection();
10743  }
10744 
10752  String getCaseHandleIdentifier() {
10753  return caseHandleIdentifier;
10754  }
10755 
10756  @SuppressWarnings("deprecation")
10757  @Override
10758  protected void finalize() throws Throwable {
10759  try {
10760  close();
10761  } finally {
10762  super.finalize();
10763  }
10764  }
10765 
10769  public synchronized void close() {
10771 
10772  try {
10773  connections.close();
10774  } catch (TskCoreException ex) {
10775  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
10776  }
10777 
10778  fileSystemIdMap.clear();
10779 
10780  try {
10781  if (this.caseHandle != null) {
10782  this.caseHandle.free();
10783  this.caseHandle = null;
10784  }
10785  } catch (TskCoreException ex) {
10786  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
10787  } finally {
10789  }
10790  }
10791 
10804  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
10805  long id = file.getId();
10806  FileKnown currentKnown = file.getKnown();
10807  if (currentKnown.compareTo(fileKnown) > 0) {
10808  return false;
10809  }
10811  try (CaseDbConnection connection = connections.getConnection();
10812  Statement statement = connection.createStatement();) {
10813  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
10814  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
10815  + "WHERE obj_id=" + id); //NON-NLS
10816 
10817  file.setKnown(fileKnown);
10818  } catch (SQLException ex) {
10819  throw new TskCoreException("Error setting Known status.", ex);
10820  } finally {
10822  }
10823  return true;
10824  }
10825 
10834  void setFileName(String name, long objId) throws TskCoreException {
10836  try (CaseDbConnection connection = connections.getConnection();) {
10837  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
10838  preparedStatement.clearParameters();
10839  preparedStatement.setString(1, name);
10840  preparedStatement.setLong(2, objId);
10841  connection.executeUpdate(preparedStatement);
10842  } catch (SQLException ex) {
10843  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10844  } finally {
10846  }
10847  }
10848 
10857  void setImageName(String name, long objId) throws TskCoreException {
10859  try (CaseDbConnection connection = connections.getConnection();) {
10860  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
10861  preparedStatement.clearParameters();
10862  preparedStatement.setString(1, name);
10863  preparedStatement.setLong(2, objId);
10864  connection.executeUpdate(preparedStatement);
10865  } catch (SQLException ex) {
10866  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10867  } finally {
10869  }
10870  }
10871 
10886  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
10887 
10889  try (CaseDbConnection connection = connections.getConnection();) {
10890  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
10891  preparedStatement.clearParameters();
10892  preparedStatement.setLong(1, totalSize);
10893  preparedStatement.setLong(2, sectorSize);
10894  preparedStatement.setLong(3, image.getId());
10895  connection.executeUpdate(preparedStatement);
10896  } catch (SQLException ex) {
10897  throw new TskCoreException(String.format("Error updating image sizes to %d and sector size to %d for object ID %d ", totalSize, sectorSize, image.getId()), ex);
10898  } finally {
10900  }
10901  }
10902 
10912  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
10914  try (CaseDbConnection connection = connections.getConnection();
10915  Statement statement = connection.createStatement()) {
10916  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
10917  file.setMIMEType(mimeType);
10918  } catch (SQLException ex) {
10919  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
10920  } finally {
10922  }
10923  }
10924 
10935  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
10936 
10937  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
10938  short metaFlag = file.getMetaFlagsAsInt();
10939  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
10940  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
10941  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
10942 
10943  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
10944  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
10945 
10947  try (CaseDbConnection connection = connections.getConnection();
10948  Statement statement = connection.createStatement();) {
10949  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
10950 
10951  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
10952  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
10953 
10954  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
10955 
10956  } catch (SQLException ex) {
10957  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
10958  } finally {
10960  }
10961  }
10962 
10972  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
10973  if (md5Hash == null) {
10974  return;
10975  }
10976  long id = file.getId();
10978  try (CaseDbConnection connection = connections.getConnection();) {
10979  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
10980  statement.clearParameters();
10981  statement.setString(1, md5Hash.toLowerCase());
10982  statement.setLong(2, id);
10983  connection.executeUpdate(statement);
10984  file.setMd5Hash(md5Hash.toLowerCase());
10985  } catch (SQLException ex) {
10986  throw new TskCoreException("Error setting MD5 hash", ex);
10987  } finally {
10989  }
10990  }
10991 
11001  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
11002  if (md5Hash == null) {
11003  return;
11004  }
11005  long id = img.getId();
11007  try (CaseDbConnection connection = connections.getConnection();) {
11008  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
11009  statement.clearParameters();
11010  statement.setString(1, md5Hash.toLowerCase());
11011  statement.setLong(2, id);
11012  connection.executeUpdate(statement);
11013  } catch (SQLException ex) {
11014  throw new TskCoreException("Error setting MD5 hash", ex);
11015  } finally {
11017  }
11018  }
11019 
11030  String getMd5ImageHash(Image img) throws TskCoreException {
11031  long id = img.getId();
11032  CaseDbConnection connection = null;
11033  ResultSet rs = null;
11034  String hash = "";
11036  try {
11037  connection = connections.getConnection();
11038 
11039  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
11040  statement.clearParameters();
11041  statement.setLong(1, id);
11042  rs = connection.executeQuery(statement);
11043  if (rs.next()) {
11044  hash = rs.getString("md5");
11045  }
11046  return hash;
11047  } catch (SQLException ex) {
11048  throw new TskCoreException("Error getting MD5 hash", ex);
11049  } finally {
11050  closeResultSet(rs);
11051  closeConnection(connection);
11053  }
11054  }
11055 
11065  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
11066  if (sha1Hash == null) {
11067  return;
11068  }
11069  long id = img.getId();
11071  try (CaseDbConnection connection = connections.getConnection();) {
11072  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
11073  statement.clearParameters();
11074  statement.setString(1, sha1Hash.toLowerCase());
11075  statement.setLong(2, id);
11076  connection.executeUpdate(statement);
11077  } catch (SQLException ex) {
11078  throw new TskCoreException("Error setting SHA1 hash", ex);
11079  } finally {
11081  }
11082  }
11083 
11094  String getSha1ImageHash(Image img) throws TskCoreException {
11095  long id = img.getId();
11096  CaseDbConnection connection = null;
11097  ResultSet rs = null;
11098  String hash = "";
11100  try {
11101  connection = connections.getConnection();
11102 
11103  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
11104  statement.clearParameters();
11105  statement.setLong(1, id);
11106  rs = connection.executeQuery(statement);
11107  if (rs.next()) {
11108  hash = rs.getString("sha1");
11109  }
11110  return hash;
11111  } catch (SQLException ex) {
11112  throw new TskCoreException("Error getting SHA1 hash", ex);
11113  } finally {
11114  closeResultSet(rs);
11115  closeConnection(connection);
11117  }
11118  }
11119 
11129  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
11130  if (sha256Hash == null) {
11131  return;
11132  }
11133  long id = img.getId();
11135  try (CaseDbConnection connection = connections.getConnection();) {
11136  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
11137  statement.clearParameters();
11138  statement.setString(1, sha256Hash.toLowerCase());
11139  statement.setLong(2, id);
11140  connection.executeUpdate(statement);
11141  } catch (SQLException ex) {
11142  throw new TskCoreException("Error setting SHA256 hash", ex);
11143  } finally {
11145  }
11146  }
11147 
11158  String getSha256ImageHash(Image img) throws TskCoreException {
11159  long id = img.getId();
11160  CaseDbConnection connection = null;
11161  ResultSet rs = null;
11162  String hash = "";
11164  try {
11165  connection = connections.getConnection();
11166 
11167  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
11168  statement.clearParameters();
11169  statement.setLong(1, id);
11170  rs = connection.executeQuery(statement);
11171  if (rs.next()) {
11172  hash = rs.getString("sha256");
11173  }
11174  return hash;
11175  } catch (SQLException ex) {
11176  throw new TskCoreException("Error setting SHA256 hash", ex);
11177  } finally {
11178  closeResultSet(rs);
11179  closeConnection(connection);
11181  }
11182  }
11183 
11192  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
11193 
11194  long id = datasource.getId();
11196  try (CaseDbConnection connection = connections.getConnection();) {
11197  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11198  statement.clearParameters();
11199  statement.setString(1, details);
11200  statement.setLong(2, id);
11201  connection.executeUpdate(statement);
11202  } catch (SQLException ex) {
11203  throw new TskCoreException("Error setting acquisition details", ex);
11204  } finally {
11206  }
11207  }
11208 
11220  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
11221 
11222  long id = datasource.getId();
11224  try (CaseDbConnection connection = connections.getConnection();) {
11225  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
11226  statement.clearParameters();
11227  statement.setString(1, settings);
11228  statement.setString(2, name);
11229  statement.setString(3, version);
11230  statement.setLong(4, id);
11231  connection.executeUpdate(statement);
11232  } catch (SQLException ex) {
11233  throw new TskCoreException("Error setting acquisition details", ex);
11234  } finally {
11236  }
11237  }
11238 
11248  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
11249  try {
11250  CaseDbConnection connection = trans.getConnection();
11251  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11252  statement.clearParameters();
11253  statement.setString(1, details);
11254  statement.setLong(2, dataSourceId);
11255  connection.executeUpdate(statement);
11256  } catch (SQLException ex) {
11257  throw new TskCoreException("Error setting acquisition details", ex);
11258  }
11259  }
11260 
11270  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
11271  long id = datasource.getId();
11272  CaseDbConnection connection = null;
11273  ResultSet rs = null;
11274  String hash = "";
11276  try {
11277  connection = connections.getConnection();
11278 
11279  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
11280  statement.clearParameters();
11281  statement.setLong(1, id);
11282  rs = connection.executeQuery(statement);
11283  if (rs.next()) {
11284  hash = rs.getString("acquisition_details");
11285  }
11286  return hash;
11287  } catch (SQLException ex) {
11288  throw new TskCoreException("Error setting acquisition details", ex);
11289  } finally {
11290  closeResultSet(rs);
11291  closeConnection(connection);
11293  }
11294  }
11295 
11306  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
11307  long id = datasource.getId();
11308  CaseDbConnection connection = null;
11309  ResultSet rs = null;
11310  String returnValue = "";
11312  try {
11313  connection = connections.getConnection();
11314 
11315  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11316  statement.clearParameters();
11317  statement.setLong(1, id);
11318  rs = connection.executeQuery(statement);
11319  if (rs.next()) {
11320  returnValue = rs.getString(columnName);
11321  }
11322  return returnValue;
11323  } catch (SQLException ex) {
11324  throw new TskCoreException("Error setting acquisition details", ex);
11325  } finally {
11326  closeResultSet(rs);
11327  closeConnection(connection);
11329  }
11330  }
11331 
11342  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
11343  long id = datasource.getId();
11344  CaseDbConnection connection = null;
11345  ResultSet rs = null;
11346  Long returnValue = null;
11348  try {
11349  connection = connections.getConnection();
11350 
11351  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11352  statement.clearParameters();
11353  statement.setLong(1, id);
11354  rs = connection.executeQuery(statement);
11355  if (rs.next()) {
11356  returnValue = rs.getLong(columnName);
11357  }
11358  return returnValue;
11359  } catch (SQLException ex) {
11360  throw new TskCoreException("Error setting acquisition details", ex);
11361  } finally {
11362  closeResultSet(rs);
11363  closeConnection(connection);
11365  }
11366  }
11367 
11378  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
11379  if (newStatus == null) {
11380  return;
11381  }
11383  try (CaseDbConnection connection = connections.getConnection();
11384  Statement statement = connection.createStatement();) {
11385  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
11386  + " SET review_status_id=" + newStatus.getID()
11387  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
11388  } catch (SQLException ex) {
11389  throw new TskCoreException("Error setting review status", ex);
11390  } finally {
11392  }
11393  }
11394 
11405  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
11406  CaseDbConnection connection = null;
11407  Statement s = null;
11408  ResultSet rs = null;
11410  try {
11411  connection = connections.getConnection();
11412  s = connection.createStatement();
11413  Short contentShort = contentType.getValue();
11414  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
11415  int count = 0;
11416  if (rs.next()) {
11417  count = rs.getInt("count");
11418  }
11419  return count;
11420  } catch (SQLException ex) {
11421  throw new TskCoreException("Error getting number of objects.", ex);
11422  } finally {
11423  closeResultSet(rs);
11424  closeStatement(s);
11425  closeConnection(connection);
11427  }
11428  }
11429 
11438  public static String escapeSingleQuotes(String text) {
11439  String escapedText = null;
11440  if (text != null) {
11441  escapedText = text.replaceAll("'", "''");
11442  }
11443  return escapedText;
11444  }
11445 
11453  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11454  if (md5Hash == null) {
11455  return Collections.<AbstractFile>emptyList();
11456  }
11457 
11458  CaseDbConnection connection = null;
11459  Statement s = null;
11460  ResultSet rs = null;
11462  try {
11463  connection = connections.getConnection();
11464  s = connection.createStatement();
11465  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11466  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11467  + "AND size > 0"); //NON-NLS
11468  return resultSetToAbstractFiles(rs, connection);
11469  } catch (SQLException | TskCoreException ex) {
11470  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11471  } finally {
11472  closeResultSet(rs);
11473  closeStatement(s);
11474  closeConnection(connection);
11476  }
11477  return Collections.<AbstractFile>emptyList();
11478  }
11479 
11486  public boolean allFilesMd5Hashed() {
11487  boolean allFilesAreHashed = false;
11488 
11489  CaseDbConnection connection = null;
11490  Statement s = null;
11491  ResultSet rs = null;
11493  try {
11494  connection = connections.getConnection();
11495  s = connection.createStatement();
11496  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11497  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11498  + "AND md5 IS NULL " //NON-NLS
11499  + "AND size > '0'"); //NON-NLS
11500  if (rs.next() && rs.getInt("count") == 0) {
11501  allFilesAreHashed = true;
11502  }
11503  } catch (SQLException | TskCoreException ex) {
11504  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11505  } finally {
11506  closeResultSet(rs);
11507  closeStatement(s);
11508  closeConnection(connection);
11510  }
11511  return allFilesAreHashed;
11512  }
11513 
11519  public int countFilesMd5Hashed() {
11520  int count = 0;
11521 
11523  CaseDbConnection connection = null;
11524  Statement s = null;
11525  ResultSet rs = null;
11526  try {
11527  connection = connections.getConnection();
11528  s = connection.createStatement();
11529  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11530  + "WHERE md5 IS NOT NULL " //NON-NLS
11531  + "AND size > '0'"); //NON-NLS
11532  if (rs.next()) {
11533  count = rs.getInt("count");
11534  }
11535  } catch (SQLException | TskCoreException ex) {
11536  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11537  } finally {
11538  closeResultSet(rs);
11539  closeStatement(s);
11540  closeConnection(connection);
11542  }
11543  return count;
11544 
11545  }
11546 
11555  public List<TagName> getAllTagNames() throws TskCoreException {
11556  CaseDbConnection connection = null;
11557  ResultSet resultSet = null;
11559  try {
11560  connection = connections.getConnection();
11561 
11562  // SELECT * FROM tag_names
11563  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11564  resultSet = connection.executeQuery(statement);
11565  ArrayList<TagName> tagNames = new ArrayList<>();
11566  while (resultSet.next()) {
11567  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11568  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11569  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11570  }
11571  return tagNames;
11572  } catch (SQLException ex) {
11573  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11574  } finally {
11575  closeResultSet(resultSet);
11576  closeConnection(connection);
11578  }
11579  }
11580 
11591  public List<TagName> getTagNamesInUse() throws TskCoreException {
11592  CaseDbConnection connection = null;
11593  ResultSet resultSet = null;
11595  try {
11596  connection = connections.getConnection();
11597 
11598  // 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)
11599  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
11600  resultSet = connection.executeQuery(statement);
11601  ArrayList<TagName> tagNames = new ArrayList<>();
11602  while (resultSet.next()) {
11603  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11604  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11605  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11606  }
11607  return tagNames;
11608  } catch (SQLException ex) {
11609  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11610  } finally {
11611  closeResultSet(resultSet);
11612  closeConnection(connection);
11614  }
11615  }
11616 
11629  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
11630 
11631  ArrayList<TagName> tagNames = new ArrayList<>();
11632  // SELECT * FROM tag_names WHERE tag_name_id IN
11633  // ( 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 = ? "
11634  // UNION
11635  // 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 = ? )
11636  // )
11637  CaseDbConnection connection = null;
11638  ResultSet resultSet = null;
11640  try {
11641  connection = connections.getConnection();
11642 
11643  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
11644  statement.setLong(1, dsObjId);
11645  statement.setLong(2, dsObjId);
11646  resultSet = connection.executeQuery(statement); //NON-NLS
11647  while (resultSet.next()) {
11648  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11649  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11650  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11651  }
11652  return tagNames;
11653  } catch (SQLException ex) {
11654  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
11655  } finally {
11656  closeResultSet(resultSet);
11657  closeConnection(connection);
11659  }
11660  }
11661 
11675  @Deprecated
11676  @SuppressWarnings("deprecation")
11677  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
11678  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
11679  }
11680 
11697  @Deprecated
11698  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
11699  return getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
11700  }
11701 
11716  @Deprecated
11717  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
11718  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
11719  }
11720 
11721  /*
11722  * Deletes a row from the content_tags table in the case database. @param
11723  * tag A ContentTag data transfer object (DTO) for the row to delete.
11724  * @throws TskCoreException
11725  */
11726  public void deleteContentTag(ContentTag tag) throws TskCoreException {
11728  try {
11729  // DELETE FROM content_tags WHERE tag_id = ?
11730  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
11731  statement.clearParameters();
11732  statement.setLong(1, tag.getId());
11733  trans.getConnection().executeUpdate(statement);
11734 
11735  // update the aggregate score for the content
11736  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
11737  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11738  ? tag.getContent().getDataSource().getId()
11739  : null;
11740 
11741  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
11742 
11743  trans.commit();
11744  trans = null;
11745  } catch (SQLException ex) {
11746  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
11747  } finally {
11748  if (trans != null) {
11749  trans.rollback();
11750  }
11751  }
11752  }
11753 
11762  public List<ContentTag> getAllContentTags() throws TskCoreException {
11763  CaseDbConnection connection = null;
11764  ResultSet resultSet = null;
11766  try {
11767  connection = connections.getConnection();
11768 
11769  // 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
11770  // FROM content_tags
11771  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11772  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11773  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
11774  resultSet = connection.executeQuery(statement);
11775  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11776  while (resultSet.next()) {
11777  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11778  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11779  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11780  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
11781  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
11782  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
11783  }
11784  return tags;
11785  } catch (SQLException ex) {
11786  throw new TskCoreException("Error selecting rows from content_tags table", ex);
11787  } finally {
11788  closeResultSet(resultSet);
11789  closeConnection(connection);
11791  }
11792  }
11793 
11804  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
11805  if (tagName.getId() == Tag.ID_NOT_SET) {
11806  throw new TskCoreException("TagName object is invalid, id not set");
11807  }
11808  CaseDbConnection connection = null;
11809  ResultSet resultSet = null;
11811  try {
11812  connection = connections.getConnection();
11813 
11814  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
11815  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
11816  statement.clearParameters();
11817  statement.setLong(1, tagName.getId());
11818  resultSet = connection.executeQuery(statement);
11819  if (resultSet.next()) {
11820  return resultSet.getLong("count");
11821  } else {
11822  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11823  }
11824  } catch (SQLException ex) {
11825  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11826  } finally {
11827  closeResultSet(resultSet);
11828  closeConnection(connection);
11830  }
11831  }
11832 
11848  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11849 
11850  if (tagName.getId() == Tag.ID_NOT_SET) {
11851  throw new TskCoreException("TagName object is invalid, id not set");
11852  }
11853 
11854  CaseDbConnection connection = null;
11855  ResultSet resultSet = null;
11857  try {
11858  connection = connections.getConnection();
11859 
11860  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11861  // + " AND content_tags.tag_name_id = ? "
11862  // + " AND tsk_files.data_source_obj_id = ? "
11863  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11864  statement.clearParameters();
11865  statement.setLong(1, tagName.getId());
11866  statement.setLong(2, dsObjId);
11867 
11868  resultSet = connection.executeQuery(statement);
11869  if (resultSet.next()) {
11870  return resultSet.getLong("count");
11871  } else {
11872  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11873  }
11874  } catch (SQLException ex) {
11875  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11876  } finally {
11877  closeResultSet(resultSet);
11878  closeConnection(connection);
11880  }
11881  }
11882 
11893  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
11894 
11895  CaseDbConnection connection = null;
11896  ResultSet resultSet = null;
11897  ContentTag tag = null;
11899  try {
11900  connection = connections.getConnection();
11901 
11902  // 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
11903  // FROM content_tags
11904  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11905  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11906  // WHERE tag_id = ?
11907  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
11908  statement.clearParameters();
11909  statement.setLong(1, contentTagID);
11910  resultSet = connection.executeQuery(statement);
11911 
11912  while (resultSet.next()) {
11913  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11914  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11915  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11916  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
11917  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
11918  }
11919  resultSet.close();
11920 
11921  } catch (SQLException ex) {
11922  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
11923  } finally {
11924  closeResultSet(resultSet);
11925  closeConnection(connection);
11927  }
11928  return tag;
11929  }
11930 
11942  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
11943  if (tagName.getId() == Tag.ID_NOT_SET) {
11944  throw new TskCoreException("TagName object is invalid, id not set");
11945  }
11946  CaseDbConnection connection = null;
11947  ResultSet resultSet = null;
11949  try {
11950  connection = connections.getConnection();
11951 
11952  // 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
11953  // FROM content_tags
11954  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11955  // WHERE tag_name_id = ?
11956  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
11957  statement.clearParameters();
11958  statement.setLong(1, tagName.getId());
11959  resultSet = connection.executeQuery(statement);
11960  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11961  while (resultSet.next()) {
11962  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11963  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11964  tags.add(tag);
11965  }
11966  resultSet.close();
11967  return tags;
11968  } catch (SQLException ex) {
11969  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
11970  } finally {
11971  closeResultSet(resultSet);
11972  closeConnection(connection);
11974  }
11975  }
11976 
11989  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11990 
11991  CaseDbConnection connection = null;
11992  ResultSet resultSet = null;
11994  try {
11995  connection = connections.getConnection();
11996 
11997  // 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
11998  // FROM content_tags as content_tags, tsk_files as tsk_files
11999  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12000  // WHERE content_tags.obj_id = tsk_files.obj_id
12001  // AND content_tags.tag_name_id = ?
12002  // AND tsk_files.data_source_obj_id = ?
12003  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12004  statement.clearParameters();
12005  statement.setLong(1, tagName.getId());
12006  statement.setLong(2, dsObjId);
12007  resultSet = connection.executeQuery(statement);
12008  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12009  while (resultSet.next()) {
12010  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
12011  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12012  tags.add(tag);
12013  }
12014  resultSet.close();
12015  return tags;
12016  } catch (SQLException ex) {
12017  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
12018  } finally {
12019  closeResultSet(resultSet);
12020  closeConnection(connection);
12022  }
12023  }
12024 
12036  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
12037  CaseDbConnection connection = null;
12038  ResultSet resultSet = null;
12040  try {
12041  connection = connections.getConnection();
12042 
12043  // 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
12044  // FROM content_tags
12045  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
12046  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12047  // WHERE content_tags.obj_id = ?
12048  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
12049  statement.clearParameters();
12050  statement.setLong(1, content.getId());
12051  resultSet = connection.executeQuery(statement);
12052  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12053  while (resultSet.next()) {
12054  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12055  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12056  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12057  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
12058  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12059  tags.add(tag);
12060  }
12061  return tags;
12062  } catch (SQLException ex) {
12063  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
12064  } finally {
12065  closeResultSet(resultSet);
12066  closeConnection(connection);
12068  }
12069  }
12070 
12085  @Deprecated
12086  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
12087  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
12088  }
12089 
12090  /*
12091  * Deletes a row from the blackboard_artifact_tags table in the case
12092  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
12093  * representing the row to delete. @throws TskCoreException
12094  */
12095  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
12097  try {
12098  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
12099  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
12100  statement.clearParameters();
12101  statement.setLong(1, tag.getId());
12102  trans.getConnection().executeUpdate(statement);
12103 
12104  // update the aggregate score for the artifact
12105  Long artifactObjId = tag.getArtifact().getId();
12106  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
12107  ? tag.getContent().getDataSource().getId()
12108  : null;
12109 
12110  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
12111 
12112  trans.commit();
12113  trans = null;
12114  } catch (SQLException ex) {
12115  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
12116  } finally {
12117  if (trans != null) {
12118  trans.rollback();
12119  }
12120  }
12121  }
12122 
12132  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
12133  CaseDbConnection connection = null;
12134  ResultSet resultSet = null;
12136  try {
12137  connection = connections.getConnection();
12138 
12139  // 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
12140  // FROM blackboard_artifact_tags
12141  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12142  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12143  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
12144  resultSet = connection.executeQuery(statement);
12145  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12146  while (resultSet.next()) {
12147  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12148  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12149  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12150  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12151  Content content = getContentById(artifact.getObjectID());
12152  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12153  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12154  tags.add(tag);
12155  }
12156  return tags;
12157  } catch (SQLException ex) {
12158  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
12159  } finally {
12160  closeResultSet(resultSet);
12161  closeConnection(connection);
12163  }
12164  }
12165 
12176  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
12177  if (tagName.getId() == Tag.ID_NOT_SET) {
12178  throw new TskCoreException("TagName object is invalid, id not set");
12179  }
12180  CaseDbConnection connection = null;
12181  ResultSet resultSet = null;
12183  try {
12184  connection = connections.getConnection();
12185 
12186  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
12187  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
12188  statement.clearParameters();
12189  statement.setLong(1, tagName.getId());
12190  resultSet = connection.executeQuery(statement);
12191  if (resultSet.next()) {
12192  return resultSet.getLong("count");
12193  } else {
12194  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
12195  }
12196  } catch (SQLException ex) {
12197  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
12198  } finally {
12199  closeResultSet(resultSet);
12200  closeConnection(connection);
12202  }
12203  }
12204 
12219  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12220 
12221  if (tagName.getId() == Tag.ID_NOT_SET) {
12222  throw new TskCoreException("TagName object is invalid, id not set");
12223  }
12224 
12225  CaseDbConnection connection = null;
12226  ResultSet resultSet = null;
12228  try {
12229  connection = connections.getConnection();
12230 
12231  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
12232  // + " AND artifact_tags.tag_name_id = ?"
12233  // + " AND arts.data_source_obj_id = ? "
12234  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
12235  statement.clearParameters();
12236  statement.setLong(1, tagName.getId());
12237  statement.setLong(2, dsObjId);
12238  resultSet = connection.executeQuery(statement);
12239  if (resultSet.next()) {
12240  return resultSet.getLong("count");
12241  } else {
12242  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
12243  }
12244  } catch (SQLException ex) {
12245  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12246  } finally {
12247  closeResultSet(resultSet);
12248  closeConnection(connection);
12250  }
12251  }
12252 
12264  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
12265  if (tagName.getId() == Tag.ID_NOT_SET) {
12266  throw new TskCoreException("TagName object is invalid, id not set");
12267  }
12268  CaseDbConnection connection = null;
12269  ResultSet resultSet = null;
12271  try {
12272  connection = connections.getConnection();
12273 
12274  // 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
12275  // FROM blackboard_artifact_tags
12276  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12277  // WHERE tag_name_id = ?
12278  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
12279  statement.clearParameters();
12280  statement.setLong(1, tagName.getId());
12281  resultSet = connection.executeQuery(statement);
12282  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12283  while (resultSet.next()) {
12284  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12285  Content content = getContentById(artifact.getObjectID());
12286  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12287  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12288  tags.add(tag);
12289  }
12290  return tags;
12291  } catch (SQLException ex) {
12292  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
12293  } finally {
12294  closeResultSet(resultSet);
12295  closeConnection(connection);
12297  }
12298  }
12299 
12314  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12315 
12316  if (tagName.getId() == Tag.ID_NOT_SET) {
12317  throw new TskCoreException("TagName object is invalid, id not set");
12318  }
12319 
12320  CaseDbConnection connection = null;
12321  ResultSet resultSet = null;
12323  try {
12324  connection = connections.getConnection();
12325 
12326  // 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
12327  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
12328  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
12329  // WHERE artifact_tags.artifact_id = arts.artifact_id
12330  // AND artifact_tags.tag_name_id = ?
12331  // AND arts.data_source_obj_id = ?
12332  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12333  statement.clearParameters();
12334  statement.setLong(1, tagName.getId());
12335  statement.setLong(2, dsObjId);
12336  resultSet = connection.executeQuery(statement);
12337  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12338  while (resultSet.next()) {
12339  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12340  Content content = getContentById(artifact.getObjectID());
12341  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12342  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12343  tags.add(tag);
12344  }
12345  return tags;
12346  } catch (SQLException ex) {
12347  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12348  } finally {
12349  closeResultSet(resultSet);
12350  closeConnection(connection);
12352  }
12353 
12354  }
12355 
12367  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
12368 
12369  CaseDbConnection connection = null;
12370  ResultSet resultSet = null;
12371  BlackboardArtifactTag tag = null;
12373  try {
12374  connection = connections.getConnection();
12375 
12376  //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
12377  // FROM blackboard_artifact_tags
12378  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12379  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12380  // WHERE blackboard_artifact_tags.tag_id = ?
12381  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
12382  statement.clearParameters();
12383  statement.setLong(1, artifactTagID);
12384  resultSet = connection.executeQuery(statement);
12385 
12386  while (resultSet.next()) {
12387  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12388  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12389  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12390  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12391  Content content = getContentById(artifact.getObjectID());
12392  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12393  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
12394  }
12395  resultSet.close();
12396 
12397  } catch (SQLException ex) {
12398  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12399  } finally {
12400  closeResultSet(resultSet);
12401  closeConnection(connection);
12403  }
12404  return tag;
12405  }
12406 
12419  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12420  CaseDbConnection connection = null;
12421  ResultSet resultSet = null;
12423  try {
12424  connection = connections.getConnection();
12425 
12426  // 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
12427  // FROM blackboard_artifact_tags
12428  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12429  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12430  // WHERE blackboard_artifact_tags.artifact_id = ?
12431  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12432  statement.clearParameters();
12433  statement.setLong(1, artifact.getArtifactID());
12434  resultSet = connection.executeQuery(statement);
12435  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12436  while (resultSet.next()) {
12437  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12438  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12439  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12440  Content content = getContentById(artifact.getObjectID());
12441  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12442  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12443  tags.add(tag);
12444  }
12445  return tags;
12446  } catch (SQLException ex) {
12447  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12448  } finally {
12449  closeResultSet(resultSet);
12450  closeConnection(connection);
12452  }
12453  }
12454 
12463  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12465  try (CaseDbConnection connection = connections.getConnection();) {
12466  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12467  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12468  statement.clearParameters();
12469  statement.setString(1, newPath);
12470  statement.setLong(2, objectId);
12471  connection.executeUpdate(statement);
12472  } catch (SQLException ex) {
12473  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12474  } finally {
12476  }
12477  }
12478 
12492  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12493  return addReport(localPath, sourceModuleName, reportName, null);
12494  }
12495 
12511  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12512  // Make sure the local path of the report is in the database directory
12513  // or one of its subdirectories.
12514  String relativePath = ""; //NON-NLS
12515  long createTime = 0;
12516  String localPathLower = localPath.toLowerCase();
12517 
12518  if (localPathLower.startsWith("http")) {
12519  relativePath = localPathLower;
12520  createTime = System.currentTimeMillis() / 1000;
12521  } else {
12522  /*
12523  * Note: The following call to .relativize() may be dangerous in
12524  * case-sensitive operating systems and should be looked at. For
12525  * now, we are simply relativizing the paths as all lower case, then
12526  * using the length of the result to pull out the appropriate number
12527  * of characters from the localPath String.
12528  */
12529  try {
12530  String casePathLower = getDbDirPath().toLowerCase();
12531  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12532  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12533  } catch (IllegalArgumentException ex) {
12534  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12535  throw new TskCoreException(errorMessage, ex);
12536  }
12537  try {
12538  // get its file time
12539  java.io.File tempFile = new java.io.File(localPath);
12540  // Convert to UNIX epoch (seconds, not milliseconds).
12541  createTime = tempFile.lastModified() / 1000;
12542  } catch (Exception ex) {
12543  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12544  }
12545  }
12546 
12547  // Write the report data to the database.
12549  try (CaseDbConnection connection = connections.getConnection();) {
12550  // Insert a row for the report into the tsk_objects table.
12551  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12552  long parentObjId = 0;
12553  if (parent != null) {
12554  parentObjId = parent.getId();
12555  }
12556  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
12557 
12558  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
12559  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
12560  statement.clearParameters();
12561  statement.setLong(1, objectId);
12562  statement.setString(2, relativePath);
12563  statement.setLong(3, createTime);
12564  statement.setString(4, sourceModuleName);
12565  statement.setString(5, reportName);
12566  connection.executeUpdate(statement);
12567  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
12568  } catch (SQLException ex) {
12569  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
12570  } finally {
12572  }
12573  }
12574 
12583  public List<Report> getAllReports() throws TskCoreException {
12584  CaseDbConnection connection = null;
12585  ResultSet resultSet = null;
12586  ResultSet parentResultSet = null;
12587  PreparedStatement statement = null;
12588  Statement parentStatement = null;
12590  try {
12591  connection = connections.getConnection();
12592 
12593  // SELECT * FROM reports
12594  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
12595  parentStatement = connection.createStatement();
12596  resultSet = connection.executeQuery(statement);
12597  ArrayList<Report> reports = new ArrayList<Report>();
12598  while (resultSet.next()) {
12599  String localpath = resultSet.getString("path");
12600  if (localpath.toLowerCase().startsWith("http") == false) {
12601  // make path absolute
12602  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
12603  }
12604 
12605  // get the report parent
12606  Content parent = null;
12607  long reportId = resultSet.getLong("obj_id"); // NON-NLS
12608  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
12609  parentResultSet = parentStatement.executeQuery(parentQuery);
12610  if (parentResultSet.next()) {
12611  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12612  parent = this.getContentById(parentId);
12613  }
12614  parentResultSet.close();
12615 
12616  reports.add(new Report(this,
12617  reportId,
12618  localpath,
12619  resultSet.getLong("crtime"), //NON-NLS
12620  resultSet.getString("src_module_name"), //NON-NLS
12621  resultSet.getString("report_name"),
12622  parent)); //NON-NLS
12623  }
12624  return reports;
12625  } catch (SQLException ex) {
12626  throw new TskCoreException("Error querying reports table", ex);
12627  } finally {
12628  closeResultSet(resultSet);
12629  closeResultSet(parentResultSet);
12630  closeStatement(statement);
12631  closeStatement(parentStatement);
12632 
12633  closeConnection(connection);
12635  }
12636  }
12637 
12647  public Report getReportById(long id) throws TskCoreException {
12648  CaseDbConnection connection = null;
12649  PreparedStatement statement = null;
12650  Statement parentStatement = null;
12651  ResultSet resultSet = null;
12652  ResultSet parentResultSet = null;
12653  Report report = null;
12655  try {
12656  connection = connections.getConnection();
12657 
12658  // SELECT * FROM reports WHERE obj_id = ?
12659  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
12660  parentStatement = connection.createStatement();
12661  statement.clearParameters();
12662  statement.setLong(1, id);
12663  resultSet = connection.executeQuery(statement);
12664 
12665  if (resultSet.next()) {
12666  // get the report parent
12667  Content parent = null;
12668  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
12669  parentResultSet = parentStatement.executeQuery(parentQuery);
12670  if (parentResultSet.next()) {
12671  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12672  parent = this.getContentById(parentId);
12673  }
12674 
12675  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
12676  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
12677  resultSet.getLong("crtime"), //NON-NLS
12678  resultSet.getString("src_module_name"), //NON-NLS
12679  resultSet.getString("report_name"),
12680  parent); //NON-NLS
12681  } else {
12682  throw new TskCoreException("No report found for id: " + id);
12683  }
12684  } catch (SQLException ex) {
12685  throw new TskCoreException("Error querying reports table for id: " + id, ex);
12686  } finally {
12687  closeResultSet(resultSet);
12688  closeResultSet(parentResultSet);
12689  closeStatement(statement);
12690  closeStatement(parentStatement);
12691  closeConnection(connection);
12693  }
12694 
12695  return report;
12696  }
12697 
12705  public void deleteReport(Report report) throws TskCoreException {
12707  try (CaseDbConnection connection = connections.getConnection();) {
12708  // DELETE FROM reports WHERE reports.obj_id = ?
12709  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
12710  statement.setLong(1, report.getId());
12711  connection.executeUpdate(statement);
12712  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
12713  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
12714  statement.setLong(1, report.getId());
12715  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
12716  connection.executeUpdate(statement);
12717  } catch (SQLException ex) {
12718  throw new TskCoreException("Error querying reports table", ex);
12719  } finally {
12721  }
12722  }
12723 
12724  static void closeResultSet(ResultSet resultSet) {
12725  if (resultSet != null) {
12726  try {
12727  resultSet.close();
12728  } catch (SQLException ex) {
12729  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
12730  }
12731  }
12732  }
12733 
12734  static void closeStatement(Statement statement) {
12735  if (statement != null) {
12736  try {
12737  statement.close();
12738  } catch (SQLException ex) {
12739  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
12740 
12741  }
12742  }
12743  }
12744 
12745  static void closeConnection(CaseDbConnection connection) {
12746  if (connection != null) {
12747  connection.close();
12748  }
12749  }
12750 
12751  private static void rollbackTransaction(CaseDbConnection connection) {
12752  if (connection != null) {
12753  connection.rollbackTransaction();
12754  }
12755  }
12756 
12765  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
12767  try (CaseDbConnection connection = connections.getConnection();) {
12768  Statement statement = connection.createStatement();
12769  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
12770  } catch (SQLException ex) {
12771  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
12772  } finally {
12774  }
12775  }
12776 
12777  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
12779  try (CaseDbConnection connection = connections.getConnection();
12780  Statement statement = connection.createStatement();) {
12781  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
12782  } catch (SQLException ex) {
12783  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
12784  } finally {
12786  }
12787  }
12788 
12805  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
12806  CaseDbConnection connection = null;
12808  ResultSet resultSet = null;
12809  Statement statement;
12810  try {
12811  connection = connections.getConnection();
12812  connection.beginTransaction();
12813  statement = connection.createStatement();
12814  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
12815  insertStatement.setLong(1, dataSource.getId());
12816  insertStatement.setString(2, hostName);
12817  insertStatement.setLong(3, jobStart.getTime());
12818  insertStatement.setLong(4, jobEnd.getTime());
12819  insertStatement.setInt(5, status.ordinal());
12820  insertStatement.setString(6, settingsDir);
12821  connection.executeUpdate(insertStatement);
12822  resultSet = insertStatement.getGeneratedKeys();
12823  resultSet.next();
12824  long id = resultSet.getLong(1); //last_insert_rowid()
12825  for (int i = 0; i < ingestModules.size(); i++) {
12826  IngestModuleInfo ingestModule = ingestModules.get(i);
12827  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
12828  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
12829  }
12830  resultSet.close();
12831  resultSet = null;
12832  connection.commitTransaction();
12833  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
12834  } catch (SQLException ex) {
12835  rollbackTransaction(connection);
12836  throw new TskCoreException("Error adding the ingest job.", ex);
12837  } finally {
12838  closeResultSet(resultSet);
12839  closeConnection(connection);
12841  }
12842  }
12843 
12857  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
12858  CaseDbConnection connection = null;
12859  ResultSet resultSet = null;
12860  Statement statement = null;
12861  String uniqueName = factoryClassName + "-" + displayName + "-" + version;
12863  try {
12864  connection = connections.getConnection();
12865  statement = connection.createStatement();
12866  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12867  if (!resultSet.next()) {
12868  resultSet.close();
12869  resultSet = null;
12870  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
12871  insertStatement.setString(1, displayName);
12872  insertStatement.setString(2, uniqueName);
12873  insertStatement.setInt(3, type.ordinal());
12874  insertStatement.setString(4, version);
12875  connection.executeUpdate(insertStatement);
12876  resultSet = statement.getGeneratedKeys();
12877  resultSet.next();
12878  long id = resultSet.getLong(1); //last_insert_rowid()
12879  resultSet.close();
12880  resultSet = null;
12881  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
12882  } else {
12883  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12884  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12885  }
12886  } catch (SQLException ex) {
12887  try {
12888  closeStatement(statement);
12889  if (connection != null) {
12890  statement = connection.createStatement();
12891  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12892  if (resultSet.next()) {
12893  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12894  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12895  }
12896  }
12897  throw new TskCoreException("Couldn't add new module to database.", ex);
12898  } catch (SQLException ex1) {
12899  throw new TskCoreException("Couldn't add new module to database.", ex1);
12900  }
12901  } finally {
12902  closeResultSet(resultSet);
12903  closeStatement(statement);
12904  closeConnection(connection);
12906  }
12907  }
12908 
12916  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
12917  CaseDbConnection connection = null;
12918  ResultSet resultSet = null;
12919  Statement statement = null;
12920  List<IngestJobInfo> ingestJobs = new ArrayList<>();
12922  try {
12923  connection = connections.getConnection();
12924  statement = connection.createStatement();
12925  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
12926  while (resultSet.next()) {
12927  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
12928  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
12929  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
12930  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
12931  }
12932  return ingestJobs;
12933  } catch (SQLException ex) {
12934  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
12935  } finally {
12936  closeResultSet(resultSet);
12937  closeStatement(statement);
12938  closeConnection(connection);
12940  }
12941  }
12942 
12953  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
12954  ResultSet resultSet = null;
12955  Statement statement = null;
12956  List<IngestModuleInfo> ingestModules = new ArrayList<>();
12958  try {
12959  statement = connection.createStatement();
12960  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
12961  + "ingest_job_modules.pipeline_position AS pipeline_position, "
12962  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
12963  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
12964  + "FROM ingest_job_modules, ingest_modules "
12965  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
12966  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
12967  + "ORDER BY (ingest_job_modules.pipeline_position);");
12968  while (resultSet.next()) {
12969  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12970  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
12971  }
12972  return ingestModules;
12973  } finally {
12974  closeResultSet(resultSet);
12975  closeStatement(statement);
12977 
12978  }
12979  }
12980 
12990  String getInsertOrIgnoreSQL(String sql) {
12991  switch (getDatabaseType()) {
12992  case POSTGRESQL:
12993  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
12994  case SQLITE:
12995  return " INSERT OR IGNORE " + sql; //NON-NLS
12996  default:
12997  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
12998  }
12999  }
13000 
13021  private List<? extends BlackboardArtifact> getArtifactsForValues(BlackboardArtifact.Category category, String dbColumn, List<? extends Number> values, CaseDbConnection connection) throws TskCoreException {
13022  String where = "";
13023  // This look creates the OR statment with the following format:
13024  // <dbColumn> = <value> OR <dbColumn> = <value2> OR ...
13025  for (Number value : values) {
13026  if (!where.isEmpty()) {
13027  where += " OR ";
13028  }
13029  where += dbColumn + " = " + value;
13030  }
13031 
13032  // Base on the category pass the OR statement to the approprate method
13033  // that will retrieve the artifacts.
13034  if (category == BlackboardArtifact.Category.DATA_ARTIFACT) {
13035  return blackboard.getDataArtifactsWhere(where, connection);
13036  } else {
13037  return blackboard.getAnalysisResultsWhere(where, connection);
13038  }
13039  }
13040 
13044  static class ObjectInfo {
13045 
13046  private long id;
13047  private TskData.ObjectType type;
13048 
13049  ObjectInfo(long id, ObjectType type) {
13050  this.id = id;
13051  this.type = type;
13052  }
13053 
13054  long getId() {
13055  return id;
13056  }
13057 
13058  TskData.ObjectType getType() {
13059  return type;
13060  }
13061  }
13062 
13063  private interface DbCommand {
13064 
13065  void execute() throws SQLException;
13066  }
13067 
13068  private enum PREPARED_STATEMENT {
13069 
13070  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
13071  + "WHERE artifact_type_id = ?"), //NON-NLS
13072  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
13073  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
13074  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
13075  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
13076  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
13077  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13078  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13079  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
13080  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
13081  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
13082  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13083  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13084  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
13085  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13086  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13087  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13088  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13089  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
13090  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13091  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13092  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13093  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13094  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13095  + "WHERE tsk_files.extension = ? AND "
13096  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
13097  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13098  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13099  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13100  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13101  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13102  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
13103  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13104  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13105  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13106  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
13107  + "AND tsk_files.type = ? )"), //NON-NLS
13108  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
13109  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13110  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13111  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
13112  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
13113  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13114  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
13115  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13116  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
13117  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13118  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
13119  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13120  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
13121  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13122  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
13123  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13124  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
13125  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13126  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
13127  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13128  INSERT_FILE_ATTRIBUTE("INSERT INTO tsk_file_attributes (obj_id, attribute_type_id, value_type, value_byte, value_text, value_int32, value_int64, value_double) " //NON-NLS
13129  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
13130  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
13131  SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME("SELECT * FROM tsk_files WHERE extension = ? AND LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND data_source_obj_id = ?"), //NON-NLS
13132  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
13133  SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME("SELECT * FROM tsk_files WHERE extension = ? AND LOWER(name) LIKE LOWER(?) AND LOWER(name) NOT LIKE LOWER('%journal%') AND LOWER(parent_path) LIKE LOWER(?) AND data_source_obj_id = ?"), //NON-NLS
13134  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13135  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13136  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
13137  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
13138  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13139  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13140  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13141  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
13142  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
13143  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
13144  SELECT_ACQUISITION_TOOL_SETTINGS("SELECT acquisition_tool_settings, acquisition_tool_name, acquisition_tool_version, added_date_time FROM data_source_info WHERE obj_id = ?"), //NON-NLS
13145  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
13146  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
13147  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
13148  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13149  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13150  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
13151  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
13152  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
13153  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
13154  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, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id, collected) " //NON-NLS
13155  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
13156  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, md5, sha256, sha1, mime_type, parent_path, extension, owner_uid, os_account_obj_id, collected)"
13157  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
13158  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
13159  + "WHERE obj_id = ?"), //NON-NLS
13160  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
13161  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13162  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
13163  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
13164  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
13165  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
13166  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
13167  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
13168  + "WHERE tag_name_id IN " //NON-NLS
13169  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
13170  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
13171  + "WHERE tag_name_id IN "
13172  + "( SELECT content_tags.tag_name_id as tag_name_id "
13173  + "FROM content_tags as content_tags, tsk_files as tsk_files"
13174  + " WHERE content_tags.obj_id = tsk_files.obj_id"
13175  + " AND tsk_files.data_source_obj_id = ?"
13176  + " UNION "
13177  + "SELECT artifact_tags.tag_name_id as tag_name_id "
13178  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
13179  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
13180  + " AND arts.data_source_obj_id = ?"
13181  + " )"),
13182  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
13183  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13184  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
13185  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
13186  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
13187  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
13188  + " AND content_tags.tag_name_id = ? "
13189  + " AND tsk_files.data_source_obj_id = ? "
13190  ),
13191  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 "
13192  + "FROM content_tags "
13193  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13194  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13195  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 "
13196  + "FROM content_tags "
13197  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13198  + "WHERE tag_name_id = ?"), //NON-NLS
13199  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 "
13200  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
13201  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
13202  + " AND content_tags.obj_id = tsk_files.obj_id"
13203  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
13204  + " AND content_tags.tag_name_id = ?"
13205  + " AND tsk_files.data_source_obj_id = ? "),
13206  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 "
13207  + "FROM content_tags "
13208  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13209  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13210  + "WHERE tag_id = ?"), //NON-NLS
13211  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 "
13212  + "FROM content_tags "
13213  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13214  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13215  + "WHERE content_tags.obj_id = ?"), //NON-NLS
13216  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
13217  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13218  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
13219  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 "
13220  + "FROM blackboard_artifact_tags "
13221  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13222  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13223  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
13224  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"
13225  + " AND artifact_tags.tag_name_id = ?"
13226  + " AND arts.data_source_obj_id = ? "),
13227  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 "
13228  + "FROM blackboard_artifact_tags "
13229  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13230  + "WHERE tag_name_id = ?"), //NON-NLS
13231  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 "
13232  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
13233  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
13234  + " AND artifact_tags.artifact_id = arts.artifact_id"
13235  + " AND artifact_tags.tag_name_id = ? "
13236  + " AND arts.data_source_obj_id = ? "),
13237  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 "
13238  + "FROM blackboard_artifact_tags "
13239  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13240  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13241  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
13242  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 "
13243  + "FROM blackboard_artifact_tags "
13244  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13245  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13246  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
13247  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
13248  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
13249  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
13250  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
13251  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
13252  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13253  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
13254  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
13255  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
13256  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
13257  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
13258  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
13259  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
13260  + "WHERE (tsk_objects.par_obj_id = ?)"),
13261  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
13262  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
13263  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
13264  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
13265  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
13266  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
13267  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
13268  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
13269  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
13270  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
13271  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13272  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"),
13273  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
13274  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13275  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13276  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
13277  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)"
13278  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13279  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?");
13280 
13281  private final String sql;
13282 
13283  private PREPARED_STATEMENT(String sql) {
13284  this.sql = sql;
13285  }
13286 
13287  String getSQL() {
13288  return sql;
13289  }
13290  }
13291 
13297  abstract private class ConnectionPool {
13298 
13299  private PooledDataSource pooledDataSource;
13300 
13301  public ConnectionPool() {
13302  pooledDataSource = null;
13303  }
13304 
13305  CaseDbConnection getConnection() throws TskCoreException {
13306  if (pooledDataSource == null) {
13307  throw new TskCoreException("Error getting case database connection - case is closed");
13308  }
13309  try {
13310  return getPooledConnection();
13311  } catch (SQLException exp) {
13312  throw new TskCoreException(exp.getMessage());
13313  }
13314  }
13315 
13316  void close() throws TskCoreException {
13317  if (pooledDataSource != null) {
13318  try {
13319  pooledDataSource.close();
13320  } catch (SQLException exp) {
13321  throw new TskCoreException(exp.getMessage());
13322  } finally {
13323  pooledDataSource = null;
13324  }
13325  }
13326  }
13327 
13328  abstract CaseDbConnection getPooledConnection() throws SQLException;
13329 
13330  public PooledDataSource getPooledDataSource() {
13331  return pooledDataSource;
13332  }
13333 
13334  public void setPooledDataSource(PooledDataSource pooledDataSource) {
13335  this.pooledDataSource = pooledDataSource;
13336  }
13337  }
13338 
13343  private final class SQLiteConnections extends ConnectionPool {
13344 
13345  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
13346 
13347  SQLiteConnections(String dbPath) throws SQLException {
13348  configurationOverrides.put("acquireIncrement", "2");
13349  configurationOverrides.put("initialPoolSize", "5");
13350  configurationOverrides.put("minPoolSize", "5");
13351  /*
13352  * NOTE: max pool size and max statements are related. If you
13353  * increase max pool size, then also increase statements.
13354  */
13355  configurationOverrides.put("maxPoolSize", "20");
13356  configurationOverrides.put("maxStatements", "200");
13357  configurationOverrides.put("maxStatementsPerConnection", "20");
13358 
13359  SQLiteConfig config = new SQLiteConfig();
13360  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
13361  config.setReadUncommited(true);
13362  config.enforceForeignKeys(true); // Enforce foreign key constraints.
13363  SQLiteDataSource unpooled = new SQLiteDataSource(config);
13364  unpooled.setUrl("jdbc:sqlite:" + dbPath);
13365  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
13366  }
13367 
13368  @Override
13369  public CaseDbConnection getPooledConnection() throws SQLException {
13370  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
13371  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
13372  // Temporarily filter out Image Gallery threads
13373  if (!Thread.currentThread().getName().contains("ImageGallery")) {
13374  logger.log(Level.WARNING, String.format("Thread %s (ID = %d) already has an open transaction. New connection may encounter SQLITE_BUSY error. ", Thread.currentThread().getName(), Thread.currentThread().getId()), new Throwable());
13375  }
13376  }
13377  return new SQLiteConnection(getPooledDataSource().getConnection());
13378  }
13379  }
13380 
13385  private final class PostgreSQLConnections extends ConnectionPool {
13386 
13387  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
13388  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
13389  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
13390  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
13391  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
13392  comboPooledDataSource.setUser(userName);
13393  comboPooledDataSource.setPassword(password);
13394  comboPooledDataSource.setAcquireIncrement(2);
13395  comboPooledDataSource.setInitialPoolSize(5);
13396  comboPooledDataSource.setMinPoolSize(5);
13397  /*
13398  * NOTE: max pool size and max statements are related. If you
13399  * increase max pool size, then also increase statements.
13400  */
13401  comboPooledDataSource.setMaxPoolSize(20);
13402  comboPooledDataSource.setMaxStatements(200);
13403  comboPooledDataSource.setMaxStatementsPerConnection(20);
13404  setPooledDataSource(comboPooledDataSource);
13405  }
13406 
13407  @Override
13408  public CaseDbConnection getPooledConnection() throws SQLException {
13409  return new PostgreSQLConnection(getPooledDataSource().getConnection());
13410  }
13411  }
13412 
13416  abstract class CaseDbConnection implements AutoCloseable {
13417 
13418  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
13419  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
13420 
13421  private class CreateStatement implements DbCommand {
13422 
13423  private final Connection connection;
13424  private Statement statement = null;
13425 
13426  CreateStatement(Connection connection) {
13427  this.connection = connection;
13428  }
13429 
13430  Statement getStatement() {
13431  return statement;
13432  }
13433 
13434  @Override
13435  public void execute() throws SQLException {
13436  statement = connection.createStatement();
13437  }
13438  }
13439 
13440  private class SetAutoCommit implements DbCommand {
13441 
13442  private final Connection connection;
13443  private final boolean mode;
13444 
13445  SetAutoCommit(Connection connection, boolean mode) {
13446  this.connection = connection;
13447  this.mode = mode;
13448  }
13449 
13450  @Override
13451  public void execute() throws SQLException {
13452  connection.setAutoCommit(mode);
13453  }
13454  }
13455 
13456  private class Commit implements DbCommand {
13457 
13458  private final Connection connection;
13459 
13460  Commit(Connection connection) {
13461  this.connection = connection;
13462  }
13463 
13464  @Override
13465  public void execute() throws SQLException {
13466  connection.commit();
13467  }
13468  }
13469 
13478  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13479 
13480  private final Connection connection;
13481 
13482  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13483  this.connection = connection;
13484  }
13485 
13486  @Override
13487  public void execute() throws SQLException {
13488  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13489  preparedStatement.execute();
13490 
13491  }
13492  }
13493 
13494  private class ExecuteQuery implements DbCommand {
13495 
13496  private final Statement statement;
13497  private final String query;
13498  private ResultSet resultSet;
13499 
13500  ExecuteQuery(Statement statement, String query) {
13501  this.statement = statement;
13502  this.query = query;
13503  }
13504 
13505  ResultSet getResultSet() {
13506  return resultSet;
13507  }
13508 
13509  @Override
13510  public void execute() throws SQLException {
13511  resultSet = statement.executeQuery(query);
13512  }
13513  }
13514 
13515  private class ExecutePreparedStatementQuery implements DbCommand {
13516 
13517  private final PreparedStatement preparedStatement;
13518  private ResultSet resultSet;
13519 
13520  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13521  this.preparedStatement = preparedStatement;
13522  }
13523 
13524  ResultSet getResultSet() {
13525  return resultSet;
13526  }
13527 
13528  @Override
13529  public void execute() throws SQLException {
13530  resultSet = preparedStatement.executeQuery();
13531  }
13532  }
13533 
13534  private class ExecutePreparedStatementUpdate implements DbCommand {
13535 
13536  private final PreparedStatement preparedStatement;
13537 
13538  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
13539  this.preparedStatement = preparedStatement;
13540  }
13541 
13542  @Override
13543  public void execute() throws SQLException {
13544  preparedStatement.executeUpdate();
13545  }
13546  }
13547 
13548  private class ExecuteStatementUpdate implements DbCommand {
13549 
13550  private final Statement statement;
13551  private final String updateCommand;
13552 
13553  ExecuteStatementUpdate(Statement statement, String updateCommand) {
13554  this.statement = statement;
13555  this.updateCommand = updateCommand;
13556  }
13557 
13558  @Override
13559  public void execute() throws SQLException {
13560  statement.executeUpdate(updateCommand);
13561  }
13562  }
13563 
13564  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
13565 
13566  private final Statement statement;
13567  private final int generateKeys;
13568  private final String updateCommand;
13569 
13570  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
13571  this.statement = statement;
13572  this.generateKeys = generateKeys;
13573  this.updateCommand = updateCommand;
13574  }
13575 
13576  @Override
13577  public void execute() throws SQLException {
13578  statement.executeUpdate(updateCommand, generateKeys);
13579  }
13580  }
13581 
13582  private class PrepareStatement implements DbCommand {
13583 
13584  private final Connection connection;
13585  private final String input;
13586  private PreparedStatement preparedStatement = null;
13587 
13588  PrepareStatement(Connection connection, String input) {
13589  this.connection = connection;
13590  this.input = input;
13591  }
13592 
13593  PreparedStatement getPreparedStatement() {
13594  return preparedStatement;
13595  }
13596 
13597  @Override
13598  public void execute() throws SQLException {
13599  preparedStatement = connection.prepareStatement(input);
13600  }
13601  }
13602 
13603  private class PrepareStatementGenerateKeys implements DbCommand {
13604 
13605  private final Connection connection;
13606  private final String input;
13607  private final int generateKeys;
13608  private PreparedStatement preparedStatement = null;
13609 
13610  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
13611  this.connection = connection;
13612  this.input = input;
13613  this.generateKeys = generateKeysInput;
13614  }
13615 
13616  PreparedStatement getPreparedStatement() {
13617  return preparedStatement;
13618  }
13619 
13620  @Override
13621  public void execute() throws SQLException {
13622  preparedStatement = connection.prepareStatement(input, generateKeys);
13623  }
13624  }
13625 
13626  abstract void executeCommand(DbCommand command) throws SQLException;
13627 
13628  private final Connection connection;
13629  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
13630  private final Map<String, PreparedStatement> adHocPreparedStatements;
13631 
13632  CaseDbConnection(Connection connection) {
13633  this.connection = connection;
13634  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
13635  adHocPreparedStatements = new HashMap<>();
13636  }
13637 
13638  boolean isOpen() {
13639  return this.connection != null;
13640  }
13641 
13642  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
13643  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
13644  }
13645 
13646  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
13647  // Lazy statement preparation.
13648  PreparedStatement statement;
13649  if (this.preparedStatements.containsKey(statementKey)) {
13650  statement = this.preparedStatements.get(statementKey);
13651  } else {
13652  statement = prepareStatement(statementKey.getSQL(), generateKeys);
13653  this.preparedStatements.put(statementKey, statement);
13654  }
13655  return statement;
13656  }
13657 
13669  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
13670  PreparedStatement statement;
13671  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
13672  if (adHocPreparedStatements.containsKey(statementKey) && !adHocPreparedStatements.get(statementKey).isClosed()) {
13673  statement = this.adHocPreparedStatements.get(statementKey);
13674  } else {
13675  statement = prepareStatement(sqlStatement, generateKeys);
13676  this.adHocPreparedStatements.put(statementKey, statement);
13677  }
13678  return statement;
13679  }
13680 
13681  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13682  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
13683  executeCommand(prepareStatement);
13684  return prepareStatement.getPreparedStatement();
13685  }
13686 
13687  Statement createStatement() throws SQLException {
13688  CreateStatement createStatement = new CreateStatement(this.connection);
13689  executeCommand(createStatement);
13690  return createStatement.getStatement();
13691  }
13692 
13693  void beginTransaction() throws SQLException {
13694  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
13695  executeCommand(setAutoCommit);
13696  }
13697 
13698  void commitTransaction() throws SQLException {
13699  Commit commit = new Commit(connection);
13700  executeCommand(commit);
13701  // You must turn auto commit back on when done with the transaction.
13702  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
13703  executeCommand(setAutoCommit);
13704  }
13705 
13711  void rollbackTransaction() {
13712  try {
13713  connection.rollback();
13714  } catch (SQLException e) {
13715  logger.log(Level.SEVERE, "Error rolling back transaction", e);
13716  }
13717  try {
13718  connection.setAutoCommit(true);
13719  } catch (SQLException e) {
13720  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
13721  }
13722  }
13723 
13731  void rollbackTransactionWithThrow() throws SQLException {
13732  try {
13733  connection.rollback();
13734  } finally {
13735  connection.setAutoCommit(true);
13736  }
13737  }
13738 
13747  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
13748  switch (getDatabaseType()) {
13749  case POSTGRESQL:
13750  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
13751  executeCommand(tableWriteLock);
13752  break;
13753  case SQLITE:
13754  // We do nothing here because we assume the entire SQLite DB is already locked from
13755  // when the analysis results were added/deleted in the same transaction.
13756  break;
13757  default:
13758  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
13759  }
13760  }
13761 
13762  ResultSet executeQuery(Statement statement, String query) throws SQLException {
13763  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
13764  executeCommand(queryCommand);
13765  return queryCommand.getResultSet();
13766  }
13767 
13777  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
13778  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
13779  executeCommand(executePreparedStatementQuery);
13780  return executePreparedStatementQuery.getResultSet();
13781  }
13782 
13783  void executeUpdate(Statement statement, String update) throws SQLException {
13784  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
13785  }
13786 
13787  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13788  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
13789  executeCommand(executeStatementUpdate);
13790  }
13791 
13792  void executeUpdate(PreparedStatement statement) throws SQLException {
13793  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
13794  executeCommand(executePreparedStatementUpdate);
13795  }
13796 
13800  @Override
13801  public void close() {
13802  try {
13803  for (PreparedStatement stmt : preparedStatements.values()) {
13804  closeStatement(stmt);
13805  }
13806  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
13807  closeStatement(stmt);
13808  }
13809  connection.close();
13810  } catch (SQLException ex) {
13811  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
13812  }
13813  }
13814 
13815  Connection getConnection() {
13816  return this.connection;
13817  }
13818  }
13819 
13823  private final class SQLiteConnection extends CaseDbConnection {
13824 
13825  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
13826  private static final int SQLITE_BUSY_ERROR = 5;
13827 
13828  SQLiteConnection(Connection conn) {
13829  super(conn);
13830  }
13831 
13832  @Override
13833  void executeCommand(DbCommand command) throws SQLException {
13834  int retryCounter = 0;
13835  while (true) {
13836  try {
13837  command.execute(); // Perform the operation
13838  break;
13839  } catch (SQLException ex) {
13840  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
13841  try {
13842 
13843  // We do not notify of error here, as this is not an
13844  // error condition. It is likely a temporary busy or
13845  // locked issue and we will retry.
13846  retryCounter++;
13847  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13848  } catch (InterruptedException exp) {
13849  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13850  }
13851  } else {
13852  throw ex;
13853  }
13854  }
13855  }
13856  }
13857  }
13858 
13862  private final class PostgreSQLConnection extends CaseDbConnection {
13863 
13864  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
13865  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
13866  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
13867  private static final int MAX_RETRIES = 3;
13868 
13869  PostgreSQLConnection(Connection conn) {
13870  super(conn);
13871  }
13872 
13873  @Override
13874  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13875  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
13876  executeCommand(executeStatementUpdateGenerateKeys);
13877  }
13878 
13879  @Override
13880  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13881  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
13882  executeCommand(prepareStatementGenerateKeys);
13883  return prepareStatementGenerateKeys.getPreparedStatement();
13884  }
13885 
13886  @Override
13887  void executeCommand(DbCommand command) throws SQLException {
13888  SQLException lastException = null;
13889  for (int retries = 0; retries < MAX_RETRIES; retries++) {
13890  try {
13891  command.execute();
13892  lastException = null; // reset since we had a successful execution
13893  break;
13894  } catch (SQLException ex) {
13895  lastException = ex;
13896  String sqlState = ex.getSQLState();
13897  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
13898  try {
13899  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13900  } catch (InterruptedException exp) {
13901  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13902  }
13903  } else {
13904  throw ex;
13905  }
13906  }
13907  }
13908 
13909  // rethrow the exception if we bailed because of too many retries
13910  if (lastException != null) {
13911  throw lastException;
13912  }
13913  }
13914  }
13915 
13947  public static final class CaseDbTransaction {
13948 
13949  private final CaseDbConnection connection;
13950  private SleuthkitCase sleuthkitCase;
13951 
13952  /* This class can store information about what was
13953  * inserted as part of the transaction so that we can
13954  * fire events after the data has been persisted. */
13955 
13956  // Score changes are stored as a map keyed by objId to prevent duplicates.
13957  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
13958  private List<Host> hostsAdded = new ArrayList<>();
13959  private List<TimelineEventAddedEvent> timelineEvents = new ArrayList<>();
13960  private List<OsAccount> accountsChanged = new ArrayList<>();
13961  private List<OsAccount> accountsAdded = new ArrayList<>();
13962  private List<TskEvent.MergedAccountsPair> accountsMerged = new ArrayList<>();
13963 
13964  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
13965  private List<Long> deletedResultObjectIds = new ArrayList<>();
13966 
13967  // Keep track of which threads have connections to debug deadlocks
13968  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
13969  private static final Object threadsWithOpenTransactionLock = new Object();
13970 
13971  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
13972  this.sleuthkitCase = sleuthkitCase;
13973 
13974  sleuthkitCase.acquireSingleUserCaseWriteLock();
13975  this.connection = sleuthkitCase.getConnection();
13976  try {
13977  synchronized (threadsWithOpenTransactionLock) {
13978  this.connection.beginTransaction();
13979  threadsWithOpenTransaction.add(Thread.currentThread().getId());
13980  }
13981  } catch (SQLException ex) {
13982  sleuthkitCase.releaseSingleUserCaseWriteLock();
13983  throw new TskCoreException("Failed to create transaction on case database", ex);
13984  }
13985 
13986  }
13987 
13995  CaseDbConnection getConnection() {
13996  return this.connection;
13997  }
13998 
14004  void registerScoreChange(ScoreChange scoreChange) {
14005  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
14006  }
14007 
14012  void registerTimelineEvent(TimelineEventAddedEvent timelineEvent) {
14013  if (timelineEvent != null) {
14014  timelineEvents.add(timelineEvent);
14015  }
14016  }
14017 
14023  void registerAddedHost(Host host) {
14024  if (host != null) {
14025  this.hostsAdded.add(host);
14026  }
14027  }
14028 
14034  void registerChangedOsAccount(OsAccount account) {
14035  if (account != null) {
14036  accountsChanged.add(account);
14037  }
14038  }
14039 
14045  void registerDeletedOsAccount(long osAccountObjId) {
14046  deletedOsAccountObjectIds.add(osAccountObjId);
14047  }
14048 
14054  void registerAddedOsAccount(OsAccount account) {
14055  if (account != null) {
14056  accountsAdded.add(account);
14057  }
14058  }
14059 
14066  void registerMergedOsAccount(long sourceOsAccountObjId, long destinationOsAccountObjId) {
14067  accountsMerged.add(new TskEvent.MergedAccountsPair(sourceOsAccountObjId, destinationOsAccountObjId));
14068  }
14069 
14076  void registerDeletedAnalysisResult(long analysisResultObjId) {
14077  this.deletedResultObjectIds.add(analysisResultObjId);
14078  }
14079 
14088  private static boolean hasOpenTransaction(long threadId) {
14089  synchronized (threadsWithOpenTransactionLock) {
14090  return threadsWithOpenTransaction.contains(threadId);
14091  }
14092  }
14093 
14100  public void commit() throws TskCoreException {
14101  try {
14102  this.connection.commitTransaction();
14103  } catch (SQLException ex) {
14104  throw new TskCoreException("Failed to commit transaction on case database", ex);
14105  } finally {
14106  close();
14107 
14108  if (!scoreChangeMap.isEmpty()) {
14109  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
14110  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
14111  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
14112  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
14113  }
14114  }
14115  if (!timelineEvents.isEmpty()) {
14116  for (TimelineEventAddedEvent evt : timelineEvents) {
14117  sleuthkitCase.fireTSKEvent(evt);
14118  }
14119  }
14120  if (!hostsAdded.isEmpty()) {
14121  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
14122  }
14123  if (!accountsAdded.isEmpty()) {
14124  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
14125  }
14126  if (!accountsChanged.isEmpty()) {
14127  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
14128  }
14129  if (!accountsMerged.isEmpty()) {
14130  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsMergedTskEvent(accountsMerged));
14131  }
14132  if (!deletedOsAccountObjectIds.isEmpty()) {
14133  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
14134  }
14135  if (!deletedResultObjectIds.isEmpty()) {
14136  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
14137  }
14138  }
14139  }
14140 
14147  public void rollback() throws TskCoreException {
14148  try {
14149  this.connection.rollbackTransactionWithThrow();
14150  } catch (SQLException ex) {
14151  throw new TskCoreException("Case database transaction rollback failed", ex);
14152  } finally {
14153  close();
14154  }
14155  }
14156 
14161  void close() {
14162  this.connection.close();
14163  sleuthkitCase.releaseSingleUserCaseWriteLock();
14164  synchronized (threadsWithOpenTransactionLock) {
14165  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
14166  }
14167  }
14168  }
14169 
14179  public final class CaseDbQuery implements AutoCloseable {
14180 
14181  private ResultSet resultSet;
14182  private CaseDbConnection connection;
14183 
14184  private CaseDbQuery(String query) throws TskCoreException {
14185  this(query, false);
14186  }
14187 
14188  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
14189  if (!allowWriteQuery) {
14190  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
14191  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
14192  }
14193  }
14194 
14196  try {
14197  connection = connections.getConnection();
14198  resultSet = connection.executeQuery(connection.createStatement(), query);
14199  } catch (SQLException ex) {
14201  throw new TskCoreException("Error executing query: ", ex);
14202  } catch (TskCoreException ex) {
14204  throw ex;
14205  }
14206  }
14207 
14213  public ResultSet getResultSet() {
14214  return resultSet;
14215  }
14216 
14217  @Override
14218  public void close() throws TskCoreException {
14219  try {
14220  if (resultSet != null) {
14221  final Statement statement = resultSet.getStatement();
14222  if (statement != null) {
14223  statement.close();
14224  }
14225  resultSet.close();
14226  }
14227  closeConnection(connection);
14228  } catch (SQLException ex) {
14229  throw new TskCoreException("Error closing query: ", ex);
14230  } finally {
14232  }
14233  }
14234  }
14235 
14243  @Deprecated
14244  public void addErrorObserver(ErrorObserver observer) {
14245  sleuthkitCaseErrorObservers.add(observer);
14246  }
14247 
14255  @Deprecated
14256  public void removeErrorObserver(ErrorObserver observer) {
14257  int i = sleuthkitCaseErrorObservers.indexOf(observer);
14258  if (i >= 0) {
14259  sleuthkitCaseErrorObservers.remove(i);
14260  }
14261  }
14262 
14271  @Deprecated
14272  public void submitError(String context, String errorMessage) {
14273  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
14274  if (observer != null) {
14275  try {
14276  observer.receiveError(context, errorMessage);
14277  } catch (Exception ex) {
14278  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
14279 
14280  }
14281  }
14282  }
14283  }
14284 
14290  @Deprecated
14291  public interface ErrorObserver {
14292 
14299  public enum Context {
14300 
14304  IMAGE_READ_ERROR("Image File Read Error"),
14308  DATABASE_READ_ERROR("Database Read Error");
14309 
14310  private final String contextString;
14311 
14312  private Context(String context) {
14313  this.contextString = context;
14314  }
14315 
14316  public String getContextString() {
14317  return contextString;
14318  }
14319  };
14320 
14321  void receiveError(String context, String errorMessage);
14322  }
14323 
14334  @Deprecated
14335  long getDataSourceObjectId(long objectId) {
14336  try {
14337  CaseDbConnection connection = connections.getConnection();
14338  try {
14339  return getDataSourceObjectId(connection, objectId);
14340  } finally {
14341  closeConnection(connection);
14342  }
14343  } catch (TskCoreException ex) {
14344  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
14345  return 0;
14346  }
14347  }
14348 
14358  @Deprecated
14359  public long getLastObjectId() throws TskCoreException {
14360  CaseDbConnection connection = null;
14361  ResultSet rs = null;
14363  try {
14364  connection = connections.getConnection();
14365 
14366  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
14367  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
14368  rs = connection.executeQuery(statement);
14369  long id = -1;
14370  if (rs.next()) {
14371  id = rs.getLong("max_obj_id");
14372  }
14373  return id;
14374  } catch (SQLException e) {
14375  throw new TskCoreException("Error getting last object id", e);
14376  } finally {
14377  closeResultSet(rs);
14378  closeConnection(connection);
14380  }
14381  }
14382 
14396  @Deprecated
14397  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
14398  CaseDbConnection connection = null;
14399  Statement s = null;
14400  ResultSet rs = null;
14402  try {
14403  connection = connections.getConnection();
14404  s = connection.createStatement();
14405  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
14406  List<FsContent> results = new ArrayList<FsContent>();
14407  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
14408  for (AbstractFile f : temp) {
14409  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
14410  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
14411  results.add((FsContent) f);
14412  }
14413  }
14414  return results;
14415  } catch (SQLException e) {
14416  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
14417  } finally {
14418  closeResultSet(rs);
14419  closeStatement(s);
14420  closeConnection(connection);
14422  }
14423  }
14424 
14436  @Deprecated
14437  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
14438  CaseDbConnection connection = null;
14439  Statement s = null;
14440  ResultSet rs = null;
14442  try {
14443  connection = connections.getConnection();
14444  s = connection.createStatement();
14445  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
14446  int typeId = -1;
14447  if (rs.next()) {
14448  typeId = rs.getInt("artifact_type_id");
14449  }
14450  return typeId;
14451  } catch (SQLException ex) {
14452  throw new TskCoreException("Error getting artifact type id", ex);
14453  } finally {
14454  closeResultSet(rs);
14455  closeStatement(s);
14456  closeConnection(connection);
14458  }
14459  }
14460 
14470  @Deprecated
14471  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
14472  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
14473  }
14474 
14488  @Deprecated
14489  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14490  try {
14491  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14492  } catch (TskDataException ex) {
14493  throw new TskCoreException("Failed to add artifact type.", ex);
14494  }
14495  }
14496 
14510  @Deprecated
14511  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14512  try {
14513  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14514  } catch (TskDataException ex) {
14515  throw new TskCoreException("Couldn't add new attribute type");
14516  }
14517  }
14518 
14529  @Deprecated
14530  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14531  CaseDbConnection connection = null;
14532  Statement s = null;
14533  ResultSet rs = null;
14535  try {
14536  connection = connections.getConnection();
14537  s = connection.createStatement();
14538  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
14539  int typeId = -1;
14540  if (rs.next()) {
14541  typeId = rs.getInt("attribute_type_id");
14542  }
14543  return typeId;
14544  } catch (SQLException ex) {
14545  throw new TskCoreException("Error getting attribute type id", ex);
14546  } finally {
14547  closeResultSet(rs);
14548  closeStatement(s);
14549  closeConnection(connection);
14551  }
14552  }
14553 
14566  @Deprecated
14567  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
14568  CaseDbConnection connection = null;
14569  Statement s = null;
14570  ResultSet rs = null;
14572  try {
14573  connection = connections.getConnection();
14574  s = connection.createStatement();
14575  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14576  if (rs.next()) {
14577  return rs.getString("type_name");
14578  } else {
14579  throw new TskCoreException("No type with that id");
14580  }
14581  } catch (SQLException ex) {
14582  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14583  } finally {
14584  closeResultSet(rs);
14585  closeStatement(s);
14586  closeConnection(connection);
14588  }
14589  }
14590 
14603  @Deprecated
14604  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
14605  CaseDbConnection connection = null;
14606  Statement s = null;
14607  ResultSet rs = null;
14609  try {
14610  connection = connections.getConnection();
14611  s = connection.createStatement();
14612  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14613  if (rs.next()) {
14614  return rs.getString("display_name");
14615  } else {
14616  throw new TskCoreException("No type with that id");
14617  }
14618  } catch (SQLException ex) {
14619  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14620  } finally {
14621  closeResultSet(rs);
14622  closeStatement(s);
14623  closeConnection(connection);
14625  }
14626  }
14627 
14637  @Deprecated
14638  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
14639  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
14640  }
14641 
14657  @Deprecated
14658  public ResultSet runQuery(String query) throws SQLException {
14659  CaseDbConnection connection = null;
14661  try {
14662  connection = connections.getConnection();
14663  return connection.executeQuery(connection.createStatement(), query);
14664  } catch (TskCoreException ex) {
14665  throw new SQLException("Error getting connection for ad hoc query", ex);
14666  } finally {
14667  //TODO unlock should be done in closeRunQuery()
14668  //but currently not all code calls closeRunQuery - need to fix this
14669  closeConnection(connection);
14671  }
14672  }
14673 
14683  @Deprecated
14684  public void closeRunQuery(ResultSet resultSet) throws SQLException {
14685  final Statement statement = resultSet.getStatement();
14686  resultSet.close();
14687  if (statement != null) {
14688  statement.close();
14689  }
14690  }
14691 
14708  @Deprecated
14709  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
14710  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
14711  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
14712  files.add(carvedFile);
14713  CarvingResult carvingResult;
14714  Content parent = getContentById(containerId);
14715  if (parent instanceof FileSystem
14716  || parent instanceof Volume
14717  || parent instanceof Image) {
14718  carvingResult = new CarvingResult(parent, files);
14719  } else {
14720  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
14721  }
14722  return addCarvedFiles(carvingResult).get(0);
14723  }
14724 
14738  @Deprecated
14739  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
14740  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
14741  for (CarvedFileContainer container : filesToAdd) {
14742  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
14743  carvedFiles.add(carvedFile);
14744  }
14745  CarvingResult carvingResult;
14746  Content parent = getContentById(filesToAdd.get(0).getId());
14747  if (parent instanceof FileSystem
14748  || parent instanceof Volume
14749  || parent instanceof Image) {
14750  carvingResult = new CarvingResult(parent, carvedFiles);
14751  } else {
14752  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
14753  }
14754  return addCarvedFiles(carvingResult);
14755  }
14756 
14786  @Deprecated
14787  public DerivedFile addDerivedFile(String fileName, String localPath,
14788  long size, long ctime, long crtime, long atime, long mtime,
14789  boolean isFile, AbstractFile parentFile,
14790  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
14791  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14792  isFile, parentFile, rederiveDetails, toolName, toolVersion,
14793  otherDetails, TskData.EncodingType.NONE);
14794  }
14795 
14825  @Deprecated
14826  public LocalFile addLocalFile(String fileName, String localPath,
14827  long size, long ctime, long crtime, long atime, long mtime,
14828  String md5, FileKnown known, String mimeType,
14829  boolean isFile, TskData.EncodingType encodingType,
14830  Content parent, CaseDbTransaction transaction) throws TskCoreException {
14831 
14832  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14833  md5, null, known, mimeType, isFile, encodingType,
14834  parent, transaction);
14835  }
14836 
14861  @Deprecated
14862  public LocalFile addLocalFile(String fileName, String localPath,
14863  long size, long ctime, long crtime, long atime, long mtime,
14864  boolean isFile,
14865  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
14866  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
14867  TskData.EncodingType.NONE, parent, transaction);
14868  }
14869 
14889  @Deprecated
14890  public LocalFile addLocalFile(String fileName, String localPath,
14891  long size, long ctime, long crtime, long atime, long mtime,
14892  boolean isFile,
14893  AbstractFile parent) throws TskCoreException {
14894  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14895  isFile, TskData.EncodingType.NONE, parent);
14896  }
14897 
14914  @Deprecated
14915  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
14916  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
14917  }
14918 
14929  @Deprecated
14930  public Collection<FileSystem> getFileSystems(Image image) {
14931  try {
14932  return getImageFileSystems(image);
14933  } catch (TskCoreException ex) {
14934  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
14935  return new ArrayList<>();
14936  }
14937  }
14938 
14956  @Deprecated
14957  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
14958  return findFilesInFolder(fileName, parentFile);
14959  }
14960 
14968  @Deprecated
14969  public void acquireExclusiveLock() {
14971  }
14972 
14980  @Deprecated
14981  public void releaseExclusiveLock() {
14983  }
14984 
14992  @Deprecated
14993  public void acquireSharedLock() {
14995  }
14996 
15004  @Deprecated
15005  public void releaseSharedLock() {
15007  }
15008 };
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone, Host host)
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)
static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider)
static Priority fromID(int id)
Definition: Score.java:184
FS
File that can be found in file system tree.
Definition: TskData.java:694
static FileKnown valueOf(byte known)
Definition: TskData.java:819
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
static Significance fromID(int id)
Definition: Score.java:118
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)
Host getHostByDataSource(DataSource dataSource)
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)
Optional< HostAddress > getHostAddress(HostAddress.HostAddressType type, String address)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
static final Score SCORE_UNKNOWN
Definition: Score.java:213
CommunicationsManager getCommunicationsManager()
AnalysisResult getAnalysisResultById(long artifactObjId)
static Set< TSK_FS_META_FLAG_ENUM > valuesOf(short metaFlags)
Definition: TskData.java:249
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)
OsAccount getOsAccountByObjectId(long osAccountObjId)
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:208
static TSK_FS_TYPE_ENUM valueOf(int fsTypeValue)
Definition: TskData.java:509
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, Content parentObj, CaseDbTransaction trans)
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)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, String sha1Hash, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount, Content parent, CaseDbTransaction transaction)
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:209
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount, Content parent, CaseDbTransaction transaction)
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)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
final List< LayoutFile > addLayoutFiles(Content parent, List< TskFileRange > fileRanges)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int addArtifactType(String artifactTypeName, String displayName)
BlackboardArtifactTagChange addArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
synchronized CaseDbAccessManager getCaseDbAccessManager()
DataArtifact getDataArtifactById(long artifactObjId)
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:703
List< AbstractFile > findAllFilesInFolderWhere(long parentId, String sqlWhereClause)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
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)
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, String md5Hash, String sha256Hash, String sha1Hash, String mimeType, boolean isFile, Content parent, String ownerUid, OsAccount osAccount, TskData.CollectedStatus collected, List< Attribute > fileAttributes, CaseDbTransaction transaction)
long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId)
static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentStreamProvider contentProvider)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
ContentTag getContentTagByID(long contentTagID)
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:697
HostAddressManager getHostAddressManager()
Map< Long, List< String > > getImagePaths()
List< Long > findAllFileIdsWhere(String sqlWhereClause)
synchronized TaggingManager getTaggingManager()
BlackboardArtifact getBlackboardArtifact(long artifactID)
List< BlackboardArtifact.Type > getArtifactTypesInUse()
OsAccountRealmManager getOsAccountRealmManager()
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:695
BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
List< AnalysisResult > getAnalysisResults(long dataSourceObjId, Integer artifactTypeID)
long countFilesWhere(String sqlWhereClause)
List< AnalysisResult > getAnalysisResultsWhere(String whereClause)
long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id)
FS
File System - see tsk_fs_info for more details.
Definition: TskData.java:640
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)
synchronized BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
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:210
void unregisterForEvents(Object listener)
LOCAL_DIR
Local directory that was added (not from a disk image)
Definition: TskData.java:702
final List< LayoutFile > addCarvedFiles(CarvingResult carvingResult)
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, String md5Hash, String sha256Hash, String sha1Hash, String mimeType, boolean isFile, Content parent, String ownerUid, OsAccount osAccount, List< Attribute > fileAttributes, CaseDbTransaction transaction)
VOL
Volume - see tsk_vs_parts for more details.
Definition: TskData.java:639
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)
static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentStreamProvider contentProvider)
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)
List< AbstractFile > findFilesInFolder(String fileName, AbstractFile parentFile)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone)
BlackboardArtifact.Type getArtifactType(String artTypeName)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:76
REPORT
Artifact - see blackboard_artifacts for more details.
Definition: TskData.java:643
List< AbstractFile > findFilesByMd5(String md5Hash)
OsAccountInstance newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID)
BlackboardArtifact.Type getArtifactType(String artTypeName)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:696
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)
static short toInt(Set< TSK_FS_META_FLAG_ENUM > metaFlags)
Definition: TskData.java:268
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()
List< DataArtifact > getDataArtifactsWhere(String whereClause)
UNALLOC_BLOCKS
Set of blocks not allocated by file system. Parent should be image, volume, or file system...
Definition: TskData.java:698
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
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)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName)
static ObjectType valueOf(short objectType)
Definition: TskData.java:678
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)
static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider)
VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset, long blockSize, CaseDbTransaction transaction)
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:800
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)
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)
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, CaseDbTransaction transaction)
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:700
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)
TagName addTagName(String displayName, String description, TagName.HTML_COLOR color)
int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType)
ABSTRACTFILE
File - see tsk_files for more details.
Definition: TskData.java:641
ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
DataSource getDataSource(long objectId)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
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)
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, String md5Hash, String sha256Hash, String mimeType, boolean isFile, Content parent, String ownerUid, OsAccount osAccount, List< Attribute > fileAttributes, CaseDbTransaction transaction)
AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath)
List< FsContent > findFilesWhere(String sqlWhereClause)
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, Host host, CaseDbTransaction transaction)
void setImagePaths(long objId, List< String > paths, CaseDbTransaction trans)
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:638
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:637
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:158
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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