Sleuth Kit Java Bindings (JNI)  4.12.1
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-2023 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  // either one of these mean connection was rejected by Postgres server
116  private static final String SQL_CONNECTION_REJECTED = "08004";
117  private static final String UNABLE_TO_VERIFY_SSL = "08006";
118 
119  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
120  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
121  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
122  private static final String SQL_ERROR_LIMIT_GROUP = "54";
123  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
124 
125  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
126  "tsk_events",
127  "tsk_event_descriptions",
128  "tsk_event_types",
129  "tsk_db_info",
130  "tsk_objects",
131  "tsk_image_info",
132  "tsk_image_names",
133  "tsk_vs_info",
134  "tsk_vs_parts",
135  "tsk_fs_info",
136  "tsk_file_layout",
137  "tsk_files",
138  "tsk_files_path",
139  "tsk_files_derived",
140  "tsk_files_derived_method",
141  "tag_names",
142  "content_tags",
143  "blackboard_artifact_tags",
144  "blackboard_artifacts",
145  "blackboard_attributes",
146  "blackboard_artifact_types",
147  "blackboard_attribute_types",
148  "data_source_info",
149  "file_encoding_types",
150  "file_collection_status_types",
151  "ingest_module_types",
152  "ingest_job_status_types",
153  "ingest_modules",
154  "ingest_jobs",
155  "ingest_job_modules",
156  "account_types",
157  "accounts",
158  "account_relationships",
159  "review_statuses",
160  "reports,");
161 
162  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
163  "parObjId",
164  "layout_objID",
165  "artifact_objID",
166  "artifact_artifact_objID",
167  "artifact_typeID",
168  "attrsArtifactID",
169  "mime_type",
170  "file_extension",
171  "relationships_account1",
172  "relationships_account2",
173  "relationships_relationship_source_obj_id",
174  "relationships_date_time",
175  "relationships_relationship_type",
176  "relationships_data_source_obj_id",
177  "events_time",
178  "events_type",
179  "events_data_source_obj_id",
180  "events_file_obj_id",
181  "events_artifact_id");
182 
183  private static final String TSK_VERSION_KEY = "TSK_VER";
184  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
185  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
186  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
187  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
188 
189  private final ConnectionPool connections;
190  private final Object carvedFileDirsLock = new Object();
191  private final static int MAX_CARVED_FILES_PER_FOLDER = 2000;
192  private final Map<Long, CarvedFileDirInfo> rootIdsToCarvedFileDirs = new HashMap<>();
193  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
194  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
195  private final String databaseName;
196  private final String dbPath;
197  private final DbType dbType;
198  private final String caseDirPath;
199  private SleuthkitJNI.CaseDbHandle caseHandle;
200  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
201  private String dbBackupPath;
202  private AtomicBoolean timelineEventsDisabled = new AtomicBoolean(false);
203 
204  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
205 
206  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
207  private final Object rootDirectoryMapLock = new Object();
208  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
209  private final Cache<Long, Boolean> isRootDirectoryCache
210  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
211  // custom provider for file bytes (can be null)
212  private final ContentStreamProvider contentProvider;
213 
214  /*
215  * First parameter is used to specify the SparseBitSet to use, as object IDs
216  * can be larger than the max size of a SparseBitSet
217  */
218  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
219 
220  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
221  // This read/write lock is used to implement a layer of locking on top of
222  // the locking protocol provided by the underlying SQLite database. The Java
223  // locking protocol improves performance for reasons that are not currently
224  // understood. Note that the lock is contructed to use a fairness policy.
225  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
226 
227  private CommunicationsManager communicationsMgr;
228  private TimelineManager timelineMgr;
229  private Blackboard blackboard;
230  private CaseDbAccessManager dbAccessManager;
231  private FileManager fileManager;
232  private TaggingManager taggingMgr;
233  private ScoringManager scoringManager;
234  private OsAccountRealmManager osAccountRealmManager;
235  private OsAccountManager osAccountManager;
236  private HostManager hostManager;
237  private PersonManager personManager;
238  private HostAddressManager hostAddressManager;
239 
240  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
241 
242  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
243 
244  public void registerForEvents(Object listener) {
245  eventBus.register(listener);
246  }
247 
248  public void unregisterForEvents(Object listener) {
249  eventBus.unregister(listener);
250  }
251 
252  void fireTSKEvent(Object event) {
253  eventBus.post(event);
254  }
255 
256  // Cache of frequently used content objects (e.g. data source, file system).
257  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
258 
259  private Examiner cachedCurrentExaminer = null;
260 
261  static {
262  Properties p = new Properties(System.getProperties());
263  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
264  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
265  System.setProperties(p);
266  }
267 
282  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
283  // Check if we can talk to the database.
284  if (info.getHost() == null || info.getHost().isEmpty()) {
285  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
286  } else if (info.getPort() == null || info.getPort().isEmpty()) {
287  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
288  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
289  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
290  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
291  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
292  }
293 
294  try {
295  Class.forName("org.postgresql.Driver"); //NON-NLS
296  String connectionURL = "jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres";
297  if (info.isSslEnabled()) {
298  if (info.isSslVerify()) {
299  if (info.getCustomSslValidationClassName().isBlank()) {
300  connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL;
301  } else {
302  // use custom SSL certificate validation class
303  connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName());
304  }
305  } else {
306  connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL;
307  }
308  }
309  Connection conn = DriverManager.getConnection(connectionURL, info.getUserName(), info.getPassword()); //NON-NLS
310  if (conn != null) {
311  conn.close();
312  }
313  } catch (SQLException ex) {
314  String result;
315  String sqlState = ex.getSQLState().toLowerCase();
316  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
317  if (SQL_CONNECTION_REJECTED.equals(ex.getSQLState())) {
318  if (info.isSslEnabled()) {
319  result = "Server rejected the SSL connection attempt. Check SSL configuration.";
320  } else {
321  result = "Server rejected the connection attempt. Check server configuration.";
322  }
323  } else if (UNABLE_TO_VERIFY_SSL.equals(ex.getSQLState())) {
324  result = "Unable to verify SSL certificates. Check SSL configuration.";
325  } else {
326  try {
327  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
328  // if we can reach the host, then it's probably port problem
329  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
330  } else {
331  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
332  }
333  } catch (IOException | MissingResourceException any) {
334  // it may be anything
335  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
336  }
337  }
338  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
339  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
340  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
341  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
342  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
343  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
344  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
345  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
346  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
347  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
348  } else {
349  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
350  }
351  throw new TskCoreException(result);
352  } catch (ClassNotFoundException ex) {
353  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
354  }
355  }
356 
369  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType, ContentStreamProvider contentProvider) throws Exception {
370  Class.forName("org.sqlite.JDBC");
371  this.dbPath = dbPath;
372  this.dbType = dbType;
373  File dbFile = new File(dbPath);
374  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
375  this.databaseName = dbFile.getName();
376  this.connections = new SQLiteConnections(dbPath);
377  this.caseHandle = caseHandle;
378  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
379  this.contentProvider = contentProvider;
380  init();
381  logSQLiteJDBCDriverInfo();
382  }
383 
395  private SleuthkitCase(CaseDbConnectionInfo info, String dbName, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, ContentStreamProvider contentProvider) throws Exception {
396  this.dbPath = "";
397  this.databaseName = dbName;
398  this.dbType = info.getDbType();
399  this.caseDirPath = caseDirPath;
400  this.connections = new PostgreSQLConnections(info, dbName);
401  this.caseHandle = caseHandle;
402  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
403  this.contentProvider = contentProvider;
404  init();
405  }
406 
407  private void init() throws Exception {
408  blackboard = new Blackboard(this);
409  updateDatabaseSchema(null);
410  try (CaseDbConnection connection = connections.getConnection()) {
411  blackboard.initBlackboardArtifactTypes(connection);
412  blackboard.initBlackboardAttributeTypes(connection);
413  initNextArtifactId(connection);
414  initIngestModuleTypes(connection);
415  initIngestStatusTypes(connection);
416  initReviewStatuses(connection);
417  initEncodingTypes(connection);
418  initCollectedStatusTypes(connection);
419  populateHasChildrenMap(connection);
420  updateExaminers(connection);
421  initDBSchemaCreationVersion(connection);
422  }
423 
424  fileManager = new FileManager(this);
425  communicationsMgr = new CommunicationsManager(this);
426  timelineMgr = new TimelineManager(this);
427  dbAccessManager = new CaseDbAccessManager(this);
428  taggingMgr = new TaggingManager(this);
429  scoringManager = new ScoringManager(this);
430  osAccountRealmManager = new OsAccountRealmManager(this);
431  osAccountManager = new OsAccountManager(this);
432  hostManager = new HostManager(this);
433  personManager = new PersonManager(this);
434  hostAddressManager = new HostAddressManager(this);
435  }
436 
444  ContentStreamProvider getContentProvider() {
445  return this.contentProvider;
446  }
447 
453  static Set<String> getCoreTableNames() {
454  return Collections.unmodifiableSet(CORE_TABLE_NAMES);
455  }
456 
462  static Set<String> getCoreIndexNames() {
463  return Collections.unmodifiableSet(CORE_INDEX_NAMES);
464  }
465 
474  boolean getHasChildren(Content content) {
475  long objId = content.getId();
476  long mapIndex = objId / Integer.MAX_VALUE;
477  int mapValue = (int) (objId % Integer.MAX_VALUE);
478 
479  synchronized (hasChildrenBitSetMap) {
480  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
481  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
482  }
483  return false;
484  }
485  }
486 
492  private void setHasChildren(Long objId) {
493  long mapIndex = objId / Integer.MAX_VALUE;
494  int mapValue = (int) (objId % Integer.MAX_VALUE);
495 
496  synchronized (hasChildrenBitSetMap) {
497  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
498  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
499  } else {
500  SparseBitSet bitSet = new SparseBitSet();
501  bitSet.set(mapValue);
502  hasChildrenBitSetMap.put(mapIndex, bitSet);
503  }
504  }
505  }
506 
515  return communicationsMgr;
516  }
517 
524  return blackboard;
525  }
526 
533  return fileManager;
534  }
535 
544  return timelineMgr;
545  }
546 
547  /*
548  * Gets the case database access manager for this case.
549  *
550  * @return The per case CaseDbAccessManager object.
551  *
552  * @throws org.sleuthkit.datamodel.TskCoreException
553  */
555  return dbAccessManager;
556  }
557 
563  public synchronized TaggingManager getTaggingManager() {
564  return taggingMgr;
565  }
566 
575  return scoringManager;
576  }
577 
586  return osAccountRealmManager;
587  }
588 
597  return osAccountManager;
598  }
599 
608  return hostManager;
609  }
610 
619  return personManager;
620  }
621 
630  return hostAddressManager;
631  }
632 
642  private void initNextArtifactId(CaseDbConnection connection) throws SQLException {
644  try (Statement statement = connection.createStatement()) {
645  ResultSet resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
646  resultSet.next();
647  nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
648  if (nextArtifactId == 1) {
649  nextArtifactId = BASE_ARTIFACT_ID;
650  }
651  } finally {
653  }
654  }
655 
663  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
664  Statement statement = null;
665  ResultSet resultSet = null;
667  try {
668  statement = connection.createStatement();
669  for (IngestModuleType type : IngestModuleType.values()) {
670  try {
671  String query = "INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
672  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
673  query += " ON CONFLICT ON CONSTRAINT ingest_module_types_pkey DO NOTHING"; // NON-NLS
674  }
675  statement.execute(query);
676  } catch (SQLException ex) {
677  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
678  resultSet.next();
679  if (resultSet.getLong("count") == 0) {
680  throw ex;
681  }
682  resultSet.close();
683  resultSet = null;
684  }
685  }
686  } finally {
687  closeResultSet(resultSet);
688  closeStatement(statement);
690  }
691  }
692 
700  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
701  Statement statement = null;
702  ResultSet resultSet = null;
704  try {
705  statement = connection.createStatement();
706  for (IngestJobStatusType type : IngestJobStatusType.values()) {
707  try {
708  String query = "INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
709  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
710  query += " ON CONFLICT ON CONSTRAINT ingest_job_status_types_pkey DO NOTHING"; // NON-NLS
711  }
712  statement.execute(query);
713  } catch (SQLException ex) {
714  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
715  resultSet.next();
716  if (resultSet.getLong("count") == 0) {
717  throw ex;
718  }
719  resultSet.close();
720  resultSet = null;
721  }
722  }
723  } finally {
724  closeResultSet(resultSet);
725  closeStatement(statement);
727  }
728  }
729 
736  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
737  Statement statement = null;
738  ResultSet resultSet = null;
740  try {
741  statement = connection.createStatement();
742  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
743  try {
744  String query = "INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
745  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')";
746  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
747  query += " ON CONFLICT ON CONSTRAINT review_statuses_pkey DO NOTHING"; // NON-NLS
748  }
749  statement.execute(query);
750  } catch (SQLException ex) {
751  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
752  resultSet.next();
753  if (resultSet.getLong("count") == 0) {
754  throw ex;
755  }
756  resultSet.close();
757  resultSet = null;
758  }
759  }
760  } finally {
761  closeResultSet(resultSet);
762  closeStatement(statement);
764  }
765  }
766 
774  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
775  Statement statement = null;
776  ResultSet resultSet = null;
778  try {
779  statement = connection.createStatement();
780  for (TskData.EncodingType type : TskData.EncodingType.values()) {
781  try {
782  String query = "INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
783  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
784  query += " ON CONFLICT ON CONSTRAINT file_encoding_types_pkey DO NOTHING"; // NON-NLS
785  }
786  statement.execute(query);
787  } catch (SQLException ex) {
788  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
789  resultSet.next();
790  if (resultSet.getLong("count") == 0) {
791  throw ex;
792  }
793  resultSet.close();
794  resultSet = null;
795  }
796  }
797  } finally {
798  closeResultSet(resultSet);
799  closeStatement(statement);
801  }
802  }
803 
811  private void initCollectedStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
812  Statement statement = null;
813  ResultSet resultSet = null;
815  try {
816  statement = connection.createStatement();
817  for (TskData.CollectedStatus type : TskData.CollectedStatus.values()) {
818  try {
819  String query = "INSERT INTO file_collection_status_types (collection_status_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
820  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
821  query += " ON CONFLICT ON CONSTRAINT file_collection_status_types_pkey DO NOTHING"; // NON-NLS
822  }
823  statement.execute(query);
824  } catch (SQLException ex) {
825  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_collection_status_types WHERE collection_status_type = " + type.getType()); //NON-NLS
826  resultSet.next();
827  if (resultSet.getLong("count") == 0) {
828  throw ex;
829  }
830  resultSet.close();
831  resultSet = null;
832  }
833  }
834  } finally {
835  closeResultSet(resultSet);
836  closeStatement(statement);
838  }
839  }
840 
849  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
850 
851  String loginName = System.getProperty("user.name");
852  if (loginName.isEmpty()) {
853  logger.log(Level.SEVERE, "Cannot determine logged in user name");
854  return;
855  }
856 
858  try {
859  PreparedStatement statement;
860  switch (getDatabaseType()) {
861  case POSTGRESQL:
862  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
863  break;
864  case SQLITE:
865  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
866  break;
867  default:
868  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
869  }
870  statement.clearParameters();
871  statement.setString(1, loginName);
872  connection.executeUpdate(statement);
873  } catch (SQLException ex) {
874  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
875  } finally {
877  }
878  }
879 
887  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
888  long timestamp = System.currentTimeMillis();
889 
890  Statement statement = null;
891  ResultSet resultSet = null;
893  try {
894  statement = connection.createStatement();
895  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
896 
897  synchronized (hasChildrenBitSetMap) {
898  while (resultSet.next()) {
899  setHasChildren(resultSet.getLong("par_obj_id"));
900  }
901  }
902  long delay = System.currentTimeMillis() - timestamp;
903  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
904  } catch (SQLException ex) {
905  throw new TskCoreException("Error populating parent node cache", ex);
906  } finally {
907  closeResultSet(resultSet);
908  closeStatement(statement);
910  }
911  }
912 
919  void addDataSourceToHasChildrenMap() throws TskCoreException {
920 
921  CaseDbConnection connection = connections.getConnection();
922  try {
923  populateHasChildrenMap(connection);
924  } finally {
925  closeConnection(connection);
926  }
927  }
928 
938  private void updateDatabaseSchema(String dbPath) throws Exception {
939  CaseDbConnection connection = null;
940  ResultSet resultSet = null;
941  Statement statement = null;
943  try {
944  connection = connections.getConnection();
945  connection.beginTransaction();
946 
947  boolean hasMinorVersion = false;
948  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
949  while (columns.next()) {
950  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
951  hasMinorVersion = true;
952  }
953  }
954 
955  // Get the schema version number of the case database from the tsk_db_info table.
956  int dbSchemaMajorVersion;
957  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
958 
959  statement = connection.createStatement();
960  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
961  + (hasMinorVersion ? ", schema_minor_ver" : "")
962  + " FROM tsk_db_info"); //NON-NLS
963  if (resultSet.next()) {
964  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
965  if (hasMinorVersion) {
966  //if there is a minor version column, use it, else default to zero.
967  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
968  }
969  } else {
970  throw new TskCoreException();
971  }
972  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
973 
974  resultSet.close();
975  resultSet = null;
976  statement.close();
977  statement = null;
978  //check schema compatibility
979  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
980  //we cannot open a db with a major schema version higher than the current one.
981  throw new TskUnsupportedSchemaVersionException(
982  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
983  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
984  //The schema version is compatible,possibly after upgrades.
985 
986  if (null != dbPath) {
987  // Make a backup copy of the database. Client code can get the path of the backup
988  // using the getBackupDatabasePath() method.
989  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
990  copyCaseDB(backupFilePath);
991  dbBackupPath = backupFilePath;
992  }
993 
994  // ***CALL SCHEMA UPDATE METHODS HERE***
995  // Each method should examine the schema version passed to it and either:
996  // a. do nothing and return the schema version unchanged, or
997  // b. upgrade the database and return the schema version that the db was upgraded to.
998  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
999  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
1000  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
1001  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
1002  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
1003  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
1004  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
1005  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
1006  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
1007  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
1008  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
1009  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
1010  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
1011  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
1012  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
1013  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
1014  dbSchemaVersion = updateFromSchema9dot1toSchema9dot2(dbSchemaVersion, connection);
1015  dbSchemaVersion = updateFromSchema9dot2toSchema9dot3(dbSchemaVersion, connection);
1016  dbSchemaVersion = updateFromSchema9dot3toSchema9dot4(dbSchemaVersion, connection);
1017 
1018 
1019 
1020  statement = connection.createStatement();
1021  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
1022  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
1023  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
1024  statement.close();
1025  statement = null;
1026  }
1027 
1028  connection.commitTransaction();
1029  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
1030  rollbackTransaction(connection);
1031  throw ex;
1032  } finally {
1033  closeResultSet(resultSet);
1034  closeStatement(statement);
1035  closeConnection(connection);
1037  }
1038  }
1039 
1047  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
1048 
1049  Statement statement = null;
1050  ResultSet resultSet = null;
1051  String createdSchemaMajorVersion = "0";
1052  String createdSchemaMinorVersion = "0";
1054  try {
1055  statement = connection.createStatement();
1056  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
1057  while (resultSet.next()) {
1058  String name = resultSet.getString("name");
1059  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
1060  createdSchemaMajorVersion = resultSet.getString("value");
1061  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
1062  createdSchemaMinorVersion = resultSet.getString("value");
1063  }
1064  }
1065 
1066  } finally {
1067  closeResultSet(resultSet);
1068  closeStatement(statement);
1070  }
1071 
1072  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
1073  }
1074 
1084  public void copyCaseDB(String newDBPath) throws IOException {
1085  if (dbPath.isEmpty()) {
1086  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1087  }
1088  InputStream in = null;
1089  OutputStream out = null;
1091  try {
1092  InputStream inFile = new FileInputStream(dbPath);
1093  in = new BufferedInputStream(inFile);
1094  OutputStream outFile = new FileOutputStream(newDBPath);
1095  out = new BufferedOutputStream(outFile);
1096  int bytesRead = in.read();
1097  while (bytesRead != -1) {
1098  out.write(bytesRead);
1099  bytesRead = in.read();
1100  }
1101  } finally {
1102  try {
1103  if (in != null) {
1104  in.close();
1105  }
1106  if (out != null) {
1107  out.flush();
1108  out.close();
1109  }
1110  } catch (IOException e) {
1111  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1112  }
1114  }
1115  }
1116 
1120  private void logSQLiteJDBCDriverInfo() {
1121  try {
1122  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1123  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1124  ? "native" : "pure-java")); //NON-NLS
1125  } catch (Exception ex) {
1126  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1127  }
1128  }
1129 
1143  @SuppressWarnings("deprecation")
1144  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1145  if (schemaVersion.getMajor() != 2) {
1146  return schemaVersion;
1147  }
1148  Statement statement = null;
1149  Statement statement2 = null;
1150  Statement updateStatement = null;
1151  ResultSet resultSet = null;
1153  try {
1154  statement = connection.createStatement();
1155  statement2 = connection.createStatement();
1156 
1157  // Add new tables for tags.
1158  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
1159  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
1160  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
1161 
1162  // Add a new table for reports.
1163  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
1164 
1165  // Add new columns to the image info table.
1166  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1167  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1168  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1169 
1170  // Add a new column to the file system info table.
1171  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1172 
1173  // Add a new column to the file table.
1174  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1175 
1176  // Add new columns and indexes to the attributes table and populate the
1177  // new column. Note that addition of the new column is a denormalization
1178  // to optimize attribute queries.
1179  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1180  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1181  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1182  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1183  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1184  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1185  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1186  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1187  + "FROM blackboard_attributes AS attrs " //NON-NLS
1188  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1189  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1190  updateStatement = connection.createStatement();
1191  while (resultSet.next()) {
1192  long artifactId = resultSet.getLong("artifact_id");
1193  int artifactTypeId = resultSet.getInt("artifact_type_id");
1194  updateStatement.executeUpdate(
1195  "UPDATE blackboard_attributes " //NON-NLS
1196  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1197  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1198  }
1199  resultSet.close();
1200 
1201  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1202  Map<String, Long> tagNames = new HashMap<>();
1203  long tagNameCounter = 1;
1204 
1205  // Convert file tags.
1206  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1207  resultSet = statement.executeQuery("SELECT * FROM \n"
1208  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1209  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1210  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1211  + "WHERE blackboard_artifacts.artifact_type_id = "
1212  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1213  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1214  + ") AS tagNames \n"
1215  + "INNER JOIN \n"
1216  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1217  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1218  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1219  + "ON tagNames.objId = fileData.objId2 \n"
1220  + "LEFT JOIN \n"
1221  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1222  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1223  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1224 
1225  while (resultSet.next()) {
1226  long objId = resultSet.getLong("objId");
1227  long fileSize = resultSet.getLong("fileSize");
1228  String tagName = resultSet.getString("name");
1229  String tagComment = resultSet.getString("comment");
1230  if (tagComment == null) {
1231  tagComment = "";
1232  }
1233 
1234  if (tagName != null && !tagName.isEmpty()) {
1235  // Get the index for the tag name, adding it to the database if needed.
1236  long tagNameIndex;
1237  if (tagNames.containsKey(tagName)) {
1238  tagNameIndex = tagNames.get(tagName);
1239  } else {
1240  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1241  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1242  tagNames.put(tagName, tagNameCounter);
1243  tagNameIndex = tagNameCounter;
1244  tagNameCounter++;
1245  }
1246 
1247  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1248  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1249  }
1250  }
1251  resultSet.close();
1252 
1253  // Convert artifact tags.
1254  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1255  resultSet = statement.executeQuery("SELECT * FROM \n"
1256  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1257  + "blackboard_attributes.value_text AS name\n"
1258  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1259  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1260  + "WHERE blackboard_artifacts.artifact_type_id = "
1261  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1262  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1263  + ") AS tagNames \n"
1264  + "INNER JOIN \n"
1265  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1266  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1267  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1268  + "LEFT JOIN \n"
1269  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1270  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1271  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1272 
1273  while (resultSet.next()) {
1274  long artifactId = resultSet.getLong("taggedArtifactId");
1275  String tagName = resultSet.getString("name");
1276  String tagComment = resultSet.getString("comment");
1277  if (tagComment == null) {
1278  tagComment = "";
1279  }
1280  if (tagName != null && !tagName.isEmpty()) {
1281  // Get the index for the tag name, adding it to the database if needed.
1282  long tagNameIndex;
1283  if (tagNames.containsKey(tagName)) {
1284  tagNameIndex = tagNames.get(tagName);
1285  } else {
1286  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1287  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1288  tagNames.put(tagName, tagNameCounter);
1289  tagNameIndex = tagNameCounter;
1290  tagNameCounter++;
1291  }
1292 
1293  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1294  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1295  }
1296  }
1297  resultSet.close();
1298 
1299  statement.execute(
1300  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1301  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1302  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1303  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1304  statement.execute(
1305  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1306  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1307  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1308 
1309  return new CaseDbSchemaVersionNumber(3, 0);
1310  } finally {
1311  closeStatement(updateStatement);
1312  closeResultSet(resultSet);
1313  closeStatement(statement);
1314  closeStatement(statement2);
1316  }
1317  }
1318 
1332  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1333  if (schemaVersion.getMajor() != 3) {
1334  return schemaVersion;
1335  }
1336 
1337  Statement statement = null;
1338  ResultSet resultSet = null;
1339  Statement queryStatement = null;
1340  ResultSet queryResultSet = null;
1341  Statement updateStatement = null;
1343  try {
1344  // Add mime_type column to tsk_files table. Populate with general
1345  // info artifact file signature data.
1346  statement = connection.createStatement();
1347  updateStatement = connection.createStatement();
1348  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1349  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1350  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1351  + "WHERE files.obj_id = arts.obj_id AND "
1352  + "arts.artifact_id = attrs.artifact_id AND "
1353  + "arts.artifact_type_id = 1 AND "
1354  + "attrs.attribute_type_id = 62");
1355  while (resultSet.next()) {
1356  updateStatement.executeUpdate(
1357  "UPDATE tsk_files " //NON-NLS
1358  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1359  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1360  }
1361  resultSet.close();
1362 
1363  // Add value_type column to blackboard_attribute_types table.
1364  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1365  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1366  while (resultSet.next()) {
1367  int attributeTypeId = resultSet.getInt("attribute_type_id");
1368  String attributeLabel = resultSet.getString("type_name");
1369  if (attributeTypeId < Blackboard.MIN_USER_DEFINED_TYPE_ID) {
1370  updateStatement.executeUpdate(
1371  "UPDATE blackboard_attribute_types " //NON-NLS
1372  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1373  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1374  }
1375  }
1376  resultSet.close();
1377 
1378  // Add a data_sources_info table.
1379  queryStatement = connection.createStatement();
1380  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));");
1381  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1382  while (resultSet.next()) {
1383  long objectId = resultSet.getLong("obj_id");
1384  String timeZone = "";
1385  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1386  if (queryResultSet.next()) {
1387  timeZone = queryResultSet.getString("tzone");
1388  }
1389  queryResultSet.close();
1390  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1391  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1392  }
1393  resultSet.close();
1394 
1395  // Add data_source_obj_id column to the tsk_files table.
1396  //
1397  // NOTE: A new case database will have the following FK constraint:
1398  //
1399  // REFERENCES data_source_info (obj_id)
1400  //
1401  // The constraint is sacrificed here to avoid having to create and
1402  // populate a new tsk_files table.
1403  //
1404  // TODO: Do this right.
1405  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1406  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");
1407  while (resultSet.next()) {
1408  long fileId = resultSet.getLong("obj_id");
1409  long dataSourceId = getDataSourceObjectId(connection, fileId);
1410  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1411  }
1412  resultSet.close();
1413  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1414  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1415  if (this.dbType.equals(DbType.SQLITE)) {
1416  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
1417  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
1418  } else {
1419  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
1420  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
1421  }
1422 
1423  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
1424  initIngestModuleTypes(connection);
1425  initIngestStatusTypes(connection);
1426 
1427  return new CaseDbSchemaVersionNumber(4, 0);
1428 
1429  } finally {
1430  closeResultSet(queryResultSet);
1431  closeStatement(queryStatement);
1432  closeStatement(updateStatement);
1433  closeResultSet(resultSet);
1434  closeStatement(statement);
1436  }
1437  }
1438 
1452  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1453  if (schemaVersion.getMajor() != 4) {
1454  return schemaVersion;
1455  }
1456 
1457  Statement statement = null;
1459  try {
1460  // Add the review_statuses lookup table.
1461  statement = connection.createStatement();
1462  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1463 
1464  /*
1465  * Add review_status_id column to artifacts table.
1466  *
1467  * NOTE: For DBs created with schema 5 we define a foreign key
1468  * constraint on the review_status_column. We don't bother with this
1469  * for DBs updated to schema 5 because of limitations of the SQLite
1470  * ALTER TABLE command.
1471  */
1472  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1473 
1474  // Add the encoding table
1475  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1476  initEncodingTypes(connection);
1477 
1478  /*
1479  * This needs to be done due to a Autopsy/TSK out of synch problem.
1480  * Without this, it is possible to upgrade from version 4 to 5 and
1481  * then 5 to 6, but not from 4 to 6.
1482  */
1483  initReviewStatuses(connection);
1484 
1485  // Add encoding type column to tsk_files_path
1486  // This should really have the FOREIGN KEY constraint but there are problems
1487  // getting that to work, so we don't add it on this upgrade path.
1488  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1489 
1490  return new CaseDbSchemaVersionNumber(5, 0);
1491 
1492  } finally {
1493  closeStatement(statement);
1495  }
1496  }
1497 
1511  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1512  if (schemaVersion.getMajor() != 5) {
1513  return schemaVersion;
1514  }
1515 
1516  /*
1517  * This upgrade fixes a bug where some releases had artifact review
1518  * status support in the case database and others did not.
1519  */
1520  Statement statement = null;
1521  ResultSet resultSet = null;
1523  try {
1524  /*
1525  * Add the review_statuses lookup table, if missing.
1526  */
1527  statement = connection.createStatement();
1528  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)");
1529 
1530  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1531  resultSet.next();
1532  if (resultSet.getLong("count") == 0) {
1533  /*
1534  * Add review_status_id column to artifacts table.
1535  *
1536  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1537  * key constraint on the review_status_column. We don't bother
1538  * with this for DBs updated to schema 5 or 6 because of
1539  * limitations of the SQLite ALTER TABLE command.
1540  */
1541  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1542  }
1543 
1544  return new CaseDbSchemaVersionNumber(6, 0);
1545 
1546  } finally {
1547  closeResultSet(resultSet);
1548  closeStatement(statement);
1550  }
1551  }
1552 
1566  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1567  if (schemaVersion.getMajor() != 6) {
1568  return schemaVersion;
1569  }
1570 
1571  /*
1572  * This upgrade adds an indexed extension column to the tsk_files table.
1573  */
1574  Statement statement = null;
1575  Statement updstatement = null;
1576  ResultSet resultSet = null;
1578  try {
1579  statement = connection.createStatement();
1580  updstatement = connection.createStatement();
1581  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1582 
1583  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1584  while (resultSet.next()) {
1585  long objID = resultSet.getLong("obj_id");
1586  String name = resultSet.getString("name");
1587  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1588  + "WHERE obj_id = " + objID);
1589  }
1590 
1591  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1592 
1593  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1594  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1595 
1596  return new CaseDbSchemaVersionNumber(7, 0);
1597 
1598  } finally {
1599  closeResultSet(resultSet);
1600  closeStatement(statement);
1601  closeStatement(updstatement);
1603  }
1604  }
1605 
1619  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1620  if (schemaVersion.getMajor() != 7) {
1621  return schemaVersion;
1622  }
1623 
1624  if (schemaVersion.getMinor() != 0) {
1625  return schemaVersion;
1626  }
1627 
1628  /*
1629  * This upgrade adds a minor version number column.
1630  */
1631  Statement statement = null;
1632  ResultSet resultSet = null;
1634  try {
1635  statement = connection.createStatement();
1636 
1637  //add the schema minor version number column.
1638  if (schemaVersion.getMinor() == 0) {
1639  //add the schema minor version number column.
1640  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1641  }
1642  return new CaseDbSchemaVersionNumber(7, 1);
1643 
1644  } finally {
1645  closeResultSet(resultSet);
1646  closeStatement(statement);
1648  }
1649  }
1650 
1664  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1665  if (schemaVersion.getMajor() != 7) {
1666  return schemaVersion;
1667  }
1668 
1669  if (schemaVersion.getMinor() != 1) {
1670  return schemaVersion;
1671  }
1672 
1673  Statement statement = null;
1674  Statement updstatement = null;
1675  ResultSet resultSet = null;
1677  try {
1678  //add the data_source_obj_id column to blackboard_artifacts.
1679  statement = connection.createStatement();
1680  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1681 
1682  // populate data_source_obj_id for each artifact
1683  updstatement = connection.createStatement();
1684  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1685  while (resultSet.next()) {
1686  long artifact_id = resultSet.getLong("artifact_id");
1687  long obj_id = resultSet.getLong("obj_id");
1688  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1689  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1690  + "WHERE artifact_id = " + artifact_id);
1691  }
1692  closeResultSet(resultSet);
1693  closeStatement(statement);
1694  closeStatement(updstatement);
1695 
1696  /*
1697  * Add a knownStatus column to the tag_names table.
1698  */
1699  statement = connection.createStatement();
1700  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1701 
1702  // Create account_types, accounts, and account_relationships table
1703  if (this.dbType.equals(DbType.SQLITE)) {
1704  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1705  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))");
1706  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))");
1707  } else {
1708  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1709  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))");
1710  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))");
1711  }
1712 
1713  // Create indexes
1714  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1715  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1716  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1717  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1718  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1719  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1720  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1721 
1722  return new CaseDbSchemaVersionNumber(7, 2);
1723  } finally {
1724  closeResultSet(resultSet);
1725  closeStatement(statement);
1726  closeStatement(updstatement);
1728  }
1729  }
1730 
1744  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1745  if (schemaVersion.getMajor() != 7) {
1746  return schemaVersion;
1747  }
1748 
1749  if (schemaVersion.getMinor() != 2) {
1750  return schemaVersion;
1751  }
1752 
1753  Statement updateSchemaStatement = connection.createStatement();
1754  Statement getExistingReportsStatement = connection.createStatement();
1755  ResultSet resultSet = null;
1756  ResultSet existingReports = null;
1757 
1759  try {
1760  // Update the schema to turn report_id into an object id.
1761 
1762  // Unfortunately, SQLite doesn't support adding a constraint
1763  // to an existing table so we have to rename the old...
1764  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1765 
1766  // ...create the new...
1767  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))");
1768 
1769  // ...add the existing report records back...
1770  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1771  while (existingReports.next()) {
1772  String path = existingReports.getString(2);
1773  long crtime = existingReports.getInt(3);
1774  String sourceModule = existingReports.getString(4);
1775  String reportName = existingReports.getString(5);
1776 
1777  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1778  insertObjectStatement.clearParameters();
1779  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1780  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1781  connection.executeUpdate(insertObjectStatement);
1782  resultSet = insertObjectStatement.getGeneratedKeys();
1783  if (!resultSet.next()) {
1784  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1785  }
1786  long objectId = resultSet.getLong(1); //last_insert_rowid()
1787 
1788  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1789  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1790  insertReportStatement.clearParameters();
1791  insertReportStatement.setLong(1, objectId);
1792  insertReportStatement.setString(2, path);
1793  insertReportStatement.setLong(3, crtime);
1794  insertReportStatement.setString(4, sourceModule);
1795  insertReportStatement.setString(5, reportName);
1796  connection.executeUpdate(insertReportStatement);
1797  }
1798 
1799  // ...and drop the old table.
1800  updateSchemaStatement.execute("DROP TABLE old_reports");
1801 
1802  return new CaseDbSchemaVersionNumber(8, 0);
1803  } finally {
1804  closeResultSet(resultSet);
1805  closeResultSet(existingReports);
1806  closeStatement(updateSchemaStatement);
1807  closeStatement(getExistingReportsStatement);
1809  }
1810  }
1811 
1825  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1826  if (schemaVersion.getMajor() != 8) {
1827  return schemaVersion;
1828  }
1829 
1830  if (schemaVersion.getMinor() != 0) {
1831  return schemaVersion;
1832  }
1833 
1835 
1836  try (Statement statement = connection.createStatement();) {
1837  // create examiners table
1838  if (this.dbType.equals(DbType.SQLITE)) {
1839  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1840  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1841  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1842  } else {
1843  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1844  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1845  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1846  }
1847 
1848  return new CaseDbSchemaVersionNumber(8, 1);
1849  } finally {
1851  }
1852  }
1853 
1867  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1868  if (schemaVersion.getMajor() != 8) {
1869  return schemaVersion;
1870  }
1871 
1872  if (schemaVersion.getMinor() != 1) {
1873  return schemaVersion;
1874  }
1875 
1877 
1878  try (Statement statement = connection.createStatement();) {
1879  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1880  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1881 
1882  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1883 
1884  /*
1885  * Add new tsk_db_extended_info table with TSK version, creation
1886  * time schema and schema version numbers as the initial data. The
1887  * creation time schema version is set to 0, 0 to indicate that it
1888  * is not known.
1889  */
1890  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1891  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1892  result.next();
1893  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1894  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1895  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1896  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1897  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1898 
1899  String primaryKeyType;
1900  switch (getDatabaseType()) {
1901  case POSTGRESQL:
1902  primaryKeyType = "BIGSERIAL";
1903  break;
1904  case SQLITE:
1905  primaryKeyType = "INTEGER";
1906  break;
1907  default:
1908  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1909  }
1910 
1911  //create and initialize tsk_event_types tables
1912  statement.execute("CREATE TABLE tsk_event_types ("
1913  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1914  + " display_name TEXT UNIQUE NOT NULL, "
1915  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1916  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1917  + " values( 0, 'Event Types', null)");
1918  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1919  + " values(1, 'File System', 0)");
1920  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1921  + " values(2, 'Web Activity', 0)");
1922  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1923  + " values(3, 'Misc Types', 0)");
1924  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1925  + " values(4, 'Modified', 1)");
1926  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1927  + " values(5, 'Accessed', 1)");
1928  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1929  + " values(6, 'Created', 1)");
1930  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1931  + " values(7, 'Changed', 1)");
1932 
1933  //create tsk_events tables
1934  statement.execute("CREATE TABLE tsk_event_descriptions ("
1935  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1936  + " full_description TEXT NOT NULL, "
1937  + " med_description TEXT, "
1938  + " short_description TEXT,"
1939  + " data_source_obj_id BIGINT NOT NULL, "
1940  + " file_obj_id BIGINT NOT NULL, "
1941  + " artifact_id BIGINT, "
1942  + " hash_hit INTEGER NOT NULL, " //boolean
1943  + " tagged INTEGER NOT NULL, " //boolean
1944  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1945  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1946  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1947  );
1948 
1949  statement.execute("CREATE TABLE tsk_events ( "
1950  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1951  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1952  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1953  + " time INTEGER NOT NULL) "
1954  );
1955 
1956  //create tsk_events indices
1957  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1958  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1959  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1960  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1961  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1962  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1963  return new CaseDbSchemaVersionNumber(8, 2);
1964 
1965  } finally {
1967  }
1968  }
1969 
1983  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1984  if (schemaVersion.getMajor() != 8) {
1985  return schemaVersion;
1986  }
1987 
1988  if (schemaVersion.getMinor() != 2) {
1989  return schemaVersion;
1990  }
1991 
1993 
1994  ResultSet resultSet = null;
1995 
1996  try (Statement statement = connection.createStatement();) {
1997 
1998  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1999  // Unfortunately, SQLite doesn't support adding a constraint
2000  // to an existing table so we have to rename the old...
2001  String primaryKeyType;
2002  switch (getDatabaseType()) {
2003  case POSTGRESQL:
2004  primaryKeyType = "BIGSERIAL";
2005  break;
2006  case SQLITE:
2007  primaryKeyType = "INTEGER";
2008  break;
2009  default:
2010  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2011  }
2012 
2013  //create and initialize tsk_event_types tables which may or may not exist
2014  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
2015  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
2016  + " display_name TEXT UNIQUE NOT NULL, "
2017  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
2018 
2019  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
2020 
2021  // If there is something in resultSet then the table must have previously
2022  // existing therefore there is not need to populate
2023  if (!resultSet.next()) {
2024 
2025  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2026  + " values( 0, 'Event Types', null)");
2027  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2028  + " values(1, 'File System', 0)");
2029  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2030  + " values(2, 'Web Activity', 0)");
2031  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2032  + " values(3, 'Misc Types', 0)");
2033  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2034  + " values(4, 'Modified', 1)");
2035  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2036  + " values(5, 'Accessed', 1)");
2037  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2038  + " values(6, 'Created', 1)");
2039  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2040  + " values(7, 'Changed', 1)");
2041  }
2042 
2043  // Delete the old table that may have been created with the upgrade
2044  // from 8.1 to 8.2.
2045  statement.execute("DROP TABLE IF EXISTS tsk_events");
2046 
2047  // Delete the old table that may have been created with the upgrade
2048  // from 8.1 to 8.2
2049  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
2050 
2051  //create new tsk_event_description table
2052  statement.execute("CREATE TABLE tsk_event_descriptions ("
2053  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2054  + " full_description TEXT NOT NULL, "
2055  + " med_description TEXT, "
2056  + " short_description TEXT,"
2057  + " data_source_obj_id BIGINT NOT NULL, "
2058  + " file_obj_id BIGINT NOT NULL, "
2059  + " artifact_id BIGINT, "
2060  + " hash_hit INTEGER NOT NULL, " //boolean
2061  + " tagged INTEGER NOT NULL, " //boolean
2062  + " UNIQUE(full_description, file_obj_id, artifact_id), "
2063  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2064  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2065  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2066  );
2067 
2068  // create a new table
2069  statement.execute("CREATE TABLE tsk_events ( "
2070  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2071  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2072  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2073  + " time INTEGER NOT NULL, "
2074  + " UNIQUE (event_type_id, event_description_id, time))"
2075  );
2076 
2077  // Fix mistakenly set names in tsk_db_info_extended
2078  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2079  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2080 
2081  return new CaseDbSchemaVersionNumber(8, 3);
2082  } finally {
2083  closeResultSet(resultSet);
2085  }
2086  }
2087 
2109  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2110  if (schemaVersion.getMajor() != 8) {
2111  return schemaVersion;
2112  }
2113 
2114  if (schemaVersion.getMinor() != 3) {
2115  return schemaVersion;
2116  }
2117 
2118  Statement statement = connection.createStatement();
2119  ResultSet results = null;
2120 
2122  try {
2123  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2124  // the previous update code.
2125  if (null == getDatabaseType()) {
2126  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2127  }
2128 
2129  switch (getDatabaseType()) {
2130  case POSTGRESQL:
2131  // Check if the misnamed column is present
2132  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2133  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2134  if (results.next()) {
2135  // In PostgreSQL we can rename the column if it exists
2136  statement.execute("ALTER TABLE tsk_event_descriptions "
2137  + "RENAME COLUMN file_obj_id TO content_obj_id");
2138 
2139  // 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
2140  // Fix the schema, preserving any data if exists.
2141  statement.execute("CREATE TABLE temp_tsk_events ( "
2142  + " event_id BIGSERIAL PRIMARY KEY, "
2143  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2144  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2145  + " time BIGINT NOT NULL, "
2146  + " UNIQUE (event_type_id, event_description_id, time))"
2147  );
2148 
2149  // Copy the data
2150  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2151  + "event_description_id, time) SELECT * FROM tsk_events");
2152 
2153  // Drop the old table
2154  statement.execute("DROP TABLE tsk_events");
2155 
2156  // Rename the new table
2157  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2158 
2159  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2160  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2161  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2162  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2163  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2164  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2165  }
2166  break;
2167  case SQLITE:
2168  boolean hasMisnamedColumn = false;
2169  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2170  while (results.next()) {
2171  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2172  hasMisnamedColumn = true;
2173  break;
2174  }
2175  }
2176 
2177  if (hasMisnamedColumn) {
2178  // Since we can't rename the column we'll need to make new tables and copy the data
2179  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2180  + " event_description_id INTEGER PRIMARY KEY, "
2181  + " full_description TEXT NOT NULL, "
2182  + " med_description TEXT, "
2183  + " short_description TEXT,"
2184  + " data_source_obj_id BIGINT NOT NULL, "
2185  + " content_obj_id BIGINT NOT NULL, "
2186  + " artifact_id BIGINT, "
2187  + " hash_hit INTEGER NOT NULL, " //boolean
2188  + " tagged INTEGER NOT NULL, " //boolean
2189  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2190  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2191  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2192  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2193  );
2194 
2195  statement.execute("CREATE TABLE temp_tsk_events ( "
2196  + " event_id INTEGER PRIMARY KEY, "
2197  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2198  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2199  + " time INTEGER NOT NULL, "
2200  + " UNIQUE (event_type_id, event_description_id, time))"
2201  );
2202 
2203  // Copy the data
2204  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2205  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2206  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2207 
2208  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2209  + "event_description_id, time) SELECT * FROM tsk_events");
2210 
2211  // Drop the old tables
2212  statement.execute("DROP TABLE tsk_events");
2213  statement.execute("DROP TABLE tsk_event_descriptions");
2214 
2215  // Rename the new tables
2216  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2217  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2218 
2219  //create tsk_events indices
2220  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2221  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2222  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2223  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2224  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2225  }
2226  break;
2227  default:
2228  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2229  }
2230 
2231  // create pool info table
2232  if (this.dbType.equals(DbType.SQLITE)) {
2233  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)");
2234  } else {
2235  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)");
2236  }
2237 
2238  // Add new account types for newly supported messaging applications, if they dont exists already.
2239  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2240  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2241  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2242  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2243  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2244  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2245  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2246  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2247  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2248  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2249 
2250  return new CaseDbSchemaVersionNumber(8, 4);
2251  } finally {
2252  closeResultSet(results);
2253  closeStatement(statement);
2255  }
2256  }
2257 
2258  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2259  if (schemaVersion.getMajor() != 8) {
2260  return schemaVersion;
2261  }
2262 
2263  if (schemaVersion.getMinor() != 4) {
2264  return schemaVersion;
2265  }
2266 
2267  Statement statement = connection.createStatement();
2269  try {
2270  switch (getDatabaseType()) {
2271  case POSTGRESQL:
2272  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2273  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2274  break;
2275  case SQLITE:
2276  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2277  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2278  break;
2279  }
2280 
2281  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2282 
2283  /*
2284  * Update existing Project Vic tag names (from Image Gallery in
2285  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2286  * date and will not work with the Project VIC Report module. New
2287  * cases will get the new names from Image Gallery.
2288  */
2289  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2290  if (getDatabaseType() == DbType.POSTGRESQL) {
2291  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2292  } else {
2293  statement.execute(insertStmt);
2294  }
2295  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2296  if (resultSet != null && resultSet.next()) {
2297  int tagSetId = resultSet.getInt(1);
2298 
2299  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2300  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2301  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2302  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2303  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2304  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2305 
2306  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')";
2307  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')";
2308  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2309  statement.executeUpdate(deleteContentTag);
2310  statement.executeUpdate(deleteArtifactTag);
2311  statement.executeUpdate(deleteCat0);
2312 
2313  } else {
2314  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2315  }
2316  }
2317 
2318  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2319  // this column will have a foreign key constraint on the data_source_info table.
2320  // There does not seem to be a reasonable way to do this in an upgrade,
2321  // so upgraded cases will be missing the foreign key.
2322  switch (getDatabaseType()) {
2323  case POSTGRESQL:
2324  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2325  break;
2326  case SQLITE:
2327  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2328  break;
2329  }
2330  Statement updateStatement = connection.createStatement();
2331  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2332  while (resultSet.next()) {
2333  long fsId = resultSet.getLong("obj_id");
2334  long dataSourceId = getDataSourceObjectId(connection, fsId);
2335  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2336  }
2337  } finally {
2338  closeStatement(updateStatement);
2339  }
2340 
2341  return new CaseDbSchemaVersionNumber(8, 5);
2342 
2343  } finally {
2344  closeStatement(statement);
2346  }
2347  }
2348 
2349  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2350  if (schemaVersion.getMajor() != 8) {
2351  return schemaVersion;
2352  }
2353 
2354  if (schemaVersion.getMinor() != 5) {
2355  return schemaVersion;
2356  }
2357 
2358  Statement statement = connection.createStatement();
2360  try {
2361  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2362 
2363  return new CaseDbSchemaVersionNumber(8, 6);
2364 
2365  } finally {
2366  closeStatement(statement);
2368  }
2369  }
2370 
2371  @SuppressWarnings("deprecation")
2372  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2373  if (schemaVersion.getMajor() != 8) {
2374  return schemaVersion;
2375  }
2376 
2377  if (schemaVersion.getMinor() != 6) {
2378  return schemaVersion;
2379  }
2380 
2381  Statement statement = connection.createStatement();
2383  try {
2384  String dateDataType = "BIGINT";
2385  String bigIntDataType = "BIGINT";
2386  String blobDataType = "BYTEA";
2387  String primaryKeyType = "BIGSERIAL";
2388 
2389  if (this.dbType.equals(DbType.SQLITE)) {
2390  dateDataType = "INTEGER";
2391  bigIntDataType = "INTEGER";
2392  blobDataType = "BLOB";
2393  primaryKeyType = "INTEGER";
2394  }
2395  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2396  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2397  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2398  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2399 
2400  // Add category type and initialize the types. We use the list of artifact types that
2401  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2402  // case the built-in types change in a later release.
2403  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2404  String analysisTypeObjIdList
2405  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2406  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2407  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2408  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2409  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2410  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2411  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2412  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2413  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2414  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2415  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2416  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2417  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2418  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2419  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2420  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2421  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2422  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2423  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2424 
2425  // Create tsk file attributes table
2426  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2427  + "obj_id " + bigIntDataType + " NOT NULL, "
2428  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2429  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2430  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2431  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2432  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2433 
2434  // create analysis results tables
2435  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2436  + "conclusion TEXT, "
2437  + "significance INTEGER NOT NULL, "
2438  /*
2439  * method_category was a column in a little distributed
2440  * version of 9.0. It was renamed to priority before public
2441  * release. The 9.1 upgrade code will add the priority
2442  * column. This is commented out since it was never used.
2443  */
2444  // + "method_category INTEGER NOT NULL, "
2445  + "configuration TEXT, justification TEXT, "
2446  + "ignore_score INTEGER DEFAULT 0 " // boolean
2447  + ")");
2448 
2449  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2450  + "data_source_obj_id " + bigIntDataType + ", "
2451  + "significance INTEGER NOT NULL, "
2452  // See comment above on why this is commented out
2453  // + "method_category INTEGER NOT NULL, "
2454  + "UNIQUE (obj_id),"
2455  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2456  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2457  + ")");
2458 
2459  // Create person table.
2460  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2461  + "name TEXT NOT NULL, " // person name
2462  + "UNIQUE(name)) ");
2463 
2464  // Create host table.
2465  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2466  + "name TEXT NOT NULL, " // host name
2467  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2468  + "person_id INTEGER, "
2469  + "merged_into " + bigIntDataType + ", "
2470  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2471  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2472  + "UNIQUE(name)) ");
2473 
2474  // Create OS Account and related tables
2475  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2476  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2477  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2478  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2479  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2480  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2481  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2482  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2483  + "UNIQUE(realm_signature), "
2484  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2485  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2486 
2487  // Add host column and create a host for each existing data source.
2488  // We will create a host for each device id so that related data sources will
2489  // be associated with the same host.
2490  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2491  Statement updateStatement = connection.createStatement();
2492  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2493  Map<String, Long> hostMap = new HashMap<>();
2494  long hostIndex = 1;
2495  while (resultSet.next()) {
2496  long objId = resultSet.getLong("obj_id");
2497  String deviceId = resultSet.getString("device_id");
2498 
2499  if (!hostMap.containsKey(deviceId)) {
2500  String hostName = "Host " + hostIndex;
2501  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2502  hostMap.put(deviceId, hostIndex);
2503  hostIndex++;
2504  }
2505  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2506  }
2507  } finally {
2508  closeStatement(updateStatement);
2509  }
2510 
2511  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2512  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2513  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2514  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2515  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2516  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2517  + "status INTEGER, " // enabled/disabled/deleted
2518  + "type INTEGER, " // service/interactive
2519  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2520  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2521  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2522  + "UNIQUE(signature, realm_id), "
2523  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2524  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2525  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2526 
2527  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2528  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2529  + "host_id " + bigIntDataType + ", "
2530  + "source_obj_id " + bigIntDataType + ", "
2531  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2532  + "value_type INTEGER NOT NULL, "
2533  + "value_byte " + bigIntDataType + ", "
2534  + "value_text TEXT, "
2535  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2536  + "value_double NUMERIC(20, 10), "
2537  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2538  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2539  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2540  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2541 
2542  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2543  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2544  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2545  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2546  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2547  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2548  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2549 
2550  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2551  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2552  + "os_account_obj_id " + bigIntDataType + ", "
2553  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2554 
2555  // add owner_uid & os_account_obj_id columns to tsk_files
2556  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2557  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2558 
2559  // create host address tables
2560  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2561  + "address_type INTEGER NOT NULL, "
2562  + "address TEXT NOT NULL, "
2563  + "UNIQUE(address_type, address)) ");
2564 
2565  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2566  + "host_id " + bigIntDataType + " NOT NULL, "
2567  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2568  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2569  + "time " + bigIntDataType + ", " // time at which the mapping existed
2570  + "UNIQUE(host_id, addr_obj_id, time), "
2571  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2572  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2573  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2574 
2575  // stores associations between DNS name and IP address
2576  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2577  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2578  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2579  + "source_obj_id " + bigIntDataType + ", "
2580  + "time " + bigIntDataType + ", " // time at which the mapping existed
2581  + "UNIQUE(dns_address_id, ip_address_id, time), "
2582  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2583  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2584  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2585 
2586  // maps an address to an artifact using it
2587  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2588  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2589  + "obj_id " + bigIntDataType + " NOT NULL, "
2590  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2591  + "UNIQUE(addr_obj_id, obj_id), "
2592  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2593  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2594 
2595  return new CaseDbSchemaVersionNumber(9, 0);
2596 
2597  } finally {
2598  closeStatement(statement);
2600  }
2601  }
2602 
2603  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2604  if (schemaVersion.getMajor() != 9) {
2605  return schemaVersion;
2606  }
2607 
2608  if (schemaVersion.getMinor() != 0) {
2609  return schemaVersion;
2610  }
2611 
2612  Statement statement = connection.createStatement();
2613  ResultSet results = null;
2615  try {
2616  // The 9.0 schema contained method_category columns that were renamed to priority.
2617  switch (getDatabaseType()) {
2618  case POSTGRESQL:
2619  // Check if the misnamed column is present. We'll assume here that the column will exist
2620  // in both tables if present in one.
2621  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2622  + "WHERE table_name='tsk_analysis_results' and column_name='method_category'");
2623  if (results.next()) {
2624  // In PostgreSQL we can delete the column
2625  statement.execute("ALTER TABLE tsk_analysis_results "
2626  + "DROP COLUMN method_category");
2627  statement.execute("ALTER TABLE tsk_aggregate_score "
2628  + "DROP COLUMN method_category");
2629  }
2630  break;
2631  case SQLITE:
2632  // Check if the misnamed column is present. We'll assume here that the column will exist
2633  // in both tables if present in one.
2634  boolean hasMisnamedColumn = false;
2635  results = statement.executeQuery("pragma table_info('tsk_analysis_results')");
2636  while (results.next()) {
2637  if (results.getString("name") != null && results.getString("name").equals("method_category")) {
2638  hasMisnamedColumn = true;
2639  break;
2640  }
2641  }
2642 
2643  if (hasMisnamedColumn) {
2644  // Since we can't rename the column we'll need to make a new table and copy the data.
2645  // We'll add the priority column later.
2646  statement.execute("CREATE TABLE temp_tsk_analysis_results (artifact_obj_id INTEGER PRIMARY KEY, "
2647  + "conclusion TEXT, "
2648  + "significance INTEGER NOT NULL, "
2649  + "configuration TEXT, justification TEXT, "
2650  + "ignore_score INTEGER DEFAULT 0 " // boolean
2651  + ")");
2652  statement.execute("CREATE TABLE temp_tsk_aggregate_score( obj_id INTEGER PRIMARY KEY, "
2653  + "data_source_obj_id INTEGER, "
2654  + "significance INTEGER NOT NULL, "
2655  + "UNIQUE (obj_id),"
2656  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2657  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2658  + ")");
2659 
2660  // Copy the data
2661  statement.execute("INSERT INTO temp_tsk_analysis_results(artifact_obj_id, "
2662  + "conclusion, justification, significance, configuration, ignore_score) "
2663  + "SELECT artifact_obj_id, conclusion, justification, significance, configuration, ignore_score FROM tsk_analysis_results");
2664  statement.execute("INSERT INTO temp_tsk_aggregate_score(obj_id, "
2665  + "data_source_obj_id, significance) "
2666  + "SELECT obj_id, data_source_obj_id, significance FROM tsk_aggregate_score");
2667 
2668  // Drop the old tables
2669  statement.execute("DROP TABLE tsk_analysis_results");
2670  statement.execute("DROP TABLE tsk_aggregate_score");
2671 
2672  // Rename the new tables
2673  statement.execute("ALTER TABLE temp_tsk_analysis_results RENAME TO tsk_analysis_results");
2674  statement.execute("ALTER TABLE temp_tsk_aggregate_score RENAME TO tsk_aggregate_score");
2675 
2676  }
2677  break;
2678  default:
2679  throw new TskCoreException("Unsupported database type: " + getDatabaseType().toString());
2680  }
2681 
2682  // add an index on tsk_file_attributes table.
2683  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2684 
2685  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2686  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2687 
2688  statement.execute("UPDATE blackboard_artifact_types SET category_type = 1 WHERE artifact_type_id = 16");
2689 
2690  return new CaseDbSchemaVersionNumber(9, 1);
2691  } finally {
2692  closeResultSet(results);
2693  closeStatement(statement);
2695  }
2696  }
2697 
2711  private CaseDbSchemaVersionNumber updateFromSchema9dot1toSchema9dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2712  if (schemaVersion.getMajor() != 9) {
2713  return schemaVersion;
2714  }
2715 
2716  if (schemaVersion.getMinor() != 1) {
2717  return schemaVersion;
2718  }
2719 
2720  Statement updateSchemaStatement = connection.createStatement();
2721  ResultSet results = null;
2723  try {
2724 
2725  String bigIntDataType = "BIGINT";
2726  String primaryKeyType = "BIGSERIAL";
2727 
2728  if (this.dbType.equals(DbType.SQLITE)) {
2729  bigIntDataType = "INTEGER";
2730  primaryKeyType = "INTEGER";
2731  }
2732 
2733  // In 9.2 we modified the UNIQUE constraint on tsk_os_account_instances to include instance_type column.
2734  // Since SQLite does not allow to drop or alter constraints, we will create a new table, copy the data and delete the old table.
2735  // Rename existing table
2736  updateSchemaStatement.execute("ALTER TABLE tsk_os_account_instances RENAME TO old_tsk_os_account_instances");
2737 
2738  // New table
2739  updateSchemaStatement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2740  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2741  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2742  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2743  + "UNIQUE(os_account_obj_id, data_source_obj_id, instance_type), "
2744  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id) ON DELETE CASCADE, "
2745  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE ) ");
2746 
2747  // Copy the data from old table, order by id preserves the primary key.
2748  updateSchemaStatement.execute("INSERT INTO tsk_os_account_instances(os_account_obj_id, "
2749  + "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");
2750 
2751  // delete old table
2752  updateSchemaStatement.execute("DROP TABLE old_tsk_os_account_instances");
2753 
2754  return new CaseDbSchemaVersionNumber(9, 2);
2755  } finally {
2756  closeResultSet(results);
2757  closeStatement(updateSchemaStatement);
2759  }
2760  }
2761 
2762  private CaseDbSchemaVersionNumber updateFromSchema9dot2toSchema9dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2763  if (schemaVersion.getMajor() != 9) {
2764  return schemaVersion;
2765  }
2766 
2767  if (schemaVersion.getMinor() != 2) {
2768  return schemaVersion;
2769  }
2770 
2771  Statement statement = connection.createStatement();
2773  try {
2774  // add a new column 'sha1' to tsk_files
2775  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha1 TEXT");
2776 
2777 
2778  return new CaseDbSchemaVersionNumber(9, 3);
2779 
2780  } finally {
2781  closeStatement(statement);
2783  }
2784  }
2785 
2786  private CaseDbSchemaVersionNumber updateFromSchema9dot3toSchema9dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2787  if (schemaVersion.getMajor() != 9) {
2788  return schemaVersion;
2789  }
2790 
2791  if (schemaVersion.getMinor() != 3) {
2792  return schemaVersion;
2793  }
2794 
2795  Statement statement = connection.createStatement();
2797  try {
2798  // Add file_collection_status_types table
2799  statement.execute("CREATE TABLE file_collection_status_types (collection_status_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
2800  initCollectedStatusTypes(connection);
2801 
2802  // add a new column 'collected' to tsk_files
2803  statement.execute("ALTER TABLE tsk_files ADD COLUMN collected INTEGER NOT NULL DEFAULT " +
2804  TskData.CollectedStatus.UNKNOWN.getType() + ";");
2805 
2806  return new CaseDbSchemaVersionNumber(9, 4);
2807 
2808  } finally {
2809  closeStatement(statement);
2811  }
2812  }
2813 
2825  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2826 
2827  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2828  switch (getDatabaseType()) {
2829  case POSTGRESQL:
2830  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2831  break;
2832  case SQLITE:
2833  insertSQL = "INSERT OR IGNORE " + insertSQL;
2834  break;
2835  default:
2836  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2837  }
2838  statement.execute(insertSQL); //NON-NLS
2839  }
2840 
2848  static String extractExtension(final String fileName) {
2849  String ext;
2850  int i = fileName.lastIndexOf(".");
2851  // > 0 because we assume it's not an extension if period is the first character
2852  if ((i > 0) && ((i + 1) < fileName.length())) {
2853  ext = fileName.substring(i + 1);
2854  } else {
2855  return "";
2856  }
2857  // we added this at one point to deal with files that had crazy names based on URLs
2858  // it's too hard though to clean those up and not mess up basic extensions though.
2859  // We need to add '-' to the below if we use it again
2860  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2861  // if (findNonAlphanumeric.length > 1) {
2862  // ext = findNonAlphanumeric[0];
2863  // }
2864  return ext.toLowerCase();
2865  }
2866 
2877  @Deprecated
2878  public int getSchemaVersion() {
2879  return getDBSchemaVersion().getMajor();
2880  }
2881 
2888  return CURRENT_DB_SCHEMA_VERSION;
2889  }
2890 
2898  return caseDBSchemaCreationVersion;
2899  }
2900 
2907  return this.dbType;
2908  }
2909 
2916  public String getBackupDatabasePath() {
2917  return dbBackupPath;
2918  }
2919 
2934  public CaseDbTransaction beginTransaction() throws TskCoreException {
2935  return new CaseDbTransaction(this);
2936  }
2937 
2943  public String getDatabaseName() {
2944  return databaseName;
2945  }
2946 
2953  public String getDbDirPath() {
2954  return caseDirPath;
2955  }
2956 
2963  if (dbType == DbType.SQLITE) {
2964  rwLock.writeLock().lock();
2965  }
2966  }
2967 
2974  if (dbType == DbType.SQLITE) {
2975  rwLock.writeLock().unlock();
2976  }
2977  }
2978 
2985  if (dbType == DbType.SQLITE) {
2986  rwLock.readLock().lock();
2987  }
2988  }
2989 
2996  if (dbType == DbType.SQLITE) {
2997  rwLock.readLock().unlock();
2998  }
2999  }
3000 
3010  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
3011  return openCase(dbPath, null);
3012  }
3013 
3024  @Beta
3025  public static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider) throws TskCoreException {
3026  try {
3027  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3028  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, provider);
3030  //don't wrap in new TskCoreException
3031  throw ex;
3032  } catch (Exception ex) {
3033  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
3034  }
3035  }
3036 
3048  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
3049  return openCase(databaseName, info, caseDir, null);
3050  }
3051 
3064  @Beta
3065  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentStreamProvider contentProvider) throws TskCoreException {
3066  try {
3067  /*
3068  * The flow of this method involves trying to open case and if
3069  * successful, return that case. If unsuccessful, an exception is
3070  * thrown. We catch any exceptions, and use tryConnect() to attempt
3071  * to obtain further information about the error. If tryConnect() is
3072  * unable to successfully connect, tryConnect() will throw a
3073  * TskCoreException with a message containing user-level error
3074  * reporting. If tryConnect() is able to connect, flow continues and
3075  * we rethrow the original exception obtained from trying to create
3076  * the case. In this way, we obtain more detailed information if we
3077  * are able, but do not lose any information if unable.
3078  */
3079  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3080  return new SleuthkitCase(info, databaseName, caseHandle, caseDir, contentProvider);
3081  } catch (PropertyVetoException exp) {
3082  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3083  throw new TskCoreException(exp.getMessage(), exp);
3085  //don't wrap in new TskCoreException
3086  throw ex;
3087  } catch (Exception exp) {
3088  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3089  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3090  }
3091  }
3092 
3102  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
3103  return newCase(dbPath, null);
3104  }
3105 
3116  @Beta
3117  public static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider) throws TskCoreException {
3118  try {
3119  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
3120  factory.createCaseDatabase();
3121 
3122  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3123  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, contentProvider);
3124  } catch (Exception ex) {
3125  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
3126  }
3127  }
3128 
3144  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
3145  return newCase(caseName, info, caseDirPath, null);
3146  }
3147 
3148 
3165  @Beta
3166  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentStreamProvider contentProvider) throws TskCoreException {
3167  String databaseName = createCaseDataBaseName(caseName);
3168  try {
3181  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
3182  factory.createCaseDatabase();
3183 
3184  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3185  return new SleuthkitCase(info, databaseName, caseHandle, caseDirPath, contentProvider);
3186  } catch (PropertyVetoException exp) {
3187  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3188  throw new TskCoreException(exp.getMessage(), exp);
3189  } catch (Exception exp) {
3190  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3191  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3192  }
3193  }
3194 
3204  private static String createCaseDataBaseName(String candidateDbName) {
3205  String dbName;
3206  if (!candidateDbName.isEmpty()) {
3207  /*
3208  * Replace all non-ASCII characters.
3209  */
3210  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
3211 
3212  /*
3213  * Replace all control characters.
3214  */
3215  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
3216 
3217  /*
3218  * Replace /, \, :, ?, space, ' ".
3219  */
3220  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
3221 
3222  /*
3223  * Make it all lowercase.
3224  */
3225  dbName = dbName.toLowerCase();
3226 
3227  /*
3228  * Must start with letter or underscore. If not, prepend an
3229  * underscore.
3230  */
3231  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
3232  dbName = "_" + dbName;
3233  }
3234 
3235  /*
3236  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
3237  * uniqueness.
3238  */
3239  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
3240  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
3241  }
3242 
3243  } else {
3244  /*
3245  * Must start with letter or underscore.
3246  */
3247  dbName = "_";
3248  }
3249  /*
3250  * Add the time stmap.
3251  */
3252  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
3253  Date date = new Date();
3254  dbName = dbName + "_" + dateFormat.format(date);
3255 
3256  return dbName;
3257  }
3258 
3264  @Beta
3266  timelineEventsDisabled.set(true);
3267  }
3268 
3276  public Examiner getCurrentExaminer() throws TskCoreException {
3277 
3278  // return cached value if there's one
3279  if (cachedCurrentExaminer != null) {
3280  return cachedCurrentExaminer;
3281  }
3282  String loginName = System.getProperty("user.name");
3283  if (loginName == null || loginName.isEmpty()) {
3284  throw new TskCoreException("Failed to determine logged in user name.");
3285  }
3286 
3287  ResultSet resultSet = null;
3288  CaseDbConnection connection = null;
3290  try {
3291  connection = connections.getConnection();
3292  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3293  statement.clearParameters();
3294  statement.setString(1, loginName);
3295  resultSet = connection.executeQuery(statement);
3296  if (resultSet.next()) {
3297  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3298  return cachedCurrentExaminer;
3299  } else {
3300  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3301  }
3302 
3303  } catch (SQLException ex) {
3304  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3305  } finally {
3306  closeResultSet(resultSet);
3307  closeConnection(connection);
3309  }
3310 
3311  }
3312 
3322  Examiner getExaminerById(long id) throws TskCoreException {
3323 
3324  CaseDbConnection connection = null;
3325  ResultSet resultSet = null;
3327  try {
3328  connection = connections.getConnection();
3329  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3330  statement.clearParameters();
3331  statement.setLong(1, id);
3332  resultSet = connection.executeQuery(statement);
3333  if (resultSet.next()) {
3334  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3335  } else {
3336  throw new TskCoreException("Error getting examaminer for id = " + id);
3337  }
3338  } catch (SQLException ex) {
3339  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3340  } finally {
3341  closeResultSet(resultSet);
3342  closeConnection(connection);
3344  }
3345  }
3346 
3364  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3365  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
3366  }
3367 
3376  public List<Content> getRootObjects() throws TskCoreException {
3377  CaseDbConnection connection = null;
3378  Statement s = null;
3379  ResultSet rs = null;
3381  try {
3382  connection = connections.getConnection();
3383  s = connection.createStatement();
3384  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
3385  + "WHERE par_obj_id IS NULL"); //NON-NLS
3386  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3387  while (rs.next()) {
3388  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3389  }
3390 
3391  List<Content> rootObjs = new ArrayList<Content>();
3392  for (ObjectInfo i : infos) {
3393  if (null != i.type) {
3394  switch (i.type) {
3395  case IMG:
3396  rootObjs.add(getImageById(i.id));
3397  break;
3398  case ABSTRACTFILE:
3399  // Check if virtual dir for local files.
3400  AbstractFile af = getAbstractFileById(i.id);
3401  if (af instanceof VirtualDirectory) {
3402  rootObjs.add(af);
3403  } else {
3404  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3405  }
3406  break;
3407  case REPORT:
3408  break;
3409  case OS_ACCOUNT:
3410  break;
3411  case HOST_ADDRESS:
3412  break;
3413  case UNSUPPORTED:
3414  break;
3415  default:
3416  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3417  }
3418  }
3419  }
3420  return rootObjs;
3421  } catch (SQLException ex) {
3422  throw new TskCoreException("Error getting root objects", ex);
3423  } finally {
3424  closeResultSet(rs);
3425  closeStatement(s);
3426  closeConnection(connection);
3428  }
3429  }
3430 
3442  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3443 
3444  // check cached map first
3445  synchronized (deviceIdToDatasourceObjIdMap) {
3446  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3447  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3448  }
3449 
3450  CaseDbConnection connection = null;
3451  Statement s = null;
3452  ResultSet rs = null;
3454  try {
3455  connection = connections.getConnection();
3456  s = connection.createStatement();
3457  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3458  List<Long> dataSourceObjIds = new ArrayList<Long>();
3459  while (rs.next()) {
3460  dataSourceObjIds.add(rs.getLong("obj_id"));
3461 
3462  // Add to map of deviceID to data_source_obj_id.
3463  long ds_obj_id = rs.getLong("obj_id");
3464  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3465  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3466  } else {
3467  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3468  }
3469  }
3470  return dataSourceObjIds;
3471  } catch (SQLException ex) {
3472  throw new TskCoreException("Error getting data sources", ex);
3473  } finally {
3474  closeResultSet(rs);
3475  closeStatement(s);
3476  closeConnection(connection);
3478  }
3479  }
3480  }
3481 
3498  public List<DataSource> getDataSources() throws TskCoreException {
3499  CaseDbConnection connection = null;
3500  Statement statement = null;
3501  ResultSet resultSet = null;
3502  Statement statement2 = null;
3503  ResultSet resultSet2 = null;
3505  try {
3506  connection = connections.getConnection();
3507  statement = connection.createStatement();
3508  statement2 = connection.createStatement();
3509  resultSet = connection.executeQuery(statement,
3510  "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 "
3511  + "FROM data_source_info AS ds "
3512  + "LEFT JOIN tsk_image_info AS img "
3513  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3514 
3515  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3516  Map<Long, List<String>> imagePathsMap = getImagePaths();
3517 
3518  while (resultSet.next()) {
3519  DataSource dataSource;
3520  Long objectId = resultSet.getLong("obj_id");
3521  String deviceId = resultSet.getString("device_id");
3522  String timezone = resultSet.getString("time_zone");
3523  String type = resultSet.getString("type");
3524 
3525  if (type == null) {
3526  /*
3527  * No data found in 'tsk_image_info', so we build a
3528  * LocalFilesDataSource.
3529  */
3530 
3531  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3532  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3533  resultSet2.close();
3534 
3538  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3539  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3540  String parentPath = "/"; //NON-NLS
3541  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3542  } else {
3543  /*
3544  * Data found in 'tsk_image_info', so we build an Image.
3545  */
3546  Long ssize = resultSet.getLong("ssize");
3547  Long size = resultSet.getLong("size");
3548  String md5 = resultSet.getString("md5");
3549  String sha1 = resultSet.getString("sha1");
3550  String sha256 = resultSet.getString("sha256");
3551  String name = resultSet.getString("display_name");
3552 
3553  List<String> imagePaths = imagePathsMap.get(objectId);
3554  if (name == null) {
3555  if (imagePaths.size() > 0) {
3556  String path = imagePaths.get(0);
3557  name = (new java.io.File(path)).getName();
3558  } else {
3559  name = "";
3560  }
3561  }
3562 
3563  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3564  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3565  }
3566 
3567  dataSourceList.add(dataSource);
3568  }
3569 
3570  return dataSourceList;
3571 
3572  } catch (SQLException ex) {
3573  throw new TskCoreException("Error getting data sources", ex);
3574  } finally {
3575  closeResultSet(resultSet);
3576  closeStatement(statement);
3577  closeResultSet(resultSet2);
3578  closeStatement(statement2);
3579  closeConnection(connection);
3581  }
3582  }
3583 
3603  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3604  DataSource dataSource = null;
3605  CaseDbConnection connection = null;
3606  Statement statement = null;
3607  ResultSet resultSet = null;
3608  Statement statement2 = null;
3609  ResultSet resultSet2 = null;
3611  try {
3612  connection = connections.getConnection();
3613  statement = connection.createStatement();
3614  statement2 = connection.createStatement();
3615  resultSet = connection.executeQuery(statement,
3616  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3617  + "FROM data_source_info AS ds "
3618  + "LEFT JOIN tsk_image_info AS img "
3619  + "ON ds.obj_id = img.obj_id "
3620  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3621  if (resultSet.next()) {
3622  String deviceId = resultSet.getString("device_id");
3623  String timezone = resultSet.getString("time_zone");
3624  String type = resultSet.getString("type");
3625 
3626  if (type == null) {
3627  /*
3628  * No data found in 'tsk_image_info', so we build an
3629  * LocalFilesDataSource.
3630  */
3631 
3632  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3633  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3634 
3638  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3639  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3640  String parentPath = "/"; //NON-NLS
3641  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3642  } else {
3643  /*
3644  * Data found in 'tsk_image_info', so we build an Image.
3645  */
3646  Long ssize = resultSet.getLong("ssize");
3647  Long size = resultSet.getLong("size");
3648  String md5 = resultSet.getString("md5");
3649  String sha1 = resultSet.getString("sha1");
3650  String sha256 = resultSet.getString("sha256");
3651  String name = resultSet.getString("display_name");
3652 
3653  List<String> imagePaths = getImagePathsById(objectId, connection);
3654  if (name == null) {
3655  if (imagePaths.size() > 0) {
3656  String path = imagePaths.get(0);
3657  name = (new java.io.File(path)).getName();
3658  } else {
3659  name = "";
3660  }
3661  }
3662 
3663  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3664  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3665  }
3666  } else {
3667  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3668  }
3669  } catch (SQLException ex) {
3670  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3671  } finally {
3672  closeResultSet(resultSet);
3673  closeStatement(statement);
3674  closeResultSet(resultSet2);
3675  closeStatement(statement2);
3676  closeConnection(connection);
3678  }
3679 
3680  return dataSource;
3681  }
3682 
3695  @Deprecated
3696  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3697  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3698  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactTypeID)));
3699  return artifacts;
3700  }
3701 
3712  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3713  CaseDbConnection connection = null;
3714  ResultSet rs = null;
3716  try {
3717  connection = connections.getConnection();
3718 
3719  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3720  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3721  statement.clearParameters();
3722  statement.setLong(1, objId);
3723  rs = connection.executeQuery(statement);
3724  long count = 0;
3725  if (rs.next()) {
3726  count = rs.getLong("count");
3727  }
3728  return count;
3729  } catch (SQLException ex) {
3730  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3731  } finally {
3732  closeResultSet(rs);
3733  closeConnection(connection);
3735  }
3736  }
3737 
3748  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3749  CaseDbConnection connection = null;
3750  ResultSet rs = null;
3752  try {
3753  connection = connections.getConnection();
3754 
3755  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3756  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3757  statement.clearParameters();
3758  statement.setInt(1, artifactTypeID);
3759  rs = connection.executeQuery(statement);
3760  long count = 0;
3761  if (rs.next()) {
3762  count = rs.getLong("count");
3763  }
3764  return count;
3765  } catch (SQLException ex) {
3766  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3767  } finally {
3768  closeResultSet(rs);
3769  closeConnection(connection);
3771  }
3772  }
3773 
3785  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3786  CaseDbConnection connection = null;
3787  ResultSet rs = null;
3789  try {
3790  connection = connections.getConnection();
3791 
3792  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3793  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3794  statement.clearParameters();
3795  statement.setInt(2, artifactTypeID);
3796  statement.setLong(1, dataSourceID);
3797  rs = connection.executeQuery(statement);
3798  long count = 0;
3799  if (rs.next()) {
3800  count = rs.getLong("count");
3801  }
3802  return count;
3803  } catch (SQLException ex) {
3804  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3805  } finally {
3806  closeResultSet(rs);
3807  closeConnection(connection);
3809  }
3810  }
3811 
3828  @Deprecated
3829  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3831  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3832  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3833  + "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, "
3834  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3835  + " arts.review_status_id AS review_status_id " //NON-NLS
3836  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3837  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3838  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3839  + " AND attrs.value_text = '" + value + "'"
3840  + " AND types.artifact_type_id=arts.artifact_type_id"
3841  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) { //NON-NLS
3842 
3843  List<Long> analysisArtifactObjIds = new ArrayList<>();
3844  List<Long> dataArtifactObjIds = new ArrayList<>();
3845  while (resultSet.next()) {
3846  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3847  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3848  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3849  } else {
3850  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3851  }
3852  }
3853 
3854  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3855  if (!analysisArtifactObjIds.isEmpty()) {
3856  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3857  }
3858 
3859  if (!dataArtifactObjIds.isEmpty()) {
3860  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3861  }
3862  return artifacts;
3863  } catch (SQLException ex) {
3864  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3865  } finally {
3867  }
3868  }
3869 
3888  @Deprecated
3889  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3890  String valSubStr = "%" + subString; //NON-NLS
3891  if (startsWith == false) {
3892  valSubStr += "%"; //NON-NLS
3893  }
3894 
3896  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3897  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3898  + " 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
3899  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3900  + " arts.review_status_id AS review_status_id " //NON-NLS
3901  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3902  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3903  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3904  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3905  + " AND types.artifact_type_id=arts.artifact_type_id "
3906  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3907  List<Long> analysisArtifactObjIds = new ArrayList<>();
3908  List<Long> dataArtifactObjIds = new ArrayList<>();
3909  while (resultSet.next()) {
3910  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3911  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3912  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3913  } else {
3914  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3915  }
3916  }
3917 
3918  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3919  if (!analysisArtifactObjIds.isEmpty()) {
3920  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3921  }
3922 
3923  if (!dataArtifactObjIds.isEmpty()) {
3924  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3925  }
3926  return artifacts;
3927  } catch (SQLException ex) {
3928  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3929  } finally {
3931  }
3932  }
3933 
3949  @Deprecated
3950  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3952  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3953  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3954  + " 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, "
3955  + " types.type_name AS type_name, types.display_name AS display_name, "
3956  + " arts.review_status_id AS review_status_id "//NON-NLS
3957  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3958  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3959  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3960  + " AND attrs.value_int32 = " + value //NON-NLS
3961  + " AND types.artifact_type_id=arts.artifact_type_id "
3962  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3963  List<Long> analysisArtifactObjIds = new ArrayList<>();
3964  List<Long> dataArtifactObjIds = new ArrayList<>();
3965  while (resultSet.next()) {
3966  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3967  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3968  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3969  } else {
3970  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3971  }
3972  }
3973 
3974  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3975  if (!analysisArtifactObjIds.isEmpty()) {
3976  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3977  }
3978 
3979  if (!dataArtifactObjIds.isEmpty()) {
3980  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3981  }
3982  return artifacts;
3983  } catch (SQLException ex) {
3984  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3985  } finally {
3987  }
3988  }
3989 
4006  @Deprecated
4007  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
4009  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4010  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4011  + " 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, "
4012  + " types.type_name AS type_name, types.display_name AS display_name, "
4013  + " arts.review_status_id AS review_status_id "//NON-NLS
4014  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4015  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4016  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4017  + " AND attrs.value_int64 = " + value //NON-NLS
4018  + " AND types.artifact_type_id=arts.artifact_type_id "
4019  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4020  List<Long> analysisArtifactObjIds = new ArrayList<>();
4021  List<Long> dataArtifactObjIds = new ArrayList<>();
4022  while (resultSet.next()) {
4023  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4024  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4025  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4026  } else {
4027  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4028  }
4029  }
4030 
4031  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4032  if (!analysisArtifactObjIds.isEmpty()) {
4033  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4034  }
4035 
4036  if (!dataArtifactObjIds.isEmpty()) {
4037  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4038  }
4039  return artifacts;
4040  } catch (SQLException ex) {
4041  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
4042  } finally {
4044  }
4045  }
4046 
4063  @Deprecated
4064  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
4066  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4067  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4068  + " 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, "
4069  + " types.type_name AS type_name, types.display_name AS display_name, "
4070  + " arts.review_status_id AS review_status_id "//NON-NLS
4071  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4072  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4073  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4074  + " AND attrs.value_double = " + value //NON-NLS
4075  + " AND types.artifact_type_id=arts.artifact_type_id "
4076  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4077  List<Long> analysisArtifactObjIds = new ArrayList<>();
4078  List<Long> dataArtifactObjIds = new ArrayList<>();
4079  while (resultSet.next()) {
4080  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4081  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4082  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4083  } else {
4084  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4085  }
4086  }
4087 
4088  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4089  if (!analysisArtifactObjIds.isEmpty()) {
4090  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4091  }
4092 
4093  if (!dataArtifactObjIds.isEmpty()) {
4094  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4095  }
4096  return artifacts;
4097  } catch (SQLException ex) {
4098  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4099  } finally {
4101  }
4102  }
4103 
4120  @Deprecated
4121  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
4122 
4124  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4125  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4126  + " 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, "
4127  + " types.type_name AS type_name, types.display_name AS display_name, "
4128  + " arts.review_status_id AS review_status_id "//NON-NLS
4129  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4130  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4131  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4132  + " AND attrs.value_byte = " + value //NON-NLS
4133  + " AND types.artifact_type_id=arts.artifact_type_id "
4134  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4135  List<Long> analysisArtifactObjIds = new ArrayList<>();
4136  List<Long> dataArtifactObjIds = new ArrayList<>();
4137  while (resultSet.next()) {
4138  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4139  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4140  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4141  } else {
4142  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4143  }
4144  }
4145 
4146  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4147  if (!analysisArtifactObjIds.isEmpty()) {
4148  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4149  }
4150 
4151  if (!dataArtifactObjIds.isEmpty()) {
4152  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4153  }
4154  return artifacts;
4155  } catch (SQLException ex) {
4156  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4157  } finally {
4159  }
4160  }
4161 
4169  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
4170  CaseDbConnection connection = null;
4171  Statement s = null;
4172  ResultSet rs = null;
4174  try {
4175  connection = connections.getConnection();
4176  s = connection.createStatement();
4177  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
4178  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
4179  while (rs.next()) {
4180  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4181  rs.getString("type_name"), rs.getString("display_name"),
4182  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4183  }
4184  return artifactTypes;
4185  } catch (SQLException ex) {
4186  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
4187  } finally {
4188  closeResultSet(rs);
4189  closeStatement(s);
4190  closeConnection(connection);
4192  }
4193  }
4194 
4203  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
4204  String typeIdList = "";
4205  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
4206  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
4207  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
4208  typeIdList += ", ";
4209  }
4210  }
4211  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
4212  + "WHERE artifact_type_id IN (" + typeIdList + ")";
4213  CaseDbConnection connection = null;
4214  Statement s = null;
4215  ResultSet rs = null;
4217  try {
4218  connection = connections.getConnection();
4219  s = connection.createStatement();
4220  rs = connection.executeQuery(s, query);
4221  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
4222  while (rs.next()) {
4223  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
4224  }
4225  return usedArts;
4226  } catch (SQLException ex) {
4227  throw new TskCoreException("Error getting artifact types in use", ex);
4228  } finally {
4229  closeResultSet(rs);
4230  closeStatement(s);
4231  closeConnection(connection);
4233  }
4234  }
4235 
4246  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
4247  CaseDbConnection connection = null;
4248  Statement s = null;
4249  ResultSet rs = null;
4251  try {
4252  connection = connections.getConnection();
4253  s = connection.createStatement();
4254  rs = connection.executeQuery(s,
4255  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
4256  + "types.type_name AS type_name, "
4257  + "types.display_name AS display_name, "
4258  + "types.category_type AS category_type "
4259  + "FROM blackboard_artifact_types AS types "
4260  + "INNER JOIN blackboard_artifacts AS arts "
4261  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
4262  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
4263  while (rs.next()) {
4264  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4265  rs.getString("type_name"), rs.getString("display_name"),
4266  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4267  }
4268  return uniqueArtifactTypes;
4269  } catch (SQLException ex) {
4270  throw new TskCoreException("Error getting attribute types", ex);
4271  } finally {
4272  closeResultSet(rs);
4273  closeStatement(s);
4274  closeConnection(connection);
4276  }
4277  }
4278 
4286  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
4287  CaseDbConnection connection = null;
4288  Statement s = null;
4289  ResultSet rs = null;
4291  try {
4292  connection = connections.getConnection();
4293  s = connection.createStatement();
4294  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
4295  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
4296  while (rs.next()) {
4297  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4298  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
4299  }
4300  return attribute_types;
4301  } catch (SQLException ex) {
4302  throw new TskCoreException("Error getting attribute types", ex);
4303  } finally {
4304  closeResultSet(rs);
4305  closeStatement(s);
4306  closeConnection(connection);
4308  }
4309  }
4310 
4322  public int getBlackboardAttributeTypesCount() throws TskCoreException {
4323  CaseDbConnection connection = null;
4324  Statement s = null;
4325  ResultSet rs = null;
4327  try {
4328  connection = connections.getConnection();
4329  s = connection.createStatement();
4330  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4331  int count = 0;
4332  if (rs.next()) {
4333  count = rs.getInt("count");
4334  }
4335  return count;
4336  } catch (SQLException ex) {
4337  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4338  } finally {
4339  closeResultSet(rs);
4340  closeStatement(s);
4341  closeConnection(connection);
4343  }
4344  }
4345 
4358  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4359  CaseDbConnection connection = null;
4360  ResultSet rs = null;
4362  try {
4363  connection = connections.getConnection();
4364 
4365  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4366  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4367  statement.clearParameters();
4368  statement.setLong(1, obj_id);
4369  statement.setInt(2, artifactTypeID);
4370  rs = connection.executeQuery(statement);
4371  long count = 0;
4372  if (rs.next()) {
4373  count = rs.getLong("count");
4374  }
4375  return count;
4376  } catch (SQLException ex) {
4377  throw new TskCoreException("Error getting blackboard artifact count", ex);
4378  } finally {
4379  closeResultSet(rs);
4380  closeConnection(connection);
4382  }
4383  }
4384 
4397  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4398  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4399  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeName), obj_id));
4400  return artifacts;
4401  }
4402 
4415  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4416  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4417  artifacts.addAll(blackboard.getArtifactsBySourceId(blackboard.getArtifactType(artifactTypeID), obj_id));
4418  return artifacts;
4419  }
4420 
4433  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4434  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4435  }
4436 
4449  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4450  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4451  if (artifactTypeID == -1) {
4452  return 0;
4453  }
4454  return getArtifactsCountHelper(artifactTypeID, obj_id);
4455  }
4456 
4469  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4470  return getArtifactsCountHelper(artifactTypeID, obj_id);
4471  }
4472 
4485  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4486  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4487  }
4488 
4500  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4501  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4502  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeName)));
4503  return artifacts;
4504  }
4505 
4517  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4518  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4519  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactType.getTypeID())));
4520  return artifacts;
4521  }
4522 
4538  @Deprecated
4539  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4540 
4541  String dataArtifactJoin = "tsk_data_artifacts AS datarts ON datarts.artifact_obj_id = arts.artifact_obj_id";
4542  String analysisResultJoin = "tsk_analysis_results AS anresult ON anresult.artifact_obj_id = arts.artifact_obj_id";
4543  String dataArtifactColumns = ", datarts.os_account_obj_id AS os_account_obj_id";
4544  String analysResultColumns = ", anresult.conclusion AS conclusion, anresult.significance AS significance, anresult.priority AS priority, anresult.configuration AS configuration, anresult.justification AS justification ";
4545 
4546  String formatQuery = "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4547  + "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, "
4548  + "types.type_name AS type_name, types.display_name AS display_name,"
4549  + "arts.review_status_id AS review_status_id %s "//NON-NLS
4550  + "FROM blackboard_artifacts AS arts "
4551  + "JOIN blackboard_attributes AS attrs ON arts.artifact_id = attrs.artifact_id "
4552  + "JOIN blackboard_artifact_types AS types ON types.artifact_type_id = arts.artifact_type_id " //NON-NLS
4553  + "LEFT JOIN %s "
4554  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4555  + "AND attrs.attribute_type_id = %d "
4556  + " AND arts.artifact_type_id = %d "
4557  + " AND attrs.value_text = '%s' " //NON-NLS
4558  + " AND types.artifact_type_id=arts.artifact_type_id "
4559  + " AND arts.review_status_id != %d";
4560 
4561  String query = String.format(formatQuery,
4562  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysResultColumns : dataArtifactColumns),
4563  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysisResultJoin : dataArtifactJoin),
4564  attrType.getTypeID(),
4565  artifactType.getTypeID(),
4566  value,
4568 
4570  try (CaseDbConnection connection = connections.getConnection(); Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
4571  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4572  while (rs.next()) {
4573  if (artifactType.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
4574  Long osAccountObjId = rs.getLong("os_account_obj_id");
4575  if (rs.wasNull()) {
4576  osAccountObjId = null;
4577  }
4578 
4579  artifacts.add(new DataArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4580  rs.getLong("artifact_obj_id"),
4581  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4582  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4583  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")), osAccountObjId, false));
4584  } else {
4585  artifacts.add(new AnalysisResult(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4586  rs.getLong("artifact_obj_id"),
4587  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4588  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4589  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")),
4590  new Score(Score.Significance.fromID(rs.getInt("significance")), Score.Priority.fromID(rs.getInt("priority"))),
4591  rs.getString("conclusion"), rs.getString("configuration"), rs.getString("justification")));
4592  }
4593  }
4594  return artifacts;
4595  } catch (SQLException ex) {
4596  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4597  } finally {
4599  }
4600  }
4601 
4613  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4614  List<DataArtifact> dataArtifacts = blackboard.getDataArtifactsWhere("artifacts.artifact_id = " + artifactID);
4615  if (!dataArtifacts.isEmpty()) {
4616  return dataArtifacts.get(0);
4617  }
4618 
4619  List<AnalysisResult> analysisResults = blackboard.getAnalysisResultsWhere("artifacts.artifact_id = " + artifactID);
4620  if (!analysisResults.isEmpty()) {
4621  return analysisResults.get(0);
4622  }
4623 
4624  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4625  }
4626 
4635  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4637  try (CaseDbConnection connection = connections.getConnection();) {
4638  addBlackBoardAttribute(attr, artifactTypeId, connection);
4639  } catch (SQLException ex) {
4640  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4641  } finally {
4643  }
4644  }
4645 
4655  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4656  CaseDbConnection connection = null;
4658  try {
4659  connection = connections.getConnection();
4660  connection.beginTransaction();
4661  for (final BlackboardAttribute attr : attributes) {
4662  addBlackBoardAttribute(attr, artifactTypeId, connection);
4663  }
4664  connection.commitTransaction();
4665  } catch (SQLException ex) {
4666  rollbackTransaction(connection);
4667  throw new TskCoreException("Error adding blackboard attributes", ex);
4668  } finally {
4669  closeConnection(connection);
4671  }
4672  }
4673 
4674  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4675  PreparedStatement statement;
4676  switch (attr.getAttributeType().getValueType()) {
4677  case STRING:
4678  case JSON:
4679  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4680  statement.clearParameters();
4681  statement.setString(7, attr.getValueString());
4682  break;
4683  case BYTE:
4684  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4685  statement.clearParameters();
4686  statement.setBytes(7, attr.getValueBytes());
4687  break;
4688  case INTEGER:
4689  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4690  statement.clearParameters();
4691  statement.setInt(7, attr.getValueInt());
4692  break;
4693  case LONG:
4694  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4695  statement.clearParameters();
4696  statement.setLong(7, attr.getValueLong());
4697  break;
4698  case DOUBLE:
4699  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4700  statement.clearParameters();
4701  statement.setDouble(7, attr.getValueDouble());
4702  break;
4703  case DATETIME:
4704  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4705  statement.clearParameters();
4706  statement.setLong(7, attr.getValueLong());
4707  break;
4708  default:
4709  throw new TskCoreException("Unrecognized artifact attribute value type");
4710  }
4711  statement.setLong(1, attr.getArtifactID());
4712  statement.setInt(2, artifactTypeId);
4713  statement.setString(3, attr.getSourcesCSV());
4714  statement.setString(4, "");
4715  statement.setInt(5, attr.getAttributeType().getTypeID());
4716  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4717  connection.executeUpdate(statement);
4718  }
4719 
4720  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4721  PreparedStatement statement;
4722  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4723  statement.clearParameters();
4724 
4725  statement.setLong(1, attr.getAttributeParentId());
4726  statement.setInt(2, attr.getAttributeType().getTypeID());
4727  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4728 
4729  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4730  statement.setBytes(4, attr.getValueBytes());
4731  } else {
4732  statement.setBytes(4, null);
4733  }
4734 
4735  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4736  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4737  statement.setString(5, attr.getValueString());
4738  } else {
4739  statement.setString(5, null);
4740  }
4741  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4742  statement.setInt(6, attr.getValueInt());
4743  } else {
4744  statement.setNull(6, java.sql.Types.INTEGER);
4745  }
4746 
4747  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4748  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4749  statement.setLong(7, attr.getValueLong());
4750  } else {
4751  statement.setNull(7, java.sql.Types.BIGINT);
4752  }
4753 
4754  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4755  statement.setDouble(8, attr.getValueDouble());
4756  } else {
4757  statement.setNull(8, java.sql.Types.DOUBLE);
4758  }
4759 
4760  connection.executeUpdate(statement);
4761  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4762  if (!resultSet.next()) {
4763  throw new TskCoreException(String.format("Failed to insert file attribute "
4764  + "with id=%d. The expected key was not generated", attr.getId()));
4765  }
4766 
4767  attr.setId(resultSet.getLong(1));
4768  }
4769  }
4770 
4781  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
4782  /*
4783  * WARNING: This is a temporary implementation that is not safe and
4784  * denormalizes the case datbase.
4785  *
4786  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
4787  * the sources of artifact attributes.
4788  */
4789  if (null == source || source.isEmpty()) {
4790  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
4791  }
4792  CaseDbConnection connection = null;
4794  Statement queryStmt = null;
4795  Statement updateStmt = null;
4796  ResultSet result = null;
4797  String newSources = "";
4798  try {
4799  connection = connections.getConnection();
4800  connection.beginTransaction();
4801  String valueClause = "";
4802  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
4803  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4804  switch (valueType) {
4805  case STRING:
4806  case JSON:
4807  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
4808  break;
4809  case INTEGER:
4810  valueClause = " value_int32 = " + attr.getValueInt();
4811  break;
4812  case LONG:
4813  case DATETIME:
4814  valueClause = " value_int64 = " + attr.getValueLong();
4815  break;
4816  case DOUBLE:
4817  valueClause = " value_double = " + attr.getValueDouble();
4818  break;
4819  default:
4820  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4821  }
4822  String query = "SELECT source FROM blackboard_attributes WHERE"
4823  + " artifact_id = " + attr.getArtifactID()
4824  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4825  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4826  + " AND " + valueClause + ";";
4827  queryStmt = connection.createStatement();
4828  updateStmt = connection.createStatement();
4829  result = connection.executeQuery(queryStmt, query);
4830  } else {
4831  /*
4832  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4833  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4834  * = ?
4835  */
4836  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4837  statement.clearParameters();
4838  statement.setLong(1, attr.getArtifactID());
4839  statement.setLong(2, attr.getAttributeType().getTypeID());
4840  statement.setBytes(3, attr.getValueBytes());
4841  result = connection.executeQuery(statement);
4842  }
4843  while (result.next()) {
4844  String oldSources = result.getString("source");
4845  if (null != oldSources && !oldSources.isEmpty()) {
4846  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4847  if (!uniqueSources.contains(source)) {
4848  newSources = oldSources + "," + source;
4849  } else {
4850  newSources = oldSources;
4851  }
4852  } else {
4853  newSources = source;
4854  }
4855  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4856  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4857  + " artifact_id = " + attr.getArtifactID()
4858  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4859  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4860  + " AND " + valueClause + ";";
4861  connection.executeUpdate(updateStmt, update);
4862  } else {
4863  /*
4864  * UPDATE blackboard_attributes SET source = ? WHERE
4865  * artifact_id = ? AND attribute_type_id = ? AND value_type
4866  * = 4 AND value_byte = ?
4867  */
4868  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4869  statement.clearParameters();
4870  statement.setString(1, newSources);
4871  statement.setLong(2, attr.getArtifactID());
4872  statement.setLong(3, attr.getAttributeType().getTypeID());
4873  statement.setBytes(4, attr.getValueBytes());
4874  connection.executeUpdate(statement);
4875  }
4876  }
4877  connection.commitTransaction();
4878  return newSources;
4879  } catch (SQLException ex) {
4880  rollbackTransaction(connection);
4881  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4882  } finally {
4883  closeResultSet(result);
4884  closeStatement(updateStmt);
4885  closeStatement(queryStmt);
4886  closeConnection(connection);
4888  }
4889  }
4890 
4905  @Deprecated
4906  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4907  try {
4908  return blackboard.getOrAddAttributeType(attrTypeString, valueType, displayName);
4909  } catch (BlackboardException ex) {
4910  throw new TskCoreException("Error adding artifact type: " + attrTypeString, ex);
4911  }
4912  }
4913 
4925  @Deprecated
4926  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4927  return blackboard.getAttributeType(attrTypeName);
4928  }
4929 
4941  @Deprecated
4942  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4943  return blackboard.getArtifactType(artTypeName);
4944  }
4945 
4962  @Deprecated
4963  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4964  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
4965  }
4966 
4982  @Deprecated
4983  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
4984  try {
4985  return blackboard.getOrAddArtifactType(displayName, displayName, category);
4986  } catch (BlackboardException ex) {
4987  throw new TskCoreException("Error getting or adding artifact type with name: " + artifactTypeName, ex);
4988  }
4989  }
4990 
5002  @Deprecated
5003  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
5004  return blackboard.getBlackboardAttributes(artifact);
5005  }
5006 
5007 
5020  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
5021  CaseDbConnection connection = null;
5022  Statement s = null;
5023  ResultSet rs = null;
5025  try {
5026  connection = connections.getConnection();
5027  s = connection.createStatement();
5028  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
5029  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
5030  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
5031  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
5032  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
5033  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
5034  + "FROM blackboard_attributes " + whereClause); //NON-NLS
5035  ArrayList<BlackboardAttribute> matches = new ArrayList<>();
5036  while (rs.next()) {
5038  // attribute type is cached, so this does not necessarily call to the db
5039  type = blackboard.getAttributeType(rs.getInt("attribute_type_id"));
5041  rs.getLong("artifact_id"),
5042  type,
5043  rs.getString("source"),
5044  rs.getString("context"),
5045  rs.getInt("value_int32"),
5046  rs.getLong("value_int64"),
5047  rs.getDouble("value_double"),
5048  rs.getString("value_text"),
5049  rs.getBytes("value_byte"), this
5050  );
5051  matches.add(attr);
5052  }
5053  return matches;
5054  } catch (SQLException ex) {
5055  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5056  } finally {
5057  closeResultSet(rs);
5058  closeStatement(s);
5059  closeConnection(connection);
5061  }
5062  }
5063 
5075  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
5076  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
5077  + "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, "
5078  + "blackboard_artifacts.review_status_id AS review_status_id "
5079  + "FROM blackboard_artifacts " + whereClause;
5081  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
5082 
5083  List<Long> analysisArtifactObjIds = new ArrayList<>();
5084  List<Long> dataArtifactObjIds = new ArrayList<>();
5085  while (resultSet.next()) {
5086  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
5087  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5088  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5089  } else {
5090  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5091  }
5092  }
5093 
5094  ArrayList<BlackboardArtifact> matches = new ArrayList<>();
5095  if (!analysisArtifactObjIds.isEmpty()) {
5096  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
5097  }
5098 
5099  if (!dataArtifactObjIds.isEmpty()) {
5100  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
5101  }
5102 
5103  return matches;
5104  } catch (SQLException ex) {
5105  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5106  } finally {
5108  }
5109  }
5110 
5125  @Deprecated
5126  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
5127  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5128  if (type == null) {
5129  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
5130  }
5131 
5132  Category category = type.getCategory();
5133  if (category == null) {
5134  throw new TskCoreException(String.format("No category for %s (id: %d)",
5135  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
5136  type.getTypeID()));
5137  }
5138 
5139  Content content = getContentById(obj_id);
5140  if (content == null) {
5141  throw new TskCoreException("No content found for object id: " + obj_id);
5142  }
5143 
5144  switch (category) {
5145  case ANALYSIS_RESULT:
5146  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
5147  .getAnalysisResult();
5148  case DATA_ARTIFACT:
5149  return content.newDataArtifact(type, Collections.emptyList());
5150  default:
5151  throw new TskCoreException("Unknown category type: " + category.getName());
5152  }
5153  }
5154 
5167  @Deprecated
5168  @SuppressWarnings("deprecation")
5169  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
5170  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
5171  }
5172 
5188  @Deprecated
5189  @SuppressWarnings("deprecation")
5190  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5191  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5192  try (CaseDbConnection connection = connections.getConnection()) {
5193  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5194  }
5195  }
5196 
5197  @Deprecated
5198  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5199  try (CaseDbConnection connection = connections.getConnection()) {
5200  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5201  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5202  }
5203  }
5204 
5205  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5206 
5207  PreparedStatement statement;
5208  if (dbType == DbType.POSTGRESQL) {
5209  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5210  statement.clearParameters();
5211  statement.setLong(1, obj_id);
5212  statement.setLong(2, artifact_obj_id);
5213  statement.setLong(3, data_source_obj_id);
5214  statement.setInt(4, artifact_type_id);
5215  } else {
5216  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5217  statement.clearParameters();
5218  this.nextArtifactId++;
5219  statement.setLong(1, this.nextArtifactId);
5220  statement.setLong(2, obj_id);
5221  statement.setLong(3, artifact_obj_id);
5222  statement.setLong(4, data_source_obj_id);
5223  statement.setInt(5, artifact_type_id);
5224  }
5225 
5226  return statement;
5227  }
5228 
5245  @Deprecated
5246  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5247  BlackboardArtifact.Type type = blackboard.getArtifactType(artifact_type_id);
5248  try {
5249  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5250  return blackboard.newAnalysisResult(type, obj_id, data_source_obj_id, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList()).getAnalysisResult();
5251  } else {
5252  return blackboard.newDataArtifact(type, obj_id, data_source_obj_id, Collections.emptyList(), null);
5253  }
5254  } catch (BlackboardException ex) {
5255  throw new TskCoreException("Error creating a blackboard artifact", ex);
5256  }
5257  }
5258 
5277  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5278 
5279  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5280  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5281  }
5282 
5283  long artifactID;
5285  try {
5286  // add a row in tsk_objects
5287  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5288 
5289  // add a row in blackboard_artifacts table
5290  PreparedStatement insertArtifactstatement;
5291  ResultSet resultSet = null;
5292  try {
5293  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5294  connection.executeUpdate(insertArtifactstatement);
5295  resultSet = insertArtifactstatement.getGeneratedKeys();
5296  resultSet.next();
5297  artifactID = resultSet.getLong(1); //last_insert_rowid()
5298 
5299  // add a row in tsk_analysis_results if any data for it is set
5300  if (score.getSignificance() != Score.Significance.UNKNOWN
5301  || !StringUtils.isBlank(conclusion)
5302  || !StringUtils.isBlank(configuration)
5303  || !StringUtils.isBlank(justification)) {
5304 
5305  PreparedStatement analysisResultsStatement;
5306 
5307  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5308  analysisResultsStatement.clearParameters();
5309 
5310  analysisResultsStatement.setLong(1, artifactObjId);
5311  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5312  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5313  analysisResultsStatement.setInt(4, score.getPriority().getId());
5314  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5315  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5316 
5317  connection.executeUpdate(analysisResultsStatement);
5318  }
5319 
5320  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5321  artifactType.getTypeName(), artifactType.getDisplayName(),
5322  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5323  score, (conclusion != null) ? conclusion : "",
5324  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5325 
5326  } finally {
5327  closeResultSet(resultSet);
5328  }
5329 
5330  } catch (SQLException ex) {
5331  throw new TskCoreException("Error creating a analysis result", ex);
5332  } finally {
5334  }
5335  }
5336 
5349  boolean getContentHasChildren(Content content) throws TskCoreException {
5350  CaseDbConnection connection = null;
5351  ResultSet rs = null;
5353  try {
5354  connection = connections.getConnection();
5355 
5356  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5357  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5358  statement.clearParameters();
5359  statement.setLong(1, content.getId());
5360  rs = connection.executeQuery(statement);
5361  boolean hasChildren = false;
5362  if (rs.next()) {
5363  hasChildren = rs.getInt("count") > 0;
5364  }
5365  return hasChildren;
5366  } catch (SQLException e) {
5367  throw new TskCoreException("Error checking for children of parent " + content, e);
5368  } finally {
5369  closeResultSet(rs);
5370  closeConnection(connection);
5372  }
5373  }
5374 
5387  int getContentChildrenCount(Content content) throws TskCoreException {
5388 
5389  if (!this.getHasChildren(content)) {
5390  return 0;
5391  }
5392 
5393  CaseDbConnection connection = null;
5394  ResultSet rs = null;
5396  try {
5397  connection = connections.getConnection();
5398 
5399  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5400  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5401  statement.clearParameters();
5402  statement.setLong(1, content.getId());
5403  rs = connection.executeQuery(statement);
5404  int countChildren = -1;
5405  if (rs.next()) {
5406  countChildren = rs.getInt("count");
5407  }
5408  return countChildren;
5409  } catch (SQLException e) {
5410  throw new TskCoreException("Error checking for children of parent " + content, e);
5411  } finally {
5412  closeResultSet(rs);
5413  closeConnection(connection);
5415  }
5416  }
5417 
5429  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5430  CaseDbConnection connection = null;
5431  ResultSet rs = null;
5433  try {
5434  connection = connections.getConnection();
5435 
5436  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5437  statement.clearParameters();
5438  long parentId = parent.getId();
5439  statement.setLong(1, parentId);
5440  statement.setShort(2, type.getFileType());
5441  rs = connection.executeQuery(statement);
5442  return fileChildren(rs, connection, parentId);
5443  } catch (SQLException ex) {
5444  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5445  } finally {
5446  closeResultSet(rs);
5447  closeConnection(connection);
5449  }
5450  }
5451 
5461  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5462  CaseDbConnection connection = null;
5463  ResultSet rs = null;
5465  try {
5466  connection = connections.getConnection();
5467 
5468  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5469  statement.clearParameters();
5470  long parentId = parent.getId();
5471  statement.setLong(1, parentId);
5472  rs = connection.executeQuery(statement);
5473  return fileChildren(rs, connection, parentId);
5474  } catch (SQLException ex) {
5475  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5476  } finally {
5477  closeResultSet(rs);
5478  closeConnection(connection);
5480  }
5481  }
5482 
5494  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5495  CaseDbConnection connection = null;
5496  ResultSet rs = null;
5498  try {
5499  connection = connections.getConnection();
5500 
5501  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5502  statement.clearParameters();
5503  statement.setLong(1, parent.getId());
5504  statement.setShort(2, type.getFileType());
5505  rs = connection.executeQuery(statement);
5506  List<Long> children = new ArrayList<Long>();
5507  while (rs.next()) {
5508  children.add(rs.getLong("obj_id"));
5509  }
5510  return children;
5511  } catch (SQLException ex) {
5512  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5513  } finally {
5514  closeResultSet(rs);
5515  closeConnection(connection);
5517  }
5518  }
5519 
5529  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5530  CaseDbConnection connection = null;
5531  ResultSet rs = null;
5533  try {
5534  connection = connections.getConnection();
5535 
5536  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5537  statement.clearParameters();
5538  statement.setLong(1, parent.getId());
5539  rs = connection.executeQuery(statement);
5540  List<Long> children = new ArrayList<Long>();
5541  while (rs.next()) {
5542  children.add(rs.getLong("obj_id"));
5543  }
5544  return children;
5545  } catch (SQLException ex) {
5546  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5547  } finally {
5548  closeResultSet(rs);
5549  closeConnection(connection);
5551  }
5552  }
5553 
5564  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5565  CaseDbConnection connection = null;
5566  ResultSet rs = null;
5568  try {
5569  connection = connections.getConnection();
5570 
5571  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5572  statement.clearParameters();
5573  statement.setLong(1, parent.getId());
5574  rs = connection.executeQuery(statement);
5575  List<Long> children = new ArrayList<Long>();
5576  while (rs.next()) {
5577  children.add(rs.getLong("obj_id"));
5578  }
5579  return children;
5580  } catch (SQLException ex) {
5581  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5582  } finally {
5583  closeResultSet(rs);
5584  closeConnection(connection);
5586  }
5587  }
5588 
5598  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5599  long parentId = parent.getId();
5600  List<Content> lc = new ArrayList<>();
5601  lc.addAll(blackboard.getAnalysisResults(parentId));
5602  lc.addAll(blackboard.getDataArtifactsBySource(parentId));
5603  return lc;
5604  }
5605 
5614  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5615  CaseDbConnection connection = null;
5616  Statement s = null;
5617  ResultSet rs = null;
5619  try {
5620  connection = connections.getConnection();
5621  s = connection.createStatement();
5622  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5623  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5624  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5625  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5626  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5627  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5628  while (rs.next()) {
5629  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5630  }
5631  return infos;
5632  } catch (SQLException ex) {
5633  throw new TskCoreException("Error getting Children Info for Content", ex);
5634  } finally {
5635  closeResultSet(rs);
5636  closeStatement(s);
5637  closeConnection(connection);
5639  }
5640  }
5641 
5652  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5653  return getParentInfo(c.getId());
5654  }
5655 
5666  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5668  CaseDbConnection connection = null;
5669  Statement s = null;
5670  ResultSet rs = null;
5671  try {
5672  connection = connections.getConnection();
5673  s = connection.createStatement();
5674  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5675  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5676  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5677  + "WHERE child.obj_id = " + contentId); //NON-NLS
5678  if (rs.next()) {
5679  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5680  } else {
5681  return null;
5682  }
5683  } catch (SQLException ex) {
5684  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5685  } finally {
5686  closeResultSet(rs);
5687  closeStatement(s);
5688  closeConnection(connection);
5690  }
5691  }
5692 
5703  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5704  if (fsc.isRoot()) {
5705  // Given FsContent is a root object and can't have parent directory
5706  return null;
5707  } else {
5708  ObjectInfo parentInfo = getParentInfo(fsc);
5709  if (parentInfo == null) {
5710  return null;
5711  }
5712  Directory parent = null;
5713  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
5714  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
5715  } else {
5716  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
5717  }
5718  return parent;
5719  }
5720  }
5721 
5733  public Content getContentById(long id) throws TskCoreException {
5734  // First check to see if this exists in our frequently used content cache.
5735  Content content = frequentlyUsedContentMap.get(id);
5736  if (null != content) {
5737  return content;
5738  }
5739 
5740  long parentId;
5741  TskData.ObjectType type;
5742 
5743  CaseDbConnection connection = null;
5744  Statement s = null;
5745  ResultSet rs = null;
5747  try {
5748  connection = connections.getConnection();
5749  s = connection.createStatement();
5750  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
5751  if (!rs.next()) {
5752  return null;
5753  }
5754  parentId = rs.getLong("par_obj_id"); //NON-NLS
5755  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
5756  } catch (SQLException ex) {
5757  throw new TskCoreException("Error getting Content by ID.", ex);
5758  } finally {
5759  closeResultSet(rs);
5760  closeStatement(s);
5761  closeConnection(connection);
5763  }
5764 
5765  // Construct the object
5766  switch (type) {
5767  case IMG:
5768  content = getImageById(id);
5769  frequentlyUsedContentMap.put(id, content);
5770  break;
5771  case VS:
5772  content = getVolumeSystemById(id, parentId);
5773  break;
5774  case VOL:
5775  content = getVolumeById(id, parentId);
5776  frequentlyUsedContentMap.put(id, content);
5777  break;
5778  case POOL:
5779  content = getPoolById(id, parentId);
5780  break;
5781  case FS:
5782  content = getFileSystemById(id, parentId);
5783  frequentlyUsedContentMap.put(id, content);
5784  break;
5785  case ABSTRACTFILE:
5786  content = getAbstractFileById(id);
5787 
5788  // Add virtual and root directories to frequently used map.
5789  // Calling isRoot() on local directories goes up the entire directory structure
5790  // and they can only be the root of portable cases, so skip trying to add
5791  // them to the cache.
5792  if (((AbstractFile) content).isVirtual()
5793  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5794  frequentlyUsedContentMap.put(id, content);
5795  }
5796  break;
5797  case ARTIFACT:
5798  content = getArtifactById(id);
5799  break;
5800  case REPORT:
5801  content = getReportById(id);
5802  break;
5803  case OS_ACCOUNT:
5804  content = this.osAccountManager.getOsAccountByObjectId(id);
5805  break;
5806  case HOST_ADDRESS:
5807  content = hostAddressManager.getHostAddress(id);
5808  break;
5809  default:
5810  content = new UnsupportedContent(this, id);
5811  }
5812 
5813  return content;
5814  }
5815 
5823  String getFilePath(long id) {
5824 
5825  String filePath = null;
5826  CaseDbConnection connection = null;
5827  ResultSet rs = null;
5829  try {
5830  connection = connections.getConnection();
5831 
5832  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5833  statement.clearParameters();
5834  statement.setLong(1, id);
5835  rs = connection.executeQuery(statement);
5836  if (rs.next()) {
5837  filePath = rs.getString("path");
5838  }
5839  } catch (SQLException | TskCoreException ex) {
5840  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5841  } finally {
5842  closeResultSet(rs);
5843  closeConnection(connection);
5845  }
5846  return filePath;
5847  }
5848 
5856  TskData.EncodingType getEncodingType(long id) {
5857 
5858  TskData.EncodingType type = TskData.EncodingType.NONE;
5859  CaseDbConnection connection = null;
5860  ResultSet rs = null;
5862  try {
5863  connection = connections.getConnection();
5864  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5865  statement.clearParameters();
5866  statement.setLong(1, id);
5867  rs = connection.executeQuery(statement);
5868  if (rs.next()) {
5869  type = TskData.EncodingType.valueOf(rs.getInt(1));
5870  }
5871  } catch (SQLException | TskCoreException ex) {
5872  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5873  } finally {
5874  closeResultSet(rs);
5875  closeConnection(connection);
5877  }
5878  return type;
5879  }
5880 
5889  String getFileParentPath(long objectId, CaseDbConnection connection) {
5890  String parentPath = null;
5892  ResultSet rs = null;
5893  try {
5894  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5895  statement.clearParameters();
5896  statement.setLong(1, objectId);
5897  rs = connection.executeQuery(statement);
5898  if (rs.next()) {
5899  parentPath = rs.getString("parent_path");
5900  }
5901  } catch (SQLException ex) {
5902  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5903  } finally {
5904  closeResultSet(rs);
5906  }
5907  return parentPath;
5908  }
5909 
5918  String getFileName(long objectId, CaseDbConnection connection) {
5919  String fileName = null;
5921  ResultSet rs = null;
5922  try {
5923  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5924  statement.clearParameters();
5925  statement.setLong(1, objectId);
5926  rs = connection.executeQuery(statement);
5927  if (rs.next()) {
5928  fileName = rs.getString("name");
5929  }
5930  } catch (SQLException ex) {
5931  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5932  } finally {
5933  closeResultSet(rs);
5935  }
5936  return fileName;
5937  }
5938 
5949  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5950 
5951  DerivedFile.DerivedMethod method = null;
5952  CaseDbConnection connection = null;
5953  ResultSet rs1 = null;
5954  ResultSet rs2 = null;
5956  try {
5957  connection = connections.getConnection();
5958 
5959  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5960  statement.clearParameters();
5961  statement.setLong(1, id);
5962  rs1 = connection.executeQuery(statement);
5963  if (rs1.next()) {
5964  int method_id = rs1.getInt("derived_id");
5965  String rederive = rs1.getString("rederive");
5966  method = new DerivedFile.DerivedMethod(method_id, rederive);
5967  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5968  statement.clearParameters();
5969  statement.setInt(1, method_id);
5970  rs2 = connection.executeQuery(statement);
5971  if (rs2.next()) {
5972  method.setToolName(rs2.getString("tool_name"));
5973  method.setToolVersion(rs2.getString("tool_version"));
5974  method.setOther(rs2.getString("other"));
5975  }
5976  }
5977  } catch (SQLException e) {
5978  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5979  } finally {
5980  closeResultSet(rs2);
5981  closeResultSet(rs1);
5982  closeConnection(connection);
5984  }
5985  return method;
5986  }
5987 
5998  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5999  CaseDbConnection connection = connections.getConnection();
6000  try {
6001  return getAbstractFileById(id, connection);
6002  } finally {
6003  closeConnection(connection);
6004  }
6005  }
6006 
6019  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
6021  ResultSet rs = null;
6022  try {
6023  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
6024  statement.clearParameters();
6025  statement.setLong(1, objectId);
6026  rs = connection.executeQuery(statement);
6027  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
6028  if (files.size() > 0) {
6029  return files.get(0);
6030  } else {
6031  return null;
6032  }
6033  } catch (SQLException ex) {
6034  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
6035  } finally {
6036  closeResultSet(rs);
6038  }
6039  }
6040 
6052  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
6053 
6054  CaseDbConnection connection = null;
6055  ResultSet rs = null;
6057  try {
6058  connection = connections.getConnection();
6059 
6060  // get the artifact type.
6061  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
6062  statement.clearParameters();
6063  statement.setLong(1, id);
6064 
6065  rs = connection.executeQuery(statement);
6066  if (!rs.next()) {
6067  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
6068  }
6069 
6070  // based on the artifact type category, get the analysis result or the data artifact
6071  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(rs.getInt("artifact_type_id"));
6072  switch (artifactType.getCategory()) {
6073  case ANALYSIS_RESULT:
6074  return blackboard.getAnalysisResultById(id);
6075  case DATA_ARTIFACT:
6076  return blackboard.getDataArtifactById(id);
6077  default:
6078  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
6079  }
6080 
6081  } catch (SQLException ex) {
6082  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
6083  } finally {
6084  closeResultSet(rs);
6085  closeConnection(connection);
6087  }
6088  }
6089 
6103  @Deprecated
6104  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
6105  String query = "SELECT artifact_type_id, artifact_obj_id FROM blackboard_artifacts WHERE artifact_id = " + id;
6107 
6108  try (CaseDbConnection connection = connections.getConnection();
6109  Statement statement = connection.createStatement();
6110  ResultSet resultSet = statement.executeQuery(query);) {
6111  if (resultSet != null && resultSet.next()) {
6112  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
6113  long artifactObjId = resultSet.getLong("artifact_obj_id");
6114  switch (artifactType.getCategory()) {
6115  case ANALYSIS_RESULT:
6116  return blackboard.getAnalysisResultById(artifactObjId);
6117  case DATA_ARTIFACT:
6118  return blackboard.getDataArtifactById(artifactObjId);
6119  }
6120  }
6121  return null;
6122  } catch (SQLException ex) {
6123  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
6124  } finally {
6126  }
6127  }
6128 
6141  private long getFileSystemId(long fileId, CaseDbConnection connection) {
6143  ResultSet rs = null;
6144  long ret = -1;
6145  try {
6146  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
6147  statement.clearParameters();
6148  statement.setLong(1, fileId);
6149  rs = connection.executeQuery(statement);
6150  if (rs.next()) {
6151  ret = rs.getLong("fs_obj_id");
6152  if (ret == 0) {
6153  ret = -1;
6154  }
6155  }
6156  } catch (SQLException e) {
6157  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
6158  } finally {
6159  closeResultSet(rs);
6161  }
6162  return ret;
6163  }
6164 
6176  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6177  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
6178  CaseDbConnection connection = null;
6179  Statement statement = null;
6180  ResultSet resultSet = null;
6182  try {
6183  connection = connections.getConnection();
6184  statement = connection.createStatement();
6185  resultSet = connection.executeQuery(statement, query);
6186  resultSet.next();
6187  return (resultSet.getLong("count") > 0L);
6188  } catch (SQLException ex) {
6189  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6190  } finally {
6191  closeResultSet(resultSet);
6192  closeStatement(statement);
6193  closeConnection(connection);
6195  }
6196  }
6197 
6207  private static boolean containsLikeWildcard(String str) {
6208  if (str == null) {
6209  return false;
6210  } else {
6211  return str.contains("%") || str.contains("_");
6212  }
6213  }
6214 
6226  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6227  String ext = "";
6228  if (!containsLikeWildcard(fileName)) {
6229  ext = SleuthkitCase.extractExtension(fileName);
6230  }
6231 
6232  List<AbstractFile> files = new ArrayList<>();
6233  CaseDbConnection connection = null;
6234  ResultSet resultSet = null;
6236  try {
6237  connection = connections.getConnection();
6238 
6239  PreparedStatement statement;
6240  if (ext.isEmpty()) {
6241  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6242  statement.clearParameters();
6243  statement.setString(1, fileName.toLowerCase());
6244  statement.setLong(2, dataSource.getId());
6245  } else {
6246  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6247  statement.clearParameters();
6248  statement.setString(1, ext);
6249  statement.setString(2, fileName.toLowerCase());
6250  statement.setLong(3, dataSource.getId());
6251  }
6252 
6253  resultSet = connection.executeQuery(statement);
6254  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6255  } catch (SQLException e) {
6256  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6257  } finally {
6258  closeResultSet(resultSet);
6259  closeConnection(connection);
6261  }
6262  return files;
6263  }
6264 
6278  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6279  String ext = "";
6280  if (!containsLikeWildcard(fileName)) {
6281  ext = SleuthkitCase.extractExtension(fileName);
6282  }
6283 
6284  List<AbstractFile> files = new ArrayList<>();
6285  CaseDbConnection connection = null;
6286  ResultSet resultSet = null;
6288  try {
6289  connection = connections.getConnection();
6290  PreparedStatement statement;
6291  if (ext.isEmpty()) {
6292  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6293  statement.clearParameters();
6294  statement.setString(1, fileName.toLowerCase());
6295  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6296  statement.setLong(3, dataSource.getId());
6297  } else {
6298  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6299  statement.clearParameters();
6300  statement.setString(1, ext);
6301  statement.setString(2, fileName.toLowerCase());
6302  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6303  statement.setLong(4, dataSource.getId());
6304  }
6305 
6306  resultSet = connection.executeQuery(statement);
6307  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6308  } catch (SQLException e) {
6309  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6310  } finally {
6311  closeResultSet(resultSet);
6312  closeConnection(connection);
6314  }
6315  return files;
6316  }
6317 
6329  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6330  CaseDbTransaction localTrans = beginTransaction();
6331  try {
6332  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6333  localTrans.commit();
6334  localTrans = null;
6335  return newVD;
6336  } finally {
6337  if (null != localTrans) {
6338  try {
6339  localTrans.rollback();
6340  } catch (TskCoreException ex2) {
6341  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6342  }
6343  }
6344  }
6345  }
6346 
6359  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6360  ResultSet resultSet = null;
6362  try {
6363  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6364  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6365  statement.clearParameters();
6366  if (parentId != 0) {
6367  statement.setLong(1, parentId);
6368  } else {
6369  statement.setNull(1, java.sql.Types.BIGINT);
6370  }
6371  statement.setInt(2, objectType);
6372  connection.executeUpdate(statement);
6373  resultSet = statement.getGeneratedKeys();
6374 
6375  if (resultSet.next()) {
6376  if (parentId != 0) {
6377  setHasChildren(parentId);
6378  }
6379  return resultSet.getLong(1); //last_insert_rowid()
6380  } else {
6381  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6382  }
6383  } finally {
6384  closeResultSet(resultSet);
6386  }
6387  }
6388 
6406  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6407  if (transaction == null) {
6408  throw new TskCoreException("Passed null CaseDbTransaction");
6409  }
6410 
6411  ResultSet resultSet = null;
6412  try {
6413  // Get the parent path.
6414  CaseDbConnection connection = transaction.getConnection();
6415 
6416  String parentPath;
6417  Content parent = this.getAbstractFileById(parentId, connection);
6418  if (parent instanceof AbstractFile) {
6419  if (isRootDirectory((AbstractFile) parent, transaction)) {
6420  if (parent.getName().isEmpty()) {
6421  parentPath = "/";
6422  } else {
6423  parentPath = "/" + parent.getName() + "/";
6424  }
6425  } else {
6426  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6427  }
6428  } else {
6429  // The parent was either null or not an abstract file
6430  parentPath = "/";
6431  }
6432 
6433  // Insert a row for the virtual directory into the tsk_objects table.
6434  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6435 
6436  // Insert a row for the virtual directory into the tsk_files table.
6437  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6438  // 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)
6439  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)
6440  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6441  statement.clearParameters();
6442  statement.setLong(1, newObjId);
6443 
6444  // If the parent is part of a file system, grab its file system ID
6445  Long fileSystemObjectId = null;
6446  if (0 != parentId) {
6447  fileSystemObjectId = this.getFileSystemId(parentId, connection);
6448  if (fileSystemObjectId != -1) {
6449  statement.setLong(2, fileSystemObjectId);
6450  } else {
6451  statement.setNull(2, java.sql.Types.BIGINT);
6452  fileSystemObjectId = null;
6453  }
6454  } else {
6455  statement.setNull(2, java.sql.Types.BIGINT);
6456  }
6457 
6458  // name
6459  statement.setString(3, directoryName);
6460 
6461  //type
6462  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6463  statement.setShort(5, (short) 1);
6464 
6465  //flags
6467  statement.setShort(6, dirType.getValue());
6469  statement.setShort(7, metaType.getValue());
6470 
6471  //allocated
6473  statement.setShort(8, dirFlag.getValue());
6474  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6475  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6476  statement.setShort(9, metaFlags);
6477 
6478  //size
6479  statement.setLong(10, 0);
6480 
6481  // nulls for params 11-14
6482  statement.setNull(11, java.sql.Types.BIGINT);
6483  statement.setNull(12, java.sql.Types.BIGINT);
6484  statement.setNull(13, java.sql.Types.BIGINT);
6485  statement.setNull(14, java.sql.Types.BIGINT);
6486 
6487  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6488  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6489  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6490 
6491  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6492  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6493 
6494  // parent path
6495  statement.setString(20, parentPath);
6496 
6497  // data source object id (same as object id if this is a data source)
6498  long dataSourceObjectId;
6499  if (0 == parentId) {
6500  dataSourceObjectId = newObjId;
6501  } else {
6502  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6503  }
6504  statement.setLong(21, dataSourceObjectId);
6505 
6506  //extension, since this is not really file we just set it to null
6507  statement.setString(22, null);
6508 
6509  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6510  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6511  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6512 
6513  connection.executeUpdate(statement);
6514 
6515  return new VirtualDirectory(this, newObjId, dataSourceObjectId, fileSystemObjectId, directoryName, dirType,
6516  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6517  parentPath);
6518  } catch (SQLException e) {
6519  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6520  } finally {
6521  closeResultSet(resultSet);
6522  }
6523  }
6524 
6537  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6538  CaseDbTransaction localTrans = beginTransaction();
6539  try {
6540  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6541  localTrans.commit();
6542  return newLD;
6543  } catch (TskCoreException ex) {
6544  try {
6545  localTrans.rollback();
6546  } catch (TskCoreException ex2) {
6547  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6548  }
6549  throw ex;
6550  }
6551  }
6552 
6570  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6571  if (transaction == null) {
6572  throw new TskCoreException("Passed null CaseDbTransaction");
6573  }
6574 
6575  ResultSet resultSet = null;
6576  try {
6577  // Get the parent path.
6578  CaseDbConnection connection = transaction.getConnection();
6579  AbstractFile parent = getAbstractFileById(parentId, connection);
6580  String parentPath;
6581  if ((parent == null) || isRootDirectory(parent, transaction)) {
6582  parentPath = "/";
6583  } else {
6584  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6585  }
6586 
6587  // Insert a row for the local directory into the tsk_objects table.
6588  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6589 
6590  // Insert a row for the local directory into the tsk_files table.
6591  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6592  // 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)
6593  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6594  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6595  statement.clearParameters();
6596  statement.setLong(1, newObjId);
6597 
6598  // The parent of a local directory will never be a file system
6599  statement.setNull(2, java.sql.Types.BIGINT);
6600 
6601  // name
6602  statement.setString(3, directoryName);
6603 
6604  //type
6605  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6606  statement.setShort(5, (short) 1);
6607 
6608  //flags
6610  statement.setShort(6, dirType.getValue());
6612  statement.setShort(7, metaType.getValue());
6613 
6614  //allocated
6616  statement.setShort(8, dirFlag.getValue());
6617  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6618  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6619  statement.setShort(9, metaFlags);
6620 
6621  //size
6622  statement.setLong(10, 0);
6623 
6624  // nulls for params 11-14
6625  statement.setNull(11, java.sql.Types.BIGINT);
6626  statement.setNull(12, java.sql.Types.BIGINT);
6627  statement.setNull(13, java.sql.Types.BIGINT);
6628  statement.setNull(14, java.sql.Types.BIGINT);
6629 
6630  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6631  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6632  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6633 
6634  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6635  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6636 
6637  // parent path
6638  statement.setString(20, parentPath);
6639 
6640  // data source object id
6641  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6642  statement.setLong(21, dataSourceObjectId);
6643 
6644  //extension, since this is a directory we just set it to null
6645  statement.setString(22, null);
6646 
6647  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6648  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6649  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6650 
6651  connection.executeUpdate(statement);
6652 
6653  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6654  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6655  parentPath);
6656  } catch (SQLException e) {
6657  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6658  } finally {
6659  closeResultSet(resultSet);
6660  }
6661  }
6662 
6682  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6683  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6684  }
6685 
6706  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6707 
6708  Statement statement = null;
6709  try {
6710  CaseDbConnection connection = transaction.getConnection();
6711 
6712  // Insert a row for the root virtual directory of the data source
6713  // into the tsk_objects table.
6714  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6715 
6716  // If no host was supplied, make one
6717  if (host == null) {
6718  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
6719  }
6720 
6721  // Insert a row for the virtual directory of the data source into
6722  // the data_source_info table.
6723  statement = connection.createStatement();
6724  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
6725  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
6726 
6727  // Insert a row for the root virtual directory of the data source
6728  // into the tsk_files table. Note that its data source object id is
6729  // its own object id.
6730  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
6731  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
6732  // atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6733  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
6734  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6735  preparedStatement.clearParameters();
6736  preparedStatement.setLong(1, newObjId);
6737  preparedStatement.setNull(2, java.sql.Types.BIGINT);
6738  preparedStatement.setString(3, rootDirectoryName);
6739  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6740  preparedStatement.setShort(5, (short) 1);
6742  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
6744  preparedStatement.setShort(7, metaType.getValue());
6746  preparedStatement.setShort(8, dirFlag.getValue());
6747  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6748  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6749  preparedStatement.setShort(9, metaFlags);
6750  preparedStatement.setLong(10, 0);
6751  preparedStatement.setNull(11, java.sql.Types.BIGINT);
6752  preparedStatement.setNull(12, java.sql.Types.BIGINT);
6753  preparedStatement.setNull(13, java.sql.Types.BIGINT);
6754  preparedStatement.setNull(14, java.sql.Types.BIGINT);
6755  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
6756  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6757  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6758  preparedStatement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6759  preparedStatement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6760  String parentPath = "/"; //NON-NLS
6761  preparedStatement.setString(20, parentPath);
6762  preparedStatement.setLong(21, newObjId);
6763  preparedStatement.setString(22, null); //extension, just set it to null
6764  preparedStatement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6765  preparedStatement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6766  preparedStatement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6767 
6768 
6769  connection.executeUpdate(preparedStatement);
6770 
6771  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, null, FileKnown.UNKNOWN, parentPath);
6772 
6773  } catch (SQLException ex) {
6774  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
6775  } finally {
6776  closeStatement(statement);
6777  }
6778  }
6779 
6799  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6800  String timezone, String md5, String sha1, String sha256,
6801  String deviceId,
6802  CaseDbTransaction transaction) throws TskCoreException {
6803  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
6804  }
6805 
6826  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6827  String timezone, String md5, String sha1, String sha256,
6828  String deviceId, Host host,
6829  CaseDbTransaction transaction) throws TskCoreException {
6830  Statement statement = null;
6831  try {
6832  // Insert a row for the Image into the tsk_objects table.
6833  CaseDbConnection connection = transaction.getConnection();
6834  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
6835 
6836  // Add a row to tsk_image_info
6837  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
6838  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
6839  preparedStatement.clearParameters();
6840  preparedStatement.setLong(1, newObjId);
6841  preparedStatement.setShort(2, (short) type.getValue());
6842  preparedStatement.setLong(3, sectorSize);
6843  preparedStatement.setString(4, timezone);
6844  //prevent negative size
6845  long savedSize = size < 0 ? 0 : size;
6846  preparedStatement.setLong(5, savedSize);
6847  preparedStatement.setString(6, md5);
6848  preparedStatement.setString(7, sha1);
6849  preparedStatement.setString(8, sha256);
6850  preparedStatement.setString(9, displayName);
6851  connection.executeUpdate(preparedStatement);
6852 
6853  // If there are paths, add them to tsk_image_names
6854  for (int i = 0; i < imagePaths.size(); i++) {
6855  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
6856  preparedStatement.clearParameters();
6857  preparedStatement.setLong(1, newObjId);
6858  preparedStatement.setString(2, imagePaths.get(i));
6859  preparedStatement.setLong(3, i);
6860  connection.executeUpdate(preparedStatement);
6861  }
6862 
6863  // Create the display name
6864  String name = displayName;
6865  if (name == null || name.isEmpty()) {
6866  if (imagePaths.size() > 0) {
6867  String path = imagePaths.get(0);
6868  name = (new java.io.File(path)).getName();
6869  } else {
6870  name = "";
6871  }
6872  }
6873 
6874  // Create a host if needed
6875  if (host == null) {
6876  if (name.isEmpty()) {
6877  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
6878  } else {
6879  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
6880  }
6881  }
6882 
6883  // Add a row to data_source_info
6884  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
6885  statement = connection.createStatement();
6886  preparedStatement.setLong(1, newObjId);
6887  preparedStatement.setString(2, deviceId);
6888  preparedStatement.setString(3, timezone);
6889  preparedStatement.setLong(4, new Date().getTime());
6890  preparedStatement.setLong(5, host.getHostId());
6891  connection.executeUpdate(preparedStatement);
6892 
6893  // Create the new Image object
6894  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
6895  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
6896  } catch (SQLException ex) {
6897  if (!imagePaths.isEmpty()) {
6898  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
6899  } else {
6900  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
6901  }
6902  } finally {
6903  closeStatement(statement);
6904  }
6905  }
6906 
6920  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
6921  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
6922  try {
6923  // Insert a row for the VolumeSystem into the tsk_objects table.
6924  CaseDbConnection connection = transaction.getConnection();
6925  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
6926 
6927  // Add a row to tsk_vs_info
6928  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
6929  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
6930  preparedStatement.clearParameters();
6931  preparedStatement.setLong(1, newObjId);
6932  preparedStatement.setShort(2, (short) type.getVsType());
6933  preparedStatement.setLong(3, imgOffset);
6934  preparedStatement.setLong(4, blockSize);
6935  connection.executeUpdate(preparedStatement);
6936 
6937  // Create the new VolumeSystem object
6938  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
6939  } catch (SQLException ex) {
6940  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
6941  parentObjId, imgOffset), ex);
6942  }
6943  }
6944 
6960  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
6961  long flags, CaseDbTransaction transaction) throws TskCoreException {
6962  try {
6963  // Insert a row for the Volume into the tsk_objects table.
6964  CaseDbConnection connection = transaction.getConnection();
6965  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
6966 
6967  // Add a row to tsk_vs_parts
6968  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
6969  PreparedStatement preparedStatement;
6970  if (this.dbType == DbType.POSTGRESQL) {
6971  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
6972  } else {
6973  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
6974  }
6975  preparedStatement.clearParameters();
6976  preparedStatement.setLong(1, newObjId);
6977  preparedStatement.setLong(2, addr);
6978  preparedStatement.setLong(3, start);
6979  preparedStatement.setLong(4, length);
6980  preparedStatement.setString(5, desc);
6981  preparedStatement.setShort(6, (short) flags);
6982  connection.executeUpdate(preparedStatement);
6983 
6984  // Create the new Volume object
6985  return new Volume(this, newObjId, addr, start, length, flags, desc);
6986  } catch (SQLException ex) {
6987  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
6988  }
6989  }
6990 
7002  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
7003  try {
7004  // Insert a row for the Pool into the tsk_objects table.
7005  CaseDbConnection connection = transaction.getConnection();
7006  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
7007 
7008  // Add a row to tsk_pool_info
7009  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
7010  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
7011  preparedStatement.clearParameters();
7012  preparedStatement.setLong(1, newObjId);
7013  preparedStatement.setShort(2, type.getValue());
7014  connection.executeUpdate(preparedStatement);
7015 
7016  // Create the new Pool object
7017  return new Pool(this, newObjId, type.getName(), type.getValue());
7018  } catch (SQLException ex) {
7019  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
7020  }
7021  }
7022 
7041  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
7042  long rootInum, long firstInum, long lastInum, String displayName,
7043  CaseDbTransaction transaction) throws TskCoreException {
7044  try {
7045  // Insert a row for the FileSystem into the tsk_objects table.
7046  CaseDbConnection connection = transaction.getConnection();
7047  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
7048 
7049  // Get the data source object ID
7050  long dataSourceId = getDataSourceObjectId(connection, newObjId);
7051 
7052  // Add a row to tsk_fs_info
7053  // 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)
7054  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
7055  preparedStatement.clearParameters();
7056  preparedStatement.setLong(1, newObjId);
7057  preparedStatement.setLong(2, dataSourceId);
7058  preparedStatement.setLong(3, imgOffset);
7059  preparedStatement.setInt(4, type.getValue());
7060  preparedStatement.setLong(5, blockSize);
7061  preparedStatement.setLong(6, blockCount);
7062  preparedStatement.setLong(7, rootInum);
7063  preparedStatement.setLong(8, firstInum);
7064  preparedStatement.setLong(9, lastInum);
7065  preparedStatement.setString(10, displayName);
7066  connection.executeUpdate(preparedStatement);
7067 
7068  // Create the new FileSystem object
7069  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
7070  firstInum, lastInum);
7071  } catch (SQLException ex) {
7072  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
7073  imgOffset, parentObjId), ex);
7074  }
7075  }
7076 
7102  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7103  String fileName,
7104  long metaAddr, int metaSeq,
7105  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7106  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7107  long ctime, long crtime, long atime, long mtime,
7108  boolean isFile, Content parent) throws TskCoreException {
7109 
7110  CaseDbTransaction transaction = beginTransaction();
7111  try {
7112 
7113  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
7114  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
7115  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
7116  OsAccount.NO_OWNER_ID, null,
7117  Collections.emptyList(), transaction);
7118 
7119  transaction.commit();
7120  transaction = null;
7121  return fileSystemFile;
7122  } finally {
7123  if (null != transaction) {
7124  try {
7125  transaction.rollback();
7126  } catch (TskCoreException ex2) {
7127  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7128  }
7129  }
7130  }
7131  }
7132 
7170  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7171  String fileName,
7172  long metaAddr, int metaSeq,
7173  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7174  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7175  long ctime, long crtime, long atime, long mtime,
7176  String md5Hash, String sha256Hash, String mimeType,
7177  boolean isFile, Content parent, String ownerUid,
7178  OsAccount osAccount, List<Attribute> fileAttributes,
7179  CaseDbTransaction transaction) throws TskCoreException {
7180 
7181  return addFileSystemFile(dataSourceObjId, fsObjId,
7182  fileName,
7183  metaAddr, metaSeq,
7184  attrType, attrId,
7185  dirFlag, metaFlags, size,
7186  ctime, crtime, atime, mtime,
7187  md5Hash, sha256Hash, null,
7188  mimeType,
7189  isFile, parent, ownerUid,
7190  osAccount, fileAttributes,
7191  transaction);
7192  }
7193 
7233  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7234  String fileName,
7235  long metaAddr, int metaSeq,
7236  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7237  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7238  long ctime, long crtime, long atime, long mtime,
7239  String md5Hash, String sha256Hash, String sha1Hash,
7240  String mimeType, boolean isFile,
7241  Content parent, String ownerUid,
7242  OsAccount osAccount, List<Attribute> fileAttributes,
7243  CaseDbTransaction transaction) throws TskCoreException {
7244  return addFileSystemFile(dataSourceObjId, fsObjId,
7245  fileName,
7246  metaAddr, metaSeq,
7247  attrType, attrId,
7248  dirFlag, metaFlags, size,
7249  ctime, crtime, atime, mtime,
7250  md5Hash, sha256Hash, sha1Hash,
7251  mimeType,
7252  isFile, parent, ownerUid,
7253  osAccount, TskData.CollectedStatus.UNKNOWN, fileAttributes,
7254  transaction);
7255  }
7256 
7297  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7298  String fileName,
7299  long metaAddr, int metaSeq,
7300  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7301  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7302  long ctime, long crtime, long atime, long mtime,
7303  String md5Hash, String sha256Hash, String sha1Hash,
7304  String mimeType, boolean isFile,
7305  Content parent, String ownerUid,
7306  OsAccount osAccount, TskData.CollectedStatus collected,
7307  List<Attribute> fileAttributes,
7308  CaseDbTransaction transaction) throws TskCoreException {
7309  TimelineManager timelineManager = getTimelineManager();
7310 
7311  Statement queryStatement = null;
7312  String parentPath = "/";
7313  try {
7314  CaseDbConnection connection = transaction.getConnection();
7315 
7316  // Insert a row for the local/logical file into the tsk_objects table.
7317  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7318  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7319 
7320  if (parent instanceof AbstractFile) {
7321  AbstractFile parentFile = (AbstractFile) parent;
7322  if (isRootDirectory(parentFile, transaction)) {
7323  parentPath = "/";
7324  } else {
7325  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7326  }
7327  } else {
7328  parentPath = "/";
7329  }
7330 
7331  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7332  statement.clearParameters();
7333  statement.setLong(1, objectId); // obj_is
7334  statement.setLong(2, fsObjId); // fs_obj_id
7335  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7336  statement.setShort(4, (short) attrType.getValue()); // attr_type
7337  statement.setInt(5, attrId); // attr_id
7338  statement.setString(6, fileName); // name
7339  statement.setLong(7, metaAddr); // meta_addr
7340  statement.setInt(8, metaSeq); // meta_addr
7341  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7342  statement.setShort(10, (short) 1); // has_path
7344  statement.setShort(11, dirType.getValue()); // dir_type
7346  statement.setShort(12, metaType.getValue()); // meta_type
7347  statement.setShort(13, dirFlag.getValue()); // dir_flags
7348  statement.setShort(14, metaFlags); // meta_flags
7349  statement.setLong(15, size < 0 ? 0 : size);
7350  statement.setLong(16, ctime);
7351  statement.setLong(17, crtime);
7352  statement.setLong(18, atime);
7353  statement.setLong(19, mtime);
7354  statement.setString(20, md5Hash);
7355  statement.setString(21, sha256Hash);
7356  statement.setString(22, sha1Hash);
7357  statement.setString(23, mimeType);
7358  statement.setString(24, parentPath);
7359  final String extension = extractExtension(fileName);
7360  statement.setString(25, extension);
7361  statement.setString(26, ownerUid);
7362  if (null != osAccount) {
7363  statement.setLong(27, osAccount.getId());
7364  } else {
7365  statement.setNull(27, java.sql.Types.BIGINT); // osAccountObjId
7366  }
7367  statement.setLong(28, collected.getType());
7368 
7369  connection.executeUpdate(statement);
7370 
7371  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7372  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7373  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, sha1Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7374 
7375  if (!timelineEventsDisabled.get()) {
7376  timelineManager.addEventsForNewFile(derivedFile, connection);
7377  }
7378 
7379  for (Attribute fileAttribute : fileAttributes) {
7380  fileAttribute.setAttributeParentId(objectId);
7381  fileAttribute.setCaseDatabase(this);
7382  addFileAttribute(fileAttribute, connection);
7383  }
7384 
7385  if (osAccount != null) {
7386  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
7387  }
7388 
7389  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7390  attrType, attrId, fileName, metaAddr, metaSeq,
7391  dirType, metaType, dirFlag, metaFlags,
7392  size, ctime, crtime, atime, mtime,
7393  (short) 0, 0, 0, md5Hash, sha256Hash, sha1Hash, null, parentPath, mimeType,
7394  extension, ownerUid, osAccountId, collected, fileAttributes);
7395 
7396  } catch (SQLException ex) {
7397  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);
7398  } finally {
7399  closeStatement(queryStatement);
7400  }
7401  }
7402 
7411  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7412  CaseDbConnection connection = null;
7413  Statement s = null;
7414  ResultSet rs = null;
7416  try {
7417  connection = connections.getConnection();
7418  s = connection.createStatement();
7419  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7420  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7421  + " AND obj_id = data_source_obj_id"
7422  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7423  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7424  while (rs.next()) {
7425  virtDirRootIds.add(virtualDirectory(rs, connection));
7426  }
7427  return virtDirRootIds;
7428  } catch (SQLException ex) {
7429  throw new TskCoreException("Error getting local files virtual folder id", ex);
7430  } finally {
7431  closeResultSet(rs);
7432  closeStatement(s);
7433  closeConnection(connection);
7435  }
7436  }
7437 
7450  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7451  assert (null != fileRanges);
7452  if (null == fileRanges) {
7453  throw new TskCoreException("TskFileRange object is null");
7454  }
7455 
7456  assert (null != parent);
7457  if (null == parent) {
7458  throw new TskCoreException("Conent is null");
7459  }
7460 
7461  String parentPath;
7462  if (parent instanceof AbstractFile) {
7463  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7464  } else {
7465  parentPath = "/";
7466  }
7467 
7468  CaseDbTransaction transaction = null;
7469  Statement statement = null;
7470  ResultSet resultSet = null;
7471 
7472  try {
7473  transaction = beginTransaction();
7474  CaseDbConnection connection = transaction.getConnection();
7475 
7476  // If the parent is part of a file system, grab its file system ID
7477  Long fileSystemObjectId;
7478  if (0 != parent.getId()) {
7479  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
7480  if (fileSystemObjectId == -1) {
7481  fileSystemObjectId = null;
7482  }
7483  } else {
7484  fileSystemObjectId = null;
7485  }
7486 
7487  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<>();
7488  for (TskFileRange fileRange : fileRanges) {
7489  /*
7490  * Insert a row for the Tsk file range into the tsk_objects
7491  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7492  * ?)
7493  */
7494  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7495  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7496  /*
7497  * Insert a row for the Tsk file range into the tsk_files table:
7498  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7499  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7500  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7501  * parent_path, data_source_obj_id,extension, owner_uid,
7502  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7503  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
7504  */
7505  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7506  prepStmt.clearParameters();
7507  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7508  if (fileSystemObjectId != null) {
7509  prepStmt.setLong(2, fileSystemObjectId);// fs_obj_id
7510  } else {
7511  prepStmt.setNull(2, java.sql.Types.BIGINT);
7512  }
7513  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]
7514  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7515  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7516  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7517  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7518  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7519  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7520  prepStmt.setLong(10, fileRange.getByteLen()); // size
7521  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7522  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7523  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7524  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7525  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7526  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7527  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7528 
7529  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7530  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7531  prepStmt.setString(20, parentPath); // parent path
7532  prepStmt.setLong(21, parent.getId()); // data_source_obj_id
7533 
7534  //extension, since this is not a FS file we just set it to null
7535  prepStmt.setString(22, null);
7536 
7537  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7538  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7539  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7540 
7541  connection.executeUpdate(prepStmt);
7542 
7543  /*
7544  * Insert a row in the tsk_layout_file table for each chunk of
7545  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7546  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7547  */
7548  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7549  prepStmt.clearParameters();
7550  prepStmt.setLong(1, fileRangeId); // obj_id
7551  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7552  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7553  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7554  connection.executeUpdate(prepStmt);
7555 
7556  /*
7557  * Create a layout file representation of the carved file.
7558  */
7559  fileRangeLayoutFiles.add(new LayoutFile(this,
7560  fileRangeId,
7561  parent.getId(),
7562  fileSystemObjectId,
7563  Long.toString(fileRange.getSequence()),
7568  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7569  fileRange.getByteLen(),
7570  0L, 0L, 0L, 0L,
7571  null, null, null,
7573  parent.getUniquePath(),
7574  null,
7575  OsAccount.NO_OWNER_ID,
7576  OsAccount.NO_ACCOUNT));
7577  }
7578 
7579  transaction.commit();
7580  transaction = null;
7581  return fileRangeLayoutFiles;
7582 
7583  } catch (SQLException ex) {
7584  throw new TskCoreException("Failed to add layout files to case database", ex);
7585  } finally {
7586  closeResultSet(resultSet);
7587  closeStatement(statement);
7588 
7589  if (null != transaction) {
7590  try {
7591  transaction.rollback();
7592  } catch (TskCoreException ex2) {
7593  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7594  }
7595  }
7596  }
7597  }
7598 
7605  private class CarvedFileDirInfo {
7606 
7607  final VirtualDirectory currentFolder;
7608  AtomicInteger count;
7609 
7610  CarvedFileDirInfo(VirtualDirectory currentFolder) {
7611  this.currentFolder = currentFolder;
7612  count = new AtomicInteger(0);
7613  }
7614 
7615  CarvedFileDirInfo(VirtualDirectory currentFolder, int count) {
7616  this.currentFolder = currentFolder;
7617  this.count = new AtomicInteger(count);
7618  }
7619 
7626  boolean isFull() {
7627  return count.get() >= MAX_CARVED_FILES_PER_FOLDER;
7628  }
7629 
7633  void incrementFileCounter() {
7634  count.incrementAndGet();
7635  }
7636  }
7637 
7647  private CarvedFileDirInfo getMostRecentCarvedDirInfo(VirtualDirectory carvedFilesBaseDir) throws TskCoreException {
7648  VirtualDirectory mostRecentDir = null;
7649  for (Content child : carvedFilesBaseDir.getChildren()) {
7650  if (isValidCarvedFileSubfolder(child)) {
7651  if (mostRecentDir == null
7652  || (mostRecentDir.getId() < child.getId())) {
7653  mostRecentDir = (VirtualDirectory) child;
7654  }
7655  }
7656  }
7657 
7658  if (mostRecentDir != null) {
7659  return new CarvedFileDirInfo(mostRecentDir, mostRecentDir.getChildrenCount());
7660  }
7661  return null;
7662  }
7663 
7672  private boolean isValidCarvedFileSubfolder(Content subfolder) {
7673  if (!(subfolder instanceof VirtualDirectory)) {
7674  return false;
7675  }
7676  return subfolder.getName().matches("^[0-9]+$");
7677  }
7678 
7692  private CarvedFileDirInfo createCarvedFilesSubfolder(Content carvedFilesBaseDir, CarvedFileDirInfo currentSubfolderInfo) throws TskCoreException {
7693  int nextIndex = 1;
7694  if (currentSubfolderInfo != null) {
7695  try {
7696  int currentIndex = Integer.parseInt(currentSubfolderInfo.currentFolder.getName());
7697  nextIndex = currentIndex + 1;
7698  } catch (NumberFormatException ex) {
7699  throw new TskCoreException("Unexpected name format for carved files subdirectory with ID: " + currentSubfolderInfo.currentFolder.getId() + " (" + currentSubfolderInfo.currentFolder.getName() + ")", ex);
7700  }
7701  }
7702 
7703  VirtualDirectory carvedFilesSubdir = addVirtualDirectory(carvedFilesBaseDir.getId(), Integer.toString(nextIndex));
7704  return new CarvedFileDirInfo(carvedFilesSubdir);
7705  }
7706 
7718  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
7719  assert (null != carvingResult);
7720  if (null == carvingResult) {
7721  throw new TskCoreException("Carving is null");
7722  }
7723  assert (null != carvingResult.getParent());
7724  if (null == carvingResult.getParent()) {
7725  throw new TskCoreException("Carving result has null parent");
7726  }
7727  assert (null != carvingResult.getCarvedFiles());
7728  if (null == carvingResult.getCarvedFiles()) {
7729  throw new TskCoreException("Carving result has null carved files");
7730  }
7731  CaseDbTransaction transaction = null;
7732  Statement statement = null;
7733  ResultSet resultSet = null;
7734  try {
7735 
7736  /*
7737  * Carved files are "re-parented" as children of the $CarvedFiles
7738  * virtual directory of the root file system, volume, or image
7739  * ancestor of the carved files parent, but if no such ancestor is
7740  * found, then the parent specified in the carving result is used.
7741  */
7742  Content root = carvingResult.getParent();
7743  while (null != root) {
7744  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
7745  break;
7746  }
7747  root = root.getParent();
7748  }
7749  if (null == root) {
7750  root = carvingResult.getParent();
7751  }
7752 
7753  /*
7754  * Get or create the $CarvedFiles virtual directory for the root
7755  * ancestor.
7756  */
7757  CarvedFileDirInfo carvedFilesDirInfo = null;
7758  synchronized (carvedFileDirsLock) {
7759  // Get the subfolder currently in use (if there is one)
7760  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7761  if (carvedFilesDirInfo != null) {
7762  carvedFilesDirInfo.incrementFileCounter();
7763 
7764  // If the current folder is full, create a new one.
7765  if (carvedFilesDirInfo.isFull()) {
7766  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesDirInfo.currentFolder.getParent(), carvedFilesDirInfo);
7767  }
7768  }
7769 
7770  if (null == carvedFilesDirInfo) {
7771  List<Content> rootChildren;
7772  if (root instanceof FileSystem) {
7773  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
7774  } else {
7775  rootChildren = root.getChildren();
7776  }
7777  for (Content child : rootChildren) {
7778  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
7779 
7780  VirtualDirectory baseDir = (VirtualDirectory) child;
7781 
7782  // Get the most recent subfolder in the carved files folder.
7783  carvedFilesDirInfo = getMostRecentCarvedDirInfo(baseDir);
7784 
7785  // If there are no subfolders, create one.
7786  if (carvedFilesDirInfo == null) {
7787  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, null);
7788  }
7789 
7790  // If there are already too many files in the subfolder, create a new one.
7791  if (carvedFilesDirInfo.isFull()) {
7792  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, carvedFilesDirInfo);
7793  }
7794 
7795  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7796  break;
7797  }
7798  }
7799  if (carvedFilesDirInfo == null) {
7800  // If we get here, we didn't have a carved files base folder in the case, so we need to make that and
7801  // the first subfolder.
7802 
7803  long parId = root.getId();
7804  // $CarvedFiles should be a child of the root directory, not the file system
7805  if (root instanceof FileSystem) {
7806  Content rootDir = ((FileSystem) root).getRootDirectory();
7807  parId = rootDir.getId();
7808  }
7809  VirtualDirectory carvedFilesBaseDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
7810  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, null);
7811  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7812  }
7813  }
7814  }
7815 
7816  /*
7817  * Add the carved files to the database as children of the
7818  * $CarvedFile directory of the root ancestor.
7819  */
7820  VirtualDirectory carvedFilesBaseDir = (VirtualDirectory) carvedFilesDirInfo.currentFolder.getParent();
7821  transaction = beginTransaction();
7822  CaseDbConnection connection = transaction.getConnection();
7823  String parentPath = getFileParentPath(carvedFilesDirInfo.currentFolder.getId(), connection) + carvedFilesDirInfo.currentFolder.getName() + "/";
7824  List<LayoutFile> carvedFiles = new ArrayList<>();
7825  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
7826 
7827  /*
7828  * Check if we need to change to a new subfolder.
7829  */
7830  VirtualDirectory carvedFilesDir = carvedFilesDirInfo.currentFolder;
7831  if (carvedFilesDirInfo.isFull()) {
7832  // To prevent deadlocks involving the case write lock and the carvedFileDirsLock,
7833  // commit the current transaction and then start a new one
7834  // after switching to the new folder.
7835  transaction.commit();
7836 
7837  synchronized (carvedFileDirsLock) {
7838  // Get the current copy from the map - another thread may have just created a new folder.
7839  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7840  if (carvedFilesDirInfo.isFull()) {
7841  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, carvedFilesDirInfo);
7842  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7843  carvedFilesDir = carvedFilesDirInfo.currentFolder;
7844  }
7845  }
7846 
7847  // Start a new transaction.
7848  transaction = beginTransaction();
7849  connection = transaction.getConnection();
7850  parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
7851 
7852  }
7853  carvedFilesDirInfo.incrementFileCounter();
7854 
7855  /*
7856  * Insert a row for the carved file into the tsk_objects table:
7857  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7858  */
7859  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7860 
7861 
7862  /*
7863  * Insert a row for the carved file into the tsk_files table:
7864  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7865  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7866  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7867  * parent_path, data_source_obj_id,extenion, owner_uid,
7868  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7869  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7870  */
7871  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7872  prepStmt.clearParameters();
7873  prepStmt.setLong(1, carvedFileId); // obj_id
7874  Long fileSystemObjectId;
7875  if (root instanceof FileSystem) {
7876  prepStmt.setLong(2, root.getId()); // fs_obj_id
7877  fileSystemObjectId = root.getId();
7878  } else {
7879  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7880  fileSystemObjectId = null;
7881  }
7882  prepStmt.setString(3, carvedFile.getName()); // name
7883  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
7884  prepStmt.setShort(5, (short) 1); // has_path
7885  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7886  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7887  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7888  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7889  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
7890  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7891  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7892  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7893  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7894  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7895  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7896  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7897 
7898  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7899  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7900  prepStmt.setString(20, parentPath); // parent path
7901  prepStmt.setLong(21, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
7902  prepStmt.setString(22, extractExtension(carvedFile.getName())); //extension
7903 
7904  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7905  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7906  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7907 
7908  connection.executeUpdate(prepStmt);
7909 
7910  /*
7911  * Insert a row in the tsk_layout_file table for each chunk of
7912  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7913  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7914  */
7915  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7916  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
7917  prepStmt.clearParameters();
7918  prepStmt.setLong(1, carvedFileId); // obj_id
7919  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7920  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7921  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7922  connection.executeUpdate(prepStmt);
7923  }
7924 
7925  /*
7926  * Create a layout file representation of the carved file.
7927  */
7928  carvedFiles.add(new LayoutFile(this,
7929  carvedFileId,
7930  carvedFilesDir.getDataSourceObjectId(),
7931  fileSystemObjectId,
7932  carvedFile.getName(),
7937  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7938  carvedFile.getSizeInBytes(),
7939  0L, 0L, 0L, 0L,
7940  null, null, null,
7942  parentPath,
7943  null,
7944  OsAccount.NO_OWNER_ID,
7945  OsAccount.NO_ACCOUNT));
7946  }
7947 
7948  transaction.commit();
7949  transaction = null;
7950  return carvedFiles;
7951 
7952  } catch (SQLException ex) {
7953  throw new TskCoreException("Failed to add carved files to case database", ex);
7954  } finally {
7955  closeResultSet(resultSet);
7956  closeStatement(statement);
7957 
7958  if (null != transaction) {
7959  try {
7960  transaction.rollback();
7961  } catch (TskCoreException ex2) {
7962  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7963  }
7964  }
7965  }
7966  }
7967 
7998  public DerivedFile addDerivedFile(String fileName, String localPath,
7999  long size, long ctime, long crtime, long atime, long mtime,
8000  boolean isFile, Content parentObj,
8001  String rederiveDetails, String toolName, String toolVersion,
8002  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
8003  CaseDbTransaction transaction = beginTransaction();
8004  try {
8005  DerivedFile df = addDerivedFile(fileName, localPath,
8006  size, ctime, crtime, atime, mtime,
8007  isFile, parentObj,
8008  rederiveDetails, toolName, toolVersion,
8009  otherDetails, encodingType, transaction);
8010  transaction.commit();
8011  return df;
8012  } catch (TskCoreException ex) {
8013  transaction.rollback();
8014  throw ex;
8015  }
8016  }
8017 
8018  public DerivedFile addDerivedFile(String fileName, String localPath,
8019  long size, long ctime, long crtime, long atime, long mtime,
8020  boolean isFile, Content parentObj,
8021  String rederiveDetails, String toolName, String toolVersion,
8022  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
8023  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8024  localPath = localPath.replaceAll("^[/\\\\]+", "");
8025 
8026  TimelineManager timelineManager = getTimelineManager();
8027 
8028  CaseDbConnection connection = transaction.getConnection();
8029  try {
8030  final long parentId = parentObj.getId();
8031  String parentPath = "";
8032  if (parentObj instanceof BlackboardArtifact) {
8033  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8034  } else if (parentObj instanceof AbstractFile) {
8035  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8036  }
8037 
8038  // Insert a row for the derived file into the tsk_objects table.
8039  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8040  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8041 
8042  // Insert a row for the virtual directory into the tsk_files table.
8043  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8044  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
8045  // parent_path, data_source_obj_id, extension)
8046  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
8047  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8048  statement.clearParameters();
8049  statement.setLong(1, newObjId);
8050 
8051  // If the parentFile is part of a file system, use its file system object ID.
8052  Long fsObjId = this.getFileSystemId(parentId, connection);
8053  if (fsObjId != -1) {
8054  statement.setLong(2, fsObjId);
8055  } else {
8056  fsObjId = null;
8057  statement.setNull(2, java.sql.Types.BIGINT);
8058  }
8059  statement.setString(3, fileName);
8060 
8061  //type, has_path
8062  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8063  statement.setShort(5, (short) 1);
8064 
8065  //flags
8067  statement.setShort(6, dirType.getValue());
8069  statement.setShort(7, metaType.getValue());
8070 
8071  //note: using alloc under assumption that derived files derive from alloc files
8073  statement.setShort(8, dirFlag.getValue());
8074  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8075  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8076  statement.setShort(9, metaFlags);
8077 
8078  //size
8079  //prevent negative size
8080  long savedSize = size < 0 ? 0 : size;
8081  statement.setLong(10, savedSize);
8082 
8083  //mactimes
8084  //long ctime, long crtime, long atime, long mtime,
8085  statement.setLong(11, ctime);
8086  statement.setLong(12, crtime);
8087  statement.setLong(13, atime);
8088  statement.setLong(14, mtime);
8089 
8090  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
8091  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8092  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8093 
8094  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8095  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
8096 
8097  //parent path
8098  statement.setString(20, parentPath);
8099 
8100  // root data source object id
8101  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
8102  statement.setLong(21, dataSourceObjId);
8103  final String extension = extractExtension(fileName);
8104  //extension
8105  statement.setString(22, extension);
8106 
8107  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8108  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8109  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8110 
8111  connection.executeUpdate(statement);
8112 
8113  //add localPath
8114  addFilePath(connection, newObjId, localPath, encodingType);
8115 
8116  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
8117  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
8118 
8119  if (!timelineEventsDisabled.get()) {
8120  timelineManager.addEventsForNewFile(derivedFile, connection);
8121  }
8122 
8123  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
8124  return derivedFile;
8125  } catch (SQLException ex) {
8126  throw new TskCoreException("Failed to add derived file to case database", ex);
8127  }
8128  }
8129 
8160  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8161  long size, long ctime, long crtime, long atime, long mtime,
8162  boolean isFile, String mimeType,
8163  String rederiveDetails, String toolName, String toolVersion,
8164  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
8165 
8166  CaseDbTransaction trans = null;
8167  try {
8168  Content parentObj = derivedFile.getParent();
8169 
8170  trans = beginTransaction();
8171  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
8172  size, ctime, crtime, atime, mtime,
8173  isFile, mimeType,
8174  rederiveDetails, toolName, toolVersion,
8175  otherDetails, encodingType, parentObj, trans);
8176  trans.commit();
8177  return updatedFile;
8178  } catch (TskCoreException ex) {
8179  if (trans != null) {
8180  trans.rollback();
8181  }
8182  throw ex;
8183  }
8184  }
8185 
8186  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8187  long size, long ctime, long crtime, long atime, long mtime,
8188  boolean isFile, String mimeType,
8189  String rederiveDetails, String toolName, String toolVersion,
8190  String otherDetails, TskData.EncodingType encodingType,
8191  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
8192 
8193  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8194  localPath = localPath.replaceAll("^[/\\\\]+", "");
8195 
8196  ResultSet rs = null;
8197  try {
8198  final long parentId = parentObj.getId();
8199  String parentPath = "";
8200  if (parentObj instanceof BlackboardArtifact) {
8201  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8202  } else if (parentObj instanceof AbstractFile) {
8203  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8204  }
8205  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
8206  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
8207  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
8208  statement.clearParameters();
8209 
8210  //type
8211  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8212 
8213  //flags
8215  statement.setShort(2, dirType.getValue());
8217  statement.setShort(3, metaType.getValue());
8218 
8219  //note: using alloc under assumption that derived files derive from alloc files
8221  statement.setShort(4, dirFlag.getValue());
8222  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8223  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8224  statement.setShort(5, metaFlags);
8225 
8226  //size
8227  //prevent negative size
8228  long savedSize = size < 0 ? 0 : size;
8229  statement.setLong(6, savedSize);
8230 
8231  //mactimes
8232  //long ctime, long crtime, long atime, long mtime,
8233  statement.setLong(7, ctime);
8234  statement.setLong(8, crtime);
8235  statement.setLong(9, atime);
8236  statement.setLong(10, mtime);
8237  statement.setString(11, mimeType);
8238  statement.setString(12, String.valueOf(derivedFile.getId()));
8239  trans.getConnection().executeUpdate(statement);
8240 
8241  //add localPath
8242  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
8243 
8244  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
8245  Long fileSystemObjId = derivedFile.getFileSystemObjectId().orElse(null);
8246  final String extension = extractExtension(derivedFile.getName());
8247  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, fileSystemObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
8248  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension,
8249  derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
8250  } catch (SQLException ex) {
8251  throw new TskCoreException("Failed to add derived file to case database", ex);
8252  } finally {
8253  closeResultSet(rs);
8254  }
8255  }
8256 
8276  public LocalFile addLocalFile(String fileName, String localPath,
8277  long size, long ctime, long crtime, long atime, long mtime,
8278  boolean isFile, TskData.EncodingType encodingType,
8279  AbstractFile parent) throws TskCoreException {
8280 
8281  CaseDbTransaction localTrans = beginTransaction();
8282  try {
8283  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
8284  localTrans.commit();
8285  localTrans = null;
8286  return created;
8287  } finally {
8288  if (null != localTrans) {
8289  try {
8290  localTrans.rollback();
8291  } catch (TskCoreException ex2) {
8292  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8293  }
8294  }
8295  }
8296  }
8297 
8322  public LocalFile addLocalFile(String fileName, String localPath,
8323  long size, long ctime, long crtime, long atime, long mtime,
8324  boolean isFile, TskData.EncodingType encodingType,
8325  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8326 
8327  return addLocalFile(fileName, localPath,
8328  size, ctime, crtime, atime, mtime,
8329  null, null, null,
8330  isFile, encodingType,
8331  parent, transaction);
8332  }
8333 
8362  public LocalFile addLocalFile(String fileName, String localPath,
8363  long size, long ctime, long crtime, long atime, long mtime,
8364  String md5, String sha256, FileKnown known, String mimeType,
8365  boolean isFile, TskData.EncodingType encodingType,
8366  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8367 
8368  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8369  md5, sha256, known, mimeType, isFile, encodingType,
8370  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8371 
8372  }
8373 
8404  public LocalFile addLocalFile(String fileName, String localPath,
8405  long size, long ctime, long crtime, long atime, long mtime,
8406  String md5, String sha256, FileKnown known, String mimeType,
8407  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8408  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8409 
8410  return addLocalFile(fileName, localPath,
8411  size, ctime, crtime, atime, mtime,
8412  md5, sha256, null, known, mimeType,
8413  isFile, encodingType, osAccountId, ownerAccount,
8414  parent, transaction);
8415  }
8416 
8417 
8450  public LocalFile addLocalFile(String fileName, String localPath,
8451  long size, long ctime, long crtime, long atime, long mtime,
8452  String md5, String sha256, String sha1Hash, FileKnown known, String mimeType,
8453  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8454  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8455  CaseDbConnection connection = transaction.getConnection();
8456  Statement queryStatement = null;
8457  try {
8458 
8459  // Insert a row for the local/logical file into the tsk_objects table.
8460  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8461  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8462 
8463  // Insert a row for the local/logical file into the tsk_files table.
8464  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8465  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
8466  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8467  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
8468  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8469  statement.clearParameters();
8470  statement.setLong(1, objectId);
8471  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8472  statement.setString(3, fileName);
8473  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8474  statement.setShort(5, (short) 1);
8476  statement.setShort(6, dirType.getValue());
8478  statement.setShort(7, metaType.getValue());
8480  statement.setShort(8, dirFlag.getValue());
8481  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8482  statement.setShort(9, metaFlags);
8483  //prevent negative size
8484  long savedSize = size < 0 ? 0 : size;
8485  statement.setLong(10, savedSize);
8486  statement.setLong(11, ctime);
8487  statement.setLong(12, crtime);
8488  statement.setLong(13, atime);
8489  statement.setLong(14, mtime);
8490  statement.setString(15, md5);
8491  statement.setString(16, sha256);
8492  statement.setString(17, sha1Hash); // sha1
8493 
8494  if (known != null) {
8495  statement.setByte(18, known.getFileKnownValue());
8496  } else {
8497  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue());
8498  }
8499  statement.setString(19, mimeType);
8500  String parentPath;
8501  long dataSourceObjId;
8502 
8503  if (parent instanceof AbstractFile) {
8504  AbstractFile parentFile = (AbstractFile) parent;
8505  if (isRootDirectory(parentFile, transaction)) {
8506  parentPath = "/";
8507  } else {
8508  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8509  }
8510  dataSourceObjId = parentFile.getDataSourceObjectId();
8511  } else {
8512  parentPath = "/";
8513  dataSourceObjId = getDataSourceObjectId(connection, parent);
8514  }
8515  statement.setString(20, parentPath);
8516  statement.setLong(21, dataSourceObjId);
8517  final String extension = extractExtension(fileName);
8518  statement.setString(22, extension);
8519 
8520  if (ownerAccount != null) {
8521  statement.setString(23, ownerAccount); // ownerUid
8522  } else {
8523  statement.setNull(23, java.sql.Types.VARCHAR);
8524  }
8525 
8526  if (osAccountId != null) {
8527  statement.setLong(24, osAccountId); // osAccountObjId
8528  } else {
8529  statement.setNull(24, java.sql.Types.BIGINT);
8530  }
8531 
8532  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8533 
8534  connection.executeUpdate(statement);
8535  addFilePath(connection, objectId, localPath, encodingType);
8536  LocalFile localFile = new LocalFile(this,
8537  objectId,
8538  fileName,
8540  dirType,
8541  metaType,
8542  dirFlag,
8543  metaFlags,
8544  savedSize,
8545  ctime, crtime, atime, mtime,
8546  mimeType, md5, sha256, sha1Hash, known,
8547  parent.getId(), parentPath,
8548  dataSourceObjId,
8549  localPath,
8550  encodingType, extension,
8551  ownerAccount, osAccountId);
8552  if (!timelineEventsDisabled.get()) {
8553  getTimelineManager().addEventsForNewFile(localFile, connection);
8554  }
8555  return localFile;
8556 
8557  } catch (SQLException ex) {
8558  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);
8559  } finally {
8560  closeStatement(queryStatement);
8561  }
8562  }
8563 
8569  private class RootDirectoryKey {
8570 
8571  private long dataSourceId;
8572  private Long fileSystemId;
8573 
8574  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8575  this.dataSourceId = dataSourceId;
8576  this.fileSystemId = fileSystemId;
8577  }
8578 
8579  @Override
8580  public int hashCode() {
8581  int hash = 7;
8582  hash = 41 * hash + Objects.hashCode(dataSourceId);
8583  hash = 41 * hash + Objects.hashCode(fileSystemId);
8584  return hash;
8585  }
8586 
8587  @Override
8588  public boolean equals(Object obj) {
8589  if (this == obj) {
8590  return true;
8591  }
8592  if (obj == null) {
8593  return false;
8594  }
8595  if (getClass() != obj.getClass()) {
8596  return false;
8597  }
8598 
8599  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8600  if (dataSourceId != otherKey.dataSourceId) {
8601  return false;
8602  }
8603 
8604  if (fileSystemId != null) {
8605  return fileSystemId.equals(otherKey.fileSystemId);
8606  }
8607  return (otherKey.fileSystemId == null);
8608  }
8609  }
8610 
8623  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8624 
8625  // First check if we know the root directory for this data source and optionally
8626  // file system. There is only one root, so if we know it we can simply compare
8627  // this file ID to the known root directory.
8628  Long fsObjId = null;
8629  if (file instanceof FsContent) {
8630  fsObjId = ((FsContent) file).getFileSystemId();
8631  }
8632  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8633  synchronized (rootDirectoryMapLock) {
8634  if (rootDirectoryMap.containsKey(key)) {
8635  return rootDirectoryMap.get(key).equals(file.getId());
8636  }
8637  }
8638 
8639  // Fallback cache. We store the result of each database lookup
8640  // so it won't be done multiple times in a row. In practice, this will
8641  // only be used if this method was never called on the root directory.
8642  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8643  if (isRoot != null) {
8644  return isRoot;
8645  }
8646 
8647  CaseDbConnection connection = transaction.getConnection();
8648  Statement statement = null;
8649  ResultSet resultSet = null;
8650 
8651  try {
8652  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8653  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8654  + "WHERE ChildRow.obj_id = %s;", file.getId());
8655 
8656  statement = connection.createStatement();
8657  resultSet = statement.executeQuery(query);
8658  if (resultSet.next()) {
8659  long parentId = resultSet.getLong("parent_object_id");
8660  if (parentId == 0) {
8661  return true;
8662  }
8663  int type = resultSet.getInt("parent_type");
8664  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8665  || type == TskData.ObjectType.VS.getObjectType()
8666  || type == TskData.ObjectType.VOL.getObjectType()
8667  || type == TskData.ObjectType.FS.getObjectType();
8668  if (result == true) {
8669  synchronized (rootDirectoryMapLock) {
8670  // This is a root directory so save it
8671  rootDirectoryMap.put(key, file.getId());
8672  }
8673  }
8674  isRootDirectoryCache.put(file.getId(), result);
8675  return result;
8676 
8677  } else {
8678  // This is a root directory so save it
8679  synchronized (rootDirectoryMapLock) {
8680  rootDirectoryMap.put(key, file.getId());
8681  }
8682  isRootDirectoryCache.put(file.getId(), true);
8683 
8684  return true; // The file has no parent
8685 
8686  }
8687  } catch (SQLException ex) {
8688  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
8689  } finally {
8690  closeResultSet(resultSet);
8691  closeStatement(statement);
8692  }
8693  }
8694 
8714  public LayoutFile addLayoutFile(String fileName,
8715  long size,
8716  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
8717  long ctime, long crtime, long atime, long mtime,
8718  List<TskFileRange> fileRanges,
8719  Content parent) throws TskCoreException {
8720 
8721  if (null == parent) {
8722  throw new TskCoreException("Parent can not be null");
8723  }
8724 
8725  String parentPath;
8726  if (parent instanceof AbstractFile) {
8727  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
8728  } else {
8729  parentPath = "/";
8730  }
8731 
8732  CaseDbTransaction transaction = null;
8733  Statement statement = null;
8734  ResultSet resultSet = null;
8735  try {
8736  transaction = beginTransaction();
8737  CaseDbConnection connection = transaction.getConnection();
8738 
8739  /*
8740  * Insert a row for the layout file into the tsk_objects table:
8741  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8742  */
8743  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8744 
8745  /*
8746  * Insert a row for the file into the tsk_files table: INSERT INTO
8747  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
8748  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
8749  * mtime, md5, known, mime_type, parent_path,
8750  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
8751  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8752  */
8753  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8754  prepStmt.clearParameters();
8755  prepStmt.setLong(1, newFileId); // obj_id
8756 
8757  // If the parent is part of a file system, grab its file system ID
8758  Long fileSystemObjectId;
8759  if (0 != parent.getId()) {
8760  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
8761  if (fileSystemObjectId != -1) {
8762  prepStmt.setLong(2, fileSystemObjectId);
8763  } else {
8764  prepStmt.setNull(2, java.sql.Types.BIGINT);
8765  fileSystemObjectId = null;
8766  }
8767  } else {
8768  prepStmt.setNull(2, java.sql.Types.BIGINT);
8769  fileSystemObjectId = null;
8770  }
8771  prepStmt.setString(3, fileName); // name
8772  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
8773  prepStmt.setShort(5, (short) 0); // has_path
8774  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8775  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8776  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
8777  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
8778  //prevent negative size
8779  long savedSize = size < 0 ? 0 : size;
8780  prepStmt.setLong(10, savedSize); // size
8781  prepStmt.setLong(11, ctime); // ctime
8782  prepStmt.setLong(12, crtime); // crtime
8783  prepStmt.setLong(13, atime); // atime
8784  prepStmt.setLong(14, mtime); // mtime
8785  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8786  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8787  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8788 
8789  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8790  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
8791  prepStmt.setString(20, parentPath); // parent path
8792  prepStmt.setLong(21, parent.getDataSource().getId()); // data_source_obj_id
8793 
8794  prepStmt.setString(22, extractExtension(fileName)); //extension
8795 
8796  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8797  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8798  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8799 
8800  connection.executeUpdate(prepStmt);
8801 
8802  /*
8803  * Insert a row in the tsk_layout_file table for each chunk of the
8804  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
8805  * byte_len, sequence) VALUES (?, ?, ?, ?)
8806  */
8807  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8808  for (TskFileRange tskFileRange : fileRanges) {
8809  prepStmt.clearParameters();
8810  prepStmt.setLong(1, newFileId); // obj_id
8811  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8812  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8813  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8814  connection.executeUpdate(prepStmt);
8815  }
8816 
8817  /*
8818  * Create a layout file representation of the carved file.
8819  */
8820  LayoutFile layoutFile = new LayoutFile(this,
8821  newFileId,
8822  parent.getDataSource().getId(),
8823  fileSystemObjectId,
8824  fileName,
8828  dirFlag,
8829  metaFlag.getValue(),
8830  savedSize,
8831  ctime, crtime, atime, mtime,
8832  null, null, null,
8834  parentPath,
8835  null,
8836  OsAccount.NO_OWNER_ID,
8837  OsAccount.NO_ACCOUNT);
8838 
8839  transaction.commit();
8840  transaction = null;
8841  return layoutFile;
8842 
8843  } catch (SQLException ex) {
8844  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
8845  } finally {
8846  closeResultSet(resultSet);
8847  closeStatement(statement);
8848 
8849  if (null != transaction) {
8850  try {
8851  transaction.rollback();
8852  } catch (TskCoreException ex2) {
8853  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8854  }
8855  }
8856  }
8857  }
8858 
8868  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
8869  if (content == null) {
8870  throw new TskCoreException("Null Content parameter given");
8871  }
8872  if (content instanceof AbstractFile) {
8873  return ((AbstractFile) content).getDataSourceObjectId();
8874  } else {
8875  return getDataSourceObjectId(connection, content.getId());
8876  }
8877  }
8878 
8891  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
8893  Statement statement = null;
8894  ResultSet resultSet = null;
8895  try {
8896  statement = connection.createStatement();
8897  long dataSourceObjId;
8898  long ancestorId = objectId;
8899  do {
8900  dataSourceObjId = ancestorId;
8901  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
8902  resultSet = statement.executeQuery(query);
8903  if (resultSet.next()) {
8904  ancestorId = resultSet.getLong("par_obj_id");
8905  } else {
8906  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
8907  }
8908  resultSet.close();
8909  resultSet = null;
8910  } while (0 != ancestorId); // Not NULL
8911  return dataSourceObjId;
8912  } catch (SQLException ex) {
8913  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
8914  } finally {
8915  closeResultSet(resultSet);
8916  closeStatement(statement);
8918  }
8919  }
8920 
8932  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8933  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
8934  statement.clearParameters();
8935  statement.setLong(1, objId);
8936  statement.setString(2, path);
8937  statement.setInt(3, type.getType());
8938  connection.executeUpdate(statement);
8939  }
8940 
8952  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8953  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
8954  statement.clearParameters();
8955  statement.setString(1, path);
8956  statement.setInt(2, type.getType());
8957  statement.setLong(3, objId);
8958  connection.executeUpdate(statement);
8959  }
8960 
8974  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
8975  String ext = "";
8976  if (!containsLikeWildcard(fileName)) {
8977  ext = SleuthkitCase.extractExtension(fileName);
8978  }
8979 
8980  CaseDbConnection connection = null;
8981  ResultSet rs = null;
8982  long parentId = parentFile.getId();
8983 
8985  try {
8986  connection = connections.getConnection();
8987 
8988  PreparedStatement statement;
8989  if (ext.isEmpty()) {
8990  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
8991  statement.clearParameters();
8992  statement.setLong(1, parentId);
8993  statement.setString(2, fileName);
8994  } else {
8995  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
8996  statement.clearParameters();
8997  statement.setString(1, ext);
8998  statement.setLong(2, parentId);
8999  statement.setString(3, fileName);
9000  }
9001 
9002  rs = connection.executeQuery(statement);
9003  return resultSetToAbstractFiles(rs, connection);
9004  } catch (SQLException ex) {
9005  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
9006  } finally {
9007  closeResultSet(rs);
9008  closeConnection(connection);
9010  }
9011  }
9012 
9024  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
9025  CaseDbConnection connection = null;
9026  Statement s = null;
9027  ResultSet rs = null;
9029  try {
9030  connection = connections.getConnection();
9031  s = connection.createStatement();
9032  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9033  rs.next();
9034  return rs.getLong("count");
9035  } catch (SQLException e) {
9036  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
9037  } finally {
9038  closeResultSet(rs);
9039  closeStatement(s);
9040  closeConnection(connection);
9042  }
9043  }
9044 
9062  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
9063  CaseDbConnection connection = null;
9064  Statement s = null;
9065  ResultSet rs = null;
9067  try {
9068  connection = connections.getConnection();
9069  s = connection.createStatement();
9070  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9071  return resultSetToAbstractFiles(rs, connection);
9072  } catch (SQLException e) {
9073  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
9074  } finally {
9075  closeResultSet(rs);
9076  closeStatement(s);
9077  closeConnection(connection);
9079  }
9080  }
9081 
9100  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
9101  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";
9103  try (CaseDbConnection connection = connections.getConnection()) {
9104  String query = String.format(queryTemplate, parentId, sqlWhereClause);
9105  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
9106  return resultSetToAbstractFiles(rs, connection);
9107  } catch (SQLException ex) {
9108  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
9109  }
9110  } finally {
9112  }
9113  }
9114 
9127  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
9128  CaseDbConnection connection = null;
9129  Statement s = null;
9130  ResultSet rs = null;
9132  try {
9133  connection = connections.getConnection();
9134  s = connection.createStatement();
9135  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9136  List<Long> ret = new ArrayList<>();
9137  while (rs.next()) {
9138  ret.add(rs.getLong("obj_id"));
9139  }
9140  return ret;
9141  } catch (SQLException e) {
9142  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
9143  } finally {
9144  closeResultSet(rs);
9145  closeStatement(s);
9146  closeConnection(connection);
9148  }
9149  }
9150 
9162  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
9163 
9164  // get the non-unique path (strip of image and volume path segments, if
9165  // the exist.
9166  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
9167 
9168  // split the file name from the parent path
9169  int lastSlash = path.lastIndexOf('/'); //NON-NLS
9170 
9171  // if the last slash is at the end, strip it off
9172  if (lastSlash == path.length()) {
9173  path = path.substring(0, lastSlash - 1);
9174  lastSlash = path.lastIndexOf('/'); //NON-NLS
9175  }
9176 
9177  String parentPath = path.substring(0, lastSlash);
9178  String fileName = path.substring(lastSlash);
9179 
9180  return findFiles(dataSource, fileName, parentPath);
9181  }
9182 
9193  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
9194  CaseDbConnection connection = null;
9195  Statement s = null;
9196  ResultSet rs = null;
9198  try {
9199  connection = connections.getConnection();
9200  s = connection.createStatement();
9201  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
9202  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
9203  while (rs.next()) {
9204  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
9205  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
9206  ranges.add(range);
9207  }
9208  return ranges;
9209  } catch (SQLException ex) {
9210  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
9211  } finally {
9212  closeResultSet(rs);
9213  closeStatement(s);
9214  closeConnection(connection);
9216  }
9217  }
9218 
9229  public Image getImageById(long id) throws TskCoreException {
9230  CaseDbConnection connection = null;
9231  Statement s = null;
9232  ResultSet rs = null;
9234  try {
9235  connection = connections.getConnection();
9236  s = connection.createStatement();
9237  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 "
9238  + "FROM tsk_image_info "
9239  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
9240  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
9241  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
9242 
9243  List<String> imagePaths = new ArrayList<>();
9244  long type, ssize, size;
9245  String tzone, md5, sha1, sha256, name, device_id, imagePath;
9246 
9247  if (rs.next()) {
9248  imagePath = rs.getString("name");
9249  if (imagePath != null) {
9250  imagePaths.add(imagePath);
9251  }
9252  type = rs.getLong("type"); //NON-NLS
9253  ssize = rs.getLong("ssize"); //NON-NLS
9254  tzone = rs.getString("tzone"); //NON-NLS
9255  size = rs.getLong("size"); //NON-NLS
9256  md5 = rs.getString("md5"); //NON-NLS
9257  sha1 = rs.getString("sha1"); //NON-NLS
9258  sha256 = rs.getString("sha256"); //NON-NLS
9259  name = rs.getString("display_name");
9260  if (name == null) {
9261  if (imagePaths.size() > 0) {
9262  String path = imagePaths.get(0);
9263  name = (new java.io.File(path)).getName();
9264  } else {
9265  name = "";
9266  }
9267  }
9268  device_id = rs.getString("device_id");
9269  } else {
9270  throw new TskCoreException("No image found for id: " + id);
9271  }
9272 
9273  // image can have multiple paths, therefore there can be multiple rows in the result set
9274  while (rs.next()) {
9275  imagePath = rs.getString("name");
9276  if (imagePath != null) {
9277  imagePaths.add(imagePath);
9278  }
9279  }
9280 
9281  return new Image(this, id, type, device_id, ssize, name,
9282  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
9283  } catch (SQLException ex) {
9284  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
9285  } finally {
9286  closeResultSet(rs);
9287  closeStatement(s);
9288  closeConnection(connection);
9290  }
9291  }
9292 
9304  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
9305  CaseDbConnection connection = null;
9306  Statement s = null;
9307  ResultSet rs = null;
9309  try {
9310  connection = connections.getConnection();
9311  s = connection.createStatement();
9312  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
9313  + "where obj_id = " + id); //NON-NLS
9314  if (rs.next()) {
9315  long type = rs.getLong("vs_type"); //NON-NLS
9316  long imgOffset = rs.getLong("img_offset"); //NON-NLS
9317  long blockSize = rs.getLong("block_size"); //NON-NLS
9318  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
9319  vs.setParent(parent);
9320  return vs;
9321  } else {
9322  throw new TskCoreException("No volume system found for id:" + id);
9323  }
9324  } catch (SQLException ex) {
9325  throw new TskCoreException("Error getting Volume System by ID.", ex);
9326  } finally {
9327  closeResultSet(rs);
9328  closeStatement(s);
9329  closeConnection(connection);
9331  }
9332  }
9333 
9342  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
9343  VolumeSystem vs = getVolumeSystemById(id, null);
9344  vs.setParentId(parentId);
9345  return vs;
9346  }
9347 
9359  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
9360  return getFileSystemByIdHelper(id, parent);
9361  }
9362 
9371  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
9372  Volume vol = null;
9373  FileSystem fs = getFileSystemById(id, vol);
9374  fs.setParentId(parentId);
9375  return fs;
9376  }
9377 
9389  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
9390  return getFileSystemByIdHelper(id, parent);
9391  }
9392 
9404  Pool getPoolById(long id, Content parent) throws TskCoreException {
9405  return getPoolByIdHelper(id, parent);
9406  }
9407 
9416  Pool getPoolById(long id, long parentId) throws TskCoreException {
9417  Pool pool = getPoolById(id, null);
9418  pool.setParentId(parentId);
9419  return pool;
9420  }
9421 
9433  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9434 
9436  try (CaseDbConnection connection = connections.getConnection();
9437  Statement s = connection.createStatement();
9438  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9439  + "where obj_id = " + id);) { //NON-NLS
9440  if (rs.next()) {
9441  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9442  pool.setParent(parent);
9443 
9444  return pool;
9445  } else {
9446  throw new TskCoreException("No pool found for ID:" + id);
9447  }
9448  } catch (SQLException ex) {
9449  throw new TskCoreException("Error getting Pool by ID", ex);
9450  } finally {
9452  }
9453  }
9454 
9466  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9467  // see if we already have it
9468  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9469  // but it should be the same...
9470  synchronized (fileSystemIdMap) {
9471  if (fileSystemIdMap.containsKey(id)) {
9472  return fileSystemIdMap.get(id);
9473  }
9474  }
9475  CaseDbConnection connection = null;
9476  Statement s = null;
9477  ResultSet rs = null;
9479  try {
9480  connection = connections.getConnection();
9481  s = connection.createStatement();
9482  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9483  + "where obj_id = " + id); //NON-NLS
9484  if (rs.next()) {
9485  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9486  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9487  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9488  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9489  fs.setParent(parent);
9490  // save it for the next call
9491  synchronized (fileSystemIdMap) {
9492  fileSystemIdMap.put(id, fs);
9493  }
9494  return fs;
9495  } else {
9496  throw new TskCoreException("No file system found for id:" + id);
9497  }
9498  } catch (SQLException ex) {
9499  throw new TskCoreException("Error getting File System by ID", ex);
9500  } finally {
9501  closeResultSet(rs);
9502  closeStatement(s);
9503  closeConnection(connection);
9505  }
9506  }
9507 
9519  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9520  CaseDbConnection connection = null;
9521  Statement s = null;
9522  ResultSet rs = null;
9524  try {
9525  connection = connections.getConnection();
9526  s = connection.createStatement();
9527  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9528  + "where obj_id = " + id); //NON-NLS
9529  if (rs.next()) {
9537  String description;
9538  try {
9539  description = rs.getString("desc");
9540  } catch (Exception ex) {
9541  description = rs.getString("descr");
9542  }
9543  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9544  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9545  description);
9546  vol.setParent(parent);
9547  return vol;
9548  } else {
9549  throw new TskCoreException("No volume found for id:" + id);
9550  }
9551  } catch (SQLException ex) {
9552  throw new TskCoreException("Error getting Volume by ID", ex);
9553  } finally {
9554  closeResultSet(rs);
9555  closeStatement(s);
9556  closeConnection(connection);
9558  }
9559  }
9560 
9569  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9570  Volume vol = getVolumeById(id, null);
9571  vol.setParentId(parentId);
9572  return vol;
9573  }
9574 
9586  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9587  CaseDbConnection connection = null;
9588  Statement s = null;
9589  ResultSet rs = null;
9591  try {
9592  connection = connections.getConnection();
9593  s = connection.createStatement();
9594  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9595  + "WHERE obj_id = " + id);
9596  Directory temp = null; //NON-NLS
9597  if (rs.next()) {
9598  final short type = rs.getShort("type"); //NON-NLS
9599  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9600  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9601  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9602  temp = directory(rs, parentFs);
9603  }
9604  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9605  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9606  }
9607  } else {
9608  throw new TskCoreException("No Directory found for id:" + id);
9609  }
9610  return temp;
9611  } catch (SQLException ex) {
9612  throw new TskCoreException("Error getting Directory by ID", ex);
9613  } finally {
9614  closeResultSet(rs);
9615  closeStatement(s);
9616  closeConnection(connection);
9618  }
9619  }
9620 
9630  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9631  List<FileSystem> fileSystems = new ArrayList<>();
9632  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9633 
9634  CaseDbConnection connection = null;
9635  Statement s = null;
9636  ResultSet rs = null;
9638  try {
9639  connection = connections.getConnection();
9640  s = connection.createStatement();
9641  rs = connection.executeQuery(s, queryStr); //NON-NLS
9642  while (rs.next()) {
9643  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9644  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9645  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9646  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9647  fs.setParent(null);
9648  fileSystems.add(fs);
9649  }
9650  } catch (SQLException ex) {
9651  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9652  } finally {
9653  closeResultSet(rs);
9654  closeStatement(s);
9655  closeConnection(connection);
9657  }
9658  return fileSystems;
9659  }
9660 
9671  List<Content> getImageChildren(Image img) throws TskCoreException {
9672  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9673  List<Content> children = new ArrayList<Content>();
9674  for (ObjectInfo info : childInfos) {
9675  if (null != info.type) {
9676  switch (info.type) {
9677  case VS:
9678  children.add(getVolumeSystemById(info.id, img));
9679  break;
9680  case POOL:
9681  children.add(getPoolById(info.id, img));
9682  break;
9683  case FS:
9684  children.add(getFileSystemById(info.id, img));
9685  break;
9686  case ABSTRACTFILE:
9687  AbstractFile f = getAbstractFileById(info.id);
9688  if (f != null) {
9689  children.add(f);
9690  }
9691  break;
9692  case ARTIFACT:
9693  BlackboardArtifact art = getArtifactById(info.id);
9694  if (art != null) {
9695  children.add(art);
9696  }
9697  break;
9698  case REPORT:
9699  // Do nothing for now - see JIRA-3673
9700  break;
9701  default:
9702  throw new TskCoreException("Image has child of invalid type: " + info.type);
9703  }
9704  }
9705  }
9706  return children;
9707  }
9708 
9719  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
9720  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9721  List<Long> children = new ArrayList<Long>();
9722  for (ObjectInfo info : childInfos) {
9723  if (info.type == ObjectType.VS
9724  || info.type == ObjectType.POOL
9725  || info.type == ObjectType.FS
9726  || info.type == ObjectType.ABSTRACTFILE
9727  || info.type == ObjectType.ARTIFACT) {
9728  children.add(info.id);
9729  } else if (info.type == ObjectType.REPORT) {
9730  // Do nothing for now - see JIRA-3673
9731  } else {
9732  throw new TskCoreException("Image has child of invalid type: " + info.type);
9733  }
9734  }
9735  return children;
9736  }
9737 
9748  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
9749  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9750  List<Content> children = new ArrayList<Content>();
9751  for (ObjectInfo info : childInfos) {
9752  if (null != info.type) {
9753  switch (info.type) {
9754  case VS:
9755  children.add(getVolumeSystemById(info.id, pool));
9756  break;
9757  case ABSTRACTFILE:
9758  AbstractFile f = getAbstractFileById(info.id);
9759  if (f != null) {
9760  children.add(f);
9761  }
9762  break;
9763  case ARTIFACT:
9764  BlackboardArtifact art = getArtifactById(info.id);
9765  if (art != null) {
9766  children.add(art);
9767  }
9768  break;
9769  default:
9770  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9771  }
9772  }
9773  }
9774  return children;
9775  }
9776 
9787  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
9788  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9789  List<Long> children = new ArrayList<Long>();
9790  for (ObjectInfo info : childInfos) {
9791  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9792  children.add(info.id);
9793  } else {
9794  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9795  }
9796  }
9797  return children;
9798  }
9799 
9810  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
9811  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9812  List<Content> children = new ArrayList<Content>();
9813  for (ObjectInfo info : childInfos) {
9814  if (null != info.type) {
9815  switch (info.type) {
9816  case VOL:
9817  children.add(getVolumeById(info.id, vs));
9818  break;
9819  case ABSTRACTFILE:
9820  AbstractFile f = getAbstractFileById(info.id);
9821  if (f != null) {
9822  children.add(f);
9823  }
9824  break;
9825  case ARTIFACT:
9826  BlackboardArtifact art = getArtifactById(info.id);
9827  if (art != null) {
9828  children.add(art);
9829  }
9830  break;
9831  default:
9832  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9833  }
9834  }
9835  }
9836  return children;
9837  }
9838 
9849  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
9850  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9851  List<Long> children = new ArrayList<Long>();
9852  for (ObjectInfo info : childInfos) {
9853  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9854  children.add(info.id);
9855  } else {
9856  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9857  }
9858  }
9859  return children;
9860  }
9861 
9872  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
9873  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9874  List<Content> children = new ArrayList<Content>();
9875  for (ObjectInfo info : childInfos) {
9876  if (null != info.type) {
9877  switch (info.type) {
9878  case POOL:
9879  children.add(getPoolById(info.id, vol));
9880  break;
9881  case FS:
9882  children.add(getFileSystemById(info.id, vol));
9883  break;
9884  case ABSTRACTFILE:
9885  AbstractFile f = getAbstractFileById(info.id);
9886  if (f != null) {
9887  children.add(f);
9888  }
9889  break;
9890  case ARTIFACT:
9891  BlackboardArtifact art = getArtifactById(info.id);
9892  if (art != null) {
9893  children.add(art);
9894  }
9895  break;
9896  default:
9897  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9898  }
9899  }
9900  }
9901  return children;
9902  }
9903 
9914  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
9915  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9916  final List<Long> children = new ArrayList<Long>();
9917  for (ObjectInfo info : childInfos) {
9918  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9919  children.add(info.id);
9920  } else {
9921  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9922  }
9923  }
9924  return children;
9925  }
9926 
9940  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
9941  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
9942  }
9943 
9958  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
9959  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this);
9960  return getImageById(imageId);
9961  }
9962 
9972  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
9973  CaseDbConnection connection = null;
9974  Statement s1 = null;
9975  ResultSet rs1 = null;
9977  try {
9978  connection = connections.getConnection();
9979  s1 = connection.createStatement();
9980  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
9981  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
9982  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
9983  while (rs1.next()) {
9984  long obj_id = rs1.getLong("obj_id"); //NON-NLS
9985  String name = rs1.getString("name"); //NON-NLS
9986  List<String> imagePaths = imgPaths.get(obj_id);
9987  if (imagePaths == null) {
9988  List<String> paths = new ArrayList<String>();
9989  if (name != null) {
9990  paths.add(name);
9991  }
9992  imgPaths.put(obj_id, paths);
9993  } else {
9994  if (name != null) {
9995  imagePaths.add(name);
9996  }
9997  }
9998  }
9999  return imgPaths;
10000  } catch (SQLException ex) {
10001  throw new TskCoreException("Error getting image paths.", ex);
10002  } finally {
10003  closeResultSet(rs1);
10004  closeStatement(s1);
10005  closeConnection(connection);
10007  }
10008  }
10009 
10021  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
10022  List<String> imagePaths = new ArrayList<>();
10024  Statement statement = null;
10025  ResultSet resultSet = null;
10026  try {
10027  statement = connection.createStatement();
10028  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
10029  while (resultSet.next()) {
10030  imagePaths.add(resultSet.getString("name"));
10031  }
10032  } catch (SQLException ex) {
10033  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
10034  } finally {
10035  closeResultSet(resultSet);
10036  closeStatement(statement);
10038  }
10039 
10040  return imagePaths;
10041  }
10042 
10049  public List<Image> getImages() throws TskCoreException {
10050  CaseDbConnection connection = null;
10051  Statement s = null;
10052  ResultSet rs = null;
10054  try {
10055  connection = connections.getConnection();
10056  s = connection.createStatement();
10057  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
10058  Collection<Long> imageIDs = new ArrayList<Long>();
10059  while (rs.next()) {
10060  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
10061  }
10062  List<Image> images = new ArrayList<Image>();
10063  for (long id : imageIDs) {
10064  images.add(getImageById(id));
10065  }
10066  return images;
10067  } catch (SQLException ex) {
10068  throw new TskCoreException("Error retrieving images.", ex);
10069  } finally {
10070  closeResultSet(rs);
10071  closeStatement(s);
10072  closeConnection(connection);
10074  }
10075  }
10076 
10087  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
10088  CaseDbTransaction transaction = beginTransaction();
10089  try {
10090  setImagePaths(obj_id, paths, transaction);
10091  transaction.commit();
10092  transaction = null;
10093  } finally {
10094  if (transaction != null) {
10095  transaction.rollback();
10096  }
10097  }
10098  }
10099 
10111  @Beta
10112  public void setImagePaths(long objId, List<String> paths, CaseDbTransaction trans) throws TskCoreException {
10113  try {
10114  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
10115  statement.clearParameters();
10116  statement.setLong(1, objId);
10117  trans.getConnection().executeUpdate(statement);
10118  for (int i = 0; i < paths.size(); i++) {
10119  statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
10120  statement.clearParameters();
10121  statement.setLong(1, objId);
10122  statement.setString(2, paths.get(i));
10123  statement.setLong(3, i);
10124  trans.getConnection().executeUpdate(statement);
10125  }
10126  } catch (SQLException ex) {
10127  throw new TskCoreException("Error updating image paths.", ex);
10128  }
10129  }
10130 
10131 
10143  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
10144 
10145  // Check if this data source is the only one associated with its host. If so,
10146  // we will delete the host and other associated data.
10147  // Note that the cascading deletes were only added in schema 9.1, so we
10148  // would get an error trying to delete a host from older cases.
10149  Host hostToDelete = null;
10151  int major = version.getMajor();
10152  int minor = version.getMinor();
10153  if (major > 9 || (major == 9 && minor >= 1)) {
10154  hostToDelete = getHostManager().getHostByDataSource(dataSourceObjectId);
10155  if (getHostManager().getDataSourcesForHost(hostToDelete).size() != 1) {
10156  hostToDelete = null;
10157  }
10158  }
10159 
10160  CaseDbConnection connection = null;
10161  Statement statement;
10163  try {
10164  connection = connections.getConnection();
10165  statement = connection.createStatement();
10166  connection.beginTransaction();
10167  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
10168  // all associated rows from tsk_object and its children. For large data sources this may take some time.
10169  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
10170  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
10171  // associated rows from accounts table and its children.
10172  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
10173  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
10174  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
10175  statement.execute(accountSql);
10176 
10177  // Now delete any host that was only associated with this data source. This will cascade to delete
10178  // realms, os accounts, and os account attributes that were associated with the host.
10179  if (hostToDelete != null) {
10180  statement.execute("DELETE FROM tsk_hosts WHERE id = " + hostToDelete.getHostId());
10181 
10182  // Clean up any stray OS Account objects
10183  String deleteOsAcctObjectsQuery = "DELETE FROM tsk_objects "
10184  + "WHERE type=" + TskData.ObjectType.OS_ACCOUNT.getObjectType() + " "
10185  + "AND obj_id NOT IN (SELECT os_account_obj_id FROM tsk_os_accounts WHERE os_account_obj_id IS NOT NULL)";
10186  statement.execute(deleteOsAcctObjectsQuery);
10187  }
10188 
10189  connection.commitTransaction();
10190  } catch (SQLException ex) {
10191  rollbackTransaction(connection);
10192  throw new TskCoreException("Error deleting data source.", ex);
10193  } finally {
10194  closeConnection(connection);
10196  }
10197  }
10198 
10224  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
10225  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
10226  try {
10227  while (rs.next()) {
10228  final short type = rs.getShort("type"); //NON-NLS
10229  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
10230  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
10231  FsContent result;
10232  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
10233  result = directory(rs, null);
10234  } else {
10235  result = file(rs, null);
10236  }
10237  results.add(result);
10238  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
10239  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
10240  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
10241  results.add(virtDir);
10242  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
10243  final LocalDirectory localDir = localDirectory(rs);
10244  results.add(localDir);
10245  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
10246  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
10247  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
10248  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
10249  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
10250  String parentPath = rs.getString("parent_path"); //NON-NLS
10251  if (parentPath == null) {
10252  parentPath = "/"; //NON-NLS
10253  }
10254 
10255  Long osAccountObjId = rs.getLong("os_account_obj_id");
10256  if (rs.wasNull()) {
10257  osAccountObjId = null;
10258  }
10259 
10260  LayoutFile lf = new LayoutFile(this,
10261  rs.getLong("obj_id"), //NON-NLS
10262  rs.getLong("data_source_obj_id"),
10263  rs.getLong("fs_obj_id"),
10264  rs.getString("name"), //NON-NLS
10265  atype,
10266  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10267  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10268  rs.getLong("size"), //NON-NLS
10269  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10270  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10271  FileKnown.valueOf(rs.getByte("known")), parentPath,
10272  rs.getString("mime_type"),
10273  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10274  results.add(lf);
10275  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
10276  final DerivedFile df;
10277  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
10278  results.add(df);
10279  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
10280  final LocalFile lf;
10281  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
10282  results.add(lf);
10283  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
10284  final SlackFile sf = slackFile(rs, null);
10285  results.add(sf);
10286  }
10287  } //end for each resultSet
10288  } catch (SQLException e) {
10289  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
10290  }
10291 
10292  return results;
10293  }
10294 
10295  // This following methods generate AbstractFile objects from a ResultSet
10307  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
10308  Long osAccountObjId = rs.getLong("os_account_obj_id");
10309  if (rs.wasNull()) {
10310  osAccountObjId = null;
10311  }
10312 
10313  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
10314  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10315  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10316  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10317  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10318  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10319  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10320  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10321  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10322  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10323  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10324  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10325  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"),
10326  osAccountObjId, TskData.CollectedStatus.valueOf(rs.getInt("collected")), Collections.emptyList()); //NON-NLS
10327  f.setFileSystem(fs);
10328  return f;
10329  }
10330 
10342  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
10343  Long osAccountObjId = rs.getLong("os_account_obj_id");
10344  if (rs.wasNull()) {
10345  osAccountObjId = null;
10346  }
10347 
10348  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10349  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10350  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10351  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10352  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10353  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10354  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10355  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10356  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10357  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10358  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10359  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10360  dir.setFileSystem(fs);
10361  return dir;
10362  }
10363 
10374  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
10375  String parentPath = rs.getString("parent_path"); //NON-NLS
10376  if (parentPath == null) {
10377  parentPath = "";
10378  }
10379 
10380  long objId = rs.getLong("obj_id");
10381  long dsObjId = rs.getLong("data_source_obj_id");
10382  if (objId == dsObjId) { // virtual directory is a data source
10383 
10384  String deviceId = "";
10385  String timeZone = "";
10386  Statement s = null;
10387  ResultSet rsDataSourceInfo = null;
10388 
10390  try {
10391  s = connection.createStatement();
10392  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
10393  if (rsDataSourceInfo.next()) {
10394  deviceId = rsDataSourceInfo.getString("device_id");
10395  timeZone = rsDataSourceInfo.getString("time_zone");
10396  }
10397  } catch (SQLException ex) {
10398  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
10399  } finally {
10400  closeResultSet(rsDataSourceInfo);
10401  closeStatement(s);
10403  }
10404 
10405  return new LocalFilesDataSource(this,
10406  objId, dsObjId,
10407  deviceId,
10408  rs.getString("name"),
10409  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10410  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10411  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
10412  rs.getShort("meta_flags"),
10413  timeZone,
10414  rs.getString("md5"),
10415  rs.getString("sha256"),
10416  rs.getString("sha1"),
10417  FileKnown.valueOf(rs.getByte("known")),
10418  parentPath);
10419  } else {
10420  final VirtualDirectory vd = new VirtualDirectory(this,
10421  objId, dsObjId,
10422  rs.getLong("fs_obj_id"),
10423  rs.getString("name"), //NON-NLS
10424  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10425  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10426  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10427  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10428  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10429  return vd;
10430  }
10431  }
10432 
10442  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
10443  String parentPath = rs.getString("parent_path"); //NON-NLS
10444  if (parentPath == null) {
10445  parentPath = "";
10446  }
10447  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
10448  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
10449  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10450  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10451  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10452  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10453  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10454  return ld;
10455  }
10456 
10470  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10471  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10472  long objId = rs.getLong("obj_id"); //NON-NLS
10473  String localPath = null;
10474  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10475  if (hasLocalPath) {
10476  ResultSet rsFilePath = null;
10478  try {
10479  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10480  statement.clearParameters();
10481  statement.setLong(1, objId);
10482  rsFilePath = connection.executeQuery(statement);
10483  if (rsFilePath.next()) {
10484  localPath = rsFilePath.getString("path");
10485  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10486  }
10487  } catch (SQLException ex) {
10488  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10489  } finally {
10490  closeResultSet(rsFilePath);
10492  }
10493  }
10494  String parentPath = rs.getString("parent_path"); //NON-NLS
10495  if (parentPath == null) {
10496  parentPath = "";
10497  }
10498 
10499  Long osAccountObjId = rs.getLong("os_account_obj_id");
10500  if (rs.wasNull()) {
10501  osAccountObjId = null;
10502  }
10503 
10504  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10505  rs.getLong("fs_obj_id"),
10506  rs.getString("name"), //NON-NLS
10507  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10508  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10509  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10510  rs.getLong("size"), //NON-NLS
10511  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10512  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10513  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10514  parentPath, localPath, parentId, rs.getString("mime_type"),
10515  encodingType, rs.getString("extension"),
10516  rs.getString("owner_uid"), osAccountObjId);
10517  return df;
10518  }
10519 
10533  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10534  long objId = rs.getLong("obj_id"); //NON-NLS
10535  String localPath = null;
10536  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10537  if (rs.getBoolean("has_path")) {
10538  ResultSet rsFilePath = null;
10540  try {
10541  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10542  statement.clearParameters();
10543  statement.setLong(1, objId);
10544  rsFilePath = connection.executeQuery(statement);
10545  if (rsFilePath.next()) {
10546  localPath = rsFilePath.getString("path");
10547  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10548  }
10549  } catch (SQLException ex) {
10550  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10551  } finally {
10552  closeResultSet(rsFilePath);
10554  }
10555  }
10556  String parentPath = rs.getString("parent_path"); //NON-NLS
10557  if (null == parentPath) {
10558  parentPath = "";
10559  }
10560  Long osAccountObjId = rs.getLong("os_account_obj_id");
10561  if (rs.wasNull()) {
10562  osAccountObjId = null;
10563  }
10564 
10565  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10566  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10567  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10568  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10569  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10570  rs.getLong("size"), //NON-NLS
10571  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10572  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10573  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10574  parentId, parentPath, rs.getLong("data_source_obj_id"),
10575  localPath, encodingType, rs.getString("extension"),
10576  rs.getString("owner_uid"), osAccountObjId);
10577  return file;
10578  }
10579 
10591  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10592  Long osAccountObjId = rs.getLong("os_account_obj_id");
10593  if (rs.wasNull()) {
10594  osAccountObjId = null;
10595  }
10596  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10597  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10598  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10599  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10600  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10601  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10602  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10603  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10604  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10605  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10606  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10607  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10608  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10609  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10610  f.setFileSystem(fs);
10611  return f;
10612  }
10613 
10625  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10626  List<Content> children = new ArrayList<Content>();
10627 
10628  while (rs.next()) {
10629  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10630 
10631  if (null != type) {
10632  switch (type) {
10633  case FS:
10634  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10635  FsContent result;
10636  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10637  result = directory(rs, null);
10638  } else {
10639  result = file(rs, null);
10640  }
10641  children.add(result);
10642  } else {
10643  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10644  children.add(virtDir);
10645  }
10646  break;
10647  case VIRTUAL_DIR:
10648  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10649  children.add(virtDir);
10650  break;
10651  case LOCAL_DIR:
10652  LocalDirectory localDir = localDirectory(rs);
10653  children.add(localDir);
10654  break;
10655  case UNALLOC_BLOCKS:
10656  case UNUSED_BLOCKS:
10657  case CARVED:
10658  case LAYOUT_FILE: {
10659  String parentPath = rs.getString("parent_path");
10660  if (parentPath == null) {
10661  parentPath = "";
10662  }
10663  Long osAccountObjId = rs.getLong("os_account_obj_id");
10664  if (rs.wasNull()) {
10665  osAccountObjId = null;
10666  }
10667  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
10668  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"),
10669  rs.getString("name"), type,
10670  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
10671  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
10672  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
10673  rs.getLong("size"),
10674  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
10675  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10676  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
10677  rs.getString("owner_uid"), osAccountObjId);
10678  children.add(lf);
10679  break;
10680  }
10681  case DERIVED:
10682  final DerivedFile df = derivedFile(rs, connection, parentId);
10683  children.add(df);
10684  break;
10685  case LOCAL: {
10686  final LocalFile lf = localFile(rs, connection, parentId);
10687  children.add(lf);
10688  break;
10689  }
10690  case SLACK: {
10691  final SlackFile sf = slackFile(rs, null);
10692  children.add(sf);
10693  break;
10694  }
10695  default:
10696  break;
10697  }
10698  }
10699  }
10700  return children;
10701  }
10702 
10724  public CaseDbQuery executeQuery(String query) throws TskCoreException {
10725  return new CaseDbQuery(query);
10726  }
10727 
10749  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
10750  return new CaseDbQuery(query, true);
10751  }
10752 
10760  CaseDbConnection getConnection() throws TskCoreException {
10761  return connections.getConnection();
10762  }
10763 
10771  String getCaseHandleIdentifier() {
10772  return caseHandleIdentifier;
10773  }
10774 
10775  @SuppressWarnings("deprecation")
10776  @Override
10777  protected void finalize() throws Throwable {
10778  try {
10779  close();
10780  } finally {
10781  super.finalize();
10782  }
10783  }
10784 
10788  public synchronized void close() {
10790 
10791  try {
10792  connections.close();
10793  } catch (TskCoreException ex) {
10794  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
10795  }
10796 
10797  fileSystemIdMap.clear();
10798 
10799  try {
10800  if (this.caseHandle != null) {
10801  this.caseHandle.free();
10802  this.caseHandle = null;
10803  }
10804  } catch (TskCoreException ex) {
10805  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
10806  } finally {
10808  }
10809  }
10810 
10823  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
10824  long id = file.getId();
10825  FileKnown currentKnown = file.getKnown();
10826  if (currentKnown.compareTo(fileKnown) > 0) {
10827  return false;
10828  }
10830  try (CaseDbConnection connection = connections.getConnection();
10831  Statement statement = connection.createStatement();) {
10832  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
10833  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
10834  + "WHERE obj_id=" + id); //NON-NLS
10835 
10836  file.setKnown(fileKnown);
10837  } catch (SQLException ex) {
10838  throw new TskCoreException("Error setting Known status.", ex);
10839  } finally {
10841  }
10842  return true;
10843  }
10844 
10853  void setFileName(String name, long objId) throws TskCoreException {
10855  try (CaseDbConnection connection = connections.getConnection();) {
10856  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
10857  preparedStatement.clearParameters();
10858  preparedStatement.setString(1, name);
10859  preparedStatement.setLong(2, objId);
10860  connection.executeUpdate(preparedStatement);
10861  } catch (SQLException ex) {
10862  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10863  } finally {
10865  }
10866  }
10867 
10876  void setImageName(String name, long objId) throws TskCoreException {
10878  try (CaseDbConnection connection = connections.getConnection();) {
10879  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
10880  preparedStatement.clearParameters();
10881  preparedStatement.setString(1, name);
10882  preparedStatement.setLong(2, objId);
10883  connection.executeUpdate(preparedStatement);
10884  } catch (SQLException ex) {
10885  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10886  } finally {
10888  }
10889  }
10890 
10905  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
10906 
10908  try (CaseDbConnection connection = connections.getConnection();) {
10909  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
10910  preparedStatement.clearParameters();
10911  preparedStatement.setLong(1, totalSize);
10912  preparedStatement.setLong(2, sectorSize);
10913  preparedStatement.setLong(3, image.getId());
10914  connection.executeUpdate(preparedStatement);
10915  } catch (SQLException ex) {
10916  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);
10917  } finally {
10919  }
10920  }
10921 
10931  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
10933  try (CaseDbConnection connection = connections.getConnection();
10934  Statement statement = connection.createStatement()) {
10935  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
10936  file.setMIMEType(mimeType);
10937  } catch (SQLException ex) {
10938  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
10939  } finally {
10941  }
10942  }
10943 
10954  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
10955 
10956  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
10957  short metaFlag = file.getMetaFlagsAsInt();
10958  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
10959  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
10960  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
10961 
10962  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
10963  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
10964 
10966  try (CaseDbConnection connection = connections.getConnection();
10967  Statement statement = connection.createStatement();) {
10968  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
10969 
10970  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
10971  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
10972 
10973  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
10974 
10975  } catch (SQLException ex) {
10976  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
10977  } finally {
10979  }
10980  }
10981 
10991  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
10992  if (md5Hash == null) {
10993  return;
10994  }
10995  long id = file.getId();
10997  try (CaseDbConnection connection = connections.getConnection();) {
10998  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
10999  statement.clearParameters();
11000  statement.setString(1, md5Hash.toLowerCase());
11001  statement.setLong(2, id);
11002  connection.executeUpdate(statement);
11003  file.setMd5Hash(md5Hash.toLowerCase());
11004  } catch (SQLException ex) {
11005  throw new TskCoreException("Error setting MD5 hash", ex);
11006  } finally {
11008  }
11009  }
11010 
11020  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
11021  if (md5Hash == null) {
11022  return;
11023  }
11024  long id = img.getId();
11026  try (CaseDbConnection connection = connections.getConnection();) {
11027  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
11028  statement.clearParameters();
11029  statement.setString(1, md5Hash.toLowerCase());
11030  statement.setLong(2, id);
11031  connection.executeUpdate(statement);
11032  } catch (SQLException ex) {
11033  throw new TskCoreException("Error setting MD5 hash", ex);
11034  } finally {
11036  }
11037  }
11038 
11049  String getMd5ImageHash(Image img) throws TskCoreException {
11050  long id = img.getId();
11051  CaseDbConnection connection = null;
11052  ResultSet rs = null;
11053  String hash = "";
11055  try {
11056  connection = connections.getConnection();
11057 
11058  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
11059  statement.clearParameters();
11060  statement.setLong(1, id);
11061  rs = connection.executeQuery(statement);
11062  if (rs.next()) {
11063  hash = rs.getString("md5");
11064  }
11065  return hash;
11066  } catch (SQLException ex) {
11067  throw new TskCoreException("Error getting MD5 hash", ex);
11068  } finally {
11069  closeResultSet(rs);
11070  closeConnection(connection);
11072  }
11073  }
11074 
11084  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
11085  if (sha1Hash == null) {
11086  return;
11087  }
11088  long id = img.getId();
11090  try (CaseDbConnection connection = connections.getConnection();) {
11091  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
11092  statement.clearParameters();
11093  statement.setString(1, sha1Hash.toLowerCase());
11094  statement.setLong(2, id);
11095  connection.executeUpdate(statement);
11096  } catch (SQLException ex) {
11097  throw new TskCoreException("Error setting SHA1 hash", ex);
11098  } finally {
11100  }
11101  }
11102 
11113  String getSha1ImageHash(Image img) throws TskCoreException {
11114  long id = img.getId();
11115  CaseDbConnection connection = null;
11116  ResultSet rs = null;
11117  String hash = "";
11119  try {
11120  connection = connections.getConnection();
11121 
11122  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
11123  statement.clearParameters();
11124  statement.setLong(1, id);
11125  rs = connection.executeQuery(statement);
11126  if (rs.next()) {
11127  hash = rs.getString("sha1");
11128  }
11129  return hash;
11130  } catch (SQLException ex) {
11131  throw new TskCoreException("Error getting SHA1 hash", ex);
11132  } finally {
11133  closeResultSet(rs);
11134  closeConnection(connection);
11136  }
11137  }
11138 
11148  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
11149  if (sha256Hash == null) {
11150  return;
11151  }
11152  long id = img.getId();
11154  try (CaseDbConnection connection = connections.getConnection();) {
11155  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
11156  statement.clearParameters();
11157  statement.setString(1, sha256Hash.toLowerCase());
11158  statement.setLong(2, id);
11159  connection.executeUpdate(statement);
11160  } catch (SQLException ex) {
11161  throw new TskCoreException("Error setting SHA256 hash", ex);
11162  } finally {
11164  }
11165  }
11166 
11177  String getSha256ImageHash(Image img) throws TskCoreException {
11178  long id = img.getId();
11179  CaseDbConnection connection = null;
11180  ResultSet rs = null;
11181  String hash = "";
11183  try {
11184  connection = connections.getConnection();
11185 
11186  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
11187  statement.clearParameters();
11188  statement.setLong(1, id);
11189  rs = connection.executeQuery(statement);
11190  if (rs.next()) {
11191  hash = rs.getString("sha256");
11192  }
11193  return hash;
11194  } catch (SQLException ex) {
11195  throw new TskCoreException("Error setting SHA256 hash", ex);
11196  } finally {
11197  closeResultSet(rs);
11198  closeConnection(connection);
11200  }
11201  }
11202 
11211  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
11212 
11213  long id = datasource.getId();
11215  try (CaseDbConnection connection = connections.getConnection();) {
11216  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11217  statement.clearParameters();
11218  statement.setString(1, details);
11219  statement.setLong(2, id);
11220  connection.executeUpdate(statement);
11221  } catch (SQLException ex) {
11222  throw new TskCoreException("Error setting acquisition details", ex);
11223  } finally {
11225  }
11226  }
11227 
11239  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
11240 
11241  long id = datasource.getId();
11243  try (CaseDbConnection connection = connections.getConnection();) {
11244  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
11245  statement.clearParameters();
11246  statement.setString(1, settings);
11247  statement.setString(2, name);
11248  statement.setString(3, version);
11249  statement.setLong(4, id);
11250  connection.executeUpdate(statement);
11251  } catch (SQLException ex) {
11252  throw new TskCoreException("Error setting acquisition details", ex);
11253  } finally {
11255  }
11256  }
11257 
11267  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
11268  try {
11269  CaseDbConnection connection = trans.getConnection();
11270  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11271  statement.clearParameters();
11272  statement.setString(1, details);
11273  statement.setLong(2, dataSourceId);
11274  connection.executeUpdate(statement);
11275  } catch (SQLException ex) {
11276  throw new TskCoreException("Error setting acquisition details", ex);
11277  }
11278  }
11279 
11289  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
11290  long id = datasource.getId();
11291  CaseDbConnection connection = null;
11292  ResultSet rs = null;
11293  String hash = "";
11295  try {
11296  connection = connections.getConnection();
11297 
11298  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
11299  statement.clearParameters();
11300  statement.setLong(1, id);
11301  rs = connection.executeQuery(statement);
11302  if (rs.next()) {
11303  hash = rs.getString("acquisition_details");
11304  }
11305  return hash;
11306  } catch (SQLException ex) {
11307  throw new TskCoreException("Error setting acquisition details", ex);
11308  } finally {
11309  closeResultSet(rs);
11310  closeConnection(connection);
11312  }
11313  }
11314 
11325  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
11326  long id = datasource.getId();
11327  CaseDbConnection connection = null;
11328  ResultSet rs = null;
11329  String returnValue = "";
11331  try {
11332  connection = connections.getConnection();
11333 
11334  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11335  statement.clearParameters();
11336  statement.setLong(1, id);
11337  rs = connection.executeQuery(statement);
11338  if (rs.next()) {
11339  returnValue = rs.getString(columnName);
11340  }
11341  return returnValue;
11342  } catch (SQLException ex) {
11343  throw new TskCoreException("Error setting acquisition details", ex);
11344  } finally {
11345  closeResultSet(rs);
11346  closeConnection(connection);
11348  }
11349  }
11350 
11361  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
11362  long id = datasource.getId();
11363  CaseDbConnection connection = null;
11364  ResultSet rs = null;
11365  Long returnValue = null;
11367  try {
11368  connection = connections.getConnection();
11369 
11370  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11371  statement.clearParameters();
11372  statement.setLong(1, id);
11373  rs = connection.executeQuery(statement);
11374  if (rs.next()) {
11375  returnValue = rs.getLong(columnName);
11376  }
11377  return returnValue;
11378  } catch (SQLException ex) {
11379  throw new TskCoreException("Error setting acquisition details", ex);
11380  } finally {
11381  closeResultSet(rs);
11382  closeConnection(connection);
11384  }
11385  }
11386 
11397  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
11398  if (newStatus == null) {
11399  return;
11400  }
11402  try (CaseDbConnection connection = connections.getConnection();
11403  Statement statement = connection.createStatement();) {
11404  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
11405  + " SET review_status_id=" + newStatus.getID()
11406  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
11407  } catch (SQLException ex) {
11408  throw new TskCoreException("Error setting review status", ex);
11409  } finally {
11411  }
11412  }
11413 
11424  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
11425  CaseDbConnection connection = null;
11426  Statement s = null;
11427  ResultSet rs = null;
11429  try {
11430  connection = connections.getConnection();
11431  s = connection.createStatement();
11432  Short contentShort = contentType.getValue();
11433  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
11434  int count = 0;
11435  if (rs.next()) {
11436  count = rs.getInt("count");
11437  }
11438  return count;
11439  } catch (SQLException ex) {
11440  throw new TskCoreException("Error getting number of objects.", ex);
11441  } finally {
11442  closeResultSet(rs);
11443  closeStatement(s);
11444  closeConnection(connection);
11446  }
11447  }
11448 
11457  public static String escapeSingleQuotes(String text) {
11458  String escapedText = null;
11459  if (text != null) {
11460  escapedText = text.replaceAll("'", "''");
11461  }
11462  return escapedText;
11463  }
11464 
11472  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11473  if (md5Hash == null) {
11474  return Collections.<AbstractFile>emptyList();
11475  }
11476 
11477  CaseDbConnection connection = null;
11478  Statement s = null;
11479  ResultSet rs = null;
11481  try {
11482  connection = connections.getConnection();
11483  s = connection.createStatement();
11484  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11485  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11486  + "AND size > 0"); //NON-NLS
11487  return resultSetToAbstractFiles(rs, connection);
11488  } catch (SQLException | TskCoreException ex) {
11489  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11490  } finally {
11491  closeResultSet(rs);
11492  closeStatement(s);
11493  closeConnection(connection);
11495  }
11496  return Collections.<AbstractFile>emptyList();
11497  }
11498 
11505  public boolean allFilesMd5Hashed() {
11506  boolean allFilesAreHashed = false;
11507 
11508  CaseDbConnection connection = null;
11509  Statement s = null;
11510  ResultSet rs = null;
11512  try {
11513  connection = connections.getConnection();
11514  s = connection.createStatement();
11515  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11516  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11517  + "AND md5 IS NULL " //NON-NLS
11518  + "AND size > '0'"); //NON-NLS
11519  if (rs.next() && rs.getInt("count") == 0) {
11520  allFilesAreHashed = true;
11521  }
11522  } catch (SQLException | TskCoreException ex) {
11523  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11524  } finally {
11525  closeResultSet(rs);
11526  closeStatement(s);
11527  closeConnection(connection);
11529  }
11530  return allFilesAreHashed;
11531  }
11532 
11538  public int countFilesMd5Hashed() {
11539  int count = 0;
11540 
11542  CaseDbConnection connection = null;
11543  Statement s = null;
11544  ResultSet rs = null;
11545  try {
11546  connection = connections.getConnection();
11547  s = connection.createStatement();
11548  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11549  + "WHERE md5 IS NOT NULL " //NON-NLS
11550  + "AND size > '0'"); //NON-NLS
11551  if (rs.next()) {
11552  count = rs.getInt("count");
11553  }
11554  } catch (SQLException | TskCoreException ex) {
11555  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11556  } finally {
11557  closeResultSet(rs);
11558  closeStatement(s);
11559  closeConnection(connection);
11561  }
11562  return count;
11563 
11564  }
11565 
11574  public List<TagName> getAllTagNames() throws TskCoreException {
11575  CaseDbConnection connection = null;
11576  ResultSet resultSet = null;
11578  try {
11579  connection = connections.getConnection();
11580 
11581  // SELECT * FROM tag_names
11582  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11583  resultSet = connection.executeQuery(statement);
11584  ArrayList<TagName> tagNames = new ArrayList<>();
11585  while (resultSet.next()) {
11586  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11587  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11588  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11589  }
11590  return tagNames;
11591  } catch (SQLException ex) {
11592  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11593  } finally {
11594  closeResultSet(resultSet);
11595  closeConnection(connection);
11597  }
11598  }
11599 
11610  public List<TagName> getTagNamesInUse() throws TskCoreException {
11611  CaseDbConnection connection = null;
11612  ResultSet resultSet = null;
11614  try {
11615  connection = connections.getConnection();
11616 
11617  // 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)
11618  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
11619  resultSet = connection.executeQuery(statement);
11620  ArrayList<TagName> tagNames = new ArrayList<>();
11621  while (resultSet.next()) {
11622  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11623  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11624  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11625  }
11626  return tagNames;
11627  } catch (SQLException ex) {
11628  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11629  } finally {
11630  closeResultSet(resultSet);
11631  closeConnection(connection);
11633  }
11634  }
11635 
11648  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
11649 
11650  ArrayList<TagName> tagNames = new ArrayList<>();
11651  // SELECT * FROM tag_names WHERE tag_name_id IN
11652  // ( 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 = ? "
11653  // UNION
11654  // 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 = ? )
11655  // )
11656  CaseDbConnection connection = null;
11657  ResultSet resultSet = null;
11659  try {
11660  connection = connections.getConnection();
11661 
11662  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
11663  statement.setLong(1, dsObjId);
11664  statement.setLong(2, dsObjId);
11665  resultSet = connection.executeQuery(statement); //NON-NLS
11666  while (resultSet.next()) {
11667  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11668  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11669  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11670  }
11671  return tagNames;
11672  } catch (SQLException ex) {
11673  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
11674  } finally {
11675  closeResultSet(resultSet);
11676  closeConnection(connection);
11678  }
11679  }
11680 
11694  @Deprecated
11695  @SuppressWarnings("deprecation")
11696  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
11697  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
11698  }
11699 
11716  @Deprecated
11717  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
11718  return getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
11719  }
11720 
11735  @Deprecated
11736  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
11737  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
11738  }
11739 
11740  /*
11741  * Deletes a row from the content_tags table in the case database. @param
11742  * tag A ContentTag data transfer object (DTO) for the row to delete.
11743  * @throws TskCoreException
11744  */
11745  public void deleteContentTag(ContentTag tag) throws TskCoreException {
11747  try {
11748  // DELETE FROM content_tags WHERE tag_id = ?
11749  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
11750  statement.clearParameters();
11751  statement.setLong(1, tag.getId());
11752  trans.getConnection().executeUpdate(statement);
11753 
11754  // update the aggregate score for the content
11755  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
11756  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11757  ? tag.getContent().getDataSource().getId()
11758  : null;
11759 
11760  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
11761 
11762  trans.commit();
11763  trans = null;
11764  } catch (SQLException ex) {
11765  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
11766  } finally {
11767  if (trans != null) {
11768  trans.rollback();
11769  }
11770  }
11771  }
11772 
11781  public List<ContentTag> getAllContentTags() throws TskCoreException {
11782  CaseDbConnection connection = null;
11783  ResultSet resultSet = null;
11785  try {
11786  connection = connections.getConnection();
11787 
11788  // 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
11789  // FROM content_tags
11790  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11791  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11792  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
11793  resultSet = connection.executeQuery(statement);
11794  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11795  while (resultSet.next()) {
11796  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11797  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11798  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11799  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
11800  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
11801  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
11802  }
11803  return tags;
11804  } catch (SQLException ex) {
11805  throw new TskCoreException("Error selecting rows from content_tags table", ex);
11806  } finally {
11807  closeResultSet(resultSet);
11808  closeConnection(connection);
11810  }
11811  }
11812 
11823  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
11824  if (tagName.getId() == Tag.ID_NOT_SET) {
11825  throw new TskCoreException("TagName object is invalid, id not set");
11826  }
11827  CaseDbConnection connection = null;
11828  ResultSet resultSet = null;
11830  try {
11831  connection = connections.getConnection();
11832 
11833  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
11834  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
11835  statement.clearParameters();
11836  statement.setLong(1, tagName.getId());
11837  resultSet = connection.executeQuery(statement);
11838  if (resultSet.next()) {
11839  return resultSet.getLong("count");
11840  } else {
11841  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11842  }
11843  } catch (SQLException ex) {
11844  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11845  } finally {
11846  closeResultSet(resultSet);
11847  closeConnection(connection);
11849  }
11850  }
11851 
11867  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11868 
11869  if (tagName.getId() == Tag.ID_NOT_SET) {
11870  throw new TskCoreException("TagName object is invalid, id not set");
11871  }
11872 
11873  CaseDbConnection connection = null;
11874  ResultSet resultSet = null;
11876  try {
11877  connection = connections.getConnection();
11878 
11879  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11880  // + " AND content_tags.tag_name_id = ? "
11881  // + " AND tsk_files.data_source_obj_id = ? "
11882  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11883  statement.clearParameters();
11884  statement.setLong(1, tagName.getId());
11885  statement.setLong(2, dsObjId);
11886 
11887  resultSet = connection.executeQuery(statement);
11888  if (resultSet.next()) {
11889  return resultSet.getLong("count");
11890  } else {
11891  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11892  }
11893  } catch (SQLException ex) {
11894  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11895  } finally {
11896  closeResultSet(resultSet);
11897  closeConnection(connection);
11899  }
11900  }
11901 
11912  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
11913 
11914  CaseDbConnection connection = null;
11915  ResultSet resultSet = null;
11916  ContentTag tag = null;
11918  try {
11919  connection = connections.getConnection();
11920 
11921  // 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
11922  // FROM content_tags
11923  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11924  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11925  // WHERE tag_id = ?
11926  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
11927  statement.clearParameters();
11928  statement.setLong(1, contentTagID);
11929  resultSet = connection.executeQuery(statement);
11930 
11931  while (resultSet.next()) {
11932  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11933  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11934  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11935  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
11936  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
11937  }
11938  resultSet.close();
11939 
11940  } catch (SQLException ex) {
11941  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
11942  } finally {
11943  closeResultSet(resultSet);
11944  closeConnection(connection);
11946  }
11947  return tag;
11948  }
11949 
11961  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
11962  if (tagName.getId() == Tag.ID_NOT_SET) {
11963  throw new TskCoreException("TagName object is invalid, id not set");
11964  }
11965  CaseDbConnection connection = null;
11966  ResultSet resultSet = null;
11968  try {
11969  connection = connections.getConnection();
11970 
11971  // 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
11972  // FROM content_tags
11973  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11974  // WHERE tag_name_id = ?
11975  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
11976  statement.clearParameters();
11977  statement.setLong(1, tagName.getId());
11978  resultSet = connection.executeQuery(statement);
11979  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11980  while (resultSet.next()) {
11981  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11982  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11983  tags.add(tag);
11984  }
11985  resultSet.close();
11986  return tags;
11987  } catch (SQLException ex) {
11988  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
11989  } finally {
11990  closeResultSet(resultSet);
11991  closeConnection(connection);
11993  }
11994  }
11995 
12010  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12011 
12012  CaseDbConnection connection = null;
12013  ResultSet resultSet = null;
12015  try {
12016  connection = connections.getConnection();
12017 
12018  // NOTE: Getting all content tags by tag name for a given data source includes
12019  // looking up all Content objects that have entries in tsk_files, as well as
12020  // all OsAccounts. OsAccounts do not have corresponding entries in tsk_files so we
12021  // have to do a separate query to look them up, and then do a UNION of the results.
12022 
12023 // "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, tag_names.tag_set_id, tsk_examiners.login_name "
12024 // + "FROM content_tags "
12025 // + "JOIN tsk_os_accounts acc ON content_tags.obj_id = acc.os_account_obj_id "
12026 // + "JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12027 // + "JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12028 // + "WHERE content_tags.tag_name_id = ? "
12029 // + "AND acc.os_account_obj_id IN (SELECT os_account_obj_id FROM tsk_os_account_instances WHERE data_source_obj_id = ?) "
12030 // + "AND acc.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
12031 // + " UNION "
12032 // + "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, tag_names.tag_set_id, tsk_examiners.login_name "
12033 // + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
12034 // + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id "
12035 // + "AND content_tags.obj_id = tsk_files.obj_id "
12036 // + "AND content_tags.tag_name_id = tag_names.tag_name_id "
12037 // + "AND content_tags.tag_name_id = ? "
12038 // + "AND tsk_files.data_source_obj_id = ? "
12039 
12040  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12041  statement.clearParameters();
12042  statement.setLong(1, tagName.getId());
12043  statement.setLong(2, dsObjId);
12044  statement.setLong(3, tagName.getId());
12045  statement.setLong(4, dsObjId);
12046  resultSet = connection.executeQuery(statement);
12047  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12048  while (resultSet.next()) {
12049  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
12050  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12051  tags.add(tag);
12052  }
12053  resultSet.close();
12054  return tags;
12055  } catch (SQLException ex) {
12056  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
12057  } finally {
12058  closeResultSet(resultSet);
12059  closeConnection(connection);
12061  }
12062  }
12063 
12075  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
12076  CaseDbConnection connection = null;
12077  ResultSet resultSet = null;
12079  try {
12080  connection = connections.getConnection();
12081 
12082  // 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
12083  // FROM content_tags
12084  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
12085  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12086  // WHERE content_tags.obj_id = ?
12087  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
12088  statement.clearParameters();
12089  statement.setLong(1, content.getId());
12090  resultSet = connection.executeQuery(statement);
12091  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12092  while (resultSet.next()) {
12093  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12094  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12095  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12096  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
12097  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12098  tags.add(tag);
12099  }
12100  return tags;
12101  } catch (SQLException ex) {
12102  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
12103  } finally {
12104  closeResultSet(resultSet);
12105  closeConnection(connection);
12107  }
12108  }
12109 
12124  @Deprecated
12125  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
12126  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
12127  }
12128 
12129  /*
12130  * Deletes a row from the blackboard_artifact_tags table in the case
12131  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
12132  * representing the row to delete. @throws TskCoreException
12133  */
12134  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
12136  try {
12137  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
12138  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
12139  statement.clearParameters();
12140  statement.setLong(1, tag.getId());
12141  trans.getConnection().executeUpdate(statement);
12142 
12143  // update the aggregate score for the artifact
12144  Long artifactObjId = tag.getArtifact().getId();
12145  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
12146  ? tag.getContent().getDataSource().getId()
12147  : null;
12148 
12149  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
12150 
12151  trans.commit();
12152  trans = null;
12153  } catch (SQLException ex) {
12154  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
12155  } finally {
12156  if (trans != null) {
12157  trans.rollback();
12158  }
12159  }
12160  }
12161 
12171  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
12172  CaseDbConnection connection = null;
12173  ResultSet resultSet = null;
12175  try {
12176  connection = connections.getConnection();
12177 
12178  // 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
12179  // FROM blackboard_artifact_tags
12180  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12181  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12182  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
12183  resultSet = connection.executeQuery(statement);
12184  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12185  while (resultSet.next()) {
12186  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12187  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12188  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12189  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12190  Content content = getContentById(artifact.getObjectID());
12191  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12192  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12193  tags.add(tag);
12194  }
12195  return tags;
12196  } catch (SQLException ex) {
12197  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
12198  } finally {
12199  closeResultSet(resultSet);
12200  closeConnection(connection);
12202  }
12203  }
12204 
12215  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
12216  if (tagName.getId() == Tag.ID_NOT_SET) {
12217  throw new TskCoreException("TagName object is invalid, id not set");
12218  }
12219  CaseDbConnection connection = null;
12220  ResultSet resultSet = null;
12222  try {
12223  connection = connections.getConnection();
12224 
12225  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
12226  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
12227  statement.clearParameters();
12228  statement.setLong(1, tagName.getId());
12229  resultSet = connection.executeQuery(statement);
12230  if (resultSet.next()) {
12231  return resultSet.getLong("count");
12232  } else {
12233  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
12234  }
12235  } catch (SQLException ex) {
12236  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
12237  } finally {
12238  closeResultSet(resultSet);
12239  closeConnection(connection);
12241  }
12242  }
12243 
12258  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12259 
12260  if (tagName.getId() == Tag.ID_NOT_SET) {
12261  throw new TskCoreException("TagName object is invalid, id not set");
12262  }
12263 
12264  CaseDbConnection connection = null;
12265  ResultSet resultSet = null;
12267  try {
12268  connection = connections.getConnection();
12269 
12270  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
12271  // + " AND artifact_tags.tag_name_id = ?"
12272  // + " AND arts.data_source_obj_id = ? "
12273  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
12274  statement.clearParameters();
12275  statement.setLong(1, tagName.getId());
12276  statement.setLong(2, dsObjId);
12277  resultSet = connection.executeQuery(statement);
12278  if (resultSet.next()) {
12279  return resultSet.getLong("count");
12280  } else {
12281  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
12282  }
12283  } catch (SQLException ex) {
12284  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12285  } finally {
12286  closeResultSet(resultSet);
12287  closeConnection(connection);
12289  }
12290  }
12291 
12303  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
12304  if (tagName.getId() == Tag.ID_NOT_SET) {
12305  throw new TskCoreException("TagName object is invalid, id not set");
12306  }
12307  CaseDbConnection connection = null;
12308  ResultSet resultSet = null;
12310  try {
12311  connection = connections.getConnection();
12312 
12313  // 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
12314  // FROM blackboard_artifact_tags
12315  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12316  // WHERE tag_name_id = ?
12317  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
12318  statement.clearParameters();
12319  statement.setLong(1, tagName.getId());
12320  resultSet = connection.executeQuery(statement);
12321  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12322  while (resultSet.next()) {
12323  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12324  Content content = getContentById(artifact.getObjectID());
12325  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12326  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12327  tags.add(tag);
12328  }
12329  return tags;
12330  } catch (SQLException ex) {
12331  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
12332  } finally {
12333  closeResultSet(resultSet);
12334  closeConnection(connection);
12336  }
12337  }
12338 
12353  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12354 
12355  if (tagName.getId() == Tag.ID_NOT_SET) {
12356  throw new TskCoreException("TagName object is invalid, id not set");
12357  }
12358 
12359  CaseDbConnection connection = null;
12360  ResultSet resultSet = null;
12362  try {
12363  connection = connections.getConnection();
12364 
12365  // 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
12366  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
12367  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
12368  // WHERE artifact_tags.artifact_id = arts.artifact_id
12369  // AND artifact_tags.tag_name_id = ?
12370  // AND arts.data_source_obj_id = ?
12371  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12372  statement.clearParameters();
12373  statement.setLong(1, tagName.getId());
12374  statement.setLong(2, dsObjId);
12375  resultSet = connection.executeQuery(statement);
12376  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12377  while (resultSet.next()) {
12378  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12379  Content content = getContentById(artifact.getObjectID());
12380  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12381  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12382  tags.add(tag);
12383  }
12384  return tags;
12385  } catch (SQLException ex) {
12386  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12387  } finally {
12388  closeResultSet(resultSet);
12389  closeConnection(connection);
12391  }
12392 
12393  }
12394 
12406  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
12407 
12408  CaseDbConnection connection = null;
12409  ResultSet resultSet = null;
12410  BlackboardArtifactTag tag = null;
12412  try {
12413  connection = connections.getConnection();
12414 
12415  //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
12416  // FROM blackboard_artifact_tags
12417  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12418  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12419  // WHERE blackboard_artifact_tags.tag_id = ?
12420  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
12421  statement.clearParameters();
12422  statement.setLong(1, artifactTagID);
12423  resultSet = connection.executeQuery(statement);
12424 
12425  while (resultSet.next()) {
12426  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12427  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12428  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12429  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12430  Content content = getContentById(artifact.getObjectID());
12431  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12432  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
12433  }
12434  resultSet.close();
12435 
12436  } catch (SQLException ex) {
12437  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12438  } finally {
12439  closeResultSet(resultSet);
12440  closeConnection(connection);
12442  }
12443  return tag;
12444  }
12445 
12458  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12459  CaseDbConnection connection = null;
12460  ResultSet resultSet = null;
12462  try {
12463  connection = connections.getConnection();
12464 
12465  // 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
12466  // FROM blackboard_artifact_tags
12467  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12468  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12469  // WHERE blackboard_artifact_tags.artifact_id = ?
12470  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12471  statement.clearParameters();
12472  statement.setLong(1, artifact.getArtifactID());
12473  resultSet = connection.executeQuery(statement);
12474  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12475  while (resultSet.next()) {
12476  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12477  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12478  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12479  Content content = getContentById(artifact.getObjectID());
12480  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12481  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12482  tags.add(tag);
12483  }
12484  return tags;
12485  } catch (SQLException ex) {
12486  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12487  } finally {
12488  closeResultSet(resultSet);
12489  closeConnection(connection);
12491  }
12492  }
12493 
12502  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12504  try (CaseDbConnection connection = connections.getConnection();) {
12505  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12506  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12507  statement.clearParameters();
12508  statement.setString(1, newPath);
12509  statement.setLong(2, objectId);
12510  connection.executeUpdate(statement);
12511  } catch (SQLException ex) {
12512  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12513  } finally {
12515  }
12516  }
12517 
12531  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12532  return addReport(localPath, sourceModuleName, reportName, null);
12533  }
12534 
12550  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12551  // Make sure the local path of the report is in the database directory
12552  // or one of its subdirectories.
12553  String relativePath = ""; //NON-NLS
12554  long createTime = 0;
12555  String localPathLower = localPath.toLowerCase();
12556 
12557  if (localPathLower.startsWith("http")) {
12558  relativePath = localPathLower;
12559  createTime = System.currentTimeMillis() / 1000;
12560  } else {
12561  /*
12562  * Note: The following call to .relativize() may be dangerous in
12563  * case-sensitive operating systems and should be looked at. For
12564  * now, we are simply relativizing the paths as all lower case, then
12565  * using the length of the result to pull out the appropriate number
12566  * of characters from the localPath String.
12567  */
12568  try {
12569  String casePathLower = getDbDirPath().toLowerCase();
12570  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12571  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12572  } catch (IllegalArgumentException ex) {
12573  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12574  throw new TskCoreException(errorMessage, ex);
12575  }
12576  try {
12577  // get its file time
12578  java.io.File tempFile = new java.io.File(localPath);
12579  // Convert to UNIX epoch (seconds, not milliseconds).
12580  createTime = tempFile.lastModified() / 1000;
12581  } catch (Exception ex) {
12582  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12583  }
12584  }
12585 
12586  // Write the report data to the database.
12588  try (CaseDbConnection connection = connections.getConnection();) {
12589  // Insert a row for the report into the tsk_objects table.
12590  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12591  long parentObjId = 0;
12592  if (parent != null) {
12593  parentObjId = parent.getId();
12594  }
12595  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
12596 
12597  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
12598  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
12599  statement.clearParameters();
12600  statement.setLong(1, objectId);
12601  statement.setString(2, relativePath);
12602  statement.setLong(3, createTime);
12603  statement.setString(4, sourceModuleName);
12604  statement.setString(5, reportName);
12605  connection.executeUpdate(statement);
12606  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
12607  } catch (SQLException ex) {
12608  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
12609  } finally {
12611  }
12612  }
12613 
12622  public List<Report> getAllReports() throws TskCoreException {
12623  CaseDbConnection connection = null;
12624  ResultSet resultSet = null;
12625  ResultSet parentResultSet = null;
12626  PreparedStatement statement = null;
12627  Statement parentStatement = null;
12629  try {
12630  connection = connections.getConnection();
12631 
12632  // SELECT * FROM reports
12633  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
12634  parentStatement = connection.createStatement();
12635  resultSet = connection.executeQuery(statement);
12636  ArrayList<Report> reports = new ArrayList<Report>();
12637  while (resultSet.next()) {
12638  String localpath = resultSet.getString("path");
12639  if (localpath.toLowerCase().startsWith("http") == false) {
12640  // make path absolute
12641  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
12642  }
12643 
12644  // get the report parent
12645  Content parent = null;
12646  long reportId = resultSet.getLong("obj_id"); // NON-NLS
12647  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
12648  parentResultSet = parentStatement.executeQuery(parentQuery);
12649  if (parentResultSet.next()) {
12650  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12651  parent = this.getContentById(parentId);
12652  }
12653  parentResultSet.close();
12654 
12655  reports.add(new Report(this,
12656  reportId,
12657  localpath,
12658  resultSet.getLong("crtime"), //NON-NLS
12659  resultSet.getString("src_module_name"), //NON-NLS
12660  resultSet.getString("report_name"),
12661  parent)); //NON-NLS
12662  }
12663  return reports;
12664  } catch (SQLException ex) {
12665  throw new TskCoreException("Error querying reports table", ex);
12666  } finally {
12667  closeResultSet(resultSet);
12668  closeResultSet(parentResultSet);
12669  closeStatement(statement);
12670  closeStatement(parentStatement);
12671 
12672  closeConnection(connection);
12674  }
12675  }
12676 
12686  public Report getReportById(long id) throws TskCoreException {
12687  CaseDbConnection connection = null;
12688  PreparedStatement statement = null;
12689  Statement parentStatement = null;
12690  ResultSet resultSet = null;
12691  ResultSet parentResultSet = null;
12692  Report report = null;
12694  try {
12695  connection = connections.getConnection();
12696 
12697  // SELECT * FROM reports WHERE obj_id = ?
12698  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
12699  parentStatement = connection.createStatement();
12700  statement.clearParameters();
12701  statement.setLong(1, id);
12702  resultSet = connection.executeQuery(statement);
12703 
12704  if (resultSet.next()) {
12705  // get the report parent
12706  Content parent = null;
12707  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
12708  parentResultSet = parentStatement.executeQuery(parentQuery);
12709  if (parentResultSet.next()) {
12710  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12711  parent = this.getContentById(parentId);
12712  }
12713 
12714  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
12715  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
12716  resultSet.getLong("crtime"), //NON-NLS
12717  resultSet.getString("src_module_name"), //NON-NLS
12718  resultSet.getString("report_name"),
12719  parent); //NON-NLS
12720  } else {
12721  throw new TskCoreException("No report found for id: " + id);
12722  }
12723  } catch (SQLException ex) {
12724  throw new TskCoreException("Error querying reports table for id: " + id, ex);
12725  } finally {
12726  closeResultSet(resultSet);
12727  closeResultSet(parentResultSet);
12728  closeStatement(statement);
12729  closeStatement(parentStatement);
12730  closeConnection(connection);
12732  }
12733 
12734  return report;
12735  }
12736 
12744  public void deleteReport(Report report) throws TskCoreException {
12746  try (CaseDbConnection connection = connections.getConnection();) {
12747  // DELETE FROM reports WHERE reports.obj_id = ?
12748  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
12749  statement.setLong(1, report.getId());
12750  connection.executeUpdate(statement);
12751  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
12752  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
12753  statement.setLong(1, report.getId());
12754  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
12755  connection.executeUpdate(statement);
12756  } catch (SQLException ex) {
12757  throw new TskCoreException("Error querying reports table", ex);
12758  } finally {
12760  }
12761  }
12762 
12763  static void closeResultSet(ResultSet resultSet) {
12764  if (resultSet != null) {
12765  try {
12766  resultSet.close();
12767  } catch (SQLException ex) {
12768  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
12769  }
12770  }
12771  }
12772 
12773  static void closeStatement(Statement statement) {
12774  if (statement != null) {
12775  try {
12776  statement.close();
12777  } catch (SQLException ex) {
12778  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
12779 
12780  }
12781  }
12782  }
12783 
12784  static void closeConnection(CaseDbConnection connection) {
12785  if (connection != null) {
12786  connection.close();
12787  }
12788  }
12789 
12790  private static void rollbackTransaction(CaseDbConnection connection) {
12791  if (connection != null) {
12792  connection.rollbackTransaction();
12793  }
12794  }
12795 
12804  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
12806  try (CaseDbConnection connection = connections.getConnection();) {
12807  Statement statement = connection.createStatement();
12808  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
12809  } catch (SQLException ex) {
12810  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
12811  } finally {
12813  }
12814  }
12815 
12816  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
12818  try (CaseDbConnection connection = connections.getConnection();
12819  Statement statement = connection.createStatement();) {
12820  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
12821  } catch (SQLException ex) {
12822  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
12823  } finally {
12825  }
12826  }
12827 
12844  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
12845  CaseDbConnection connection = null;
12847  ResultSet resultSet = null;
12848  Statement statement;
12849  try {
12850  connection = connections.getConnection();
12851  connection.beginTransaction();
12852  statement = connection.createStatement();
12853  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
12854  insertStatement.setLong(1, dataSource.getId());
12855  insertStatement.setString(2, hostName);
12856  insertStatement.setLong(3, jobStart.getTime());
12857  insertStatement.setLong(4, jobEnd.getTime());
12858  insertStatement.setInt(5, status.ordinal());
12859  insertStatement.setString(6, settingsDir);
12860  connection.executeUpdate(insertStatement);
12861  resultSet = insertStatement.getGeneratedKeys();
12862  resultSet.next();
12863  long id = resultSet.getLong(1); //last_insert_rowid()
12864  for (int i = 0; i < ingestModules.size(); i++) {
12865  IngestModuleInfo ingestModule = ingestModules.get(i);
12866  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
12867  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
12868  }
12869  resultSet.close();
12870  resultSet = null;
12871  connection.commitTransaction();
12872  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
12873  } catch (SQLException ex) {
12874  rollbackTransaction(connection);
12875  throw new TskCoreException("Error adding the ingest job.", ex);
12876  } finally {
12877  closeResultSet(resultSet);
12878  closeConnection(connection);
12880  }
12881  }
12882 
12896  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
12897  CaseDbConnection connection = null;
12898  ResultSet resultSet = null;
12899  Statement statement = null;
12900  String uniqueName = factoryClassName + "-" + displayName + "-" + version;
12902  try {
12903  connection = connections.getConnection();
12904  statement = connection.createStatement();
12905  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12906  if (!resultSet.next()) {
12907  resultSet.close();
12908  resultSet = null;
12909  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
12910  insertStatement.setString(1, displayName);
12911  insertStatement.setString(2, uniqueName);
12912  insertStatement.setInt(3, type.ordinal());
12913  insertStatement.setString(4, version);
12914  connection.executeUpdate(insertStatement);
12915  resultSet = statement.getGeneratedKeys();
12916  resultSet.next();
12917  long id = resultSet.getLong(1); //last_insert_rowid()
12918  resultSet.close();
12919  resultSet = null;
12920  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
12921  } else {
12922  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12923  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12924  }
12925  } catch (SQLException ex) {
12926  try {
12927  closeStatement(statement);
12928  if (connection != null) {
12929  statement = connection.createStatement();
12930  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12931  if (resultSet.next()) {
12932  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12933  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12934  }
12935  }
12936  throw new TskCoreException("Couldn't add new module to database.", ex);
12937  } catch (SQLException ex1) {
12938  throw new TskCoreException("Couldn't add new module to database.", ex1);
12939  }
12940  } finally {
12941  closeResultSet(resultSet);
12942  closeStatement(statement);
12943  closeConnection(connection);
12945  }
12946  }
12947 
12955  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
12956  CaseDbConnection connection = null;
12957  ResultSet resultSet = null;
12958  Statement statement = null;
12959  List<IngestJobInfo> ingestJobs = new ArrayList<>();
12961  try {
12962  connection = connections.getConnection();
12963  statement = connection.createStatement();
12964  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
12965  while (resultSet.next()) {
12966  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
12967  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
12968  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
12969  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
12970  }
12971  return ingestJobs;
12972  } catch (SQLException ex) {
12973  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
12974  } finally {
12975  closeResultSet(resultSet);
12976  closeStatement(statement);
12977  closeConnection(connection);
12979  }
12980  }
12981 
12992  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
12993  ResultSet resultSet = null;
12994  Statement statement = null;
12995  List<IngestModuleInfo> ingestModules = new ArrayList<>();
12997  try {
12998  statement = connection.createStatement();
12999  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
13000  + "ingest_job_modules.pipeline_position AS pipeline_position, "
13001  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
13002  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
13003  + "FROM ingest_job_modules, ingest_modules "
13004  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
13005  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
13006  + "ORDER BY (ingest_job_modules.pipeline_position);");
13007  while (resultSet.next()) {
13008  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
13009  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
13010  }
13011  return ingestModules;
13012  } finally {
13013  closeResultSet(resultSet);
13014  closeStatement(statement);
13016 
13017  }
13018  }
13019 
13029  String getInsertOrIgnoreSQL(String sql) {
13030  switch (getDatabaseType()) {
13031  case POSTGRESQL:
13032  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
13033  case SQLITE:
13034  return " INSERT OR IGNORE " + sql; //NON-NLS
13035  default:
13036  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
13037  }
13038  }
13039 
13060  private List<? extends BlackboardArtifact> getArtifactsForValues(BlackboardArtifact.Category category, String dbColumn, List<? extends Number> values, CaseDbConnection connection) throws TskCoreException {
13061  String where = "";
13062  // This look creates the OR statment with the following format:
13063  // <dbColumn> = <value> OR <dbColumn> = <value2> OR ...
13064  for (Number value : values) {
13065  if (!where.isEmpty()) {
13066  where += " OR ";
13067  }
13068  where += dbColumn + " = " + value;
13069  }
13070 
13071  // Base on the category pass the OR statement to the approprate method
13072  // that will retrieve the artifacts.
13073  if (category == BlackboardArtifact.Category.DATA_ARTIFACT) {
13074  return blackboard.getDataArtifactsWhere(where, connection);
13075  } else {
13076  return blackboard.getAnalysisResultsWhere(where, connection);
13077  }
13078  }
13079 
13083  static class ObjectInfo {
13084 
13085  private long id;
13086  private TskData.ObjectType type;
13087 
13088  ObjectInfo(long id, ObjectType type) {
13089  this.id = id;
13090  this.type = type;
13091  }
13092 
13093  long getId() {
13094  return id;
13095  }
13096 
13097  TskData.ObjectType getType() {
13098  return type;
13099  }
13100  }
13101 
13102  private interface DbCommand {
13103 
13104  void execute() throws SQLException;
13105  }
13106 
13107  private enum PREPARED_STATEMENT {
13108 
13109  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
13110  + "WHERE artifact_type_id = ?"), //NON-NLS
13111  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
13112  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
13113  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
13114  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
13115  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
13116  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13117  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13118  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
13119  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
13120  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
13121  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13122  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13123  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
13124  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13125  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13126  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13127  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13128  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
13129  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13130  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13131  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13132  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13133  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13134  + "WHERE tsk_files.extension = ? AND "
13135  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
13136  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13137  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13138  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13139  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13140  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13141  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
13142  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13143  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13144  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13145  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
13146  + "AND tsk_files.type = ? )"), //NON-NLS
13147  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
13148  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13149  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13150  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
13151  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
13152  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13153  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
13154  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13155  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
13156  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13157  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
13158  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13159  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
13160  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13161  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
13162  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13163  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
13164  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13165  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
13166  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13167  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
13168  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
13169  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
13170  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
13171  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
13172  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
13173  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13174  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13175  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
13176  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
13177  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13178  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13179  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13180  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
13181  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
13182  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
13183  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
13184  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
13185  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
13186  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
13187  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13188  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13189  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
13190  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
13191  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
13192  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
13193  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
13194  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
13195  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)"
13196  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
13197  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
13198  + "WHERE obj_id = ?"), //NON-NLS
13199  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
13200  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13201  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
13202  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
13203  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
13204  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
13205  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
13206  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
13207  + "WHERE tag_name_id IN " //NON-NLS
13208  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
13209  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
13210  + "WHERE tag_name_id IN "
13211  + "( SELECT content_tags.tag_name_id as tag_name_id "
13212  + "FROM content_tags as content_tags, tsk_files as tsk_files"
13213  + " WHERE content_tags.obj_id = tsk_files.obj_id"
13214  + " AND tsk_files.data_source_obj_id = ?"
13215  + " UNION "
13216  + "SELECT artifact_tags.tag_name_id as tag_name_id "
13217  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
13218  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
13219  + " AND arts.data_source_obj_id = ?"
13220  + " )"),
13221  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
13222  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13223  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
13224  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
13225  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
13226  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
13227  + " AND content_tags.tag_name_id = ? "
13228  + " AND tsk_files.data_source_obj_id = ? "
13229  ),
13230  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 "
13231  + "FROM content_tags "
13232  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13233  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13234  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 "
13235  + "FROM content_tags "
13236  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13237  + "WHERE tag_name_id = ?"), //NON-NLS
13238  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, tag_names.tag_set_id, tsk_examiners.login_name "
13239  + "FROM content_tags "
13240  + "JOIN tsk_os_accounts acc ON content_tags.obj_id = acc.os_account_obj_id "
13241  + "JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13242  + "JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13243  + "WHERE content_tags.tag_name_id = ? "
13244  + "AND acc.os_account_obj_id IN (SELECT os_account_obj_id FROM tsk_os_account_instances WHERE data_source_obj_id = ?) "
13245  + "AND acc.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
13246  + " UNION "
13247  + "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, tag_names.tag_set_id, tsk_examiners.login_name "
13248  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
13249  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id "
13250  + "AND content_tags.obj_id = tsk_files.obj_id "
13251  + "AND content_tags.tag_name_id = tag_names.tag_name_id "
13252  + "AND content_tags.tag_name_id = ? "
13253  + "AND tsk_files.data_source_obj_id = ? "), //NON-NLS
13254  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 "
13255  + "FROM content_tags "
13256  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13257  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13258  + "WHERE tag_id = ?"), //NON-NLS
13259  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 "
13260  + "FROM content_tags "
13261  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13262  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13263  + "WHERE content_tags.obj_id = ?"), //NON-NLS
13264  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
13265  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13266  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
13267  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 "
13268  + "FROM blackboard_artifact_tags "
13269  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13270  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13271  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
13272  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"
13273  + " AND artifact_tags.tag_name_id = ?"
13274  + " AND arts.data_source_obj_id = ? "),
13275  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 "
13276  + "FROM blackboard_artifact_tags "
13277  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13278  + "WHERE tag_name_id = ?"), //NON-NLS
13279  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 "
13280  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
13281  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
13282  + " AND artifact_tags.artifact_id = arts.artifact_id"
13283  + " AND artifact_tags.tag_name_id = ? "
13284  + " AND arts.data_source_obj_id = ? "),
13285  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 "
13286  + "FROM blackboard_artifact_tags "
13287  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13288  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13289  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
13290  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 "
13291  + "FROM blackboard_artifact_tags "
13292  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13293  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13294  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
13295  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
13296  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
13297  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
13298  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
13299  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
13300  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13301  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
13302  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
13303  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
13304  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
13305  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
13306  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
13307  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
13308  + "WHERE (tsk_objects.par_obj_id = ?)"),
13309  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
13310  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
13311  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
13312  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
13313  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
13314  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
13315  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
13316  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
13317  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
13318  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
13319  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13320  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"),
13321  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
13322  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13323  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13324  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
13325  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)"
13326  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13327  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?");
13328 
13329  private final String sql;
13330 
13331  private PREPARED_STATEMENT(String sql) {
13332  this.sql = sql;
13333  }
13334 
13335  String getSQL() {
13336  return sql;
13337  }
13338  }
13339 
13345  abstract private class ConnectionPool {
13346 
13347  private PooledDataSource pooledDataSource;
13348 
13349  public ConnectionPool() {
13350  pooledDataSource = null;
13351  }
13352 
13353  CaseDbConnection getConnection() throws TskCoreException {
13354  if (pooledDataSource == null) {
13355  throw new TskCoreException("Error getting case database connection - case is closed");
13356  }
13357  try {
13358  return getPooledConnection();
13359  } catch (SQLException exp) {
13360  throw new TskCoreException(exp.getMessage());
13361  }
13362  }
13363 
13364  void close() throws TskCoreException {
13365  if (pooledDataSource != null) {
13366  try {
13367  pooledDataSource.close();
13368  } catch (SQLException exp) {
13369  throw new TskCoreException(exp.getMessage());
13370  } finally {
13371  pooledDataSource = null;
13372  }
13373  }
13374  }
13375 
13376  abstract CaseDbConnection getPooledConnection() throws SQLException;
13377 
13378  public PooledDataSource getPooledDataSource() {
13379  return pooledDataSource;
13380  }
13381 
13382  public void setPooledDataSource(PooledDataSource pooledDataSource) {
13383  this.pooledDataSource = pooledDataSource;
13384  }
13385  }
13386 
13391  private final class SQLiteConnections extends ConnectionPool {
13392 
13393  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
13394 
13395  SQLiteConnections(String dbPath) throws SQLException {
13396  configurationOverrides.put("acquireIncrement", "2");
13397  configurationOverrides.put("initialPoolSize", "5");
13398  configurationOverrides.put("minPoolSize", "5");
13399  /*
13400  * NOTE: max pool size and max statements are related. If you
13401  * increase max pool size, then also increase statements.
13402  */
13403  configurationOverrides.put("maxPoolSize", "20");
13404  configurationOverrides.put("maxStatements", "200");
13405  configurationOverrides.put("maxStatementsPerConnection", "20");
13406 
13407  SQLiteConfig config = new SQLiteConfig();
13408  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
13409  config.setReadUncommitted(true);
13410  config.enforceForeignKeys(true); // Enforce foreign key constraints.
13411  SQLiteDataSource unpooled = new SQLiteDataSource(config);
13412  unpooled.setUrl("jdbc:sqlite:" + dbPath);
13413  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
13414  }
13415 
13416  @Override
13417  public CaseDbConnection getPooledConnection() throws SQLException {
13418  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
13419  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
13420  // Temporarily filter out Image Gallery threads
13421  if (!Thread.currentThread().getName().contains("ImageGallery")) {
13422  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());
13423  }
13424  }
13425  return new SQLiteConnection(getPooledDataSource().getConnection());
13426  }
13427  }
13428 
13433  private final class PostgreSQLConnections extends ConnectionPool {
13434 
13435  PostgreSQLConnections(CaseDbConnectionInfo info, String dbName) throws PropertyVetoException, UnsupportedEncodingException {
13436 
13437  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
13438  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
13439 
13440  String connectionURL = "jdbc:postgresql://" + info.getHost() + ":" + Integer.valueOf(info.getPort()) + "/"
13441  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString());
13442  if (info.isSslEnabled()) {
13443  if (info.isSslVerify()) {
13444  if (info.getCustomSslValidationClassName().isBlank()) {
13445  connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL;
13446  } else {
13447  // use custom SSL certificate validation class
13448  connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName());
13449  }
13450  } else {
13451  connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL;
13452  }
13453  }
13454  comboPooledDataSource.setJdbcUrl(connectionURL);
13455  comboPooledDataSource.setUser(info.getUserName());
13456  comboPooledDataSource.setPassword(info.getPassword());
13457  comboPooledDataSource.setAcquireIncrement(2);
13458  comboPooledDataSource.setInitialPoolSize(5);
13459  comboPooledDataSource.setMinPoolSize(5);
13460  /*
13461  * NOTE: max pool size and max statements are related. If you
13462  * increase max pool size, then also increase statements.
13463  */
13464  comboPooledDataSource.setMaxPoolSize(20);
13465  comboPooledDataSource.setMaxStatements(200);
13466  comboPooledDataSource.setMaxStatementsPerConnection(20);
13467  setPooledDataSource(comboPooledDataSource);
13468  }
13469 
13470  @Override
13471  public CaseDbConnection getPooledConnection() throws SQLException {
13472  return new PostgreSQLConnection(getPooledDataSource().getConnection());
13473  }
13474  }
13475 
13479  abstract class CaseDbConnection implements AutoCloseable {
13480 
13481  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
13482  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
13483 
13484  private class CreateStatement implements DbCommand {
13485 
13486  private final Connection connection;
13487  private Statement statement = null;
13488 
13489  CreateStatement(Connection connection) {
13490  this.connection = connection;
13491  }
13492 
13493  Statement getStatement() {
13494  return statement;
13495  }
13496 
13497  @Override
13498  public void execute() throws SQLException {
13499  statement = connection.createStatement();
13500  }
13501  }
13502 
13503  private class SetAutoCommit implements DbCommand {
13504 
13505  private final Connection connection;
13506  private final boolean mode;
13507 
13508  SetAutoCommit(Connection connection, boolean mode) {
13509  this.connection = connection;
13510  this.mode = mode;
13511  }
13512 
13513  @Override
13514  public void execute() throws SQLException {
13515  connection.setAutoCommit(mode);
13516  }
13517  }
13518 
13519  private class Commit implements DbCommand {
13520 
13521  private final Connection connection;
13522 
13523  Commit(Connection connection) {
13524  this.connection = connection;
13525  }
13526 
13527  @Override
13528  public void execute() throws SQLException {
13529  connection.commit();
13530  }
13531  }
13532 
13541  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13542 
13543  private final Connection connection;
13544 
13545  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13546  this.connection = connection;
13547  }
13548 
13549  @Override
13550  public void execute() throws SQLException {
13551  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13552  preparedStatement.execute();
13553 
13554  }
13555  }
13556 
13557  private class ExecuteQuery implements DbCommand {
13558 
13559  private final Statement statement;
13560  private final String query;
13561  private ResultSet resultSet;
13562 
13563  ExecuteQuery(Statement statement, String query) {
13564  this.statement = statement;
13565  this.query = query;
13566  }
13567 
13568  ResultSet getResultSet() {
13569  return resultSet;
13570  }
13571 
13572  @Override
13573  public void execute() throws SQLException {
13574  resultSet = statement.executeQuery(query);
13575  }
13576  }
13577 
13578  private class ExecutePreparedStatementQuery implements DbCommand {
13579 
13580  private final PreparedStatement preparedStatement;
13581  private ResultSet resultSet;
13582 
13583  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13584  this.preparedStatement = preparedStatement;
13585  }
13586 
13587  ResultSet getResultSet() {
13588  return resultSet;
13589  }
13590 
13591  @Override
13592  public void execute() throws SQLException {
13593  resultSet = preparedStatement.executeQuery();
13594  }
13595  }
13596 
13597  private class ExecutePreparedStatementUpdate implements DbCommand {
13598 
13599  private final PreparedStatement preparedStatement;
13600 
13601  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
13602  this.preparedStatement = preparedStatement;
13603  }
13604 
13605  @Override
13606  public void execute() throws SQLException {
13607  preparedStatement.executeUpdate();
13608  }
13609  }
13610 
13611  private class ExecuteStatementUpdate implements DbCommand {
13612 
13613  private final Statement statement;
13614  private final String updateCommand;
13615 
13616  ExecuteStatementUpdate(Statement statement, String updateCommand) {
13617  this.statement = statement;
13618  this.updateCommand = updateCommand;
13619  }
13620 
13621  @Override
13622  public void execute() throws SQLException {
13623  statement.executeUpdate(updateCommand);
13624  }
13625  }
13626 
13627  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
13628 
13629  private final Statement statement;
13630  private final int generateKeys;
13631  private final String updateCommand;
13632 
13633  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
13634  this.statement = statement;
13635  this.generateKeys = generateKeys;
13636  this.updateCommand = updateCommand;
13637  }
13638 
13639  @Override
13640  public void execute() throws SQLException {
13641  statement.executeUpdate(updateCommand, generateKeys);
13642  }
13643  }
13644 
13645  private class PrepareStatement implements DbCommand {
13646 
13647  private final Connection connection;
13648  private final String input;
13649  private PreparedStatement preparedStatement = null;
13650 
13651  PrepareStatement(Connection connection, String input) {
13652  this.connection = connection;
13653  this.input = input;
13654  }
13655 
13656  PreparedStatement getPreparedStatement() {
13657  return preparedStatement;
13658  }
13659 
13660  @Override
13661  public void execute() throws SQLException {
13662  preparedStatement = connection.prepareStatement(input);
13663  }
13664  }
13665 
13666  private class PrepareStatementGenerateKeys implements DbCommand {
13667 
13668  private final Connection connection;
13669  private final String input;
13670  private final int generateKeys;
13671  private PreparedStatement preparedStatement = null;
13672 
13673  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
13674  this.connection = connection;
13675  this.input = input;
13676  this.generateKeys = generateKeysInput;
13677  }
13678 
13679  PreparedStatement getPreparedStatement() {
13680  return preparedStatement;
13681  }
13682 
13683  @Override
13684  public void execute() throws SQLException {
13685  preparedStatement = connection.prepareStatement(input, generateKeys);
13686  }
13687  }
13688 
13689  abstract void executeCommand(DbCommand command) throws SQLException;
13690 
13691  private final Connection connection;
13692  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
13693  private final Map<String, PreparedStatement> adHocPreparedStatements;
13694 
13695  CaseDbConnection(Connection connection) {
13696  this.connection = connection;
13697  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
13698  adHocPreparedStatements = new HashMap<>();
13699  }
13700 
13701  boolean isOpen() {
13702  return this.connection != null;
13703  }
13704 
13705  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
13706  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
13707  }
13708 
13709  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
13710  // Lazy statement preparation.
13711  PreparedStatement statement;
13712  if (this.preparedStatements.containsKey(statementKey)) {
13713  statement = this.preparedStatements.get(statementKey);
13714  } else {
13715  statement = prepareStatement(statementKey.getSQL(), generateKeys);
13716  this.preparedStatements.put(statementKey, statement);
13717  }
13718  return statement;
13719  }
13720 
13732  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
13733  PreparedStatement statement;
13734  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
13735  if (adHocPreparedStatements.containsKey(statementKey) && !adHocPreparedStatements.get(statementKey).isClosed()) {
13736  statement = this.adHocPreparedStatements.get(statementKey);
13737  } else {
13738  statement = prepareStatement(sqlStatement, generateKeys);
13739  this.adHocPreparedStatements.put(statementKey, statement);
13740  }
13741  return statement;
13742  }
13743 
13744  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13745  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
13746  executeCommand(prepareStatement);
13747  return prepareStatement.getPreparedStatement();
13748  }
13749 
13750  Statement createStatement() throws SQLException {
13751  CreateStatement createStatement = new CreateStatement(this.connection);
13752  executeCommand(createStatement);
13753  return createStatement.getStatement();
13754  }
13755 
13756  void beginTransaction() throws SQLException {
13757  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
13758  executeCommand(setAutoCommit);
13759  }
13760 
13761  void commitTransaction() throws SQLException {
13762  Commit commit = new Commit(connection);
13763  executeCommand(commit);
13764  // You must turn auto commit back on when done with the transaction.
13765  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
13766  executeCommand(setAutoCommit);
13767  }
13768 
13774  void rollbackTransaction() {
13775  try {
13776  connection.rollback();
13777  } catch (SQLException e) {
13778  logger.log(Level.SEVERE, "Error rolling back transaction", e);
13779  }
13780  try {
13781  connection.setAutoCommit(true);
13782  } catch (SQLException e) {
13783  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
13784  }
13785  }
13786 
13794  void rollbackTransactionWithThrow() throws SQLException {
13795  try {
13796  connection.rollback();
13797  } finally {
13798  connection.setAutoCommit(true);
13799  }
13800  }
13801 
13810  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
13811  switch (getDatabaseType()) {
13812  case POSTGRESQL:
13813  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
13814  executeCommand(tableWriteLock);
13815  break;
13816  case SQLITE:
13817  // We do nothing here because we assume the entire SQLite DB is already locked from
13818  // when the analysis results were added/deleted in the same transaction.
13819  break;
13820  default:
13821  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
13822  }
13823  }
13824 
13825  ResultSet executeQuery(Statement statement, String query) throws SQLException {
13826  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
13827  executeCommand(queryCommand);
13828  return queryCommand.getResultSet();
13829  }
13830 
13840  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
13841  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
13842  executeCommand(executePreparedStatementQuery);
13843  return executePreparedStatementQuery.getResultSet();
13844  }
13845 
13846  void executeUpdate(Statement statement, String update) throws SQLException {
13847  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
13848  }
13849 
13850  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13851  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
13852  executeCommand(executeStatementUpdate);
13853  }
13854 
13855  void executeUpdate(PreparedStatement statement) throws SQLException {
13856  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
13857  executeCommand(executePreparedStatementUpdate);
13858  }
13859 
13863  @Override
13864  public void close() {
13865  try {
13866  for (PreparedStatement stmt : preparedStatements.values()) {
13867  closeStatement(stmt);
13868  }
13869  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
13870  closeStatement(stmt);
13871  }
13872  connection.close();
13873  } catch (SQLException ex) {
13874  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
13875  }
13876  }
13877 
13878  Connection getConnection() {
13879  return this.connection;
13880  }
13881  }
13882 
13886  private final class SQLiteConnection extends CaseDbConnection {
13887 
13888  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
13889  private static final int SQLITE_BUSY_ERROR = 5;
13890 
13891  SQLiteConnection(Connection conn) {
13892  super(conn);
13893  }
13894 
13895  @Override
13896  void executeCommand(DbCommand command) throws SQLException {
13897  int retryCounter = 0;
13898  while (true) {
13899  try {
13900  command.execute(); // Perform the operation
13901  break;
13902  } catch (SQLException ex) {
13903  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
13904  try {
13905 
13906  // We do not notify of error here, as this is not an
13907  // error condition. It is likely a temporary busy or
13908  // locked issue and we will retry.
13909  retryCounter++;
13910  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13911  } catch (InterruptedException exp) {
13912  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13913  }
13914  } else {
13915  throw ex;
13916  }
13917  }
13918  }
13919  }
13920  }
13921 
13925  private final class PostgreSQLConnection extends CaseDbConnection {
13926 
13927  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
13928  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
13929  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
13930  private static final int MAX_RETRIES = 3;
13931 
13932  PostgreSQLConnection(Connection conn) {
13933  super(conn);
13934  }
13935 
13936  @Override
13937  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13938  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
13939  executeCommand(executeStatementUpdateGenerateKeys);
13940  }
13941 
13942  @Override
13943  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13944  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
13945  executeCommand(prepareStatementGenerateKeys);
13946  return prepareStatementGenerateKeys.getPreparedStatement();
13947  }
13948 
13949  @Override
13950  void executeCommand(DbCommand command) throws SQLException {
13951  SQLException lastException = null;
13952  for (int retries = 0; retries < MAX_RETRIES; retries++) {
13953  try {
13954  command.execute();
13955  lastException = null; // reset since we had a successful execution
13956  break;
13957  } catch (SQLException ex) {
13958  lastException = ex;
13959  String sqlState = ex.getSQLState();
13960  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
13961  try {
13962  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13963  } catch (InterruptedException exp) {
13964  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13965  }
13966  } else {
13967  throw ex;
13968  }
13969  }
13970  }
13971 
13972  // rethrow the exception if we bailed because of too many retries
13973  if (lastException != null) {
13974  throw lastException;
13975  }
13976  }
13977  }
13978 
14010  public static final class CaseDbTransaction {
14011 
14012  private final CaseDbConnection connection;
14013  private SleuthkitCase sleuthkitCase;
14014 
14015  /* This class can store information about what was
14016  * inserted as part of the transaction so that we can
14017  * fire events after the data has been persisted. */
14018 
14019  // Score changes are stored as a map keyed by objId to prevent duplicates.
14020  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
14021  private List<Host> hostsAdded = new ArrayList<>();
14022  private List<TimelineEventAddedEvent> timelineEvents = new ArrayList<>();
14023  private List<OsAccount> accountsChanged = new ArrayList<>();
14024  private List<OsAccount> accountsAdded = new ArrayList<>();
14025  private List<TskEvent.MergedAccountsPair> accountsMerged = new ArrayList<>();
14026 
14027  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
14028  private List<Long> deletedResultObjectIds = new ArrayList<>();
14029 
14030  // Keep track of which threads have connections to debug deadlocks
14031  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
14032  private static final Object threadsWithOpenTransactionLock = new Object();
14033 
14034  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
14035  this.sleuthkitCase = sleuthkitCase;
14036 
14037  sleuthkitCase.acquireSingleUserCaseWriteLock();
14038  this.connection = sleuthkitCase.getConnection();
14039  try {
14040  synchronized (threadsWithOpenTransactionLock) {
14041  this.connection.beginTransaction();
14042  threadsWithOpenTransaction.add(Thread.currentThread().getId());
14043  }
14044  } catch (SQLException ex) {
14045  sleuthkitCase.releaseSingleUserCaseWriteLock();
14046  throw new TskCoreException("Failed to create transaction on case database", ex);
14047  }
14048 
14049  }
14050 
14058  CaseDbConnection getConnection() {
14059  return this.connection;
14060  }
14061 
14067  void registerScoreChange(ScoreChange scoreChange) {
14068  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
14069  }
14070 
14075  void registerTimelineEvent(TimelineEventAddedEvent timelineEvent) {
14076  if (timelineEvent != null) {
14077  timelineEvents.add(timelineEvent);
14078  }
14079  }
14080 
14086  void registerAddedHost(Host host) {
14087  if (host != null) {
14088  this.hostsAdded.add(host);
14089  }
14090  }
14091 
14097  void registerChangedOsAccount(OsAccount account) {
14098  if (account != null) {
14099  accountsChanged.add(account);
14100  }
14101  }
14102 
14108  void registerDeletedOsAccount(long osAccountObjId) {
14109  deletedOsAccountObjectIds.add(osAccountObjId);
14110  }
14111 
14117  void registerAddedOsAccount(OsAccount account) {
14118  if (account != null) {
14119  accountsAdded.add(account);
14120  }
14121  }
14122 
14129  void registerMergedOsAccount(long sourceOsAccountObjId, long destinationOsAccountObjId) {
14130  accountsMerged.add(new TskEvent.MergedAccountsPair(sourceOsAccountObjId, destinationOsAccountObjId));
14131  }
14132 
14139  void registerDeletedAnalysisResult(long analysisResultObjId) {
14140  this.deletedResultObjectIds.add(analysisResultObjId);
14141  }
14142 
14151  private static boolean hasOpenTransaction(long threadId) {
14152  synchronized (threadsWithOpenTransactionLock) {
14153  return threadsWithOpenTransaction.contains(threadId);
14154  }
14155  }
14156 
14163  public void commit() throws TskCoreException {
14164  try {
14165  this.connection.commitTransaction();
14166  } catch (SQLException ex) {
14167  throw new TskCoreException("Failed to commit transaction on case database", ex);
14168  } finally {
14169  close();
14170 
14171  if (!scoreChangeMap.isEmpty()) {
14172  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
14173  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
14174  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
14175  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
14176  }
14177  }
14178  if (!timelineEvents.isEmpty()) {
14179  for (TimelineEventAddedEvent evt : timelineEvents) {
14180  sleuthkitCase.fireTSKEvent(evt);
14181  }
14182  }
14183  if (!hostsAdded.isEmpty()) {
14184  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
14185  }
14186  if (!accountsAdded.isEmpty()) {
14187  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
14188  }
14189  if (!accountsChanged.isEmpty()) {
14190  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
14191  }
14192  if (!accountsMerged.isEmpty()) {
14193  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsMergedTskEvent(accountsMerged));
14194  }
14195  if (!deletedOsAccountObjectIds.isEmpty()) {
14196  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
14197  }
14198  if (!deletedResultObjectIds.isEmpty()) {
14199  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
14200  }
14201  }
14202  }
14203 
14210  public void rollback() throws TskCoreException {
14211  try {
14212  this.connection.rollbackTransactionWithThrow();
14213  } catch (SQLException ex) {
14214  throw new TskCoreException("Case database transaction rollback failed", ex);
14215  } finally {
14216  close();
14217  }
14218  }
14219 
14224  void close() {
14225  this.connection.close();
14226  sleuthkitCase.releaseSingleUserCaseWriteLock();
14227  synchronized (threadsWithOpenTransactionLock) {
14228  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
14229  }
14230  }
14231  }
14232 
14242  public final class CaseDbQuery implements AutoCloseable {
14243 
14244  private ResultSet resultSet;
14245  private CaseDbConnection connection;
14246 
14247  private CaseDbQuery(String query) throws TskCoreException {
14248  this(query, false);
14249  }
14250 
14251  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
14252  if (!allowWriteQuery) {
14253  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
14254  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
14255  }
14256  }
14257 
14259  try {
14260  connection = connections.getConnection();
14261  resultSet = connection.executeQuery(connection.createStatement(), query);
14262  } catch (SQLException ex) {
14264  throw new TskCoreException("Error executing query: ", ex);
14265  } catch (TskCoreException ex) {
14267  throw ex;
14268  }
14269  }
14270 
14276  public ResultSet getResultSet() {
14277  return resultSet;
14278  }
14279 
14280  @Override
14281  public void close() throws TskCoreException {
14282  try {
14283  if (resultSet != null) {
14284  final Statement statement = resultSet.getStatement();
14285  if (statement != null) {
14286  statement.close();
14287  }
14288  resultSet.close();
14289  }
14290  closeConnection(connection);
14291  } catch (SQLException ex) {
14292  throw new TskCoreException("Error closing query: ", ex);
14293  } finally {
14295  }
14296  }
14297  }
14298 
14306  @Deprecated
14307  public void addErrorObserver(ErrorObserver observer) {
14308  sleuthkitCaseErrorObservers.add(observer);
14309  }
14310 
14318  @Deprecated
14319  public void removeErrorObserver(ErrorObserver observer) {
14320  int i = sleuthkitCaseErrorObservers.indexOf(observer);
14321  if (i >= 0) {
14322  sleuthkitCaseErrorObservers.remove(i);
14323  }
14324  }
14325 
14334  @Deprecated
14335  public void submitError(String context, String errorMessage) {
14336  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
14337  if (observer != null) {
14338  try {
14339  observer.receiveError(context, errorMessage);
14340  } catch (Exception ex) {
14341  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
14342 
14343  }
14344  }
14345  }
14346  }
14347 
14353  @Deprecated
14354  public interface ErrorObserver {
14355 
14362  public enum Context {
14363 
14367  IMAGE_READ_ERROR("Image File Read Error"),
14371  DATABASE_READ_ERROR("Database Read Error");
14372 
14373  private final String contextString;
14374 
14375  private Context(String context) {
14376  this.contextString = context;
14377  }
14378 
14379  public String getContextString() {
14380  return contextString;
14381  }
14382  };
14383 
14384  void receiveError(String context, String errorMessage);
14385  }
14386 
14397  @Deprecated
14398  long getDataSourceObjectId(long objectId) {
14399  try {
14400  CaseDbConnection connection = connections.getConnection();
14401  try {
14402  return getDataSourceObjectId(connection, objectId);
14403  } finally {
14404  closeConnection(connection);
14405  }
14406  } catch (TskCoreException ex) {
14407  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
14408  return 0;
14409  }
14410  }
14411 
14421  @Deprecated
14422  public long getLastObjectId() throws TskCoreException {
14423  CaseDbConnection connection = null;
14424  ResultSet rs = null;
14426  try {
14427  connection = connections.getConnection();
14428 
14429  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
14430  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
14431  rs = connection.executeQuery(statement);
14432  long id = -1;
14433  if (rs.next()) {
14434  id = rs.getLong("max_obj_id");
14435  }
14436  return id;
14437  } catch (SQLException e) {
14438  throw new TskCoreException("Error getting last object id", e);
14439  } finally {
14440  closeResultSet(rs);
14441  closeConnection(connection);
14443  }
14444  }
14445 
14459  @Deprecated
14460  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
14461  CaseDbConnection connection = null;
14462  Statement s = null;
14463  ResultSet rs = null;
14465  try {
14466  connection = connections.getConnection();
14467  s = connection.createStatement();
14468  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
14469  List<FsContent> results = new ArrayList<FsContent>();
14470  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
14471  for (AbstractFile f : temp) {
14472  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
14473  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
14474  results.add((FsContent) f);
14475  }
14476  }
14477  return results;
14478  } catch (SQLException e) {
14479  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
14480  } finally {
14481  closeResultSet(rs);
14482  closeStatement(s);
14483  closeConnection(connection);
14485  }
14486  }
14487 
14499  @Deprecated
14500  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
14501  CaseDbConnection connection = null;
14502  Statement s = null;
14503  ResultSet rs = null;
14505  try {
14506  connection = connections.getConnection();
14507  s = connection.createStatement();
14508  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
14509  int typeId = -1;
14510  if (rs.next()) {
14511  typeId = rs.getInt("artifact_type_id");
14512  }
14513  return typeId;
14514  } catch (SQLException ex) {
14515  throw new TskCoreException("Error getting artifact type id", ex);
14516  } finally {
14517  closeResultSet(rs);
14518  closeStatement(s);
14519  closeConnection(connection);
14521  }
14522  }
14523 
14533  @Deprecated
14534  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
14535  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
14536  }
14537 
14551  @Deprecated
14552  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14553  try {
14554  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14555  } catch (TskDataException ex) {
14556  throw new TskCoreException("Failed to add artifact type.", ex);
14557  }
14558  }
14559 
14573  @Deprecated
14574  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14575  try {
14576  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14577  } catch (TskDataException ex) {
14578  throw new TskCoreException("Couldn't add new attribute type");
14579  }
14580  }
14581 
14592  @Deprecated
14593  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14594  CaseDbConnection connection = null;
14595  Statement s = null;
14596  ResultSet rs = null;
14598  try {
14599  connection = connections.getConnection();
14600  s = connection.createStatement();
14601  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
14602  int typeId = -1;
14603  if (rs.next()) {
14604  typeId = rs.getInt("attribute_type_id");
14605  }
14606  return typeId;
14607  } catch (SQLException ex) {
14608  throw new TskCoreException("Error getting attribute type id", ex);
14609  } finally {
14610  closeResultSet(rs);
14611  closeStatement(s);
14612  closeConnection(connection);
14614  }
14615  }
14616 
14629  @Deprecated
14630  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
14631  CaseDbConnection connection = null;
14632  Statement s = null;
14633  ResultSet rs = null;
14635  try {
14636  connection = connections.getConnection();
14637  s = connection.createStatement();
14638  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14639  if (rs.next()) {
14640  return rs.getString("type_name");
14641  } else {
14642  throw new TskCoreException("No type with that id");
14643  }
14644  } catch (SQLException ex) {
14645  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14646  } finally {
14647  closeResultSet(rs);
14648  closeStatement(s);
14649  closeConnection(connection);
14651  }
14652  }
14653 
14666  @Deprecated
14667  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
14668  CaseDbConnection connection = null;
14669  Statement s = null;
14670  ResultSet rs = null;
14672  try {
14673  connection = connections.getConnection();
14674  s = connection.createStatement();
14675  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14676  if (rs.next()) {
14677  return rs.getString("display_name");
14678  } else {
14679  throw new TskCoreException("No type with that id");
14680  }
14681  } catch (SQLException ex) {
14682  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14683  } finally {
14684  closeResultSet(rs);
14685  closeStatement(s);
14686  closeConnection(connection);
14688  }
14689  }
14690 
14700  @Deprecated
14701  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
14702  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
14703  }
14704 
14720  @Deprecated
14721  public ResultSet runQuery(String query) throws SQLException {
14722  CaseDbConnection connection = null;
14724  try {
14725  connection = connections.getConnection();
14726  return connection.executeQuery(connection.createStatement(), query);
14727  } catch (TskCoreException ex) {
14728  throw new SQLException("Error getting connection for ad hoc query", ex);
14729  } finally {
14730  //TODO unlock should be done in closeRunQuery()
14731  //but currently not all code calls closeRunQuery - need to fix this
14732  closeConnection(connection);
14734  }
14735  }
14736 
14746  @Deprecated
14747  public void closeRunQuery(ResultSet resultSet) throws SQLException {
14748  final Statement statement = resultSet.getStatement();
14749  resultSet.close();
14750  if (statement != null) {
14751  statement.close();
14752  }
14753  }
14754 
14771  @Deprecated
14772  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
14773  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
14774  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
14775  files.add(carvedFile);
14776  CarvingResult carvingResult;
14777  Content parent = getContentById(containerId);
14778  if (parent instanceof FileSystem
14779  || parent instanceof Volume
14780  || parent instanceof Image) {
14781  carvingResult = new CarvingResult(parent, files);
14782  } else {
14783  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
14784  }
14785  return addCarvedFiles(carvingResult).get(0);
14786  }
14787 
14801  @Deprecated
14802  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
14803  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
14804  for (CarvedFileContainer container : filesToAdd) {
14805  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
14806  carvedFiles.add(carvedFile);
14807  }
14808  CarvingResult carvingResult;
14809  Content parent = getContentById(filesToAdd.get(0).getId());
14810  if (parent instanceof FileSystem
14811  || parent instanceof Volume
14812  || parent instanceof Image) {
14813  carvingResult = new CarvingResult(parent, carvedFiles);
14814  } else {
14815  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
14816  }
14817  return addCarvedFiles(carvingResult);
14818  }
14819 
14849  @Deprecated
14850  public DerivedFile addDerivedFile(String fileName, String localPath,
14851  long size, long ctime, long crtime, long atime, long mtime,
14852  boolean isFile, AbstractFile parentFile,
14853  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
14854  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14855  isFile, parentFile, rederiveDetails, toolName, toolVersion,
14856  otherDetails, TskData.EncodingType.NONE);
14857  }
14858 
14888  @Deprecated
14889  public LocalFile addLocalFile(String fileName, String localPath,
14890  long size, long ctime, long crtime, long atime, long mtime,
14891  String md5, FileKnown known, String mimeType,
14892  boolean isFile, TskData.EncodingType encodingType,
14893  Content parent, CaseDbTransaction transaction) throws TskCoreException {
14894 
14895  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14896  md5, null, known, mimeType, isFile, encodingType,
14897  parent, transaction);
14898  }
14899 
14924  @Deprecated
14925  public LocalFile addLocalFile(String fileName, String localPath,
14926  long size, long ctime, long crtime, long atime, long mtime,
14927  boolean isFile,
14928  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
14929  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
14930  TskData.EncodingType.NONE, parent, transaction);
14931  }
14932 
14952  @Deprecated
14953  public LocalFile addLocalFile(String fileName, String localPath,
14954  long size, long ctime, long crtime, long atime, long mtime,
14955  boolean isFile,
14956  AbstractFile parent) throws TskCoreException {
14957  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14958  isFile, TskData.EncodingType.NONE, parent);
14959  }
14960 
14977  @Deprecated
14978  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
14979  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
14980  }
14981 
14992  @Deprecated
14993  public Collection<FileSystem> getFileSystems(Image image) {
14994  try {
14995  return getImageFileSystems(image);
14996  } catch (TskCoreException ex) {
14997  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
14998  return new ArrayList<>();
14999  }
15000  }
15001 
15019  @Deprecated
15020  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
15021  return findFilesInFolder(fileName, parentFile);
15022  }
15023 
15031  @Deprecated
15032  public void acquireExclusiveLock() {
15034  }
15035 
15043  @Deprecated
15044  public void releaseExclusiveLock() {
15046  }
15047 
15055  @Deprecated
15056  public void acquireSharedLock() {
15058  }
15059 
15067  @Deprecated
15068  public void releaseSharedLock() {
15070  }
15071 };
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.