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.google.gson.Gson;
27 import com.mchange.v2.c3p0.ComboPooledDataSource;
28 import com.mchange.v2.c3p0.DataSources;
29 import com.mchange.v2.c3p0.PooledDataSource;
30 import com.zaxxer.sparsebits.SparseBitSet;
31 import java.beans.PropertyVetoException;
32 import java.io.BufferedInputStream;
33 import java.io.BufferedOutputStream;
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.OutputStream;
40 import java.io.UnsupportedEncodingException;
41 import java.net.InetAddress;
42 import java.net.URLEncoder;
43 import java.nio.charset.StandardCharsets;
44 import java.nio.file.Paths;
45 import java.sql.Connection;
46 import java.sql.DriverManager;
47 import java.sql.PreparedStatement;
48 import java.sql.ResultSet;
49 import java.sql.SQLException;
50 import java.sql.Statement;
51 import java.text.SimpleDateFormat;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Collection;
55 import java.util.Collections;
56 import java.util.concurrent.atomic.AtomicBoolean;
57 import java.util.concurrent.atomic.AtomicInteger;
58 import java.util.Date;
59 import java.util.EnumMap;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.LinkedHashMap;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.MissingResourceException;
66 import java.util.Objects;
67 import java.util.Properties;
68 import java.util.ResourceBundle;
69 import java.util.Set;
70 import java.util.UUID;
71 import java.util.concurrent.CompletableFuture;
72 import java.util.concurrent.CountDownLatch;
73 import java.util.concurrent.TimeUnit;
74 import java.util.concurrent.locks.ReentrantLock;
75 import java.util.concurrent.locks.ReentrantReadWriteLock;
76 import java.util.logging.Level;
77 import java.util.logging.Logger;
78 import java.util.stream.Collectors;
79 import org.apache.commons.lang3.StringUtils;
80 import org.postgresql.util.PSQLState;
101 import org.sqlite.SQLiteConfig;
102 import org.sqlite.SQLiteDataSource;
103 import org.sqlite.SQLiteJDBCLoader;
104 
109 public class SleuthkitCase {
110 
111  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
112 
113  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
114  = new CaseDbSchemaVersionNumber(9, 6);
115 
116  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
117  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
118  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
119  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
120  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
121  // either one of these mean connection was rejected by Postgres server
122  private static final String SQL_CONNECTION_REJECTED = "08004";
123  private static final String UNABLE_TO_VERIFY_SSL = "08006";
124 
125  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
126  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
127  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
128  private static final String SQL_ERROR_LIMIT_GROUP = "54";
129  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
130 
131  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
132  "tsk_events",
133  "tsk_event_descriptions",
134  "tsk_event_types",
135  "tsk_db_info",
136  "tsk_objects",
137  "tsk_image_info",
138  "tsk_image_names",
139  "tsk_vs_info",
140  "tsk_vs_parts",
141  "tsk_fs_info",
142  "tsk_file_layout",
143  "tsk_files",
144  "tsk_files_path",
145  "tsk_files_derived",
146  "tsk_files_derived_method",
147  "tag_names",
148  "content_tags",
149  "blackboard_artifact_tags",
150  "blackboard_artifacts",
151  "blackboard_attributes",
152  "blackboard_artifact_types",
153  "blackboard_attribute_types",
154  "data_source_info",
155  "file_encoding_types",
156  "file_collection_status_types",
157  "ingest_module_types",
158  "ingest_job_status_types",
159  "ingest_modules",
160  "ingest_jobs",
161  "ingest_job_modules",
162  "account_types",
163  "accounts",
164  "account_relationships",
165  "review_statuses",
166  "reports,");
167 
168  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
169  "parObjId",
170  "layout_objID",
171  "artifact_objID",
172  "artifact_artifact_objID",
173  "artifact_typeID",
174  "attrsArtifactID",
175  "mime_type",
176  "file_extension",
177  "relationships_account1",
178  "relationships_account2",
179  "relationships_relationship_source_obj_id",
180  "relationships_date_time",
181  "relationships_relationship_type",
182  "relationships_data_source_obj_id",
183  "events_time",
184  "events_type",
185  "events_data_source_obj_id",
186  "events_file_obj_id",
187  "events_artifact_id");
188 
189  private static final String TSK_VERSION_KEY = "TSK_VER";
190  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
191  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
192  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
193  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
194 
195  // key in acquisition tool settings; the password for decrypting an image
196  static final String IMAGE_PASSWORD_KEY = "imagePassword";
197 
198  private final ConnectionPool connections;
199  private final Object carvedFileDirsLock = new Object();
200  private final static int MAX_CARVED_FILES_PER_FOLDER = 2000;
201  private final Map<Long, CarvedFileDirInfo> rootIdsToCarvedFileDirs = new HashMap<>();
202  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
203  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
204  private final String databaseName;
205  private final String dbPath;
206  private final DbType dbType;
207  private final String caseDirPath;
208  private SleuthkitJNI.CaseDbHandle caseHandle;
209  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
210  private String dbBackupPath;
211  private AtomicBoolean timelineEventsDisabled = new AtomicBoolean(false);
212 
213  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
214 
215  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
216  private final Object rootDirectoryMapLock = new Object();
217  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
218  private final Cache<Long, Boolean> isRootDirectoryCache
219  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
220  // custom provider for file bytes (can be null)
221  private final ContentStreamProvider contentProvider;
222  private final LockResources lockResources;
223 
224  /*
225  * First parameter is used to specify the SparseBitSet to use, as object IDs
226  * can be larger than the max size of a SparseBitSet
227  */
228  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
229  // Lock to serialize access to the bitset.
230  private final ReentrantLock childrenBitSetLock = new ReentrantLock();
231  // Latch to enforce a happens before relation
232  private final CountDownLatch childrenBitSetInitLatch = new CountDownLatch(1);
233 
234 
235  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
236  // This read/write lock is used to implement a layer of locking on top of
237  // the locking protocol provided by the underlying SQLite database. The Java
238  // locking protocol improves performance for reasons that are not currently
239  // understood. Note that the lock is contructed to use a fairness policy.
240  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
241 
242  private CommunicationsManager communicationsMgr;
243  private TimelineManager timelineMgr;
244  private Blackboard blackboard;
245  private CaseDbAccessManager dbAccessManager;
246  private FileManager fileManager;
247  private TaggingManager taggingMgr;
248  private ScoringManager scoringManager;
249  private OsAccountRealmManager osAccountRealmManager;
250  private OsAccountManager osAccountManager;
251  private HostManager hostManager;
252  private PersonManager personManager;
253  private HostAddressManager hostAddressManager;
254 
255  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
256 
257  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
258 
259  public void registerForEvents(Object listener) {
260  eventBus.register(listener);
261  }
262 
263  public void unregisterForEvents(Object listener) {
264  eventBus.unregister(listener);
265  }
266 
267  void fireTSKEvent(Object event) {
268  eventBus.post(event);
269  }
270 
271  // Cache of frequently used content objects (e.g. data source, file system).
272  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
273 
274  private Examiner cachedCurrentExaminer = null;
275 
276  static {
277  Properties p = new Properties(System.getProperties());
278  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
279  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
280  System.setProperties(p);
281  }
282 
297  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
298  // Check if we can talk to the database.
299  if (info.getHost() == null || info.getHost().isEmpty()) {
300  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
301  } else if (info.getPort() == null || info.getPort().isEmpty()) {
302  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
303  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
304  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
305  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
306  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
307  }
308 
309  try {
310  Class.forName("org.postgresql.Driver"); //NON-NLS
311  String connectionURL = "jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres";
312  if (info.isSslEnabled()) {
313  if (info.isSslVerify()) {
314  if (info.getCustomSslValidationClassName().isBlank()) {
315  connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL;
316  } else {
317  // use custom SSL certificate validation class
318  connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName());
319  }
320  } else {
321  connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL;
322  }
323  }
324  Connection conn = DriverManager.getConnection(connectionURL, info.getUserName(), info.getPassword()); //NON-NLS
325  if (conn != null) {
326  conn.close();
327  }
328  } catch (SQLException ex) {
329  String result;
330  String sqlState = ex.getSQLState().toLowerCase();
331  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
332  if (SQL_CONNECTION_REJECTED.equals(ex.getSQLState())) {
333  if (info.isSslEnabled()) {
334  result = "Server rejected the SSL connection attempt. Check SSL configuration.";
335  } else {
336  result = "Server rejected the connection attempt. Check server configuration.";
337  }
338  } else if (UNABLE_TO_VERIFY_SSL.equals(ex.getSQLState())) {
339  result = "Unable to verify SSL certificates. Check SSL configuration.";
340  } else {
341  try {
342  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
343  // if we can reach the host, then it's probably port problem
344  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
345  } else {
346  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
347  }
348  } catch (IOException | MissingResourceException any) {
349  // it may be anything
350  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
351  }
352  }
353  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
354  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
355  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
356  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
357  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
358  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
359  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
360  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
361  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
362  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
363  } else {
364  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
365  }
366  throw new TskCoreException(result);
367  } catch (ClassNotFoundException ex) {
368  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
369  }
370  }
371 
389  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType, ContentStreamProvider contentProvider, String lockingApplicationName) throws Exception {
390  Class.forName("org.sqlite.JDBC");
391  this.dbPath = dbPath;
392  this.dbType = dbType;
393  File dbFile = new File(dbPath);
394  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
395  this.databaseName = dbFile.getName();
396 
397  this.lockResources = lockingApplicationName == null
398  ? null
399  : LockResources.tryAcquireFileLock(this.caseDirPath, this.databaseName, lockingApplicationName);
400 
401  this.connections = new SQLiteConnections(dbPath);
402  this.caseHandle = caseHandle;
403  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
404  this.contentProvider = contentProvider;
405  init();
406  logSQLiteJDBCDriverInfo();
407  }
408 
420  private SleuthkitCase(CaseDbConnectionInfo info, String dbName, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, ContentStreamProvider contentProvider) throws Exception {
421  this.dbPath = "";
422  this.databaseName = dbName;
423  this.dbType = info.getDbType();
424  this.caseDirPath = caseDirPath;
425  this.connections = new PostgreSQLConnections(info, dbName);
426  this.caseHandle = caseHandle;
427  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
428  this.contentProvider = contentProvider;
429  this.lockResources = null;
430  init();
431  }
432 
433  private void init() throws Exception {
434  blackboard = new Blackboard(this);
435  updateDatabaseSchema(null);
436  try (CaseDbConnection connection = connections.getConnection()) {
437  blackboard.initBlackboardArtifactTypes(connection);
438  blackboard.initBlackboardAttributeTypes(connection);
439  initNextArtifactId(connection);
440  initIngestModuleTypes(connection);
441  initIngestStatusTypes(connection);
442  initReviewStatuses(connection);
443  initEncodingTypes(connection);
444  initCollectedStatusTypes(connection);
445  populateHasChildrenMap(true);
446  updateExaminers(connection);
447  initDBSchemaCreationVersion(connection);
448  }
449 
450  fileManager = new FileManager(this);
451  communicationsMgr = new CommunicationsManager(this);
452  timelineMgr = new TimelineManager(this);
453  dbAccessManager = new CaseDbAccessManager(this);
454  taggingMgr = new TaggingManager(this);
455  scoringManager = new ScoringManager(this);
456  osAccountRealmManager = new OsAccountRealmManager(this);
457  osAccountManager = new OsAccountManager(this);
458  hostManager = new HostManager(this);
459  personManager = new PersonManager(this);
460  hostAddressManager = new HostAddressManager(this);
461  }
462 
470  ContentStreamProvider getContentProvider() {
471  return this.contentProvider;
472  }
473 
479  static Set<String> getCoreTableNames() {
480  return Collections.unmodifiableSet(CORE_TABLE_NAMES);
481  }
482 
488  static Set<String> getCoreIndexNames() {
489  return Collections.unmodifiableSet(CORE_INDEX_NAMES);
490  }
491 
500  boolean getHasChildren(Content content) {
501 
502  try {
503  // Await initialization
504  childrenBitSetInitLatch.await();
505  } catch (InterruptedException ex) {
506  throw new AssertionError("Interrupted Exception awaiting Children bit set initialization", ex); //NON-NLS
507  }
508  childrenBitSetLock.lock();
509  try {
510  long objId = content.getId();
511  long mapIndex = objId / Integer.MAX_VALUE;
512  int mapValue = (int) (objId % Integer.MAX_VALUE);
513 
514  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
515  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
516  }
517  return false;
518 
519  } finally {
520  childrenBitSetLock.unlock();
521  }
522  }
523 
529  private void setHasChildren(Long objId) {
530  setHasChildren(objId, false);
531  }
532 
538  private void setHasChildren(Long objId, boolean initializing) {
539  try {
540  if (!initializing) {
541  // Await initialization
542  childrenBitSetInitLatch.await();
543  }
544  } catch (InterruptedException ex) {
545  throw new AssertionError("Interrupted Exception awaiting Children bit set initialization",ex); //NON-NLS
546  }
547 
548  childrenBitSetLock.lock();
549  try {
550  long mapIndex = objId / Integer.MAX_VALUE;
551  int mapValue = (int) (objId % Integer.MAX_VALUE);
552 
553  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
554  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
555  } else {
556  SparseBitSet bitSet = new SparseBitSet();
557  bitSet.set(mapValue);
558  hasChildrenBitSetMap.put(mapIndex, bitSet);
559  }
560  } finally {
561  childrenBitSetLock.unlock();
562  }
563  }
564 
573  return communicationsMgr;
574  }
575 
582  return blackboard;
583  }
584 
591  return fileManager;
592  }
593 
602  return timelineMgr;
603  }
604 
605  /*
606  * Gets the case database access manager for this case.
607  *
608  * @return The per case CaseDbAccessManager object.
609  *
610  * @throws org.sleuthkit.datamodel.TskCoreException
611  */
613  return dbAccessManager;
614  }
615 
621  public synchronized TaggingManager getTaggingManager() {
622  return taggingMgr;
623  }
624 
633  return scoringManager;
634  }
635 
644  return osAccountRealmManager;
645  }
646 
655  return osAccountManager;
656  }
657 
666  return hostManager;
667  }
668 
677  return personManager;
678  }
679 
688  return hostAddressManager;
689  }
690 
700  private void initNextArtifactId(CaseDbConnection connection) throws SQLException {
702  try (Statement statement = connection.createStatement()) {
703  ResultSet resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
704  resultSet.next();
705  nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
706  if (nextArtifactId == 1) {
707  nextArtifactId = BASE_ARTIFACT_ID;
708  }
709  } finally {
711  }
712  }
713 
721  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
722  Statement statement = null;
723  ResultSet resultSet = null;
725  try {
726  statement = connection.createStatement();
727  for (IngestModuleType type : IngestModuleType.values()) {
728  try {
729  String query = "INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
730  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
731  query += " ON CONFLICT ON CONSTRAINT ingest_module_types_pkey DO NOTHING"; // NON-NLS
732  }
733  statement.execute(query);
734  } catch (SQLException ex) {
735  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
736  resultSet.next();
737  if (resultSet.getLong("count") == 0) {
738  throw ex;
739  }
740  resultSet.close();
741  resultSet = null;
742  }
743  }
744  } finally {
745  closeResultSet(resultSet);
746  closeStatement(statement);
748  }
749  }
750 
758  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
759  Statement statement = null;
760  ResultSet resultSet = null;
762  try {
763  statement = connection.createStatement();
764  for (IngestJobStatusType type : IngestJobStatusType.values()) {
765  try {
766  String query = "INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
767  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
768  query += " ON CONFLICT ON CONSTRAINT ingest_job_status_types_pkey DO NOTHING"; // NON-NLS
769  }
770  statement.execute(query);
771  } catch (SQLException ex) {
772  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
773  resultSet.next();
774  if (resultSet.getLong("count") == 0) {
775  throw ex;
776  }
777  resultSet.close();
778  resultSet = null;
779  }
780  }
781  } finally {
782  closeResultSet(resultSet);
783  closeStatement(statement);
785  }
786  }
787 
794  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
795  Statement statement = null;
796  ResultSet resultSet = null;
798  try {
799  statement = connection.createStatement();
800  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
801  try {
802  String query = "INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
803  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')";
804  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
805  query += " ON CONFLICT ON CONSTRAINT review_statuses_pkey DO NOTHING"; // NON-NLS
806  }
807  statement.execute(query);
808  } catch (SQLException ex) {
809  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
810  resultSet.next();
811  if (resultSet.getLong("count") == 0) {
812  throw ex;
813  }
814  resultSet.close();
815  resultSet = null;
816  }
817  }
818  } finally {
819  closeResultSet(resultSet);
820  closeStatement(statement);
822  }
823  }
824 
832  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
833  Statement statement = null;
834  ResultSet resultSet = null;
836  try {
837  statement = connection.createStatement();
838  for (TskData.EncodingType type : TskData.EncodingType.values()) {
839  try {
840  String query = "INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
841  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
842  query += " ON CONFLICT ON CONSTRAINT file_encoding_types_pkey DO NOTHING"; // NON-NLS
843  }
844  statement.execute(query);
845  } catch (SQLException ex) {
846  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
847  resultSet.next();
848  if (resultSet.getLong("count") == 0) {
849  throw ex;
850  }
851  resultSet.close();
852  resultSet = null;
853  }
854  }
855  } finally {
856  closeResultSet(resultSet);
857  closeStatement(statement);
859  }
860  }
861 
869  private void initCollectedStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
870  Statement statement = null;
871  ResultSet resultSet = null;
873  try {
874  statement = connection.createStatement();
875  for (TskData.CollectedStatus type : TskData.CollectedStatus.values()) {
876  try {
877  String query = "INSERT INTO file_collection_status_types (collection_status_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
878  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
879  query += " ON CONFLICT ON CONSTRAINT file_collection_status_types_pkey DO NOTHING"; // NON-NLS
880  }
881  statement.execute(query);
882  } catch (SQLException ex) {
883  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_collection_status_types WHERE collection_status_type = " + type.getType()); //NON-NLS
884  resultSet.next();
885  if (resultSet.getLong("count") == 0) {
886  throw ex;
887  }
888  resultSet.close();
889  resultSet = null;
890  }
891  }
892  } finally {
893  closeResultSet(resultSet);
894  closeStatement(statement);
896  }
897  }
898 
907  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
908 
909  String loginName = System.getProperty("user.name");
910  if (loginName.isEmpty()) {
911  logger.log(Level.SEVERE, "Cannot determine logged in user name");
912  return;
913  }
914 
916  try {
917  PreparedStatement statement;
918  switch (getDatabaseType()) {
919  case POSTGRESQL:
920  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
921  break;
922  case SQLITE:
923  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
924  break;
925  default:
926  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
927  }
928  statement.clearParameters();
929  statement.setString(1, loginName);
930  connection.executeUpdate(statement);
931  } catch (SQLException ex) {
932  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
933  } finally {
935  }
936  }
937 
943  private void populateHasChildrenMap(boolean async) throws TskCoreException {
944 
945  Runnable childrenBitSetLockInitRunnable = () -> {
946 
952  childrenBitSetLock.lock();
953  // The distinct parent objeect id lookup is expensive in postgresql
954  // This is offloaded into a thread and the incident open proceeds.
955  // The access to the results are guarded by an object lock on hasChildrenBitSetMap.
956  // The issue with this approach is that the SQLException will not cause a TSKCOreException.
957  // Since this is running async, it also acquires a new connection from the pool
958 
959  long timestamp = System.currentTimeMillis();
960 
961  Statement statement = null;
962  ResultSet resultSet = null;
964  try (CaseDbConnection neoConnection = connections.getConnection()) {
965  statement = neoConnection.createStatement();
966  String query = "select distinct par_obj_id from tsk_objects";
967  if (dbType == DbType.POSTGRESQL) {
968  query = "select distinct ON (par_obj_id) par_obj_id from tsk_objects";
969  }
970 
971  resultSet = statement.executeQuery(query); //NON-NLS
972 
976  while (resultSet.next()) {
977  setHasChildren(resultSet.getLong("par_obj_id"), true);
978  }
979 
980  long delay = System.currentTimeMillis() - timestamp;
981  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
982  } catch (SQLException ex) {
983  logger.log(Level.SEVERE, "Error populating parent node cache", ex); //NON-NLS
984  // Dont really expect this to be thrown, but if this happens, then it is non-recoverable.
985  throw new AssertionError("Error populating parent node cache",ex); //NON-NLS
986  } catch (TskCoreException ex) {
987  logger.log(Level.SEVERE, "Error acquiring connection", ex); //NON-NLS
988  throw new AssertionError("Error acquiring connection",ex); //NON-NLS
989  } finally {
990  closeResultSet(resultSet);
991  closeStatement(statement);
993  childrenBitSetLock.unlock();
994  // Countdown the latch as initialization has completed.
995  childrenBitSetInitLatch.countDown();
996  }
997  };
998 
999  if (async) {
1000  CompletableFuture.runAsync(childrenBitSetLockInitRunnable);
1001  } else {
1002  childrenBitSetLockInitRunnable.run();
1003  }
1004  }
1005 
1012  void addDataSourceToHasChildrenMap() throws TskCoreException {
1013  try {
1014  // Await initialization. ensure no async version of the init is still running.
1015  childrenBitSetInitLatch.await();
1016  } catch (InterruptedException ex) {
1017  throw new AssertionError("Interrupted Exception awaiting Children bit set initialization", ex); //NON-NLS
1018  }
1019  populateHasChildrenMap(false);
1020  }
1021 
1031  private void updateDatabaseSchema(String dbPath) throws Exception {
1032  CaseDbConnection connection = null;
1033  ResultSet resultSet = null;
1034  Statement statement = null;
1036  try {
1037  connection = connections.getConnection();
1038  connection.beginTransaction();
1039 
1040  boolean hasMinorVersion = false;
1041  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
1042  while (columns.next()) {
1043  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
1044  hasMinorVersion = true;
1045  }
1046  }
1047 
1048  // Get the schema version number of the case database from the tsk_db_info table.
1049  int dbSchemaMajorVersion;
1050  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
1051 
1052  statement = connection.createStatement();
1053  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
1054  + (hasMinorVersion ? ", schema_minor_ver" : "")
1055  + " FROM tsk_db_info"); //NON-NLS
1056  if (resultSet.next()) {
1057  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
1058  if (hasMinorVersion) {
1059  //if there is a minor version column, use it, else default to zero.
1060  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
1061  }
1062  } else {
1063  throw new TskCoreException();
1064  }
1065  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
1066 
1067  resultSet.close();
1068  resultSet = null;
1069  statement.close();
1070  statement = null;
1071  //check schema compatibility
1072  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
1073  //we cannot open a db with a major schema version higher than the current one.
1074  throw new TskUnsupportedSchemaVersionException(
1075  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
1076  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
1077  //The schema version is compatible,possibly after upgrades.
1078 
1079  if (null != dbPath) {
1080  // Make a backup copy of the database. Client code can get the path of the backup
1081  // using the getBackupDatabasePath() method.
1082  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
1083  copyCaseDB(backupFilePath);
1084  dbBackupPath = backupFilePath;
1085  }
1086 
1087  // ***CALL SCHEMA UPDATE METHODS HERE***
1088  // Each method should examine the schema version passed to it and either:
1089  // a. do nothing and return the schema version unchanged, or
1090  // b. upgrade the database and return the schema version that the db was upgraded to.
1091  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
1092  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
1093  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
1094  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
1095  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
1096  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
1097  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
1098  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
1099  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
1100  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
1101  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
1102  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
1103  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
1104  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
1105  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
1106  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
1107  dbSchemaVersion = updateFromSchema9dot1toSchema9dot2(dbSchemaVersion, connection);
1108  dbSchemaVersion = updateFromSchema9dot2toSchema9dot3(dbSchemaVersion, connection);
1109  dbSchemaVersion = updateFromSchema9dot3toSchema9dot4(dbSchemaVersion, connection);
1110  dbSchemaVersion = updateFromSchema9dot4toSchema9dot5(dbSchemaVersion, connection);
1111  dbSchemaVersion = updateFromSchema9dot5toSchema9dot6(dbSchemaVersion, connection);
1112 
1113 
1114  statement = connection.createStatement();
1115  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
1116  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
1117  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
1118  statement.close();
1119  statement = null;
1120  }
1121 
1122  connection.commitTransaction();
1123  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
1124  rollbackTransaction(connection);
1125  throw ex;
1126  } finally {
1127  closeResultSet(resultSet);
1128  closeStatement(statement);
1129  closeConnection(connection);
1131  }
1132  }
1133 
1141  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
1142 
1143  Statement statement = null;
1144  ResultSet resultSet = null;
1145  String createdSchemaMajorVersion = "0";
1146  String createdSchemaMinorVersion = "0";
1148  try {
1149  statement = connection.createStatement();
1150  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
1151  while (resultSet.next()) {
1152  String name = resultSet.getString("name");
1153  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
1154  createdSchemaMajorVersion = resultSet.getString("value");
1155  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
1156  createdSchemaMinorVersion = resultSet.getString("value");
1157  }
1158  }
1159 
1160  } finally {
1161  closeResultSet(resultSet);
1162  closeStatement(statement);
1164  }
1165 
1166  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
1167  }
1168 
1178  public void copyCaseDB(String newDBPath) throws IOException {
1179  if (dbPath.isEmpty()) {
1180  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1181  }
1182  InputStream in = null;
1183  OutputStream out = null;
1185  try {
1186  InputStream inFile = new FileInputStream(dbPath);
1187  in = new BufferedInputStream(inFile);
1188  OutputStream outFile = new FileOutputStream(newDBPath);
1189  out = new BufferedOutputStream(outFile);
1190  int bytesRead = in.read();
1191  while (bytesRead != -1) {
1192  out.write(bytesRead);
1193  bytesRead = in.read();
1194  }
1195  } finally {
1196  try {
1197  if (in != null) {
1198  in.close();
1199  }
1200  if (out != null) {
1201  out.flush();
1202  out.close();
1203  }
1204  } catch (IOException e) {
1205  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1206  }
1208  }
1209  }
1210 
1214  private void logSQLiteJDBCDriverInfo() {
1215  try {
1216  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1217  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1218  ? "native" : "pure-java")); //NON-NLS
1219  } catch (Exception ex) {
1220  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1221  }
1222  }
1223 
1237  @SuppressWarnings("deprecation")
1238  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1239  if (schemaVersion.getMajor() != 2) {
1240  return schemaVersion;
1241  }
1242  Statement statement = null;
1243  Statement statement2 = null;
1244  Statement updateStatement = null;
1245  ResultSet resultSet = null;
1247  try {
1248  statement = connection.createStatement();
1249  statement2 = connection.createStatement();
1250 
1251  // Add new tables for tags.
1252  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
1253  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
1254  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
1255 
1256  // Add a new table for reports.
1257  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
1258 
1259  // Add new columns to the image info table.
1260  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1261  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1262  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1263 
1264  // Add a new column to the file system info table.
1265  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1266 
1267  // Add a new column to the file table.
1268  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1269 
1270  // Add new columns and indexes to the attributes table and populate the
1271  // new column. Note that addition of the new column is a denormalization
1272  // to optimize attribute queries.
1273  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1274  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1275  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1276  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1277  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1278  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1279  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1280  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1281  + "FROM blackboard_attributes AS attrs " //NON-NLS
1282  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1283  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1284  updateStatement = connection.createStatement();
1285  while (resultSet.next()) {
1286  long artifactId = resultSet.getLong("artifact_id");
1287  int artifactTypeId = resultSet.getInt("artifact_type_id");
1288  updateStatement.executeUpdate(
1289  "UPDATE blackboard_attributes " //NON-NLS
1290  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1291  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1292  }
1293  resultSet.close();
1294 
1295  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1296  Map<String, Long> tagNames = new HashMap<>();
1297  long tagNameCounter = 1;
1298 
1299  // Convert file tags.
1300  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1301  resultSet = statement.executeQuery("SELECT * FROM \n"
1302  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1303  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1304  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1305  + "WHERE blackboard_artifacts.artifact_type_id = "
1306  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1307  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1308  + ") AS tagNames \n"
1309  + "INNER JOIN \n"
1310  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1311  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1312  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1313  + "ON tagNames.objId = fileData.objId2 \n"
1314  + "LEFT JOIN \n"
1315  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1316  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1317  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1318 
1319  while (resultSet.next()) {
1320  long objId = resultSet.getLong("objId");
1321  long fileSize = resultSet.getLong("fileSize");
1322  String tagName = resultSet.getString("name");
1323  String tagComment = resultSet.getString("comment");
1324  if (tagComment == null) {
1325  tagComment = "";
1326  }
1327 
1328  if (tagName != null && !tagName.isEmpty()) {
1329  // Get the index for the tag name, adding it to the database if needed.
1330  long tagNameIndex;
1331  if (tagNames.containsKey(tagName)) {
1332  tagNameIndex = tagNames.get(tagName);
1333  } else {
1334  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1335  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1336  tagNames.put(tagName, tagNameCounter);
1337  tagNameIndex = tagNameCounter;
1338  tagNameCounter++;
1339  }
1340 
1341  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1342  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1343  }
1344  }
1345  resultSet.close();
1346 
1347  // Convert artifact tags.
1348  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1349  resultSet = statement.executeQuery("SELECT * FROM \n"
1350  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1351  + "blackboard_attributes.value_text AS name\n"
1352  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1353  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1354  + "WHERE blackboard_artifacts.artifact_type_id = "
1355  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1356  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1357  + ") AS tagNames \n"
1358  + "INNER JOIN \n"
1359  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1360  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1361  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1362  + "LEFT JOIN \n"
1363  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1364  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1365  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1366 
1367  while (resultSet.next()) {
1368  long artifactId = resultSet.getLong("taggedArtifactId");
1369  String tagName = resultSet.getString("name");
1370  String tagComment = resultSet.getString("comment");
1371  if (tagComment == null) {
1372  tagComment = "";
1373  }
1374  if (tagName != null && !tagName.isEmpty()) {
1375  // Get the index for the tag name, adding it to the database if needed.
1376  long tagNameIndex;
1377  if (tagNames.containsKey(tagName)) {
1378  tagNameIndex = tagNames.get(tagName);
1379  } else {
1380  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1381  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1382  tagNames.put(tagName, tagNameCounter);
1383  tagNameIndex = tagNameCounter;
1384  tagNameCounter++;
1385  }
1386 
1387  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1388  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1389  }
1390  }
1391  resultSet.close();
1392 
1393  statement.execute(
1394  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1395  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1396  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1397  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1398  statement.execute(
1399  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1400  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1401  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1402 
1403  return new CaseDbSchemaVersionNumber(3, 0);
1404  } finally {
1405  closeStatement(updateStatement);
1406  closeResultSet(resultSet);
1407  closeStatement(statement);
1408  closeStatement(statement2);
1410  }
1411  }
1412 
1426  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1427  if (schemaVersion.getMajor() != 3) {
1428  return schemaVersion;
1429  }
1430 
1431  Statement statement = null;
1432  ResultSet resultSet = null;
1433  Statement queryStatement = null;
1434  ResultSet queryResultSet = null;
1435  Statement updateStatement = null;
1437  try {
1438  // Add mime_type column to tsk_files table. Populate with general
1439  // info artifact file signature data.
1440  statement = connection.createStatement();
1441  updateStatement = connection.createStatement();
1442  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1443  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1444  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1445  + "WHERE files.obj_id = arts.obj_id AND "
1446  + "arts.artifact_id = attrs.artifact_id AND "
1447  + "arts.artifact_type_id = 1 AND "
1448  + "attrs.attribute_type_id = 62");
1449  while (resultSet.next()) {
1450  updateStatement.executeUpdate(
1451  "UPDATE tsk_files " //NON-NLS
1452  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1453  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1454  }
1455  resultSet.close();
1456 
1457  // Add value_type column to blackboard_attribute_types table.
1458  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1459  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1460  while (resultSet.next()) {
1461  int attributeTypeId = resultSet.getInt("attribute_type_id");
1462  String attributeLabel = resultSet.getString("type_name");
1463  if (attributeTypeId < Blackboard.MIN_USER_DEFINED_TYPE_ID) {
1464  updateStatement.executeUpdate(
1465  "UPDATE blackboard_attribute_types " //NON-NLS
1466  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1467  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1468  }
1469  }
1470  resultSet.close();
1471 
1472  // Add a data_sources_info table.
1473  queryStatement = connection.createStatement();
1474  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));");
1475  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1476  while (resultSet.next()) {
1477  long objectId = resultSet.getLong("obj_id");
1478  String timeZone = "";
1479  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1480  if (queryResultSet.next()) {
1481  timeZone = queryResultSet.getString("tzone");
1482  }
1483  queryResultSet.close();
1484  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1485  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1486  }
1487  resultSet.close();
1488 
1489  // Add data_source_obj_id column to the tsk_files table.
1490  //
1491  // NOTE: A new case database will have the following FK constraint:
1492  //
1493  // REFERENCES data_source_info (obj_id)
1494  //
1495  // The constraint is sacrificed here to avoid having to create and
1496  // populate a new tsk_files table.
1497  //
1498  // TODO: Do this right.
1499  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1500  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");
1501  while (resultSet.next()) {
1502  long fileId = resultSet.getLong("obj_id");
1503  long dataSourceId = getDataSourceObjectId(connection, fileId);
1504  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1505  }
1506  resultSet.close();
1507  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1508  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1509  if (this.dbType.equals(DbType.SQLITE)) {
1510  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
1511  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
1512  } else {
1513  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
1514  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
1515  }
1516 
1517  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
1518  initIngestModuleTypes(connection);
1519  initIngestStatusTypes(connection);
1520 
1521  return new CaseDbSchemaVersionNumber(4, 0);
1522 
1523  } finally {
1524  closeResultSet(queryResultSet);
1525  closeStatement(queryStatement);
1526  closeStatement(updateStatement);
1527  closeResultSet(resultSet);
1528  closeStatement(statement);
1530  }
1531  }
1532 
1546  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1547  if (schemaVersion.getMajor() != 4) {
1548  return schemaVersion;
1549  }
1550 
1551  Statement statement = null;
1553  try {
1554  // Add the review_statuses lookup table.
1555  statement = connection.createStatement();
1556  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1557 
1558  /*
1559  * Add review_status_id column to artifacts table.
1560  *
1561  * NOTE: For DBs created with schema 5 we define a foreign key
1562  * constraint on the review_status_column. We don't bother with this
1563  * for DBs updated to schema 5 because of limitations of the SQLite
1564  * ALTER TABLE command.
1565  */
1566  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1567 
1568  // Add the encoding table
1569  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1570  initEncodingTypes(connection);
1571 
1572  /*
1573  * This needs to be done due to a Autopsy/TSK out of synch problem.
1574  * Without this, it is possible to upgrade from version 4 to 5 and
1575  * then 5 to 6, but not from 4 to 6.
1576  */
1577  initReviewStatuses(connection);
1578 
1579  // Add encoding type column to tsk_files_path
1580  // This should really have the FOREIGN KEY constraint but there are problems
1581  // getting that to work, so we don't add it on this upgrade path.
1582  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1583 
1584  return new CaseDbSchemaVersionNumber(5, 0);
1585 
1586  } finally {
1587  closeStatement(statement);
1589  }
1590  }
1591 
1605  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1606  if (schemaVersion.getMajor() != 5) {
1607  return schemaVersion;
1608  }
1609 
1610  /*
1611  * This upgrade fixes a bug where some releases had artifact review
1612  * status support in the case database and others did not.
1613  */
1614  Statement statement = null;
1615  ResultSet resultSet = null;
1617  try {
1618  /*
1619  * Add the review_statuses lookup table, if missing.
1620  */
1621  statement = connection.createStatement();
1622  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)");
1623 
1624  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1625  resultSet.next();
1626  if (resultSet.getLong("count") == 0) {
1627  /*
1628  * Add review_status_id column to artifacts table.
1629  *
1630  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1631  * key constraint on the review_status_column. We don't bother
1632  * with this for DBs updated to schema 5 or 6 because of
1633  * limitations of the SQLite ALTER TABLE command.
1634  */
1635  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1636  }
1637 
1638  return new CaseDbSchemaVersionNumber(6, 0);
1639 
1640  } finally {
1641  closeResultSet(resultSet);
1642  closeStatement(statement);
1644  }
1645  }
1646 
1660  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1661  if (schemaVersion.getMajor() != 6) {
1662  return schemaVersion;
1663  }
1664 
1665  /*
1666  * This upgrade adds an indexed extension column to the tsk_files table.
1667  */
1668  Statement statement = null;
1669  Statement updstatement = null;
1670  ResultSet resultSet = null;
1672  try {
1673  statement = connection.createStatement();
1674  updstatement = connection.createStatement();
1675  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1676 
1677  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1678  while (resultSet.next()) {
1679  long objID = resultSet.getLong("obj_id");
1680  String name = resultSet.getString("name");
1681  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1682  + "WHERE obj_id = " + objID);
1683  }
1684 
1685  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1686 
1687  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1688  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1689 
1690  return new CaseDbSchemaVersionNumber(7, 0);
1691 
1692  } finally {
1693  closeResultSet(resultSet);
1694  closeStatement(statement);
1695  closeStatement(updstatement);
1697  }
1698  }
1699 
1713  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1714  if (schemaVersion.getMajor() != 7) {
1715  return schemaVersion;
1716  }
1717 
1718  if (schemaVersion.getMinor() != 0) {
1719  return schemaVersion;
1720  }
1721 
1722  /*
1723  * This upgrade adds a minor version number column.
1724  */
1725  Statement statement = null;
1726  ResultSet resultSet = null;
1728  try {
1729  statement = connection.createStatement();
1730 
1731  //add the schema minor version number column.
1732  if (schemaVersion.getMinor() == 0) {
1733  //add the schema minor version number column.
1734  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1735  }
1736  return new CaseDbSchemaVersionNumber(7, 1);
1737 
1738  } finally {
1739  closeResultSet(resultSet);
1740  closeStatement(statement);
1742  }
1743  }
1744 
1758  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1759  if (schemaVersion.getMajor() != 7) {
1760  return schemaVersion;
1761  }
1762 
1763  if (schemaVersion.getMinor() != 1) {
1764  return schemaVersion;
1765  }
1766 
1767  Statement statement = null;
1768  Statement updstatement = null;
1769  ResultSet resultSet = null;
1771  try {
1772  //add the data_source_obj_id column to blackboard_artifacts.
1773  statement = connection.createStatement();
1774  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1775 
1776  // populate data_source_obj_id for each artifact
1777  updstatement = connection.createStatement();
1778  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1779  while (resultSet.next()) {
1780  long artifact_id = resultSet.getLong("artifact_id");
1781  long obj_id = resultSet.getLong("obj_id");
1782  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1783  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1784  + "WHERE artifact_id = " + artifact_id);
1785  }
1786  closeResultSet(resultSet);
1787  closeStatement(statement);
1788  closeStatement(updstatement);
1789 
1790  /*
1791  * Add a knownStatus column to the tag_names table.
1792  */
1793  statement = connection.createStatement();
1794  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1795 
1796  // Create account_types, accounts, and account_relationships table
1797  if (this.dbType.equals(DbType.SQLITE)) {
1798  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1799  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))");
1800  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))");
1801  } else {
1802  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1803  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))");
1804  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))");
1805  }
1806 
1807  // Create indexes
1808  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1809  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1810  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1811  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1812  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1813  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1814  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1815 
1816  return new CaseDbSchemaVersionNumber(7, 2);
1817  } finally {
1818  closeResultSet(resultSet);
1819  closeStatement(statement);
1820  closeStatement(updstatement);
1822  }
1823  }
1824 
1838  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1839  if (schemaVersion.getMajor() != 7) {
1840  return schemaVersion;
1841  }
1842 
1843  if (schemaVersion.getMinor() != 2) {
1844  return schemaVersion;
1845  }
1846 
1847  Statement updateSchemaStatement = connection.createStatement();
1848  Statement getExistingReportsStatement = connection.createStatement();
1849  ResultSet resultSet = null;
1850  ResultSet existingReports = null;
1851 
1853  try {
1854  // Update the schema to turn report_id into an object id.
1855 
1856  // Unfortunately, SQLite doesn't support adding a constraint
1857  // to an existing table so we have to rename the old...
1858  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1859 
1860  // ...create the new...
1861  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))");
1862 
1863  // ...add the existing report records back...
1864  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1865  while (existingReports.next()) {
1866  String path = existingReports.getString(2);
1867  long crtime = existingReports.getInt(3);
1868  String sourceModule = existingReports.getString(4);
1869  String reportName = existingReports.getString(5);
1870 
1871  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1872  insertObjectStatement.clearParameters();
1873  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1874  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1875  connection.executeUpdate(insertObjectStatement);
1876  resultSet = insertObjectStatement.getGeneratedKeys();
1877  if (!resultSet.next()) {
1878  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1879  }
1880  long objectId = resultSet.getLong(1); //last_insert_rowid()
1881 
1882  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1883  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1884  insertReportStatement.clearParameters();
1885  insertReportStatement.setLong(1, objectId);
1886  insertReportStatement.setString(2, path);
1887  insertReportStatement.setLong(3, crtime);
1888  insertReportStatement.setString(4, sourceModule);
1889  insertReportStatement.setString(5, reportName);
1890  connection.executeUpdate(insertReportStatement);
1891  }
1892 
1893  // ...and drop the old table.
1894  updateSchemaStatement.execute("DROP TABLE old_reports");
1895 
1896  return new CaseDbSchemaVersionNumber(8, 0);
1897  } finally {
1898  closeResultSet(resultSet);
1899  closeResultSet(existingReports);
1900  closeStatement(updateSchemaStatement);
1901  closeStatement(getExistingReportsStatement);
1903  }
1904  }
1905 
1919  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1920  if (schemaVersion.getMajor() != 8) {
1921  return schemaVersion;
1922  }
1923 
1924  if (schemaVersion.getMinor() != 0) {
1925  return schemaVersion;
1926  }
1927 
1929 
1930  try (Statement statement = connection.createStatement();) {
1931  // create examiners table
1932  if (this.dbType.equals(DbType.SQLITE)) {
1933  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1934  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1935  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1936  } else {
1937  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1938  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1939  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1940  }
1941 
1942  return new CaseDbSchemaVersionNumber(8, 1);
1943  } finally {
1945  }
1946  }
1947 
1961  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1962  if (schemaVersion.getMajor() != 8) {
1963  return schemaVersion;
1964  }
1965 
1966  if (schemaVersion.getMinor() != 1) {
1967  return schemaVersion;
1968  }
1969 
1971 
1972  try (Statement statement = connection.createStatement();) {
1973  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1974  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1975 
1976  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1977 
1978  /*
1979  * Add new tsk_db_extended_info table with TSK version, creation
1980  * time schema and schema version numbers as the initial data. The
1981  * creation time schema version is set to 0, 0 to indicate that it
1982  * is not known.
1983  */
1984  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1985  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1986  result.next();
1987  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1988  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1989  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1990  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1991  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1992 
1993  String primaryKeyType;
1994  switch (getDatabaseType()) {
1995  case POSTGRESQL:
1996  primaryKeyType = "BIGSERIAL";
1997  break;
1998  case SQLITE:
1999  primaryKeyType = "INTEGER";
2000  break;
2001  default:
2002  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2003  }
2004 
2005  //create and initialize tsk_event_types tables
2006  statement.execute("CREATE TABLE tsk_event_types ("
2007  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
2008  + " display_name TEXT UNIQUE NOT NULL, "
2009  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
2010  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2011  + " values( 0, 'Event Types', null)");
2012  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2013  + " values(1, 'File System', 0)");
2014  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2015  + " values(2, 'Web Activity', 0)");
2016  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2017  + " values(3, 'Misc Types', 0)");
2018  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2019  + " values(4, 'Modified', 1)");
2020  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2021  + " values(5, 'Accessed', 1)");
2022  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2023  + " values(6, 'Created', 1)");
2024  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2025  + " values(7, 'Changed', 1)");
2026 
2027  //create tsk_events tables
2028  statement.execute("CREATE TABLE tsk_event_descriptions ("
2029  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2030  + " full_description TEXT NOT NULL, "
2031  + " med_description TEXT, "
2032  + " short_description TEXT,"
2033  + " data_source_obj_id BIGINT NOT NULL, "
2034  + " file_obj_id BIGINT NOT NULL, "
2035  + " artifact_id BIGINT, "
2036  + " hash_hit INTEGER NOT NULL, " //boolean
2037  + " tagged INTEGER NOT NULL, " //boolean
2038  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2039  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2040  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2041  );
2042 
2043  statement.execute("CREATE TABLE tsk_events ( "
2044  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2045  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2046  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2047  + " time INTEGER NOT NULL) "
2048  );
2049 
2050  //create tsk_events indices
2051  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
2052  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
2053  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2054  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
2055  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2056  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2057  return new CaseDbSchemaVersionNumber(8, 2);
2058 
2059  } finally {
2061  }
2062  }
2063 
2077  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2078  if (schemaVersion.getMajor() != 8) {
2079  return schemaVersion;
2080  }
2081 
2082  if (schemaVersion.getMinor() != 2) {
2083  return schemaVersion;
2084  }
2085 
2087 
2088  ResultSet resultSet = null;
2089 
2090  try (Statement statement = connection.createStatement();) {
2091 
2092  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
2093  // Unfortunately, SQLite doesn't support adding a constraint
2094  // to an existing table so we have to rename the old...
2095  String primaryKeyType;
2096  switch (getDatabaseType()) {
2097  case POSTGRESQL:
2098  primaryKeyType = "BIGSERIAL";
2099  break;
2100  case SQLITE:
2101  primaryKeyType = "INTEGER";
2102  break;
2103  default:
2104  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2105  }
2106 
2107  //create and initialize tsk_event_types tables which may or may not exist
2108  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
2109  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
2110  + " display_name TEXT UNIQUE NOT NULL, "
2111  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
2112 
2113  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
2114 
2115  // If there is something in resultSet then the table must have previously
2116  // existing therefore there is not need to populate
2117  if (!resultSet.next()) {
2118 
2119  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2120  + " values( 0, 'Event Types', null)");
2121  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2122  + " values(1, 'File System', 0)");
2123  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2124  + " values(2, 'Web Activity', 0)");
2125  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2126  + " values(3, 'Misc Types', 0)");
2127  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2128  + " values(4, 'Modified', 1)");
2129  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2130  + " values(5, 'Accessed', 1)");
2131  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2132  + " values(6, 'Created', 1)");
2133  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2134  + " values(7, 'Changed', 1)");
2135  }
2136 
2137  // Delete the old table that may have been created with the upgrade
2138  // from 8.1 to 8.2.
2139  statement.execute("DROP TABLE IF EXISTS tsk_events");
2140 
2141  // Delete the old table that may have been created with the upgrade
2142  // from 8.1 to 8.2
2143  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
2144 
2145  //create new tsk_event_description table
2146  statement.execute("CREATE TABLE tsk_event_descriptions ("
2147  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2148  + " full_description TEXT NOT NULL, "
2149  + " med_description TEXT, "
2150  + " short_description TEXT,"
2151  + " data_source_obj_id BIGINT NOT NULL, "
2152  + " file_obj_id BIGINT NOT NULL, "
2153  + " artifact_id BIGINT, "
2154  + " hash_hit INTEGER NOT NULL, " //boolean
2155  + " tagged INTEGER NOT NULL, " //boolean
2156  + " UNIQUE(full_description, file_obj_id, artifact_id), "
2157  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2158  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2159  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2160  );
2161 
2162  // create a new table
2163  statement.execute("CREATE TABLE tsk_events ( "
2164  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2165  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2166  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2167  + " time INTEGER NOT NULL, "
2168  + " UNIQUE (event_type_id, event_description_id, time))"
2169  );
2170 
2171  // Fix mistakenly set names in tsk_db_info_extended
2172  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2173  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2174 
2175  return new CaseDbSchemaVersionNumber(8, 3);
2176  } finally {
2177  closeResultSet(resultSet);
2179  }
2180  }
2181 
2203  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2204  if (schemaVersion.getMajor() != 8) {
2205  return schemaVersion;
2206  }
2207 
2208  if (schemaVersion.getMinor() != 3) {
2209  return schemaVersion;
2210  }
2211 
2212  Statement statement = connection.createStatement();
2213  ResultSet results = null;
2214 
2216  try {
2217  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2218  // the previous update code.
2219  if (null == getDatabaseType()) {
2220  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2221  }
2222 
2223  switch (getDatabaseType()) {
2224  case POSTGRESQL:
2225  // Check if the misnamed column is present
2226  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2227  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2228  if (results.next()) {
2229  // In PostgreSQL we can rename the column if it exists
2230  statement.execute("ALTER TABLE tsk_event_descriptions "
2231  + "RENAME COLUMN file_obj_id TO content_obj_id");
2232 
2233  // 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
2234  // Fix the schema, preserving any data if exists.
2235  statement.execute("CREATE TABLE temp_tsk_events ( "
2236  + " event_id BIGSERIAL PRIMARY KEY, "
2237  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2238  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2239  + " time BIGINT NOT NULL, "
2240  + " UNIQUE (event_type_id, event_description_id, time))"
2241  );
2242 
2243  // Copy the data
2244  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2245  + "event_description_id, time) SELECT * FROM tsk_events");
2246 
2247  // Drop the old table
2248  statement.execute("DROP TABLE tsk_events");
2249 
2250  // Rename the new table
2251  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2252 
2253  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2254  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2255  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2256  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2257  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2258  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2259  }
2260  break;
2261  case SQLITE:
2262  boolean hasMisnamedColumn = false;
2263  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2264  while (results.next()) {
2265  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2266  hasMisnamedColumn = true;
2267  break;
2268  }
2269  }
2270 
2271  if (hasMisnamedColumn) {
2272  // Since we can't rename the column we'll need to make new tables and copy the data
2273  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2274  + " event_description_id INTEGER PRIMARY KEY, "
2275  + " full_description TEXT NOT NULL, "
2276  + " med_description TEXT, "
2277  + " short_description TEXT,"
2278  + " data_source_obj_id BIGINT NOT NULL, "
2279  + " content_obj_id BIGINT NOT NULL, "
2280  + " artifact_id BIGINT, "
2281  + " hash_hit INTEGER NOT NULL, " //boolean
2282  + " tagged INTEGER NOT NULL, " //boolean
2283  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2284  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2285  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2286  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2287  );
2288 
2289  statement.execute("CREATE TABLE temp_tsk_events ( "
2290  + " event_id INTEGER PRIMARY KEY, "
2291  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2292  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2293  + " time INTEGER NOT NULL, "
2294  + " UNIQUE (event_type_id, event_description_id, time))"
2295  );
2296 
2297  // Copy the data
2298  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2299  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2300  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2301 
2302  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2303  + "event_description_id, time) SELECT * FROM tsk_events");
2304 
2305  // Drop the old tables
2306  statement.execute("DROP TABLE tsk_events");
2307  statement.execute("DROP TABLE tsk_event_descriptions");
2308 
2309  // Rename the new tables
2310  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2311  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2312 
2313  //create tsk_events indices
2314  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2315  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2316  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2317  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2318  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2319  }
2320  break;
2321  default:
2322  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2323  }
2324 
2325  // create pool info table
2326  if (this.dbType.equals(DbType.SQLITE)) {
2327  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)");
2328  } else {
2329  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)");
2330  }
2331 
2332  // Add new account types for newly supported messaging applications, if they dont exists already.
2333  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2334  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2335  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2336  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2337  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2338  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2339  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2340  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2341  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2342  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2343 
2344  return new CaseDbSchemaVersionNumber(8, 4);
2345  } finally {
2346  closeResultSet(results);
2347  closeStatement(statement);
2349  }
2350  }
2351 
2352  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2353  if (schemaVersion.getMajor() != 8) {
2354  return schemaVersion;
2355  }
2356 
2357  if (schemaVersion.getMinor() != 4) {
2358  return schemaVersion;
2359  }
2360 
2361  Statement statement = connection.createStatement();
2363  try {
2364  switch (getDatabaseType()) {
2365  case POSTGRESQL:
2366  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2367  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2368  break;
2369  case SQLITE:
2370  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2371  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2372  break;
2373  }
2374 
2375  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2376 
2377  /*
2378  * Update existing Project Vic tag names (from Image Gallery in
2379  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2380  * date and will not work with the Project VIC Report module. New
2381  * cases will get the new names from Image Gallery.
2382  */
2383  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2384  if (getDatabaseType() == DbType.POSTGRESQL) {
2385  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2386  } else {
2387  statement.execute(insertStmt);
2388  }
2389  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2390  if (resultSet != null && resultSet.next()) {
2391  int tagSetId = resultSet.getInt(1);
2392 
2393  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2394  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2395  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2396  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2397  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2398  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2399 
2400  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')";
2401  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')";
2402  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2403  statement.executeUpdate(deleteContentTag);
2404  statement.executeUpdate(deleteArtifactTag);
2405  statement.executeUpdate(deleteCat0);
2406 
2407  } else {
2408  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2409  }
2410  }
2411 
2412  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2413  // this column will have a foreign key constraint on the data_source_info table.
2414  // There does not seem to be a reasonable way to do this in an upgrade,
2415  // so upgraded cases will be missing the foreign key.
2416  switch (getDatabaseType()) {
2417  case POSTGRESQL:
2418  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2419  break;
2420  case SQLITE:
2421  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2422  break;
2423  }
2424  Statement updateStatement = connection.createStatement();
2425  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2426  while (resultSet.next()) {
2427  long fsId = resultSet.getLong("obj_id");
2428  long dataSourceId = getDataSourceObjectId(connection, fsId);
2429  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2430  }
2431  } finally {
2432  closeStatement(updateStatement);
2433  }
2434 
2435  return new CaseDbSchemaVersionNumber(8, 5);
2436 
2437  } finally {
2438  closeStatement(statement);
2440  }
2441  }
2442 
2443  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2444  if (schemaVersion.getMajor() != 8) {
2445  return schemaVersion;
2446  }
2447 
2448  if (schemaVersion.getMinor() != 5) {
2449  return schemaVersion;
2450  }
2451 
2452  Statement statement = connection.createStatement();
2454  try {
2455  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2456 
2457  return new CaseDbSchemaVersionNumber(8, 6);
2458 
2459  } finally {
2460  closeStatement(statement);
2462  }
2463  }
2464 
2465  @SuppressWarnings("deprecation")
2466  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2467  if (schemaVersion.getMajor() != 8) {
2468  return schemaVersion;
2469  }
2470 
2471  if (schemaVersion.getMinor() != 6) {
2472  return schemaVersion;
2473  }
2474 
2475  Statement statement = connection.createStatement();
2477  try {
2478  String dateDataType = "BIGINT";
2479  String bigIntDataType = "BIGINT";
2480  String blobDataType = "BYTEA";
2481  String primaryKeyType = "BIGSERIAL";
2482 
2483  if (this.dbType.equals(DbType.SQLITE)) {
2484  dateDataType = "INTEGER";
2485  bigIntDataType = "INTEGER";
2486  blobDataType = "BLOB";
2487  primaryKeyType = "INTEGER";
2488  }
2489  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2490  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2491  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2492  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2493 
2494  // Add category type and initialize the types. We use the list of artifact types that
2495  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2496  // case the built-in types change in a later release.
2497  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2498  String analysisTypeObjIdList
2499  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2500  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2501  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2502  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2503  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2504  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2505  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2506  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2507  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2508  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2509  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2510  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2511  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2512  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2513  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2514  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2515  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2516  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2517  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2518 
2519  // Create tsk file attributes table
2520  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2521  + "obj_id " + bigIntDataType + " NOT NULL, "
2522  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2523  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2524  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2525  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2526  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2527 
2528  // create analysis results tables
2529  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2530  + "conclusion TEXT, "
2531  + "significance INTEGER NOT NULL, "
2532  /*
2533  * method_category was a column in a little distributed
2534  * version of 9.0. It was renamed to priority before public
2535  * release. The 9.1 upgrade code will add the priority
2536  * column. This is commented out since it was never used.
2537  */
2538  // + "method_category INTEGER NOT NULL, "
2539  + "configuration TEXT, justification TEXT, "
2540  + "ignore_score INTEGER DEFAULT 0 " // boolean
2541  + ")");
2542 
2543  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2544  + "data_source_obj_id " + bigIntDataType + ", "
2545  + "significance INTEGER NOT NULL, "
2546  // See comment above on why this is commented out
2547  // + "method_category INTEGER NOT NULL, "
2548  + "UNIQUE (obj_id),"
2549  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2550  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2551  + ")");
2552 
2553  // Create person table.
2554  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2555  + "name TEXT NOT NULL, " // person name
2556  + "UNIQUE(name)) ");
2557 
2558  // Create host table.
2559  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2560  + "name TEXT NOT NULL, " // host name
2561  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2562  + "person_id INTEGER, "
2563  + "merged_into " + bigIntDataType + ", "
2564  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2565  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2566  + "UNIQUE(name)) ");
2567 
2568  // Create OS Account and related tables
2569  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2570  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2571  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2572  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2573  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2574  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2575  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2576  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2577  + "UNIQUE(realm_signature), "
2578  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2579  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2580 
2581  // Add host column and create a host for each existing data source.
2582  // We will create a host for each device id so that related data sources will
2583  // be associated with the same host.
2584  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2585  Statement updateStatement = connection.createStatement();
2586  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2587  Map<String, Long> hostMap = new HashMap<>();
2588  long hostIndex = 1;
2589  while (resultSet.next()) {
2590  long objId = resultSet.getLong("obj_id");
2591  String deviceId = resultSet.getString("device_id");
2592 
2593  if (!hostMap.containsKey(deviceId)) {
2594  String hostName = "Host " + hostIndex;
2595  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2596  hostMap.put(deviceId, hostIndex);
2597  hostIndex++;
2598  }
2599  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2600  }
2601  } finally {
2602  closeStatement(updateStatement);
2603  }
2604 
2605  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2606  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2607  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2608  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2609  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2610  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2611  + "status INTEGER, " // enabled/disabled/deleted
2612  + "type INTEGER, " // service/interactive
2613  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2614  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2615  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2616  + "UNIQUE(signature, realm_id), "
2617  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2618  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2619  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2620 
2621  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2622  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2623  + "host_id " + bigIntDataType + ", "
2624  + "source_obj_id " + bigIntDataType + ", "
2625  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2626  + "value_type INTEGER NOT NULL, "
2627  + "value_byte " + bigIntDataType + ", "
2628  + "value_text TEXT, "
2629  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2630  + "value_double NUMERIC(20, 10), "
2631  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2632  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2633  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2634  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2635 
2636  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2637  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2638  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2639  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2640  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2641  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2642  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2643 
2644  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2645  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2646  + "os_account_obj_id " + bigIntDataType + ", "
2647  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2648 
2649  // add owner_uid & os_account_obj_id columns to tsk_files
2650  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2651  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2652 
2653  // create host address tables
2654  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2655  + "address_type INTEGER NOT NULL, "
2656  + "address TEXT NOT NULL, "
2657  + "UNIQUE(address_type, address)) ");
2658 
2659  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2660  + "host_id " + bigIntDataType + " NOT NULL, "
2661  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2662  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2663  + "time " + bigIntDataType + ", " // time at which the mapping existed
2664  + "UNIQUE(host_id, addr_obj_id, time), "
2665  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2666  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2667  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2668 
2669  // stores associations between DNS name and IP address
2670  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2671  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2672  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2673  + "source_obj_id " + bigIntDataType + ", "
2674  + "time " + bigIntDataType + ", " // time at which the mapping existed
2675  + "UNIQUE(dns_address_id, ip_address_id, time), "
2676  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2677  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2678  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2679 
2680  // maps an address to an artifact using it
2681  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2682  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2683  + "obj_id " + bigIntDataType + " NOT NULL, "
2684  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2685  + "UNIQUE(addr_obj_id, obj_id), "
2686  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2687  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2688 
2689  return new CaseDbSchemaVersionNumber(9, 0);
2690 
2691  } finally {
2692  closeStatement(statement);
2694  }
2695  }
2696 
2697  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2698  if (schemaVersion.getMajor() != 9) {
2699  return schemaVersion;
2700  }
2701 
2702  if (schemaVersion.getMinor() != 0) {
2703  return schemaVersion;
2704  }
2705 
2706  Statement statement = connection.createStatement();
2707  ResultSet results = null;
2709  try {
2710  // The 9.0 schema contained method_category columns that were renamed to priority.
2711  switch (getDatabaseType()) {
2712  case POSTGRESQL:
2713  // Check if the misnamed column is present. We'll assume here that the column will exist
2714  // in both tables if present in one.
2715  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2716  + "WHERE table_name='tsk_analysis_results' and column_name='method_category'");
2717  if (results.next()) {
2718  // In PostgreSQL we can delete the column
2719  statement.execute("ALTER TABLE tsk_analysis_results "
2720  + "DROP COLUMN method_category");
2721  statement.execute("ALTER TABLE tsk_aggregate_score "
2722  + "DROP COLUMN method_category");
2723  }
2724  break;
2725  case SQLITE:
2726  // Check if the misnamed column is present. We'll assume here that the column will exist
2727  // in both tables if present in one.
2728  boolean hasMisnamedColumn = false;
2729  results = statement.executeQuery("pragma table_info('tsk_analysis_results')");
2730  while (results.next()) {
2731  if (results.getString("name") != null && results.getString("name").equals("method_category")) {
2732  hasMisnamedColumn = true;
2733  break;
2734  }
2735  }
2736 
2737  if (hasMisnamedColumn) {
2738  // Since we can't rename the column we'll need to make a new table and copy the data.
2739  // We'll add the priority column later.
2740  statement.execute("CREATE TABLE temp_tsk_analysis_results (artifact_obj_id INTEGER PRIMARY KEY, "
2741  + "conclusion TEXT, "
2742  + "significance INTEGER NOT NULL, "
2743  + "configuration TEXT, justification TEXT, "
2744  + "ignore_score INTEGER DEFAULT 0 " // boolean
2745  + ")");
2746  statement.execute("CREATE TABLE temp_tsk_aggregate_score( obj_id INTEGER PRIMARY KEY, "
2747  + "data_source_obj_id INTEGER, "
2748  + "significance INTEGER NOT NULL, "
2749  + "UNIQUE (obj_id),"
2750  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2751  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2752  + ")");
2753 
2754  // Copy the data
2755  statement.execute("INSERT INTO temp_tsk_analysis_results(artifact_obj_id, "
2756  + "conclusion, justification, significance, configuration, ignore_score) "
2757  + "SELECT artifact_obj_id, conclusion, justification, significance, configuration, ignore_score FROM tsk_analysis_results");
2758  statement.execute("INSERT INTO temp_tsk_aggregate_score(obj_id, "
2759  + "data_source_obj_id, significance) "
2760  + "SELECT obj_id, data_source_obj_id, significance FROM tsk_aggregate_score");
2761 
2762  // Drop the old tables
2763  statement.execute("DROP TABLE tsk_analysis_results");
2764  statement.execute("DROP TABLE tsk_aggregate_score");
2765 
2766  // Rename the new tables
2767  statement.execute("ALTER TABLE temp_tsk_analysis_results RENAME TO tsk_analysis_results");
2768  statement.execute("ALTER TABLE temp_tsk_aggregate_score RENAME TO tsk_aggregate_score");
2769 
2770  }
2771  break;
2772  default:
2773  throw new TskCoreException("Unsupported database type: " + getDatabaseType().toString());
2774  }
2775 
2776  // add an index on tsk_file_attributes table.
2777  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2778 
2779  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2780  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2781 
2782  statement.execute("UPDATE blackboard_artifact_types SET category_type = 1 WHERE artifact_type_id = 16");
2783 
2784  return new CaseDbSchemaVersionNumber(9, 1);
2785  } finally {
2786  closeResultSet(results);
2787  closeStatement(statement);
2789  }
2790  }
2791 
2805  private CaseDbSchemaVersionNumber updateFromSchema9dot1toSchema9dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2806  if (schemaVersion.getMajor() != 9) {
2807  return schemaVersion;
2808  }
2809 
2810  if (schemaVersion.getMinor() != 1) {
2811  return schemaVersion;
2812  }
2813 
2814  Statement updateSchemaStatement = connection.createStatement();
2815  ResultSet results = null;
2817  try {
2818 
2819  String bigIntDataType = "BIGINT";
2820  String primaryKeyType = "BIGSERIAL";
2821 
2822  if (this.dbType.equals(DbType.SQLITE)) {
2823  bigIntDataType = "INTEGER";
2824  primaryKeyType = "INTEGER";
2825  }
2826 
2827  // In 9.2 we modified the UNIQUE constraint on tsk_os_account_instances to include instance_type column.
2828  // Since SQLite does not allow to drop or alter constraints, we will create a new table, copy the data and delete the old table.
2829  // Rename existing table
2830  updateSchemaStatement.execute("ALTER TABLE tsk_os_account_instances RENAME TO old_tsk_os_account_instances");
2831 
2832  // New table
2833  updateSchemaStatement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2834  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2835  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2836  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2837  + "UNIQUE(os_account_obj_id, data_source_obj_id, instance_type), "
2838  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id) ON DELETE CASCADE, "
2839  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE ) ");
2840 
2841  // Copy the data from old table, order by id preserves the primary key.
2842  updateSchemaStatement.execute("INSERT INTO tsk_os_account_instances(os_account_obj_id, "
2843  + "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");
2844 
2845  // delete old table
2846  updateSchemaStatement.execute("DROP TABLE old_tsk_os_account_instances");
2847 
2848  return new CaseDbSchemaVersionNumber(9, 2);
2849  } finally {
2850  closeResultSet(results);
2851  closeStatement(updateSchemaStatement);
2853  }
2854  }
2855 
2856  private CaseDbSchemaVersionNumber updateFromSchema9dot2toSchema9dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2857  if (schemaVersion.getMajor() != 9) {
2858  return schemaVersion;
2859  }
2860 
2861  if (schemaVersion.getMinor() != 2) {
2862  return schemaVersion;
2863  }
2864 
2865  Statement statement = connection.createStatement();
2867  try {
2868  // add a new column 'sha1' to tsk_files
2869  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha1 TEXT");
2870 
2871 
2872  return new CaseDbSchemaVersionNumber(9, 3);
2873 
2874  } finally {
2875  closeStatement(statement);
2877  }
2878  }
2879 
2880  private CaseDbSchemaVersionNumber updateFromSchema9dot3toSchema9dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2881  if (schemaVersion.getMajor() != 9) {
2882  return schemaVersion;
2883  }
2884 
2885  if (schemaVersion.getMinor() != 3) {
2886  return schemaVersion;
2887  }
2888 
2889  Statement statement = connection.createStatement();
2891  try {
2892  // Add file_collection_status_types table
2893  statement.execute("CREATE TABLE file_collection_status_types (collection_status_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
2894  initCollectedStatusTypes(connection);
2895 
2896  // add a new column 'collected' to tsk_files
2897  statement.execute("ALTER TABLE tsk_files ADD COLUMN collected INTEGER NOT NULL DEFAULT " +
2898  TskData.CollectedStatus.UNKNOWN.getType() + ";");
2899 
2900  return new CaseDbSchemaVersionNumber(9, 4);
2901 
2902  } finally {
2903  closeStatement(statement);
2905  }
2906  }
2907 
2908  private CaseDbSchemaVersionNumber updateFromSchema9dot4toSchema9dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2909  if (schemaVersion.getMajor() != 9) {
2910  return schemaVersion;
2911  }
2912 
2913  if (schemaVersion.getMinor() != 4) {
2914  return schemaVersion;
2915  }
2916 
2917  Statement statement = connection.createStatement();
2919  try {
2920  // Adding indexes to the os account table
2921  statement.execute("CREATE INDEX tsk_os_accounts_login_name_idx ON tsk_os_accounts(login_name, db_status, realm_id)");
2922  statement.execute("CREATE INDEX tsk_os_accounts_addr_idx ON tsk_os_accounts(addr, db_status, realm_id)");
2923  statement.execute("CREATE INDEX tsk_os_account_realms_realm_name_idx ON tsk_os_account_realms(realm_name)");
2924  statement.execute("CREATE INDEX tsk_os_account_realms_realm_addr_idx ON tsk_os_account_realms(realm_addr)");
2925 
2926  return new CaseDbSchemaVersionNumber(9, 5);
2927 
2928  } finally {
2929  closeStatement(statement);
2931  }
2932  }
2933 
2934  private CaseDbSchemaVersionNumber updateFromSchema9dot5toSchema9dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2935  if (schemaVersion.getMajor() != 9) {
2936  return schemaVersion;
2937  }
2938 
2939  if (schemaVersion.getMinor() != 5) {
2940  return schemaVersion;
2941  }
2942 
2943  String insertSQL = "";
2944  switch (getDatabaseType()) {
2945  case POSTGRESQL:
2946  insertSQL = "CREATE INDEX tsk_files_datasrc_md5_size_partial_index ON tsk_files(data_source_obj_id, md5, size) WHERE md5 IS NOT NULL AND size > 0"; //NON-NLS
2947  break;
2948  case SQLITE:
2949  insertSQL = "CREATE INDEX tsk_files_datasrc_md5_size_index ON tsk_files(data_source_obj_id, md5, size)";
2950  break;
2951  default:
2952  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2953  }
2954 
2955  Statement statement = connection.createStatement();
2957  try {
2958  // Adding index to the tsk_files table
2959  statement.execute(insertSQL);
2960 
2961  return new CaseDbSchemaVersionNumber(9, 6);
2962 
2963  } finally {
2964  closeStatement(statement);
2966  }
2967  }
2968 
2980  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2981 
2982  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2983  switch (getDatabaseType()) {
2984  case POSTGRESQL:
2985  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2986  break;
2987  case SQLITE:
2988  insertSQL = "INSERT OR IGNORE " + insertSQL;
2989  break;
2990  default:
2991  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2992  }
2993  statement.execute(insertSQL); //NON-NLS
2994  }
2995 
3003  static String extractExtension(final String fileName) {
3004  String ext;
3005  int i = fileName.lastIndexOf(".");
3006  // > 0 because we assume it's not an extension if period is the first character
3007  if ((i > 0) && ((i + 1) < fileName.length())) {
3008  ext = fileName.substring(i + 1);
3009  } else {
3010  return "";
3011  }
3012  // we added this at one point to deal with files that had crazy names based on URLs
3013  // it's too hard though to clean those up and not mess up basic extensions though.
3014  // We need to add '-' to the below if we use it again
3015  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
3016  // if (findNonAlphanumeric.length > 1) {
3017  // ext = findNonAlphanumeric[0];
3018  // }
3019  return ext.toLowerCase();
3020  }
3021 
3032  @Deprecated
3033  public int getSchemaVersion() {
3034  return getDBSchemaVersion().getMajor();
3035  }
3036 
3043  return CURRENT_DB_SCHEMA_VERSION;
3044  }
3045 
3053  return caseDBSchemaCreationVersion;
3054  }
3055 
3062  return this.dbType;
3063  }
3064 
3071  public String getBackupDatabasePath() {
3072  return dbBackupPath;
3073  }
3074 
3089  public CaseDbTransaction beginTransaction() throws TskCoreException {
3090  return new CaseDbTransaction(this);
3091  }
3092 
3098  public String getDatabaseName() {
3099  return databaseName;
3100  }
3101 
3108  public String getDbDirPath() {
3109  return caseDirPath;
3110  }
3111 
3118  if (dbType == DbType.SQLITE) {
3119  rwLock.writeLock().lock();
3120  }
3121  }
3122 
3129  if (dbType == DbType.SQLITE) {
3130  rwLock.writeLock().unlock();
3131  }
3132  }
3133 
3140  if (dbType == DbType.SQLITE) {
3141  rwLock.readLock().lock();
3142  }
3143  }
3144 
3151  if (dbType == DbType.SQLITE) {
3152  rwLock.readLock().unlock();
3153  }
3154  }
3155 
3165  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
3166  return openCase(dbPath, null);
3167  }
3168 
3179  @Beta
3180  public static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider) throws TskCoreException {
3181  return openCase(dbPath, provider, null);
3182  }
3183 
3196  @Beta
3197  public static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider, String lockingApplicationName) throws TskCoreException {
3198  try {
3199  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3200  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, provider, lockingApplicationName);
3202  //don't wrap in new TskCoreException
3203  throw ex;
3204  } catch (Exception ex) {
3205  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
3206  }
3207  }
3208 
3209 
3210 
3211 
3223  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
3224  return openCase(databaseName, info, caseDir, null);
3225  }
3226 
3239  @Beta
3240  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentStreamProvider contentProvider) throws TskCoreException {
3241  try {
3242  /*
3243  * The flow of this method involves trying to open case and if
3244  * successful, return that case. If unsuccessful, an exception is
3245  * thrown. We catch any exceptions, and use tryConnect() to attempt
3246  * to obtain further information about the error. If tryConnect() is
3247  * unable to successfully connect, tryConnect() will throw a
3248  * TskCoreException with a message containing user-level error
3249  * reporting. If tryConnect() is able to connect, flow continues and
3250  * we rethrow the original exception obtained from trying to create
3251  * the case. In this way, we obtain more detailed information if we
3252  * are able, but do not lose any information if unable.
3253  */
3254  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3255  return new SleuthkitCase(info, databaseName, caseHandle, caseDir, contentProvider);
3256  } catch (PropertyVetoException exp) {
3257  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3258  throw new TskCoreException(exp.getMessage(), exp);
3260  //don't wrap in new TskCoreException
3261  throw ex;
3262  } catch (Exception exp) {
3263  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3264  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3265  }
3266  }
3267 
3277  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
3278  return newCase(dbPath, null);
3279  }
3280 
3291  @Beta
3292  public static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider) throws TskCoreException {
3293  return newCase(dbPath, contentProvider, null);
3294  }
3295 
3311  @Beta
3312  public static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider, String lockingApplicationName) throws TskCoreException {
3313 
3314  try {
3315  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
3316  factory.createCaseDatabase();
3317 
3318  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
3319  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, contentProvider, lockingApplicationName);
3320  } catch (Exception ex) {
3321  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
3322  }
3323  }
3324 
3340  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
3341  return newCase(caseName, info, caseDirPath, null);
3342  }
3343 
3344 
3361  @Beta
3362  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentStreamProvider contentProvider) throws TskCoreException {
3363  String databaseName = createCaseDataBaseName(caseName);
3364  try {
3377  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
3378  factory.createCaseDatabase();
3379 
3380  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3381  return new SleuthkitCase(info, databaseName, caseHandle, caseDirPath, contentProvider);
3382  } catch (PropertyVetoException exp) {
3383  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3384  throw new TskCoreException(exp.getMessage(), exp);
3385  } catch (Exception exp) {
3386  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3387  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3388  }
3389  }
3390 
3400  private static String createCaseDataBaseName(String candidateDbName) {
3401  String dbName;
3402  if (!candidateDbName.isEmpty()) {
3403  /*
3404  * Replace all non-ASCII characters.
3405  */
3406  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
3407 
3408  /*
3409  * Replace all control characters.
3410  */
3411  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
3412 
3413  /*
3414  * Replace /, \, :, ?, space, ' ".
3415  */
3416  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
3417 
3418  /*
3419  * Make it all lowercase.
3420  */
3421  dbName = dbName.toLowerCase();
3422 
3423  /*
3424  * Must start with letter or underscore. If not, prepend an
3425  * underscore.
3426  */
3427  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
3428  dbName = "_" + dbName;
3429  }
3430 
3431  /*
3432  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
3433  * uniqueness.
3434  */
3435  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
3436  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
3437  }
3438 
3439  } else {
3440  /*
3441  * Must start with letter or underscore.
3442  */
3443  dbName = "_";
3444  }
3445  /*
3446  * Add the time stmap.
3447  */
3448  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
3449  Date date = new Date();
3450  dbName = dbName + "_" + dateFormat.format(date);
3451 
3452  return dbName;
3453  }
3454 
3460  @Beta
3462  timelineEventsDisabled.set(true);
3463  }
3464 
3472  public Examiner getCurrentExaminer() throws TskCoreException {
3473 
3474  // return cached value if there's one
3475  if (cachedCurrentExaminer != null) {
3476  return cachedCurrentExaminer;
3477  }
3478  String loginName = System.getProperty("user.name");
3479  if (loginName == null || loginName.isEmpty()) {
3480  throw new TskCoreException("Failed to determine logged in user name.");
3481  }
3482 
3483  ResultSet resultSet = null;
3484  CaseDbConnection connection = null;
3486  try {
3487  connection = connections.getConnection();
3488  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3489  statement.clearParameters();
3490  statement.setString(1, loginName);
3491  resultSet = connection.executeQuery(statement);
3492  if (resultSet.next()) {
3493  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3494  return cachedCurrentExaminer;
3495  } else {
3496  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3497  }
3498 
3499  } catch (SQLException ex) {
3500  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3501  } finally {
3502  closeResultSet(resultSet);
3503  closeConnection(connection);
3505  }
3506 
3507  }
3508 
3518  Examiner getExaminerById(long id) throws TskCoreException {
3519 
3520  CaseDbConnection connection = null;
3521  ResultSet resultSet = null;
3523  try {
3524  connection = connections.getConnection();
3525  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3526  statement.clearParameters();
3527  statement.setLong(1, id);
3528  resultSet = connection.executeQuery(statement);
3529  if (resultSet.next()) {
3530  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3531  } else {
3532  throw new TskCoreException("Error getting examaminer for id = " + id);
3533  }
3534  } catch (SQLException ex) {
3535  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3536  } finally {
3537  closeResultSet(resultSet);
3538  closeConnection(connection);
3540  }
3541  }
3542 
3560  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3561  return makeAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, null);
3562  }
3563 
3583  @Beta
3584  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath, String password) {
3585  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, password, this);
3586  }
3587 
3596  public List<Content> getRootObjects() throws TskCoreException {
3597  CaseDbConnection connection = null;
3598  Statement s = null;
3599  ResultSet rs = null;
3601  try {
3602  connection = connections.getConnection();
3603  s = connection.createStatement();
3604  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
3605  + "WHERE par_obj_id IS NULL"); //NON-NLS
3606  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3607  while (rs.next()) {
3608  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3609  }
3610 
3611  List<Content> rootObjs = new ArrayList<Content>();
3612  for (ObjectInfo i : infos) {
3613  if (null != i.type) {
3614  switch (i.type) {
3615  case IMG:
3616  rootObjs.add(getImageById(i.id));
3617  break;
3618  case ABSTRACTFILE:
3619  // Check if virtual dir for local files.
3620  AbstractFile af = getAbstractFileById(i.id);
3621  if (af instanceof VirtualDirectory) {
3622  rootObjs.add(af);
3623  } else {
3624  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3625  }
3626  break;
3627  case REPORT:
3628  break;
3629  case OS_ACCOUNT:
3630  break;
3631  case HOST_ADDRESS:
3632  break;
3633  case UNSUPPORTED:
3634  break;
3635  default:
3636  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3637  }
3638  }
3639  }
3640  return rootObjs;
3641  } catch (SQLException ex) {
3642  throw new TskCoreException("Error getting root objects", ex);
3643  } finally {
3644  closeResultSet(rs);
3645  closeStatement(s);
3646  closeConnection(connection);
3648  }
3649  }
3650 
3662  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3663 
3664  // check cached map first
3665  synchronized (deviceIdToDatasourceObjIdMap) {
3666  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3667  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3668  }
3669 
3670  CaseDbConnection connection = null;
3671  Statement s = null;
3672  ResultSet rs = null;
3674  try {
3675  connection = connections.getConnection();
3676  s = connection.createStatement();
3677  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3678  List<Long> dataSourceObjIds = new ArrayList<Long>();
3679  while (rs.next()) {
3680  dataSourceObjIds.add(rs.getLong("obj_id"));
3681 
3682  // Add to map of deviceID to data_source_obj_id.
3683  long ds_obj_id = rs.getLong("obj_id");
3684  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3685  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3686  } else {
3687  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3688  }
3689  }
3690  return dataSourceObjIds;
3691  } catch (SQLException ex) {
3692  throw new TskCoreException("Error getting data sources", ex);
3693  } finally {
3694  closeResultSet(rs);
3695  closeStatement(s);
3696  closeConnection(connection);
3698  }
3699  }
3700  }
3701 
3718  public List<DataSource> getDataSources() throws TskCoreException {
3719  CaseDbConnection connection = null;
3720  Statement statement = null;
3721  ResultSet resultSet = null;
3722  Statement statement2 = null;
3723  ResultSet resultSet2 = null;
3725  try {
3726  connection = connections.getConnection();
3727  statement = connection.createStatement();
3728  statement2 = connection.createStatement();
3729  resultSet = connection.executeQuery(statement,
3730  "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 "
3731  + "FROM data_source_info AS ds "
3732  + "LEFT JOIN tsk_image_info AS img "
3733  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3734 
3735  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3736  Map<Long, List<String>> imagePathsMap = getImagePaths();
3737 
3738  while (resultSet.next()) {
3739  DataSource dataSource;
3740  Long objectId = resultSet.getLong("obj_id");
3741  String deviceId = resultSet.getString("device_id");
3742  String timezone = resultSet.getString("time_zone");
3743  String type = resultSet.getString("type");
3744 
3745  if (type == null) {
3746  /*
3747  * No data found in 'tsk_image_info', so we build a
3748  * LocalFilesDataSource.
3749  */
3750 
3751  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3752  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3753  resultSet2.close();
3754 
3758  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3759  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3760  String parentPath = "/"; //NON-NLS
3761  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3762  } else {
3763  /*
3764  * Data found in 'tsk_image_info', so we build an Image.
3765  */
3766  Long ssize = resultSet.getLong("ssize");
3767  Long size = resultSet.getLong("size");
3768  String md5 = resultSet.getString("md5");
3769  String sha1 = resultSet.getString("sha1");
3770  String sha256 = resultSet.getString("sha256");
3771  String name = resultSet.getString("display_name");
3772 
3773  List<String> imagePaths = imagePathsMap.get(objectId);
3774  if (name == null) {
3775  if (imagePaths.size() > 0) {
3776  String path = imagePaths.get(0);
3777  name = (new java.io.File(path)).getName();
3778  } else {
3779  name = "";
3780  }
3781  }
3782 
3783  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3784  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3785  }
3786 
3787  dataSourceList.add(dataSource);
3788  }
3789 
3790  return dataSourceList;
3791 
3792  } catch (SQLException ex) {
3793  throw new TskCoreException("Error getting data sources", ex);
3794  } finally {
3795  closeResultSet(resultSet);
3796  closeStatement(statement);
3797  closeResultSet(resultSet2);
3798  closeStatement(statement2);
3799  closeConnection(connection);
3801  }
3802  }
3803 
3823  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3824  DataSource dataSource = null;
3825  CaseDbConnection connection = null;
3826  Statement statement = null;
3827  ResultSet resultSet = null;
3828  Statement statement2 = null;
3829  ResultSet resultSet2 = null;
3831  try {
3832  connection = connections.getConnection();
3833  statement = connection.createStatement();
3834  statement2 = connection.createStatement();
3835  resultSet = connection.executeQuery(statement,
3836  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3837  + "FROM data_source_info AS ds "
3838  + "LEFT JOIN tsk_image_info AS img "
3839  + "ON ds.obj_id = img.obj_id "
3840  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3841  if (resultSet.next()) {
3842  String deviceId = resultSet.getString("device_id");
3843  String timezone = resultSet.getString("time_zone");
3844  String type = resultSet.getString("type");
3845 
3846  if (type == null) {
3847  /*
3848  * No data found in 'tsk_image_info', so we build an
3849  * LocalFilesDataSource.
3850  */
3851 
3852  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3853  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3854 
3858  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3859  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3860  String parentPath = "/"; //NON-NLS
3861  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3862  } else {
3863  /*
3864  * Data found in 'tsk_image_info', so we build an Image.
3865  */
3866  Long ssize = resultSet.getLong("ssize");
3867  Long size = resultSet.getLong("size");
3868  String md5 = resultSet.getString("md5");
3869  String sha1 = resultSet.getString("sha1");
3870  String sha256 = resultSet.getString("sha256");
3871  String name = resultSet.getString("display_name");
3872 
3873  List<String> imagePaths = getImagePathsById(objectId, connection);
3874  if (name == null) {
3875  if (imagePaths.size() > 0) {
3876  String path = imagePaths.get(0);
3877  name = (new java.io.File(path)).getName();
3878  } else {
3879  name = "";
3880  }
3881  }
3882 
3883  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3884  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3885  }
3886  } else {
3887  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3888  }
3889  } catch (SQLException ex) {
3890  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3891  } finally {
3892  closeResultSet(resultSet);
3893  closeStatement(statement);
3894  closeResultSet(resultSet2);
3895  closeStatement(statement2);
3896  closeConnection(connection);
3898  }
3899 
3900  return dataSource;
3901  }
3902 
3915  @Deprecated
3916  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3917  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3918  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactTypeID)));
3919  return artifacts;
3920  }
3921 
3932  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3933  CaseDbConnection connection = null;
3934  ResultSet rs = null;
3936  try {
3937  connection = connections.getConnection();
3938 
3939  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3940  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3941  statement.clearParameters();
3942  statement.setLong(1, objId);
3943  rs = connection.executeQuery(statement);
3944  long count = 0;
3945  if (rs.next()) {
3946  count = rs.getLong("count");
3947  }
3948  return count;
3949  } catch (SQLException ex) {
3950  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3951  } finally {
3952  closeResultSet(rs);
3953  closeConnection(connection);
3955  }
3956  }
3957 
3968  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3969  CaseDbConnection connection = null;
3970  ResultSet rs = null;
3972  try {
3973  connection = connections.getConnection();
3974 
3975  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3976  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3977  statement.clearParameters();
3978  statement.setInt(1, artifactTypeID);
3979  rs = connection.executeQuery(statement);
3980  long count = 0;
3981  if (rs.next()) {
3982  count = rs.getLong("count");
3983  }
3984  return count;
3985  } catch (SQLException ex) {
3986  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3987  } finally {
3988  closeResultSet(rs);
3989  closeConnection(connection);
3991  }
3992  }
3993 
4005  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
4006  CaseDbConnection connection = null;
4007  ResultSet rs = null;
4009  try {
4010  connection = connections.getConnection();
4011 
4012  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
4013  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
4014  statement.clearParameters();
4015  statement.setInt(2, artifactTypeID);
4016  statement.setLong(1, dataSourceID);
4017  rs = connection.executeQuery(statement);
4018  long count = 0;
4019  if (rs.next()) {
4020  count = rs.getLong("count");
4021  }
4022  return count;
4023  } catch (SQLException ex) {
4024  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
4025  } finally {
4026  closeResultSet(rs);
4027  closeConnection(connection);
4029  }
4030  }
4031 
4048  @Deprecated
4049  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4051  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4052  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4053  + "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, "
4054  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
4055  + " arts.review_status_id AS review_status_id " //NON-NLS
4056  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4057  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4058  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4059  + " AND attrs.value_text = '" + value + "'"
4060  + " AND types.artifact_type_id=arts.artifact_type_id"
4061  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) { //NON-NLS
4062 
4063  List<Long> analysisArtifactObjIds = new ArrayList<>();
4064  List<Long> dataArtifactObjIds = new ArrayList<>();
4065  while (resultSet.next()) {
4066  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4067  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4068  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4069  } else {
4070  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4071  }
4072  }
4073 
4074  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4075  if (!analysisArtifactObjIds.isEmpty()) {
4076  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4077  }
4078 
4079  if (!dataArtifactObjIds.isEmpty()) {
4080  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4081  }
4082  return artifacts;
4083  } catch (SQLException ex) {
4084  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4085  } finally {
4087  }
4088  }
4089 
4108  @Deprecated
4109  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
4110  String valSubStr = "%" + subString; //NON-NLS
4111  if (startsWith == false) {
4112  valSubStr += "%"; //NON-NLS
4113  }
4114 
4116  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4117  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4118  + " 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
4119  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
4120  + " arts.review_status_id AS review_status_id " //NON-NLS
4121  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4122  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4123  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4124  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
4125  + " AND types.artifact_type_id=arts.artifact_type_id "
4126  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4127  List<Long> analysisArtifactObjIds = new ArrayList<>();
4128  List<Long> dataArtifactObjIds = new ArrayList<>();
4129  while (resultSet.next()) {
4130  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4131  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4132  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4133  } else {
4134  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4135  }
4136  }
4137 
4138  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4139  if (!analysisArtifactObjIds.isEmpty()) {
4140  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4141  }
4142 
4143  if (!dataArtifactObjIds.isEmpty()) {
4144  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4145  }
4146  return artifacts;
4147  } catch (SQLException ex) {
4148  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
4149  } finally {
4151  }
4152  }
4153 
4169  @Deprecated
4170  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
4172  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4173  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4174  + " 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, "
4175  + " types.type_name AS type_name, types.display_name AS display_name, "
4176  + " arts.review_status_id AS review_status_id "//NON-NLS
4177  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4178  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4179  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4180  + " AND attrs.value_int32 = " + value //NON-NLS
4181  + " AND types.artifact_type_id=arts.artifact_type_id "
4182  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4183  List<Long> analysisArtifactObjIds = new ArrayList<>();
4184  List<Long> dataArtifactObjIds = new ArrayList<>();
4185  while (resultSet.next()) {
4186  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4187  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4188  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4189  } else {
4190  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4191  }
4192  }
4193 
4194  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4195  if (!analysisArtifactObjIds.isEmpty()) {
4196  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4197  }
4198 
4199  if (!dataArtifactObjIds.isEmpty()) {
4200  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4201  }
4202  return artifacts;
4203  } catch (SQLException ex) {
4204  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4205  } finally {
4207  }
4208  }
4209 
4226  @Deprecated
4227  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
4229  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4230  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4231  + " 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, "
4232  + " types.type_name AS type_name, types.display_name AS display_name, "
4233  + " arts.review_status_id AS review_status_id "//NON-NLS
4234  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4235  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4236  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4237  + " AND attrs.value_int64 = " + value //NON-NLS
4238  + " AND types.artifact_type_id=arts.artifact_type_id "
4239  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4240  List<Long> analysisArtifactObjIds = new ArrayList<>();
4241  List<Long> dataArtifactObjIds = new ArrayList<>();
4242  while (resultSet.next()) {
4243  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4244  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4245  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4246  } else {
4247  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4248  }
4249  }
4250 
4251  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4252  if (!analysisArtifactObjIds.isEmpty()) {
4253  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4254  }
4255 
4256  if (!dataArtifactObjIds.isEmpty()) {
4257  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4258  }
4259  return artifacts;
4260  } catch (SQLException ex) {
4261  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
4262  } finally {
4264  }
4265  }
4266 
4283  @Deprecated
4284  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
4286  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4287  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4288  + " 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, "
4289  + " types.type_name AS type_name, types.display_name AS display_name, "
4290  + " arts.review_status_id AS review_status_id "//NON-NLS
4291  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4292  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4293  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4294  + " AND attrs.value_double = " + value //NON-NLS
4295  + " AND types.artifact_type_id=arts.artifact_type_id "
4296  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4297  List<Long> analysisArtifactObjIds = new ArrayList<>();
4298  List<Long> dataArtifactObjIds = new ArrayList<>();
4299  while (resultSet.next()) {
4300  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4301  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4302  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4303  } else {
4304  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4305  }
4306  }
4307 
4308  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4309  if (!analysisArtifactObjIds.isEmpty()) {
4310  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4311  }
4312 
4313  if (!dataArtifactObjIds.isEmpty()) {
4314  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4315  }
4316  return artifacts;
4317  } catch (SQLException ex) {
4318  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4319  } finally {
4321  }
4322  }
4323 
4340  @Deprecated
4341  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
4342 
4344  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
4345  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4346  + " 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, "
4347  + " types.type_name AS type_name, types.display_name AS display_name, "
4348  + " arts.review_status_id AS review_status_id "//NON-NLS
4349  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4350  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4351  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4352  + " AND attrs.value_byte = " + value //NON-NLS
4353  + " AND types.artifact_type_id=arts.artifact_type_id "
4354  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
4355  List<Long> analysisArtifactObjIds = new ArrayList<>();
4356  List<Long> dataArtifactObjIds = new ArrayList<>();
4357  while (resultSet.next()) {
4358  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4359  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4360  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4361  } else {
4362  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4363  }
4364  }
4365 
4366  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4367  if (!analysisArtifactObjIds.isEmpty()) {
4368  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4369  }
4370 
4371  if (!dataArtifactObjIds.isEmpty()) {
4372  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4373  }
4374  return artifacts;
4375  } catch (SQLException ex) {
4376  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
4377  } finally {
4379  }
4380  }
4381 
4389  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
4390  CaseDbConnection connection = null;
4391  Statement s = null;
4392  ResultSet rs = null;
4394  try {
4395  connection = connections.getConnection();
4396  s = connection.createStatement();
4397  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
4398  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
4399  while (rs.next()) {
4400  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4401  rs.getString("type_name"), rs.getString("display_name"),
4402  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4403  }
4404  return artifactTypes;
4405  } catch (SQLException ex) {
4406  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
4407  } finally {
4408  closeResultSet(rs);
4409  closeStatement(s);
4410  closeConnection(connection);
4412  }
4413  }
4414 
4423  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
4424  String typeIdList = "";
4425  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
4426  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
4427  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
4428  typeIdList += ", ";
4429  }
4430  }
4431  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
4432  + "WHERE artifact_type_id IN (" + typeIdList + ")";
4433  CaseDbConnection connection = null;
4434  Statement s = null;
4435  ResultSet rs = null;
4437  try {
4438  connection = connections.getConnection();
4439  s = connection.createStatement();
4440  rs = connection.executeQuery(s, query);
4441  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
4442  while (rs.next()) {
4443  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
4444  }
4445  return usedArts;
4446  } catch (SQLException ex) {
4447  throw new TskCoreException("Error getting artifact types in use", ex);
4448  } finally {
4449  closeResultSet(rs);
4450  closeStatement(s);
4451  closeConnection(connection);
4453  }
4454  }
4455 
4466  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
4467  CaseDbConnection connection = null;
4468  Statement s = null;
4469  ResultSet rs = null;
4471  try {
4472  connection = connections.getConnection();
4473  s = connection.createStatement();
4474  rs = connection.executeQuery(s,
4475  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
4476  + "types.type_name AS type_name, "
4477  + "types.display_name AS display_name, "
4478  + "types.category_type AS category_type "
4479  + "FROM blackboard_artifact_types AS types "
4480  + "INNER JOIN blackboard_artifacts AS arts "
4481  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
4482  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
4483  while (rs.next()) {
4484  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4485  rs.getString("type_name"), rs.getString("display_name"),
4486  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4487  }
4488  return uniqueArtifactTypes;
4489  } catch (SQLException ex) {
4490  throw new TskCoreException("Error getting attribute types", ex);
4491  } finally {
4492  closeResultSet(rs);
4493  closeStatement(s);
4494  closeConnection(connection);
4496  }
4497  }
4498 
4506  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
4507  CaseDbConnection connection = null;
4508  Statement s = null;
4509  ResultSet rs = null;
4511  try {
4512  connection = connections.getConnection();
4513  s = connection.createStatement();
4514  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
4515  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
4516  while (rs.next()) {
4517  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4518  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
4519  }
4520  return attribute_types;
4521  } catch (SQLException ex) {
4522  throw new TskCoreException("Error getting attribute types", ex);
4523  } finally {
4524  closeResultSet(rs);
4525  closeStatement(s);
4526  closeConnection(connection);
4528  }
4529  }
4530 
4542  public int getBlackboardAttributeTypesCount() throws TskCoreException {
4543  CaseDbConnection connection = null;
4544  Statement s = null;
4545  ResultSet rs = null;
4547  try {
4548  connection = connections.getConnection();
4549  s = connection.createStatement();
4550  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4551  int count = 0;
4552  if (rs.next()) {
4553  count = rs.getInt("count");
4554  }
4555  return count;
4556  } catch (SQLException ex) {
4557  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4558  } finally {
4559  closeResultSet(rs);
4560  closeStatement(s);
4561  closeConnection(connection);
4563  }
4564  }
4565 
4578  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4579  CaseDbConnection connection = null;
4580  ResultSet rs = null;
4582  try {
4583  connection = connections.getConnection();
4584 
4585  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4586  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4587  statement.clearParameters();
4588  statement.setLong(1, obj_id);
4589  statement.setInt(2, artifactTypeID);
4590  rs = connection.executeQuery(statement);
4591  long count = 0;
4592  if (rs.next()) {
4593  count = rs.getLong("count");
4594  }
4595  return count;
4596  } catch (SQLException ex) {
4597  throw new TskCoreException("Error getting blackboard artifact count", ex);
4598  } finally {
4599  closeResultSet(rs);
4600  closeConnection(connection);
4602  }
4603  }
4604 
4617  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4618  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4619  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeName), obj_id));
4620  return artifacts;
4621  }
4622 
4635  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4636  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4637  artifacts.addAll(blackboard.getArtifactsBySourceId(blackboard.getArtifactType(artifactTypeID), obj_id));
4638  return artifacts;
4639  }
4640 
4653  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4654  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4655  }
4656 
4669  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4670  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4671  if (artifactTypeID == -1) {
4672  return 0;
4673  }
4674  return getArtifactsCountHelper(artifactTypeID, obj_id);
4675  }
4676 
4689  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4690  return getArtifactsCountHelper(artifactTypeID, obj_id);
4691  }
4692 
4705  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4706  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4707  }
4708 
4720  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4721  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4722  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeName)));
4723  return artifacts;
4724  }
4725 
4737  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4738  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4739  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactType.getTypeID())));
4740  return artifacts;
4741  }
4742 
4758  @Deprecated
4759  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4760 
4761  String dataArtifactJoin = "tsk_data_artifacts AS datarts ON datarts.artifact_obj_id = arts.artifact_obj_id";
4762  String analysisResultJoin = "tsk_analysis_results AS anresult ON anresult.artifact_obj_id = arts.artifact_obj_id";
4763  String dataArtifactColumns = ", datarts.os_account_obj_id AS os_account_obj_id";
4764  String analysResultColumns = ", anresult.conclusion AS conclusion, anresult.significance AS significance, anresult.priority AS priority, anresult.configuration AS configuration, anresult.justification AS justification ";
4765 
4766  String formatQuery = "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4767  + "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, "
4768  + "types.type_name AS type_name, types.display_name AS display_name,"
4769  + "arts.review_status_id AS review_status_id %s "//NON-NLS
4770  + "FROM blackboard_artifacts AS arts "
4771  + "JOIN blackboard_attributes AS attrs ON arts.artifact_id = attrs.artifact_id "
4772  + "JOIN blackboard_artifact_types AS types ON types.artifact_type_id = arts.artifact_type_id " //NON-NLS
4773  + "LEFT JOIN %s "
4774  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4775  + "AND attrs.attribute_type_id = %d "
4776  + " AND arts.artifact_type_id = %d "
4777  + " AND attrs.value_text = '%s' " //NON-NLS
4778  + " AND types.artifact_type_id=arts.artifact_type_id "
4779  + " AND arts.review_status_id != %d";
4780 
4781  String query = String.format(formatQuery,
4782  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysResultColumns : dataArtifactColumns),
4783  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysisResultJoin : dataArtifactJoin),
4784  attrType.getTypeID(),
4785  artifactType.getTypeID(),
4786  value,
4788 
4790  try (CaseDbConnection connection = connections.getConnection(); Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
4791  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4792  while (rs.next()) {
4793  if (artifactType.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
4794  Long osAccountObjId = rs.getLong("os_account_obj_id");
4795  if (rs.wasNull()) {
4796  osAccountObjId = null;
4797  }
4798 
4799  artifacts.add(new DataArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4800  rs.getLong("artifact_obj_id"),
4801  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4802  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4803  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")), osAccountObjId, false));
4804  } else {
4805  artifacts.add(new AnalysisResult(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4806  rs.getLong("artifact_obj_id"),
4807  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4808  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4809  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")),
4810  new Score(Score.Significance.fromID(rs.getInt("significance")), Score.Priority.fromID(rs.getInt("priority"))),
4811  rs.getString("conclusion"), rs.getString("configuration"), rs.getString("justification")));
4812  }
4813  }
4814  return artifacts;
4815  } catch (SQLException ex) {
4816  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4817  } finally {
4819  }
4820  }
4821 
4833  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4834  List<DataArtifact> dataArtifacts = blackboard.getDataArtifactsWhere("artifacts.artifact_id = " + artifactID);
4835  if (!dataArtifacts.isEmpty()) {
4836  return dataArtifacts.get(0);
4837  }
4838 
4839  List<AnalysisResult> analysisResults = blackboard.getAnalysisResultsWhere("artifacts.artifact_id = " + artifactID);
4840  if (!analysisResults.isEmpty()) {
4841  return analysisResults.get(0);
4842  }
4843 
4844  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4845  }
4846 
4855  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4857  try (CaseDbConnection connection = connections.getConnection();) {
4858  addBlackBoardAttribute(attr, artifactTypeId, connection);
4859  } catch (SQLException ex) {
4860  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4861  } finally {
4863  }
4864  }
4865 
4875  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4876  CaseDbConnection connection = null;
4878  try {
4879  connection = connections.getConnection();
4880  connection.beginTransaction();
4881  for (final BlackboardAttribute attr : attributes) {
4882  addBlackBoardAttribute(attr, artifactTypeId, connection);
4883  }
4884  connection.commitTransaction();
4885  } catch (SQLException ex) {
4886  rollbackTransaction(connection);
4887  throw new TskCoreException("Error adding blackboard attributes", ex);
4888  } finally {
4889  closeConnection(connection);
4891  }
4892  }
4893 
4894  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4895  PreparedStatement statement;
4896  switch (attr.getAttributeType().getValueType()) {
4897  case STRING:
4898  case JSON:
4899  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4900  statement.clearParameters();
4901  statement.setString(7, attr.getValueString());
4902  break;
4903  case BYTE:
4904  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4905  statement.clearParameters();
4906  statement.setBytes(7, attr.getValueBytes());
4907  break;
4908  case INTEGER:
4909  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4910  statement.clearParameters();
4911  statement.setInt(7, attr.getValueInt());
4912  break;
4913  case LONG:
4914  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4915  statement.clearParameters();
4916  statement.setLong(7, attr.getValueLong());
4917  break;
4918  case DOUBLE:
4919  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4920  statement.clearParameters();
4921  statement.setDouble(7, attr.getValueDouble());
4922  break;
4923  case DATETIME:
4924  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4925  statement.clearParameters();
4926  statement.setLong(7, attr.getValueLong());
4927  break;
4928  default:
4929  throw new TskCoreException("Unrecognized artifact attribute value type");
4930  }
4931  statement.setLong(1, attr.getArtifactID());
4932  statement.setInt(2, artifactTypeId);
4933  statement.setString(3, attr.getSourcesCSV());
4934  statement.setString(4, "");
4935  statement.setInt(5, attr.getAttributeType().getTypeID());
4936  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4937  connection.executeUpdate(statement);
4938  }
4939 
4940  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4941  PreparedStatement statement;
4942  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4943  statement.clearParameters();
4944 
4945  statement.setLong(1, attr.getAttributeParentId());
4946  statement.setInt(2, attr.getAttributeType().getTypeID());
4947  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4948 
4949  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4950  statement.setBytes(4, attr.getValueBytes());
4951  } else {
4952  statement.setBytes(4, null);
4953  }
4954 
4955  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4956  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4957  statement.setString(5, attr.getValueString());
4958  } else {
4959  statement.setString(5, null);
4960  }
4961  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4962  statement.setInt(6, attr.getValueInt());
4963  } else {
4964  statement.setNull(6, java.sql.Types.INTEGER);
4965  }
4966 
4967  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4968  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4969  statement.setLong(7, attr.getValueLong());
4970  } else {
4971  statement.setNull(7, java.sql.Types.BIGINT);
4972  }
4973 
4974  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4975  statement.setDouble(8, attr.getValueDouble());
4976  } else {
4977  statement.setNull(8, java.sql.Types.DOUBLE);
4978  }
4979 
4980  connection.executeUpdate(statement);
4981  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4982  if (!resultSet.next()) {
4983  throw new TskCoreException(String.format("Failed to insert file attribute "
4984  + "with id=%d. The expected key was not generated", attr.getId()));
4985  }
4986 
4987  attr.setId(resultSet.getLong(1));
4988  }
4989  }
4990 
5001  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
5002  /*
5003  * WARNING: This is a temporary implementation that is not safe and
5004  * denormalizes the case datbase.
5005  *
5006  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
5007  * the sources of artifact attributes.
5008  */
5009  if (null == source || source.isEmpty()) {
5010  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
5011  }
5012  CaseDbConnection connection = null;
5014  Statement queryStmt = null;
5015  Statement updateStmt = null;
5016  ResultSet result = null;
5017  String newSources = "";
5018  try {
5019  connection = connections.getConnection();
5020  connection.beginTransaction();
5021  String valueClause = "";
5022  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
5023  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
5024  switch (valueType) {
5025  case STRING:
5026  case JSON:
5027  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
5028  break;
5029  case INTEGER:
5030  valueClause = " value_int32 = " + attr.getValueInt();
5031  break;
5032  case LONG:
5033  case DATETIME:
5034  valueClause = " value_int64 = " + attr.getValueLong();
5035  break;
5036  case DOUBLE:
5037  valueClause = " value_double = " + attr.getValueDouble();
5038  break;
5039  default:
5040  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
5041  }
5042  String query = "SELECT source FROM blackboard_attributes WHERE"
5043  + " artifact_id = " + attr.getArtifactID()
5044  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
5045  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
5046  + " AND " + valueClause + ";";
5047  queryStmt = connection.createStatement();
5048  updateStmt = connection.createStatement();
5049  result = connection.executeQuery(queryStmt, query);
5050  } else {
5051  /*
5052  * SELECT source FROM blackboard_attributes WHERE artifact_id =
5053  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
5054  * = ?
5055  */
5056  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
5057  statement.clearParameters();
5058  statement.setLong(1, attr.getArtifactID());
5059  statement.setLong(2, attr.getAttributeType().getTypeID());
5060  statement.setBytes(3, attr.getValueBytes());
5061  result = connection.executeQuery(statement);
5062  }
5063  while (result.next()) {
5064  String oldSources = result.getString("source");
5065  if (null != oldSources && !oldSources.isEmpty()) {
5066  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
5067  if (!uniqueSources.contains(source)) {
5068  newSources = oldSources + "," + source;
5069  } else {
5070  newSources = oldSources;
5071  }
5072  } else {
5073  newSources = source;
5074  }
5075  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
5076  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
5077  + " artifact_id = " + attr.getArtifactID()
5078  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
5079  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
5080  + " AND " + valueClause + ";";
5081  connection.executeUpdate(updateStmt, update);
5082  } else {
5083  /*
5084  * UPDATE blackboard_attributes SET source = ? WHERE
5085  * artifact_id = ? AND attribute_type_id = ? AND value_type
5086  * = 4 AND value_byte = ?
5087  */
5088  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
5089  statement.clearParameters();
5090  statement.setString(1, newSources);
5091  statement.setLong(2, attr.getArtifactID());
5092  statement.setLong(3, attr.getAttributeType().getTypeID());
5093  statement.setBytes(4, attr.getValueBytes());
5094  connection.executeUpdate(statement);
5095  }
5096  }
5097  connection.commitTransaction();
5098  return newSources;
5099  } catch (SQLException ex) {
5100  rollbackTransaction(connection);
5101  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
5102  } finally {
5103  closeResultSet(result);
5104  closeStatement(updateStmt);
5105  closeStatement(queryStmt);
5106  closeConnection(connection);
5108  }
5109  }
5110 
5125  @Deprecated
5126  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
5127  try {
5128  return blackboard.getOrAddAttributeType(attrTypeString, valueType, displayName);
5129  } catch (BlackboardException ex) {
5130  throw new TskCoreException("Error adding artifact type: " + attrTypeString, ex);
5131  }
5132  }
5133 
5145  @Deprecated
5146  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
5147  return blackboard.getAttributeType(attrTypeName);
5148  }
5149 
5161  @Deprecated
5162  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
5163  return blackboard.getArtifactType(artTypeName);
5164  }
5165 
5182  @Deprecated
5183  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
5184  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
5185  }
5186 
5202  @Deprecated
5203  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
5204  try {
5205  return blackboard.getOrAddArtifactType(displayName, displayName, category);
5206  } catch (BlackboardException ex) {
5207  throw new TskCoreException("Error getting or adding artifact type with name: " + artifactTypeName, ex);
5208  }
5209  }
5210 
5222  @Deprecated
5223  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
5224  return blackboard.getBlackboardAttributes(artifact);
5225  }
5226 
5227 
5240  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
5241  CaseDbConnection connection = null;
5242  Statement s = null;
5243  ResultSet rs = null;
5245  try {
5246  connection = connections.getConnection();
5247  s = connection.createStatement();
5248  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
5249  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
5250  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
5251  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
5252  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
5253  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
5254  + "FROM blackboard_attributes " + whereClause); //NON-NLS
5255  ArrayList<BlackboardAttribute> matches = new ArrayList<>();
5256  while (rs.next()) {
5258  // attribute type is cached, so this does not necessarily call to the db
5259  type = blackboard.getAttributeType(rs.getInt("attribute_type_id"));
5261  rs.getLong("artifact_id"),
5262  type,
5263  rs.getString("source"),
5264  rs.getString("context"),
5265  rs.getInt("value_int32"),
5266  rs.getLong("value_int64"),
5267  rs.getDouble("value_double"),
5268  rs.getString("value_text"),
5269  rs.getBytes("value_byte"), this
5270  );
5271  matches.add(attr);
5272  }
5273  return matches;
5274  } catch (SQLException ex) {
5275  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5276  } finally {
5277  closeResultSet(rs);
5278  closeStatement(s);
5279  closeConnection(connection);
5281  }
5282  }
5283 
5295  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
5296  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
5297  + "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, "
5298  + "blackboard_artifacts.review_status_id AS review_status_id "
5299  + "FROM blackboard_artifacts " + whereClause;
5301  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
5302 
5303  List<Long> analysisArtifactObjIds = new ArrayList<>();
5304  List<Long> dataArtifactObjIds = new ArrayList<>();
5305  while (resultSet.next()) {
5306  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
5307  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5308  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5309  } else {
5310  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5311  }
5312  }
5313 
5314  ArrayList<BlackboardArtifact> matches = new ArrayList<>();
5315  if (!analysisArtifactObjIds.isEmpty()) {
5316  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
5317  }
5318 
5319  if (!dataArtifactObjIds.isEmpty()) {
5320  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
5321  }
5322 
5323  return matches;
5324  } catch (SQLException ex) {
5325  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5326  } finally {
5328  }
5329  }
5330 
5345  @Deprecated
5346  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
5347  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5348  if (type == null) {
5349  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
5350  }
5351 
5352  Category category = type.getCategory();
5353  if (category == null) {
5354  throw new TskCoreException(String.format("No category for %s (id: %d)",
5355  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
5356  type.getTypeID()));
5357  }
5358 
5359  Content content = getContentById(obj_id);
5360  if (content == null) {
5361  throw new TskCoreException("No content found for object id: " + obj_id);
5362  }
5363 
5364  switch (category) {
5365  case ANALYSIS_RESULT:
5366  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
5367  .getAnalysisResult();
5368  case DATA_ARTIFACT:
5369  return content.newDataArtifact(type, Collections.emptyList());
5370  default:
5371  throw new TskCoreException("Unknown category type: " + category.getName());
5372  }
5373  }
5374 
5387  @Deprecated
5388  @SuppressWarnings("deprecation")
5389  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
5390  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
5391  }
5392 
5408  @Deprecated
5409  @SuppressWarnings("deprecation")
5410  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5411  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5412  try (CaseDbConnection connection = connections.getConnection()) {
5413  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5414  }
5415  }
5416 
5417  @Deprecated
5418  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5419  try (CaseDbConnection connection = connections.getConnection()) {
5420  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5421  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5422  }
5423  }
5424 
5425  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5426 
5427  PreparedStatement statement;
5428  if (dbType == DbType.POSTGRESQL) {
5429  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5430  statement.clearParameters();
5431  statement.setLong(1, obj_id);
5432  statement.setLong(2, artifact_obj_id);
5433  statement.setLong(3, data_source_obj_id);
5434  statement.setInt(4, artifact_type_id);
5435  } else {
5436  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5437  statement.clearParameters();
5438  this.nextArtifactId++;
5439  statement.setLong(1, this.nextArtifactId);
5440  statement.setLong(2, obj_id);
5441  statement.setLong(3, artifact_obj_id);
5442  statement.setLong(4, data_source_obj_id);
5443  statement.setInt(5, artifact_type_id);
5444  }
5445 
5446  return statement;
5447  }
5448 
5465  @Deprecated
5466  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5467  BlackboardArtifact.Type type = blackboard.getArtifactType(artifact_type_id);
5468  try {
5469  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5470  return blackboard.newAnalysisResult(type, obj_id, data_source_obj_id, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList()).getAnalysisResult();
5471  } else {
5472  return blackboard.newDataArtifact(type, obj_id, data_source_obj_id, Collections.emptyList(), null);
5473  }
5474  } catch (BlackboardException ex) {
5475  throw new TskCoreException("Error creating a blackboard artifact", ex);
5476  }
5477  }
5478 
5497  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5498 
5499  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5500  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5501  }
5502 
5503  long artifactID;
5505  try {
5506  // add a row in tsk_objects
5507  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5508 
5509  // add a row in blackboard_artifacts table
5510  PreparedStatement insertArtifactstatement;
5511  ResultSet resultSet = null;
5512  try {
5513  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5514  connection.executeUpdate(insertArtifactstatement);
5515  resultSet = insertArtifactstatement.getGeneratedKeys();
5516  resultSet.next();
5517  artifactID = resultSet.getLong(1); //last_insert_rowid()
5518 
5519  // add a row in tsk_analysis_results if any data for it is set
5520  if (score.getSignificance() != Score.Significance.UNKNOWN
5521  || !StringUtils.isBlank(conclusion)
5522  || !StringUtils.isBlank(configuration)
5523  || !StringUtils.isBlank(justification)) {
5524 
5525  PreparedStatement analysisResultsStatement;
5526 
5527  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5528  analysisResultsStatement.clearParameters();
5529 
5530  analysisResultsStatement.setLong(1, artifactObjId);
5531  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5532  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5533  analysisResultsStatement.setInt(4, score.getPriority().getId());
5534  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5535  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5536 
5537  connection.executeUpdate(analysisResultsStatement);
5538  }
5539 
5540  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5541  artifactType.getTypeName(), artifactType.getDisplayName(),
5542  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5543  score, (conclusion != null) ? conclusion : "",
5544  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5545 
5546  } finally {
5547  closeResultSet(resultSet);
5548  }
5549 
5550  } catch (SQLException ex) {
5551  throw new TskCoreException("Error creating a analysis result", ex);
5552  } finally {
5554  }
5555  }
5556 
5569  boolean getContentHasChildren(Content content) throws TskCoreException {
5570  CaseDbConnection connection = null;
5571  ResultSet rs = null;
5573  try {
5574  connection = connections.getConnection();
5575 
5576  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5577  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5578  statement.clearParameters();
5579  statement.setLong(1, content.getId());
5580  rs = connection.executeQuery(statement);
5581  boolean hasChildren = false;
5582  if (rs.next()) {
5583  hasChildren = rs.getInt("count") > 0;
5584  }
5585  return hasChildren;
5586  } catch (SQLException e) {
5587  throw new TskCoreException("Error checking for children of parent " + content, e);
5588  } finally {
5589  closeResultSet(rs);
5590  closeConnection(connection);
5592  }
5593  }
5594 
5607  int getContentChildrenCount(Content content) throws TskCoreException {
5608 
5609  if (!this.getHasChildren(content)) {
5610  return 0;
5611  }
5612 
5613  CaseDbConnection connection = null;
5614  ResultSet rs = null;
5616  try {
5617  connection = connections.getConnection();
5618 
5619  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5620  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5621  statement.clearParameters();
5622  statement.setLong(1, content.getId());
5623  rs = connection.executeQuery(statement);
5624  int countChildren = -1;
5625  if (rs.next()) {
5626  countChildren = rs.getInt("count");
5627  }
5628  return countChildren;
5629  } catch (SQLException e) {
5630  throw new TskCoreException("Error checking for children of parent " + content, e);
5631  } finally {
5632  closeResultSet(rs);
5633  closeConnection(connection);
5635  }
5636  }
5637 
5657  int getAbstractFileChildrenCountByType(Content content, List<TSK_FS_NAME_TYPE_ENUM> types) throws TskCoreException {
5658 
5659  if (!this.getHasChildren(content)) {
5660  return 0;
5661  }
5662 
5663  if (types == null || types.isEmpty()) {
5664  return 0;
5665  }
5666 
5667  CaseDbConnection connection = null;
5668  ResultSet rs = null;
5670  try {
5671  connection = connections.getConnection();
5672 
5673  // Construct the IN clause dynamically
5674  StringBuilder inClause = new StringBuilder("?");
5675  for (int i = 1; i < types.size(); i++) {
5676  inClause.append(", ?");
5677  }
5678 
5679  String sql = "SELECT COUNT(*) AS count "
5680  + "FROM tsk_objects "
5681  + "INNER JOIN tsk_files ON tsk_objects.obj_id = tsk_files.obj_id "
5682  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.dir_type IN (" + inClause.toString() + "))";
5683 
5684  PreparedStatement statement = connection.getConnection().prepareStatement(sql);
5685  statement.clearParameters();
5686  statement.setLong(1, content.getId());
5687 
5688  for (int i = 0; i < types.size(); i++) {
5689  statement.setInt(i + 2, types.get(i).getValue()); // Note: i+2 because index 1 is already taken by obj_id
5690  }
5691 
5692  rs = connection.executeQuery(statement);
5693  int countChildren = -1;
5694  if (rs.next()) {
5695  countChildren = rs.getInt("count");
5696  }
5697  return countChildren;
5698  } catch (SQLException e) {
5699  throw new TskCoreException("Error checking for children of parent " + content, e);
5700  } finally {
5701  closeResultSet(rs);
5702  closeConnection(connection);
5704  }
5705  }
5706 
5718  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5719  CaseDbConnection connection = null;
5720  ResultSet rs = null;
5722  try {
5723  connection = connections.getConnection();
5724 
5725  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5726  statement.clearParameters();
5727  long parentId = parent.getId();
5728  statement.setLong(1, parentId);
5729  statement.setShort(2, type.getFileType());
5730  rs = connection.executeQuery(statement);
5731  return fileChildren(rs, connection, parentId);
5732  } catch (SQLException ex) {
5733  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5734  } finally {
5735  closeResultSet(rs);
5736  closeConnection(connection);
5738  }
5739  }
5740 
5750  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5751  CaseDbConnection connection = null;
5752  ResultSet rs = null;
5754  try {
5755  connection = connections.getConnection();
5756 
5757  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5758  statement.clearParameters();
5759  long parentId = parent.getId();
5760  statement.setLong(1, parentId);
5761  rs = connection.executeQuery(statement);
5762  return fileChildren(rs, connection, parentId);
5763  } catch (SQLException ex) {
5764  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5765  } finally {
5766  closeResultSet(rs);
5767  closeConnection(connection);
5769  }
5770  }
5771 
5783  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5784  CaseDbConnection connection = null;
5785  ResultSet rs = null;
5787  try {
5788  connection = connections.getConnection();
5789 
5790  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5791  statement.clearParameters();
5792  statement.setLong(1, parent.getId());
5793  statement.setShort(2, type.getFileType());
5794  rs = connection.executeQuery(statement);
5795  List<Long> children = new ArrayList<Long>();
5796  while (rs.next()) {
5797  children.add(rs.getLong("obj_id"));
5798  }
5799  return children;
5800  } catch (SQLException ex) {
5801  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5802  } finally {
5803  closeResultSet(rs);
5804  closeConnection(connection);
5806  }
5807  }
5808 
5818  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5819  CaseDbConnection connection = null;
5820  ResultSet rs = null;
5822  try {
5823  connection = connections.getConnection();
5824 
5825  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5826  statement.clearParameters();
5827  statement.setLong(1, parent.getId());
5828  rs = connection.executeQuery(statement);
5829  List<Long> children = new ArrayList<Long>();
5830  while (rs.next()) {
5831  children.add(rs.getLong("obj_id"));
5832  }
5833  return children;
5834  } catch (SQLException ex) {
5835  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5836  } finally {
5837  closeResultSet(rs);
5838  closeConnection(connection);
5840  }
5841  }
5842 
5853  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5854  CaseDbConnection connection = null;
5855  ResultSet rs = null;
5857  try {
5858  connection = connections.getConnection();
5859 
5860  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5861  statement.clearParameters();
5862  statement.setLong(1, parent.getId());
5863  rs = connection.executeQuery(statement);
5864  List<Long> children = new ArrayList<Long>();
5865  while (rs.next()) {
5866  children.add(rs.getLong("obj_id"));
5867  }
5868  return children;
5869  } catch (SQLException ex) {
5870  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5871  } finally {
5872  closeResultSet(rs);
5873  closeConnection(connection);
5875  }
5876  }
5877 
5887  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5888  long parentId = parent.getId();
5889  List<Content> lc = new ArrayList<>();
5890  lc.addAll(blackboard.getAnalysisResults(parentId));
5891  lc.addAll(blackboard.getDataArtifactsBySource(parentId));
5892  return lc;
5893  }
5894 
5903  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5904  CaseDbConnection connection = null;
5905  Statement s = null;
5906  ResultSet rs = null;
5908  try {
5909  connection = connections.getConnection();
5910  s = connection.createStatement();
5911  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5912  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5913  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5914  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5915  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5916  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5917  while (rs.next()) {
5918  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5919  }
5920  return infos;
5921  } catch (SQLException ex) {
5922  throw new TskCoreException("Error getting Children Info for Content", ex);
5923  } finally {
5924  closeResultSet(rs);
5925  closeStatement(s);
5926  closeConnection(connection);
5928  }
5929  }
5930 
5941  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5942  return getParentInfo(c.getId());
5943  }
5944 
5955  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5957  CaseDbConnection connection = null;
5958  Statement s = null;
5959  ResultSet rs = null;
5960  try {
5961  connection = connections.getConnection();
5962  s = connection.createStatement();
5963  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5964  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5965  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5966  + "WHERE child.obj_id = " + contentId); //NON-NLS
5967  if (rs.next()) {
5968  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5969  } else {
5970  return null;
5971  }
5972  } catch (SQLException ex) {
5973  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5974  } finally {
5975  closeResultSet(rs);
5976  closeStatement(s);
5977  closeConnection(connection);
5979  }
5980  }
5981 
5992  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5993  if (fsc.isRoot()) {
5994  // Given FsContent is a root object and can't have parent directory
5995  return null;
5996  } else {
5997  ObjectInfo parentInfo = getParentInfo(fsc);
5998  if (parentInfo == null) {
5999  return null;
6000  }
6001  Directory parent = null;
6002  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
6003  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
6004  } else {
6005  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
6006  }
6007  return parent;
6008  }
6009  }
6010 
6022  public Content getContentById(long id) throws TskCoreException {
6023  // First check to see if this exists in our frequently used content cache.
6024  Content content = frequentlyUsedContentMap.get(id);
6025  if (null != content) {
6026  return content;
6027  }
6028 
6029  long parentId;
6030  TskData.ObjectType type;
6031 
6032  CaseDbConnection connection = null;
6033  Statement s = null;
6034  ResultSet rs = null;
6036  try {
6037  connection = connections.getConnection();
6038  s = connection.createStatement();
6039  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
6040  if (!rs.next()) {
6041  return null;
6042  }
6043  parentId = rs.getLong("par_obj_id"); //NON-NLS
6044  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
6045  } catch (SQLException ex) {
6046  throw new TskCoreException("Error getting Content by ID.", ex);
6047  } finally {
6048  closeResultSet(rs);
6049  closeStatement(s);
6050  closeConnection(connection);
6052  }
6053 
6054  // Construct the object
6055  switch (type) {
6056  case IMG:
6057  content = getImageById(id);
6058  frequentlyUsedContentMap.put(id, content);
6059  break;
6060  case VS:
6061  content = getVolumeSystemById(id, parentId);
6062  break;
6063  case VOL:
6064  content = getVolumeById(id, parentId);
6065  frequentlyUsedContentMap.put(id, content);
6066  break;
6067  case POOL:
6068  content = getPoolById(id, parentId);
6069  break;
6070  case FS:
6071  content = getFileSystemById(id, parentId);
6072  frequentlyUsedContentMap.put(id, content);
6073  break;
6074  case ABSTRACTFILE:
6075  content = getAbstractFileById(id);
6076 
6077  // Add virtual and root directories to frequently used map.
6078  // Calling isRoot() on local directories goes up the entire directory structure
6079  // and they can only be the root of portable cases, so skip trying to add
6080  // them to the cache.
6081  if (((AbstractFile) content).isVirtual()
6082  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
6083  frequentlyUsedContentMap.put(id, content);
6084  }
6085  break;
6086  case ARTIFACT:
6087  content = getArtifactById(id);
6088  break;
6089  case REPORT:
6090  content = getReportById(id);
6091  break;
6092  case OS_ACCOUNT:
6093  content = this.osAccountManager.getOsAccountByObjectId(id);
6094  break;
6095  case HOST_ADDRESS:
6096  content = hostAddressManager.getHostAddress(id);
6097  break;
6098  default:
6099  content = new UnsupportedContent(this, id);
6100  }
6101 
6102  return content;
6103  }
6104 
6112  String getFilePath(long id) {
6113 
6114  String filePath = null;
6115  CaseDbConnection connection = null;
6116  ResultSet rs = null;
6118  try {
6119  connection = connections.getConnection();
6120 
6121  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
6122  statement.clearParameters();
6123  statement.setLong(1, id);
6124  rs = connection.executeQuery(statement);
6125  if (rs.next()) {
6126  filePath = rs.getString("path");
6127  }
6128  } catch (SQLException | TskCoreException ex) {
6129  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
6130  } finally {
6131  closeResultSet(rs);
6132  closeConnection(connection);
6134  }
6135  return filePath;
6136  }
6137 
6145  TskData.EncodingType getEncodingType(long id) {
6146 
6147  TskData.EncodingType type = TskData.EncodingType.NONE;
6148  CaseDbConnection connection = null;
6149  ResultSet rs = null;
6151  try {
6152  connection = connections.getConnection();
6153  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
6154  statement.clearParameters();
6155  statement.setLong(1, id);
6156  rs = connection.executeQuery(statement);
6157  if (rs.next()) {
6158  type = TskData.EncodingType.valueOf(rs.getInt(1));
6159  }
6160  } catch (SQLException | TskCoreException ex) {
6161  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
6162  } finally {
6163  closeResultSet(rs);
6164  closeConnection(connection);
6166  }
6167  return type;
6168  }
6169 
6178  String getFileParentPath(long objectId, CaseDbConnection connection) {
6179  String parentPath = null;
6181  ResultSet rs = null;
6182  try {
6183  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
6184  statement.clearParameters();
6185  statement.setLong(1, objectId);
6186  rs = connection.executeQuery(statement);
6187  if (rs.next()) {
6188  parentPath = rs.getString("parent_path");
6189  }
6190  } catch (SQLException ex) {
6191  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
6192  } finally {
6193  closeResultSet(rs);
6195  }
6196  return parentPath;
6197  }
6198 
6207  String getFileName(long objectId, CaseDbConnection connection) {
6208  String fileName = null;
6210  ResultSet rs = null;
6211  try {
6212  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
6213  statement.clearParameters();
6214  statement.setLong(1, objectId);
6215  rs = connection.executeQuery(statement);
6216  if (rs.next()) {
6217  fileName = rs.getString("name");
6218  }
6219  } catch (SQLException ex) {
6220  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
6221  } finally {
6222  closeResultSet(rs);
6224  }
6225  return fileName;
6226  }
6227 
6238  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
6239 
6240  DerivedFile.DerivedMethod method = null;
6241  CaseDbConnection connection = null;
6242  ResultSet rs1 = null;
6243  ResultSet rs2 = null;
6245  try {
6246  connection = connections.getConnection();
6247 
6248  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
6249  statement.clearParameters();
6250  statement.setLong(1, id);
6251  rs1 = connection.executeQuery(statement);
6252  if (rs1.next()) {
6253  int method_id = rs1.getInt("derived_id");
6254  String rederive = rs1.getString("rederive");
6255  method = new DerivedFile.DerivedMethod(method_id, rederive);
6256  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
6257  statement.clearParameters();
6258  statement.setInt(1, method_id);
6259  rs2 = connection.executeQuery(statement);
6260  if (rs2.next()) {
6261  method.setToolName(rs2.getString("tool_name"));
6262  method.setToolVersion(rs2.getString("tool_version"));
6263  method.setOther(rs2.getString("other"));
6264  }
6265  }
6266  } catch (SQLException e) {
6267  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
6268  } finally {
6269  closeResultSet(rs2);
6270  closeResultSet(rs1);
6271  closeConnection(connection);
6273  }
6274  return method;
6275  }
6276 
6287  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
6288  CaseDbConnection connection = connections.getConnection();
6289  try {
6290  return getAbstractFileById(id, connection);
6291  } finally {
6292  closeConnection(connection);
6293  }
6294  }
6295 
6308  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
6310  ResultSet rs = null;
6311  try {
6312  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
6313  statement.clearParameters();
6314  statement.setLong(1, objectId);
6315  rs = connection.executeQuery(statement);
6316  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
6317  if (files.size() > 0) {
6318  return files.get(0);
6319  } else {
6320  return null;
6321  }
6322  } catch (SQLException ex) {
6323  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
6324  } finally {
6325  closeResultSet(rs);
6327  }
6328  }
6329 
6341  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
6342 
6343  CaseDbConnection connection = null;
6344  ResultSet rs = null;
6346  try {
6347  connection = connections.getConnection();
6348 
6349  // get the artifact type.
6350  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
6351  statement.clearParameters();
6352  statement.setLong(1, id);
6353 
6354  rs = connection.executeQuery(statement);
6355  if (!rs.next()) {
6356  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
6357  }
6358 
6359  // based on the artifact type category, get the analysis result or the data artifact
6360  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(rs.getInt("artifact_type_id"));
6361  switch (artifactType.getCategory()) {
6362  case ANALYSIS_RESULT:
6363  return blackboard.getAnalysisResultById(id);
6364  case DATA_ARTIFACT:
6365  return blackboard.getDataArtifactById(id);
6366  default:
6367  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
6368  }
6369 
6370  } catch (SQLException ex) {
6371  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
6372  } finally {
6373  closeResultSet(rs);
6374  closeConnection(connection);
6376  }
6377  }
6378 
6392  @Deprecated
6393  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
6394  String query = "SELECT artifact_type_id, artifact_obj_id FROM blackboard_artifacts WHERE artifact_id = " + id;
6396 
6397  try (CaseDbConnection connection = connections.getConnection();
6398  Statement statement = connection.createStatement();
6399  ResultSet resultSet = statement.executeQuery(query);) {
6400  if (resultSet != null && resultSet.next()) {
6401  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
6402  long artifactObjId = resultSet.getLong("artifact_obj_id");
6403  switch (artifactType.getCategory()) {
6404  case ANALYSIS_RESULT:
6405  return blackboard.getAnalysisResultById(artifactObjId);
6406  case DATA_ARTIFACT:
6407  return blackboard.getDataArtifactById(artifactObjId);
6408  }
6409  }
6410  return null;
6411  } catch (SQLException ex) {
6412  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
6413  } finally {
6415  }
6416  }
6417 
6430  private long getFileSystemId(long fileId, CaseDbConnection connection) {
6432  ResultSet rs = null;
6433  long ret = -1;
6434  try {
6435  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
6436  statement.clearParameters();
6437  statement.setLong(1, fileId);
6438  rs = connection.executeQuery(statement);
6439  if (rs.next()) {
6440  ret = rs.getLong("fs_obj_id");
6441  if (ret == 0) {
6442  ret = -1;
6443  }
6444  }
6445  } catch (SQLException e) {
6446  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
6447  } finally {
6448  closeResultSet(rs);
6450  }
6451  return ret;
6452  }
6453 
6465  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6466  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
6467  CaseDbConnection connection = null;
6468  Statement statement = null;
6469  ResultSet resultSet = null;
6471  try {
6472  connection = connections.getConnection();
6473  statement = connection.createStatement();
6474  resultSet = connection.executeQuery(statement, query);
6475  resultSet.next();
6476  return (resultSet.getLong("count") > 0L);
6477  } catch (SQLException ex) {
6478  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6479  } finally {
6480  closeResultSet(resultSet);
6481  closeStatement(statement);
6482  closeConnection(connection);
6484  }
6485  }
6486 
6496  private static boolean containsLikeWildcard(String str) {
6497  if (str == null) {
6498  return false;
6499  } else {
6500  return str.contains("%") || str.contains("_");
6501  }
6502  }
6503 
6515  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6516  String ext = "";
6517  if (!containsLikeWildcard(fileName)) {
6518  ext = SleuthkitCase.extractExtension(fileName);
6519  }
6520 
6521  List<AbstractFile> files = new ArrayList<>();
6522  CaseDbConnection connection = null;
6523  ResultSet resultSet = null;
6525  try {
6526  connection = connections.getConnection();
6527 
6528  PreparedStatement statement;
6529  if (ext.isEmpty()) {
6530  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6531  statement.clearParameters();
6532  statement.setString(1, fileName.toLowerCase());
6533  statement.setLong(2, dataSource.getId());
6534  } else {
6535  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6536  statement.clearParameters();
6537  statement.setString(1, ext);
6538  statement.setString(2, fileName.toLowerCase());
6539  statement.setLong(3, dataSource.getId());
6540  }
6541 
6542  resultSet = connection.executeQuery(statement);
6543  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6544  } catch (SQLException e) {
6545  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6546  } finally {
6547  closeResultSet(resultSet);
6548  closeConnection(connection);
6550  }
6551  return files;
6552  }
6553 
6567  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6568  String ext = "";
6569  if (!containsLikeWildcard(fileName)) {
6570  ext = SleuthkitCase.extractExtension(fileName);
6571  }
6572 
6573  List<AbstractFile> files = new ArrayList<>();
6574  CaseDbConnection connection = null;
6575  ResultSet resultSet = null;
6577  try {
6578  connection = connections.getConnection();
6579  PreparedStatement statement;
6580  if (ext.isEmpty()) {
6581  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6582  statement.clearParameters();
6583  statement.setString(1, fileName.toLowerCase());
6584  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6585  statement.setLong(3, dataSource.getId());
6586  } else {
6587  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6588  statement.clearParameters();
6589  statement.setString(1, ext);
6590  statement.setString(2, fileName.toLowerCase());
6591  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6592  statement.setLong(4, dataSource.getId());
6593  }
6594 
6595  resultSet = connection.executeQuery(statement);
6596  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6597  } catch (SQLException e) {
6598  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6599  } finally {
6600  closeResultSet(resultSet);
6601  closeConnection(connection);
6603  }
6604  return files;
6605  }
6606 
6618  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6619  CaseDbTransaction localTrans = beginTransaction();
6620  try {
6621  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6622  localTrans.commit();
6623  localTrans = null;
6624  return newVD;
6625  } finally {
6626  if (null != localTrans) {
6627  try {
6628  localTrans.rollback();
6629  } catch (TskCoreException ex2) {
6630  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6631  }
6632  }
6633  }
6634  }
6635 
6648  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6649  ResultSet resultSet = null;
6651  try {
6652  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6653  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6654  statement.clearParameters();
6655  if (parentId != 0) {
6656  statement.setLong(1, parentId);
6657  } else {
6658  statement.setNull(1, java.sql.Types.BIGINT);
6659  }
6660  statement.setInt(2, objectType);
6661  connection.executeUpdate(statement);
6662  resultSet = statement.getGeneratedKeys();
6663 
6664  if (resultSet.next()) {
6665  if (parentId != 0) {
6666  setHasChildren(parentId);
6667  }
6668  return resultSet.getLong(1); //last_insert_rowid()
6669  } else {
6670  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6671  }
6672  } finally {
6673  closeResultSet(resultSet);
6675  }
6676  }
6677 
6695  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6696  if (transaction == null) {
6697  throw new TskCoreException("Passed null CaseDbTransaction");
6698  }
6699 
6700  ResultSet resultSet = null;
6701  try {
6702  // Get the parent path.
6703  CaseDbConnection connection = transaction.getConnection();
6704 
6705  String parentPath;
6706  Content parent = this.getAbstractFileById(parentId, connection);
6707  if (parent instanceof AbstractFile) {
6708  if (isRootDirectory((AbstractFile) parent, transaction)) {
6709  if (parent.getName().isEmpty()) {
6710  parentPath = "/";
6711  } else {
6712  parentPath = "/" + parent.getName() + "/";
6713  }
6714  } else {
6715  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6716  }
6717  } else {
6718  // The parent was either null or not an abstract file
6719  parentPath = "/";
6720  }
6721 
6722  // Insert a row for the virtual directory into the tsk_objects table.
6723  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6724 
6725  // Insert a row for the virtual directory into the tsk_files table.
6726  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6727  // 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)
6728  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)
6729  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6730  statement.clearParameters();
6731  statement.setLong(1, newObjId);
6732 
6733  // If the parent is part of a file system, grab its file system ID
6734  Long fileSystemObjectId = null;
6735  if (0 != parentId) {
6736  fileSystemObjectId = this.getFileSystemId(parentId, connection);
6737  if (fileSystemObjectId != -1) {
6738  statement.setLong(2, fileSystemObjectId);
6739  } else {
6740  statement.setNull(2, java.sql.Types.BIGINT);
6741  fileSystemObjectId = null;
6742  }
6743  } else {
6744  statement.setNull(2, java.sql.Types.BIGINT);
6745  }
6746 
6747  // name
6748  statement.setString(3, directoryName);
6749 
6750  //type
6751  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6752  statement.setShort(5, (short) 1);
6753 
6754  //flags
6756  statement.setShort(6, dirType.getValue());
6758  statement.setShort(7, metaType.getValue());
6759 
6760  //allocated
6762  statement.setShort(8, dirFlag.getValue());
6763  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6764  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6765  statement.setShort(9, metaFlags);
6766 
6767  //size
6768  statement.setLong(10, 0);
6769 
6770  // nulls for params 11-14
6771  statement.setNull(11, java.sql.Types.BIGINT);
6772  statement.setNull(12, java.sql.Types.BIGINT);
6773  statement.setNull(13, java.sql.Types.BIGINT);
6774  statement.setNull(14, java.sql.Types.BIGINT);
6775 
6776  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6777  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6778  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6779 
6780  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6781  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6782 
6783  // parent path
6784  statement.setString(20, parentPath);
6785 
6786  // data source object id (same as object id if this is a data source)
6787  long dataSourceObjectId;
6788  if (0 == parentId) {
6789  dataSourceObjectId = newObjId;
6790  } else {
6791  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6792  }
6793  statement.setLong(21, dataSourceObjectId);
6794 
6795  //extension, since this is not really file we just set it to null
6796  statement.setString(22, null);
6797 
6798  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6799  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6800  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6801 
6802  connection.executeUpdate(statement);
6803 
6804  return new VirtualDirectory(this, newObjId, dataSourceObjectId, fileSystemObjectId, directoryName, dirType,
6805  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6806  parentPath);
6807  } catch (SQLException e) {
6808  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6809  } finally {
6810  closeResultSet(resultSet);
6811  }
6812  }
6813 
6826  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6827  CaseDbTransaction localTrans = beginTransaction();
6828  try {
6829  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6830  localTrans.commit();
6831  return newLD;
6832  } catch (TskCoreException ex) {
6833  try {
6834  localTrans.rollback();
6835  } catch (TskCoreException ex2) {
6836  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6837  }
6838  throw ex;
6839  }
6840  }
6841 
6859  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6860  if (transaction == null) {
6861  throw new TskCoreException("Passed null CaseDbTransaction");
6862  }
6863 
6864  ResultSet resultSet = null;
6865  try {
6866  // Get the parent path.
6867  CaseDbConnection connection = transaction.getConnection();
6868  AbstractFile parent = getAbstractFileById(parentId, connection);
6869  String parentPath;
6870  if ((parent == null) || isRootDirectory(parent, transaction)) {
6871  parentPath = "/";
6872  } else {
6873  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6874  }
6875 
6876  // Insert a row for the local directory into the tsk_objects table.
6877  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6878 
6879  // Insert a row for the local directory into the tsk_files table.
6880  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6881  // 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)
6882  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6883  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6884  statement.clearParameters();
6885  statement.setLong(1, newObjId);
6886 
6887  // The parent of a local directory will never be a file system
6888  statement.setNull(2, java.sql.Types.BIGINT);
6889 
6890  // name
6891  statement.setString(3, directoryName);
6892 
6893  //type
6894  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6895  statement.setShort(5, (short) 1);
6896 
6897  //flags
6899  statement.setShort(6, dirType.getValue());
6901  statement.setShort(7, metaType.getValue());
6902 
6903  //allocated
6905  statement.setShort(8, dirFlag.getValue());
6906  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6907  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6908  statement.setShort(9, metaFlags);
6909 
6910  //size
6911  statement.setLong(10, 0);
6912 
6913  // nulls for params 11-14
6914  statement.setNull(11, java.sql.Types.BIGINT);
6915  statement.setNull(12, java.sql.Types.BIGINT);
6916  statement.setNull(13, java.sql.Types.BIGINT);
6917  statement.setNull(14, java.sql.Types.BIGINT);
6918 
6919  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6920  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6921  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6922 
6923  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6924  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6925 
6926  // parent path
6927  statement.setString(20, parentPath);
6928 
6929  // data source object id
6930  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6931  statement.setLong(21, dataSourceObjectId);
6932 
6933  //extension, since this is a directory we just set it to null
6934  statement.setString(22, null);
6935 
6936  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6937  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6938  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
6939 
6940  connection.executeUpdate(statement);
6941 
6942  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6943  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6944  parentPath);
6945  } catch (SQLException e) {
6946  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6947  } finally {
6948  closeResultSet(resultSet);
6949  }
6950  }
6951 
6971  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6972  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6973  }
6974 
6995  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6996 
6997  Statement statement = null;
6998  try {
6999  CaseDbConnection connection = transaction.getConnection();
7000 
7001  // Insert a row for the root virtual directory of the data source
7002  // into the tsk_objects table.
7003  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7004 
7005  // If no host was supplied, make one
7006  if (host == null) {
7007  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
7008  }
7009 
7010  // Insert a row for the virtual directory of the data source into
7011  // the data_source_info table.
7012  statement = connection.createStatement();
7013  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
7014  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
7015 
7016  // Insert a row for the root virtual directory of the data source
7017  // into the tsk_files table. Note that its data source object id is
7018  // its own object id.
7019  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
7020  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
7021  // atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
7022  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
7023  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7024  preparedStatement.clearParameters();
7025  preparedStatement.setLong(1, newObjId);
7026  preparedStatement.setNull(2, java.sql.Types.BIGINT);
7027  preparedStatement.setString(3, rootDirectoryName);
7028  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
7029  preparedStatement.setShort(5, (short) 1);
7031  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
7033  preparedStatement.setShort(7, metaType.getValue());
7035  preparedStatement.setShort(8, dirFlag.getValue());
7036  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7037  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7038  preparedStatement.setShort(9, metaFlags);
7039  preparedStatement.setLong(10, 0);
7040  preparedStatement.setNull(11, java.sql.Types.BIGINT);
7041  preparedStatement.setNull(12, java.sql.Types.BIGINT);
7042  preparedStatement.setNull(13, java.sql.Types.BIGINT);
7043  preparedStatement.setNull(14, java.sql.Types.BIGINT);
7044  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
7045  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7046  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7047  preparedStatement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7048  preparedStatement.setNull(19, java.sql.Types.VARCHAR); // MIME type
7049  String parentPath = "/"; //NON-NLS
7050  preparedStatement.setString(20, parentPath);
7051  preparedStatement.setLong(21, newObjId);
7052  preparedStatement.setString(22, null); //extension, just set it to null
7053  preparedStatement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7054  preparedStatement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7055  preparedStatement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7056 
7057 
7058  connection.executeUpdate(preparedStatement);
7059 
7060  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, null, FileKnown.UNKNOWN, parentPath);
7061 
7062  } catch (SQLException ex) {
7063  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
7064  } finally {
7065  closeStatement(statement);
7066  }
7067  }
7068 
7088  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
7089  String timezone, String md5, String sha1, String sha256,
7090  String deviceId,
7091  CaseDbTransaction transaction) throws TskCoreException {
7092  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
7093  }
7094 
7115  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
7116  String timezone, String md5, String sha1, String sha256,
7117  String deviceId, Host host,
7118  CaseDbTransaction transaction) throws TskCoreException {
7119 
7120  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, host, null, transaction);
7121  }
7122 
7144  @Beta
7145  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
7146  String timezone, String md5, String sha1, String sha256,
7147  String deviceId, Host host, String password,
7148  CaseDbTransaction transaction) throws TskCoreException {
7149  Statement statement = null;
7150  try {
7151  // Insert a row for the Image into the tsk_objects table.
7152  CaseDbConnection connection = transaction.getConnection();
7153  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
7154 
7155  // Add a row to tsk_image_info
7156  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
7157  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
7158  preparedStatement.clearParameters();
7159  preparedStatement.setLong(1, newObjId);
7160  preparedStatement.setShort(2, (short) type.getValue());
7161  preparedStatement.setLong(3, sectorSize);
7162  preparedStatement.setString(4, timezone);
7163  //prevent negative size
7164  long savedSize = size < 0 ? 0 : size;
7165  preparedStatement.setLong(5, savedSize);
7166  preparedStatement.setString(6, md5);
7167  preparedStatement.setString(7, sha1);
7168  preparedStatement.setString(8, sha256);
7169  preparedStatement.setString(9, displayName);
7170  connection.executeUpdate(preparedStatement);
7171 
7172  // If there are paths, add them to tsk_image_names
7173  for (int i = 0; i < imagePaths.size(); i++) {
7174  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
7175  preparedStatement.clearParameters();
7176  preparedStatement.setLong(1, newObjId);
7177  preparedStatement.setString(2, imagePaths.get(i));
7178  preparedStatement.setLong(3, i);
7179  connection.executeUpdate(preparedStatement);
7180  }
7181 
7182  // Create the display name
7183  String name = displayName;
7184  if (name == null || name.isEmpty()) {
7185  if (imagePaths.size() > 0) {
7186  String path = imagePaths.get(0);
7187  name = (new java.io.File(path)).getName();
7188  } else {
7189  name = "";
7190  }
7191  }
7192 
7193  // Create a host if needed
7194  if (host == null) {
7195  if (name.isEmpty()) {
7196  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
7197  } else {
7198  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
7199  }
7200  }
7201 
7202  Map<String, Object> acquisitionToolMap = new HashMap<>();
7203  if (password != null) {
7204  acquisitionToolMap.put(IMAGE_PASSWORD_KEY, password);
7205  }
7206  String acquisitionToolJson = (new Gson()).toJson(acquisitionToolMap);
7207 
7208  // Add a row to data_source_info
7209  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
7210  statement = connection.createStatement();
7211  preparedStatement.setLong(1, newObjId);
7212  preparedStatement.setString(2, deviceId);
7213  preparedStatement.setString(3, timezone);
7214  preparedStatement.setLong(4, new Date().getTime());
7215  preparedStatement.setLong(5, host.getHostId());
7216  preparedStatement.setString(6, acquisitionToolJson);
7217  connection.executeUpdate(preparedStatement);
7218 
7219  // Create the new Image object
7220  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
7221  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
7222  } catch (SQLException ex) {
7223  if (!imagePaths.isEmpty()) {
7224  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
7225  } else {
7226  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
7227  }
7228  } finally {
7229  closeStatement(statement);
7230  }
7231  }
7232 
7246  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
7247  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
7248  try {
7249  // Insert a row for the VolumeSystem into the tsk_objects table.
7250  CaseDbConnection connection = transaction.getConnection();
7251  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
7252 
7253  // Add a row to tsk_vs_info
7254  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
7255  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
7256  preparedStatement.clearParameters();
7257  preparedStatement.setLong(1, newObjId);
7258  preparedStatement.setShort(2, (short) type.getVsType());
7259  preparedStatement.setLong(3, imgOffset);
7260  preparedStatement.setLong(4, blockSize);
7261  connection.executeUpdate(preparedStatement);
7262 
7263  // Create the new VolumeSystem object
7264  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
7265  } catch (SQLException ex) {
7266  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
7267  parentObjId, imgOffset), ex);
7268  }
7269  }
7270 
7286  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
7287  long flags, CaseDbTransaction transaction) throws TskCoreException {
7288  try {
7289  // Insert a row for the Volume into the tsk_objects table.
7290  CaseDbConnection connection = transaction.getConnection();
7291  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
7292 
7293  // Add a row to tsk_vs_parts
7294  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
7295  PreparedStatement preparedStatement;
7296  if (this.dbType == DbType.POSTGRESQL) {
7297  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
7298  } else {
7299  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
7300  }
7301  preparedStatement.clearParameters();
7302  preparedStatement.setLong(1, newObjId);
7303  preparedStatement.setLong(2, addr);
7304  preparedStatement.setLong(3, start);
7305  preparedStatement.setLong(4, length);
7306  preparedStatement.setString(5, desc);
7307  preparedStatement.setShort(6, (short) flags);
7308  connection.executeUpdate(preparedStatement);
7309 
7310  // Create the new Volume object
7311  return new Volume(this, newObjId, addr, start, length, flags, desc);
7312  } catch (SQLException ex) {
7313  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
7314  }
7315  }
7316 
7328  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
7329  try {
7330  // Insert a row for the Pool into the tsk_objects table.
7331  CaseDbConnection connection = transaction.getConnection();
7332  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
7333 
7334  // Add a row to tsk_pool_info
7335  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
7336  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
7337  preparedStatement.clearParameters();
7338  preparedStatement.setLong(1, newObjId);
7339  preparedStatement.setShort(2, type.getValue());
7340  connection.executeUpdate(preparedStatement);
7341 
7342  // Create the new Pool object
7343  return new Pool(this, newObjId, type.getName(), type.getValue());
7344  } catch (SQLException ex) {
7345  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
7346  }
7347  }
7348 
7367  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
7368  long rootInum, long firstInum, long lastInum, String displayName,
7369  CaseDbTransaction transaction) throws TskCoreException {
7370  try {
7371  // Insert a row for the FileSystem into the tsk_objects table.
7372  CaseDbConnection connection = transaction.getConnection();
7373  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
7374 
7375  // Get the data source object ID
7376  long dataSourceId = getDataSourceObjectId(connection, newObjId);
7377 
7378  // Add a row to tsk_fs_info
7379  // 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)
7380  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
7381  preparedStatement.clearParameters();
7382  preparedStatement.setLong(1, newObjId);
7383  preparedStatement.setLong(2, dataSourceId);
7384  preparedStatement.setLong(3, imgOffset);
7385  preparedStatement.setInt(4, type.getValue());
7386  preparedStatement.setLong(5, blockSize);
7387  preparedStatement.setLong(6, blockCount);
7388  preparedStatement.setLong(7, rootInum);
7389  preparedStatement.setLong(8, firstInum);
7390  preparedStatement.setLong(9, lastInum);
7391  preparedStatement.setString(10, displayName);
7392  connection.executeUpdate(preparedStatement);
7393 
7394  // Create the new FileSystem object
7395  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
7396  firstInum, lastInum);
7397  } catch (SQLException ex) {
7398  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
7399  imgOffset, parentObjId), ex);
7400  }
7401  }
7402 
7428  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7429  String fileName,
7430  long metaAddr, int metaSeq,
7431  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7432  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7433  long ctime, long crtime, long atime, long mtime,
7434  boolean isFile, Content parent) throws TskCoreException {
7435 
7436  CaseDbTransaction transaction = beginTransaction();
7437  try {
7438 
7439  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
7440  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
7441  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
7442  OsAccount.NO_OWNER_ID, null,
7443  Collections.emptyList(), transaction);
7444 
7445  transaction.commit();
7446  transaction = null;
7447  return fileSystemFile;
7448  } finally {
7449  if (null != transaction) {
7450  try {
7451  transaction.rollback();
7452  } catch (TskCoreException ex2) {
7453  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7454  }
7455  }
7456  }
7457  }
7458 
7496  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7497  String fileName,
7498  long metaAddr, int metaSeq,
7499  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7500  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7501  long ctime, long crtime, long atime, long mtime,
7502  String md5Hash, String sha256Hash, String mimeType,
7503  boolean isFile, Content parent, String ownerUid,
7504  OsAccount osAccount, List<Attribute> fileAttributes,
7505  CaseDbTransaction transaction) throws TskCoreException {
7506 
7507  return addFileSystemFile(dataSourceObjId, fsObjId,
7508  fileName,
7509  metaAddr, metaSeq,
7510  attrType, attrId,
7511  dirFlag, metaFlags, size,
7512  ctime, crtime, atime, mtime,
7513  md5Hash, sha256Hash, null,
7514  mimeType,
7515  isFile, parent, ownerUid,
7516  osAccount, fileAttributes,
7517  transaction);
7518  }
7519 
7559  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7560  String fileName,
7561  long metaAddr, int metaSeq,
7562  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7563  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7564  long ctime, long crtime, long atime, long mtime,
7565  String md5Hash, String sha256Hash, String sha1Hash,
7566  String mimeType, boolean isFile,
7567  Content parent, String ownerUid,
7568  OsAccount osAccount, List<Attribute> fileAttributes,
7569  CaseDbTransaction transaction) throws TskCoreException {
7570  return addFileSystemFile(dataSourceObjId, fsObjId,
7571  fileName,
7572  metaAddr, metaSeq,
7573  attrType, attrId,
7574  dirFlag, metaFlags, size,
7575  ctime, crtime, atime, mtime,
7576  md5Hash, sha256Hash, sha1Hash,
7577  mimeType,
7578  isFile, parent, ownerUid,
7579  osAccount, TskData.CollectedStatus.UNKNOWN, fileAttributes,
7580  transaction);
7581  }
7582 
7623  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7624  String fileName,
7625  long metaAddr, int metaSeq,
7626  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7627  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7628  long ctime, long crtime, long atime, long mtime,
7629  String md5Hash, String sha256Hash, String sha1Hash,
7630  String mimeType, boolean isFile,
7631  Content parent, String ownerUid,
7632  OsAccount osAccount, TskData.CollectedStatus collected,
7633  List<Attribute> fileAttributes,
7634  CaseDbTransaction transaction) throws TskCoreException {
7635  TimelineManager timelineManager = getTimelineManager();
7636 
7637  Statement queryStatement = null;
7638  String parentPath = "/";
7639  try {
7640  CaseDbConnection connection = transaction.getConnection();
7641 
7642  // Insert a row for the local/logical file into the tsk_objects table.
7643  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7644  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7645 
7646  if (parent instanceof AbstractFile) {
7647  AbstractFile parentFile = (AbstractFile) parent;
7648  if (isRootDirectory(parentFile, transaction)) {
7649  parentPath = "/";
7650  } else {
7651  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7652  }
7653  } else {
7654  parentPath = "/";
7655  }
7656 
7657  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7658  statement.clearParameters();
7659  statement.setLong(1, objectId); // obj_is
7660  statement.setLong(2, fsObjId); // fs_obj_id
7661  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7662  statement.setShort(4, (short) attrType.getValue()); // attr_type
7663  statement.setInt(5, attrId); // attr_id
7664  statement.setString(6, fileName); // name
7665  statement.setLong(7, metaAddr); // meta_addr
7666  statement.setInt(8, metaSeq); // meta_addr
7667  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7668  statement.setShort(10, (short) 1); // has_path
7670  statement.setShort(11, dirType.getValue()); // dir_type
7672  statement.setShort(12, metaType.getValue()); // meta_type
7673  statement.setShort(13, dirFlag.getValue()); // dir_flags
7674  statement.setShort(14, metaFlags); // meta_flags
7675  statement.setLong(15, size < 0 ? 0 : size);
7676  statement.setLong(16, ctime);
7677  statement.setLong(17, crtime);
7678  statement.setLong(18, atime);
7679  statement.setLong(19, mtime);
7680  statement.setString(20, md5Hash);
7681  statement.setString(21, sha256Hash);
7682  statement.setString(22, sha1Hash);
7683  statement.setString(23, mimeType);
7684  statement.setString(24, parentPath);
7685  final String extension = extractExtension(fileName);
7686  statement.setString(25, extension);
7687  statement.setString(26, ownerUid);
7688  if (null != osAccount) {
7689  statement.setLong(27, osAccount.getId());
7690  } else {
7691  statement.setNull(27, java.sql.Types.BIGINT); // osAccountObjId
7692  }
7693  statement.setLong(28, collected.getType());
7694 
7695  connection.executeUpdate(statement);
7696 
7697  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7698  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7699  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, sha1Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7700 
7701  if (!timelineEventsDisabled.get()) {
7702  timelineManager.addEventsForNewFile(derivedFile, connection);
7703  }
7704 
7705  for (Attribute fileAttribute : fileAttributes) {
7706  fileAttribute.setAttributeParentId(objectId);
7707  fileAttribute.setCaseDatabase(this);
7708  addFileAttribute(fileAttribute, connection);
7709  }
7710 
7711  if (osAccount != null) {
7712  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
7713  }
7714 
7715  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7716  attrType, attrId, fileName, metaAddr, metaSeq,
7717  dirType, metaType, dirFlag, metaFlags,
7718  size, ctime, crtime, atime, mtime,
7719  (short) 0, 0, 0, md5Hash, sha256Hash, sha1Hash, null, parentPath, mimeType,
7720  extension, ownerUid, osAccountId, collected, fileAttributes);
7721 
7722  } catch (SQLException ex) {
7723  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);
7724  } finally {
7725  closeStatement(queryStatement);
7726  }
7727  }
7728 
7737  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7738  CaseDbConnection connection = null;
7739  Statement s = null;
7740  ResultSet rs = null;
7742  try {
7743  connection = connections.getConnection();
7744  s = connection.createStatement();
7745  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7746  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7747  + " AND obj_id = data_source_obj_id"
7748  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7749  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7750  while (rs.next()) {
7751  virtDirRootIds.add(virtualDirectory(rs, connection));
7752  }
7753  return virtDirRootIds;
7754  } catch (SQLException ex) {
7755  throw new TskCoreException("Error getting local files virtual folder id", ex);
7756  } finally {
7757  closeResultSet(rs);
7758  closeStatement(s);
7759  closeConnection(connection);
7761  }
7762  }
7763 
7776  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7777  assert (null != fileRanges);
7778  if (null == fileRanges) {
7779  throw new TskCoreException("TskFileRange object is null");
7780  }
7781 
7782  assert (null != parent);
7783  if (null == parent) {
7784  throw new TskCoreException("Conent is null");
7785  }
7786 
7787  String parentPath;
7788  if (parent instanceof AbstractFile) {
7789  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7790  } else {
7791  parentPath = "/";
7792  }
7793 
7794  CaseDbTransaction transaction = null;
7795  Statement statement = null;
7796  ResultSet resultSet = null;
7797 
7798  try {
7799  transaction = beginTransaction();
7800  CaseDbConnection connection = transaction.getConnection();
7801 
7802  // If the parent is part of a file system, grab its file system ID
7803  Long fileSystemObjectId;
7804  if (0 != parent.getId()) {
7805  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
7806  if (fileSystemObjectId == -1) {
7807  fileSystemObjectId = null;
7808  }
7809  } else {
7810  fileSystemObjectId = null;
7811  }
7812 
7813  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<>();
7814  for (TskFileRange fileRange : fileRanges) {
7815  /*
7816  * Insert a row for the Tsk file range into the tsk_objects
7817  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7818  * ?)
7819  */
7820  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7821  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7822  /*
7823  * Insert a row for the Tsk file range into the tsk_files table:
7824  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7825  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7826  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7827  * parent_path, data_source_obj_id,extension, owner_uid,
7828  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7829  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
7830  */
7831  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7832  prepStmt.clearParameters();
7833  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7834  if (fileSystemObjectId != null) {
7835  prepStmt.setLong(2, fileSystemObjectId);// fs_obj_id
7836  } else {
7837  prepStmt.setNull(2, java.sql.Types.BIGINT);
7838  }
7839  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]
7840  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7841  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7842  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7843  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7844  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7845  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7846  prepStmt.setLong(10, fileRange.getByteLen()); // size
7847  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7848  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7849  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7850  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7851  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7852  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7853  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7854 
7855  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7856  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7857  prepStmt.setString(20, parentPath); // parent path
7858  prepStmt.setLong(21, parent.getId()); // data_source_obj_id
7859 
7860  //extension, since this is not a FS file we just set it to null
7861  prepStmt.setString(22, null);
7862 
7863  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7864  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7865  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
7866 
7867  connection.executeUpdate(prepStmt);
7868 
7869  /*
7870  * Insert a row in the tsk_layout_file table for each chunk of
7871  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7872  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7873  */
7874  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7875  prepStmt.clearParameters();
7876  prepStmt.setLong(1, fileRangeId); // obj_id
7877  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7878  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7879  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7880  connection.executeUpdate(prepStmt);
7881 
7882  /*
7883  * Create a layout file representation of the carved file.
7884  */
7885  fileRangeLayoutFiles.add(new LayoutFile(this,
7886  fileRangeId,
7887  parent.getId(),
7888  fileSystemObjectId,
7889  Long.toString(fileRange.getSequence()),
7894  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7895  fileRange.getByteLen(),
7896  0L, 0L, 0L, 0L,
7897  null, null, null,
7899  parent.getUniquePath(),
7900  null,
7901  OsAccount.NO_OWNER_ID,
7902  OsAccount.NO_ACCOUNT));
7903  }
7904 
7905  transaction.commit();
7906  transaction = null;
7907  return fileRangeLayoutFiles;
7908 
7909  } catch (SQLException ex) {
7910  throw new TskCoreException("Failed to add layout files to case database", ex);
7911  } finally {
7912  closeResultSet(resultSet);
7913  closeStatement(statement);
7914 
7915  if (null != transaction) {
7916  try {
7917  transaction.rollback();
7918  } catch (TskCoreException ex2) {
7919  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7920  }
7921  }
7922  }
7923  }
7924 
7931  private class CarvedFileDirInfo {
7932 
7933  final VirtualDirectory currentFolder;
7934  AtomicInteger count;
7935 
7936  CarvedFileDirInfo(VirtualDirectory currentFolder) {
7937  this.currentFolder = currentFolder;
7938  count = new AtomicInteger(0);
7939  }
7940 
7941  CarvedFileDirInfo(VirtualDirectory currentFolder, int count) {
7942  this.currentFolder = currentFolder;
7943  this.count = new AtomicInteger(count);
7944  }
7945 
7952  boolean isFull() {
7953  return count.get() >= MAX_CARVED_FILES_PER_FOLDER;
7954  }
7955 
7959  void incrementFileCounter() {
7960  count.incrementAndGet();
7961  }
7962  }
7963 
7973  private CarvedFileDirInfo getMostRecentCarvedDirInfo(VirtualDirectory carvedFilesBaseDir) throws TskCoreException {
7974  VirtualDirectory mostRecentDir = null;
7975  for (Content child : carvedFilesBaseDir.getChildren()) {
7976  if (isValidCarvedFileSubfolder(child)) {
7977  if (mostRecentDir == null
7978  || (mostRecentDir.getId() < child.getId())) {
7979  mostRecentDir = (VirtualDirectory) child;
7980  }
7981  }
7982  }
7983 
7984  if (mostRecentDir != null) {
7985  return new CarvedFileDirInfo(mostRecentDir, mostRecentDir.getChildrenCount());
7986  }
7987  return null;
7988  }
7989 
7998  private boolean isValidCarvedFileSubfolder(Content subfolder) {
7999  if (!(subfolder instanceof VirtualDirectory)) {
8000  return false;
8001  }
8002  return subfolder.getName().matches("^[0-9]+$");
8003  }
8004 
8018  private CarvedFileDirInfo createCarvedFilesSubfolder(Content carvedFilesBaseDir, CarvedFileDirInfo currentSubfolderInfo) throws TskCoreException {
8019  int nextIndex = 1;
8020  if (currentSubfolderInfo != null) {
8021  try {
8022  int currentIndex = Integer.parseInt(currentSubfolderInfo.currentFolder.getName());
8023  nextIndex = currentIndex + 1;
8024  } catch (NumberFormatException ex) {
8025  throw new TskCoreException("Unexpected name format for carved files subdirectory with ID: " + currentSubfolderInfo.currentFolder.getId() + " (" + currentSubfolderInfo.currentFolder.getName() + ")", ex);
8026  }
8027  }
8028 
8029  VirtualDirectory carvedFilesSubdir = addVirtualDirectory(carvedFilesBaseDir.getId(), Integer.toString(nextIndex));
8030  return new CarvedFileDirInfo(carvedFilesSubdir);
8031  }
8032 
8044  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
8045  assert (null != carvingResult);
8046  if (null == carvingResult) {
8047  throw new TskCoreException("Carving is null");
8048  }
8049  assert (null != carvingResult.getParent());
8050  if (null == carvingResult.getParent()) {
8051  throw new TskCoreException("Carving result has null parent");
8052  }
8053  assert (null != carvingResult.getCarvedFiles());
8054  if (null == carvingResult.getCarvedFiles()) {
8055  throw new TskCoreException("Carving result has null carved files");
8056  }
8057  CaseDbTransaction transaction = null;
8058  Statement statement = null;
8059  ResultSet resultSet = null;
8060  try {
8061 
8062  /*
8063  * Carved files are "re-parented" as children of the $CarvedFiles
8064  * virtual directory of the root file system, volume, or image
8065  * ancestor of the carved files parent, but if no such ancestor is
8066  * found, then the parent specified in the carving result is used.
8067  */
8068  Content root = carvingResult.getParent();
8069  while (null != root) {
8070  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
8071  break;
8072  }
8073  root = root.getParent();
8074  }
8075  if (null == root) {
8076  root = carvingResult.getParent();
8077  }
8078 
8079  /*
8080  * Get or create the $CarvedFiles virtual directory for the root
8081  * ancestor.
8082  */
8083  CarvedFileDirInfo carvedFilesDirInfo = null;
8084  synchronized (carvedFileDirsLock) {
8085  // Get the subfolder currently in use (if there is one)
8086  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
8087  if (carvedFilesDirInfo != null) {
8088  carvedFilesDirInfo.incrementFileCounter();
8089 
8090  // If the current folder is full, create a new one.
8091  if (carvedFilesDirInfo.isFull()) {
8092  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesDirInfo.currentFolder.getParent(), carvedFilesDirInfo);
8093  }
8094  }
8095 
8096  if (null == carvedFilesDirInfo) {
8097  List<Content> rootChildren;
8098  if (root instanceof FileSystem) {
8099  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
8100  } else {
8101  rootChildren = root.getChildren();
8102  }
8103  for (Content child : rootChildren) {
8104  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
8105 
8106  VirtualDirectory baseDir = (VirtualDirectory) child;
8107 
8108  // Get the most recent subfolder in the carved files folder.
8109  carvedFilesDirInfo = getMostRecentCarvedDirInfo(baseDir);
8110 
8111  // If there are no subfolders, create one.
8112  if (carvedFilesDirInfo == null) {
8113  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, null);
8114  }
8115 
8116  // If there are already too many files in the subfolder, create a new one.
8117  if (carvedFilesDirInfo.isFull()) {
8118  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, carvedFilesDirInfo);
8119  }
8120 
8121  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
8122  break;
8123  }
8124  }
8125  if (carvedFilesDirInfo == null) {
8126  // If we get here, we didn't have a carved files base folder in the case, so we need to make that and
8127  // the first subfolder.
8128 
8129  long parId = root.getId();
8130  // $CarvedFiles should be a child of the root directory, not the file system
8131  if (root instanceof FileSystem) {
8132  Content rootDir = ((FileSystem) root).getRootDirectory();
8133  parId = rootDir.getId();
8134  }
8135  VirtualDirectory carvedFilesBaseDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
8136  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, null);
8137  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
8138  }
8139  }
8140  }
8141 
8142  /*
8143  * Add the carved files to the database as children of the
8144  * $CarvedFile directory of the root ancestor.
8145  */
8146  VirtualDirectory carvedFilesBaseDir = (VirtualDirectory) carvedFilesDirInfo.currentFolder.getParent();
8147  transaction = beginTransaction();
8148  CaseDbConnection connection = transaction.getConnection();
8149  String parentPath = getFileParentPath(carvedFilesDirInfo.currentFolder.getId(), connection) + carvedFilesDirInfo.currentFolder.getName() + "/";
8150  List<LayoutFile> carvedFiles = new ArrayList<>();
8151  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
8152 
8153  /*
8154  * Check if we need to change to a new subfolder.
8155  */
8156  VirtualDirectory carvedFilesDir = carvedFilesDirInfo.currentFolder;
8157  if (carvedFilesDirInfo.isFull()) {
8158  // To prevent deadlocks involving the case write lock and the carvedFileDirsLock,
8159  // commit the current transaction and then start a new one
8160  // after switching to the new folder.
8161  transaction.commit();
8162 
8163  synchronized (carvedFileDirsLock) {
8164  // Get the current copy from the map - another thread may have just created a new folder.
8165  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
8166  if (carvedFilesDirInfo.isFull()) {
8167  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, carvedFilesDirInfo);
8168  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
8169  carvedFilesDir = carvedFilesDirInfo.currentFolder;
8170  }
8171  }
8172 
8173  // Start a new transaction.
8174  transaction = beginTransaction();
8175  connection = transaction.getConnection();
8176  parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
8177 
8178  }
8179  carvedFilesDirInfo.incrementFileCounter();
8180 
8181  /*
8182  * Insert a row for the carved file into the tsk_objects table:
8183  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8184  */
8185  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8186 
8187 
8188  /*
8189  * Insert a row for the carved file into the tsk_files table:
8190  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
8191  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
8192  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
8193  * parent_path, data_source_obj_id,extenion, owner_uid,
8194  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
8195  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8196  */
8197  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8198  prepStmt.clearParameters();
8199  prepStmt.setLong(1, carvedFileId); // obj_id
8200  Long fileSystemObjectId;
8201  if (root instanceof FileSystem) {
8202  prepStmt.setLong(2, root.getId()); // fs_obj_id
8203  fileSystemObjectId = root.getId();
8204  } else {
8205  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
8206  fileSystemObjectId = null;
8207  }
8208  prepStmt.setString(3, carvedFile.getName()); // name
8209  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
8210  prepStmt.setShort(5, (short) 1); // has_path
8211  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8212  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8213  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
8214  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
8215  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
8216  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
8217  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
8218  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
8219  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
8220  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8221  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8222  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8223 
8224  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8225  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
8226  prepStmt.setString(20, parentPath); // parent path
8227  prepStmt.setLong(21, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
8228  prepStmt.setString(22, extractExtension(carvedFile.getName())); //extension
8229 
8230  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8231  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8232  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8233 
8234  connection.executeUpdate(prepStmt);
8235 
8236  /*
8237  * Insert a row in the tsk_layout_file table for each chunk of
8238  * the carved file. INSERT INTO tsk_file_layout (obj_id,
8239  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
8240  */
8241  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8242  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
8243  prepStmt.clearParameters();
8244  prepStmt.setLong(1, carvedFileId); // obj_id
8245  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8246  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8247  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8248  connection.executeUpdate(prepStmt);
8249  }
8250 
8251  /*
8252  * Create a layout file representation of the carved file.
8253  */
8254  carvedFiles.add(new LayoutFile(this,
8255  carvedFileId,
8256  carvedFilesDir.getDataSourceObjectId(),
8257  fileSystemObjectId,
8258  carvedFile.getName(),
8263  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
8264  carvedFile.getSizeInBytes(),
8265  0L, 0L, 0L, 0L,
8266  null, null, null,
8268  parentPath,
8269  null,
8270  OsAccount.NO_OWNER_ID,
8271  OsAccount.NO_ACCOUNT));
8272  }
8273 
8274  transaction.commit();
8275  transaction = null;
8276  return carvedFiles;
8277 
8278  } catch (SQLException ex) {
8279  throw new TskCoreException("Failed to add carved files to case database", ex);
8280  } finally {
8281  closeResultSet(resultSet);
8282  closeStatement(statement);
8283 
8284  if (null != transaction) {
8285  try {
8286  transaction.rollback();
8287  } catch (TskCoreException ex2) {
8288  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8289  }
8290  }
8291  }
8292  }
8293 
8324  public DerivedFile addDerivedFile(String fileName, String localPath,
8325  long size, long ctime, long crtime, long atime, long mtime,
8326  boolean isFile, Content parentObj,
8327  String rederiveDetails, String toolName, String toolVersion,
8328  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
8329  CaseDbTransaction transaction = beginTransaction();
8330  try {
8331  DerivedFile df = addDerivedFile(fileName, localPath,
8332  size, ctime, crtime, atime, mtime,
8333  isFile, parentObj,
8334  rederiveDetails, toolName, toolVersion,
8335  otherDetails, encodingType, transaction);
8336  transaction.commit();
8337  return df;
8338  } catch (TskCoreException ex) {
8339  transaction.rollback();
8340  throw ex;
8341  }
8342  }
8343 
8344  public DerivedFile addDerivedFile(String fileName, String localPath,
8345  long size, long ctime, long crtime, long atime, long mtime,
8346  boolean isFile, Content parentObj,
8347  String rederiveDetails, String toolName, String toolVersion,
8348  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
8349  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8350  localPath = localPath.replaceAll("^[/\\\\]+", "");
8351 
8352  TimelineManager timelineManager = getTimelineManager();
8353 
8354  CaseDbConnection connection = transaction.getConnection();
8355  try {
8356  final long parentId = parentObj.getId();
8357  String parentPath = "";
8358  if (parentObj instanceof BlackboardArtifact) {
8359  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8360  } else if (parentObj instanceof AbstractFile) {
8361  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8362  }
8363 
8364  // Insert a row for the derived file into the tsk_objects table.
8365  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8366  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8367 
8368  // Insert a row for the virtual directory into the tsk_files table.
8369  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8370  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
8371  // parent_path, data_source_obj_id, extension)
8372  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
8373  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8374  statement.clearParameters();
8375  statement.setLong(1, newObjId);
8376 
8377  // If the parentFile is part of a file system, use its file system object ID.
8378  Long fsObjId = this.getFileSystemId(parentId, connection);
8379  if (fsObjId != -1) {
8380  statement.setLong(2, fsObjId);
8381  } else {
8382  fsObjId = null;
8383  statement.setNull(2, java.sql.Types.BIGINT);
8384  }
8385  statement.setString(3, fileName);
8386 
8387  //type, has_path
8388  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8389  statement.setShort(5, (short) 1);
8390 
8391  //flags
8393  statement.setShort(6, dirType.getValue());
8395  statement.setShort(7, metaType.getValue());
8396 
8397  //note: using alloc under assumption that derived files derive from alloc files
8399  statement.setShort(8, dirFlag.getValue());
8400  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8401  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8402  statement.setShort(9, metaFlags);
8403 
8404  //size
8405  //prevent negative size
8406  long savedSize = size < 0 ? 0 : size;
8407  statement.setLong(10, savedSize);
8408 
8409  //mactimes
8410  //long ctime, long crtime, long atime, long mtime,
8411  statement.setLong(11, ctime);
8412  statement.setLong(12, crtime);
8413  statement.setLong(13, atime);
8414  statement.setLong(14, mtime);
8415 
8416  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
8417  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8418  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8419 
8420  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8421  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
8422 
8423  //parent path
8424  statement.setString(20, parentPath);
8425 
8426  // root data source object id
8427  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
8428  statement.setLong(21, dataSourceObjId);
8429  final String extension = extractExtension(fileName);
8430  //extension
8431  statement.setString(22, extension);
8432 
8433  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8434  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8435  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8436 
8437  connection.executeUpdate(statement);
8438 
8439  //add localPath
8440  addFilePath(connection, newObjId, localPath, encodingType);
8441 
8442  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
8443  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
8444 
8445  if (!timelineEventsDisabled.get()) {
8446  timelineManager.addEventsForNewFile(derivedFile, connection);
8447  }
8448 
8449  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
8450  return derivedFile;
8451  } catch (SQLException ex) {
8452  throw new TskCoreException("Failed to add derived file to case database", ex);
8453  }
8454  }
8455 
8486  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8487  long size, long ctime, long crtime, long atime, long mtime,
8488  boolean isFile, String mimeType,
8489  String rederiveDetails, String toolName, String toolVersion,
8490  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
8491 
8492  CaseDbTransaction trans = null;
8493  try {
8494  Content parentObj = derivedFile.getParent();
8495 
8496  trans = beginTransaction();
8497  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
8498  size, ctime, crtime, atime, mtime,
8499  isFile, mimeType,
8500  rederiveDetails, toolName, toolVersion,
8501  otherDetails, encodingType, parentObj, trans);
8502  trans.commit();
8503  return updatedFile;
8504  } catch (TskCoreException ex) {
8505  if (trans != null) {
8506  trans.rollback();
8507  }
8508  throw ex;
8509  }
8510  }
8511 
8512  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
8513  long size, long ctime, long crtime, long atime, long mtime,
8514  boolean isFile, String mimeType,
8515  String rederiveDetails, String toolName, String toolVersion,
8516  String otherDetails, TskData.EncodingType encodingType,
8517  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
8518 
8519  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
8520  localPath = localPath.replaceAll("^[/\\\\]+", "");
8521 
8522  ResultSet rs = null;
8523  try {
8524  final long parentId = parentObj.getId();
8525  String parentPath = "";
8526  if (parentObj instanceof BlackboardArtifact) {
8527  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
8528  } else if (parentObj instanceof AbstractFile) {
8529  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
8530  }
8531  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
8532  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
8533  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
8534  statement.clearParameters();
8535 
8536  //type
8537  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
8538 
8539  //flags
8541  statement.setShort(2, dirType.getValue());
8543  statement.setShort(3, metaType.getValue());
8544 
8545  //note: using alloc under assumption that derived files derive from alloc files
8547  statement.setShort(4, dirFlag.getValue());
8548  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
8549  | TSK_FS_META_FLAG_ENUM.USED.getValue());
8550  statement.setShort(5, metaFlags);
8551 
8552  //size
8553  //prevent negative size
8554  long savedSize = size < 0 ? 0 : size;
8555  statement.setLong(6, savedSize);
8556 
8557  //mactimes
8558  //long ctime, long crtime, long atime, long mtime,
8559  statement.setLong(7, ctime);
8560  statement.setLong(8, crtime);
8561  statement.setLong(9, atime);
8562  statement.setLong(10, mtime);
8563  statement.setString(11, mimeType);
8564  statement.setString(12, String.valueOf(derivedFile.getId()));
8565  trans.getConnection().executeUpdate(statement);
8566 
8567  //add localPath
8568  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
8569 
8570  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
8571  Long fileSystemObjId = derivedFile.getFileSystemObjectId().orElse(null);
8572  final String extension = extractExtension(derivedFile.getName());
8573  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, fileSystemObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
8574  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension,
8575  derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
8576  } catch (SQLException ex) {
8577  throw new TskCoreException("Failed to add derived file to case database", ex);
8578  } finally {
8579  closeResultSet(rs);
8580  }
8581  }
8582 
8602  public LocalFile addLocalFile(String fileName, String localPath,
8603  long size, long ctime, long crtime, long atime, long mtime,
8604  boolean isFile, TskData.EncodingType encodingType,
8605  AbstractFile parent) throws TskCoreException {
8606 
8607  CaseDbTransaction localTrans = beginTransaction();
8608  try {
8609  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
8610  localTrans.commit();
8611  localTrans = null;
8612  return created;
8613  } finally {
8614  if (null != localTrans) {
8615  try {
8616  localTrans.rollback();
8617  } catch (TskCoreException ex2) {
8618  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8619  }
8620  }
8621  }
8622  }
8623 
8648  public LocalFile addLocalFile(String fileName, String localPath,
8649  long size, long ctime, long crtime, long atime, long mtime,
8650  boolean isFile, TskData.EncodingType encodingType,
8651  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8652 
8653  return addLocalFile(fileName, localPath,
8654  size, ctime, crtime, atime, mtime,
8655  null, null, null,
8656  isFile, encodingType,
8657  parent, transaction);
8658  }
8659 
8688  public LocalFile addLocalFile(String fileName, String localPath,
8689  long size, long ctime, long crtime, long atime, long mtime,
8690  String md5, String sha256, FileKnown known, String mimeType,
8691  boolean isFile, TskData.EncodingType encodingType,
8692  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8693 
8694  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8695  md5, sha256, known, mimeType, isFile, encodingType,
8696  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8697 
8698  }
8699 
8730  public LocalFile addLocalFile(String fileName, String localPath,
8731  long size, long ctime, long crtime, long atime, long mtime,
8732  String md5, String sha256, FileKnown known, String mimeType,
8733  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8734  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8735 
8736  return addLocalFile(fileName, localPath,
8737  size, ctime, crtime, atime, mtime,
8738  md5, sha256, null, known, mimeType,
8739  isFile, encodingType, osAccountId, ownerAccount,
8740  parent, transaction);
8741  }
8742 
8743 
8776  public LocalFile addLocalFile(String fileName, String localPath,
8777  long size, long ctime, long crtime, long atime, long mtime,
8778  String md5, String sha256, String sha1Hash, FileKnown known, String mimeType,
8779  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8780  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8781  CaseDbConnection connection = transaction.getConnection();
8782  Statement queryStatement = null;
8783  try {
8784 
8785  // Insert a row for the local/logical file into the tsk_objects table.
8786  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8787  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8788 
8789  // Insert a row for the local/logical file into the tsk_files table.
8790  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8791  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
8792  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8793  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
8794  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8795  statement.clearParameters();
8796  statement.setLong(1, objectId);
8797  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8798  statement.setString(3, fileName);
8799  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8800  statement.setShort(5, (short) 1);
8802  statement.setShort(6, dirType.getValue());
8804  statement.setShort(7, metaType.getValue());
8806  statement.setShort(8, dirFlag.getValue());
8807  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8808  statement.setShort(9, metaFlags);
8809  //prevent negative size
8810  long savedSize = size < 0 ? 0 : size;
8811  statement.setLong(10, savedSize);
8812  statement.setLong(11, ctime);
8813  statement.setLong(12, crtime);
8814  statement.setLong(13, atime);
8815  statement.setLong(14, mtime);
8816  statement.setString(15, md5);
8817  statement.setString(16, sha256);
8818  statement.setString(17, sha1Hash); // sha1
8819 
8820  if (known != null) {
8821  statement.setByte(18, known.getFileKnownValue());
8822  } else {
8823  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue());
8824  }
8825  statement.setString(19, mimeType);
8826  String parentPath;
8827  long dataSourceObjId;
8828 
8829  if (parent instanceof AbstractFile) {
8830  AbstractFile parentFile = (AbstractFile) parent;
8831  if (isRootDirectory(parentFile, transaction)) {
8832  parentPath = "/";
8833  } else {
8834  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8835  }
8836  dataSourceObjId = parentFile.getDataSourceObjectId();
8837  } else {
8838  parentPath = "/";
8839  dataSourceObjId = getDataSourceObjectId(connection, parent);
8840  }
8841  statement.setString(20, parentPath);
8842  statement.setLong(21, dataSourceObjId);
8843  final String extension = extractExtension(fileName);
8844  statement.setString(22, extension);
8845 
8846  if (ownerAccount != null) {
8847  statement.setString(23, ownerAccount); // ownerUid
8848  } else {
8849  statement.setNull(23, java.sql.Types.VARCHAR);
8850  }
8851 
8852  if (osAccountId != null) {
8853  statement.setLong(24, osAccountId); // osAccountObjId
8854  } else {
8855  statement.setNull(24, java.sql.Types.BIGINT);
8856  }
8857 
8858  statement.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
8859 
8860  connection.executeUpdate(statement);
8861  addFilePath(connection, objectId, localPath, encodingType);
8862  LocalFile localFile = new LocalFile(this,
8863  objectId,
8864  fileName,
8866  dirType,
8867  metaType,
8868  dirFlag,
8869  metaFlags,
8870  savedSize,
8871  ctime, crtime, atime, mtime,
8872  mimeType, md5, sha256, sha1Hash, known,
8873  parent.getId(), parentPath,
8874  dataSourceObjId,
8875  localPath,
8876  encodingType, extension,
8877  ownerAccount, osAccountId);
8878  if (!timelineEventsDisabled.get()) {
8879  getTimelineManager().addEventsForNewFile(localFile, connection);
8880  }
8881  return localFile;
8882 
8883  } catch (SQLException ex) {
8884  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);
8885  } finally {
8886  closeStatement(queryStatement);
8887  }
8888  }
8889 
8895  private class RootDirectoryKey {
8896 
8897  private long dataSourceId;
8898  private Long fileSystemId;
8899 
8900  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8901  this.dataSourceId = dataSourceId;
8902  this.fileSystemId = fileSystemId;
8903  }
8904 
8905  @Override
8906  public int hashCode() {
8907  int hash = 7;
8908  hash = 41 * hash + Objects.hashCode(dataSourceId);
8909  hash = 41 * hash + Objects.hashCode(fileSystemId);
8910  return hash;
8911  }
8912 
8913  @Override
8914  public boolean equals(Object obj) {
8915  if (this == obj) {
8916  return true;
8917  }
8918  if (obj == null) {
8919  return false;
8920  }
8921  if (getClass() != obj.getClass()) {
8922  return false;
8923  }
8924 
8925  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8926  if (dataSourceId != otherKey.dataSourceId) {
8927  return false;
8928  }
8929 
8930  if (fileSystemId != null) {
8931  return fileSystemId.equals(otherKey.fileSystemId);
8932  }
8933  return (otherKey.fileSystemId == null);
8934  }
8935  }
8936 
8949  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8950 
8951  // First check if we know the root directory for this data source and optionally
8952  // file system. There is only one root, so if we know it we can simply compare
8953  // this file ID to the known root directory.
8954  Long fsObjId = null;
8955  if (file instanceof FsContent) {
8956  fsObjId = ((FsContent) file).getFileSystemId();
8957  }
8958  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8959  synchronized (rootDirectoryMapLock) {
8960  if (rootDirectoryMap.containsKey(key)) {
8961  return rootDirectoryMap.get(key).equals(file.getId());
8962  }
8963  }
8964 
8965  // Fallback cache. We store the result of each database lookup
8966  // so it won't be done multiple times in a row. In practice, this will
8967  // only be used if this method was never called on the root directory.
8968  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8969  if (isRoot != null) {
8970  return isRoot;
8971  }
8972 
8973  CaseDbConnection connection = transaction.getConnection();
8974  Statement statement = null;
8975  ResultSet resultSet = null;
8976 
8977  try {
8978  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8979  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8980  + "WHERE ChildRow.obj_id = %s;", file.getId());
8981 
8982  statement = connection.createStatement();
8983  resultSet = statement.executeQuery(query);
8984  if (resultSet.next()) {
8985  long parentId = resultSet.getLong("parent_object_id");
8986  if (parentId == 0) {
8987  return true;
8988  }
8989  int type = resultSet.getInt("parent_type");
8990  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8991  || type == TskData.ObjectType.VS.getObjectType()
8992  || type == TskData.ObjectType.VOL.getObjectType()
8993  || type == TskData.ObjectType.FS.getObjectType();
8994  if (result == true) {
8995  synchronized (rootDirectoryMapLock) {
8996  // This is a root directory so save it
8997  rootDirectoryMap.put(key, file.getId());
8998  }
8999  }
9000  isRootDirectoryCache.put(file.getId(), result);
9001  return result;
9002 
9003  } else {
9004  // This is a root directory so save it
9005  synchronized (rootDirectoryMapLock) {
9006  rootDirectoryMap.put(key, file.getId());
9007  }
9008  isRootDirectoryCache.put(file.getId(), true);
9009 
9010  return true; // The file has no parent
9011 
9012  }
9013  } catch (SQLException ex) {
9014  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
9015  } finally {
9016  closeResultSet(resultSet);
9017  closeStatement(statement);
9018  }
9019  }
9020 
9040  public LayoutFile addLayoutFile(String fileName,
9041  long size,
9042  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
9043  long ctime, long crtime, long atime, long mtime,
9044  List<TskFileRange> fileRanges,
9045  Content parent) throws TskCoreException {
9046 
9047  if (null == parent) {
9048  throw new TskCoreException("Parent can not be null");
9049  }
9050 
9051  String parentPath;
9052  if (parent instanceof AbstractFile) {
9053  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
9054  } else {
9055  parentPath = "/";
9056  }
9057 
9058  CaseDbTransaction transaction = null;
9059  Statement statement = null;
9060  ResultSet resultSet = null;
9061  try {
9062  transaction = beginTransaction();
9063  CaseDbConnection connection = transaction.getConnection();
9064 
9065  /*
9066  * Insert a row for the layout file into the tsk_objects table:
9067  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
9068  */
9069  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
9070 
9071  /*
9072  * Insert a row for the file into the tsk_files table: INSERT INTO
9073  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
9074  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
9075  * mtime, md5, known, mime_type, parent_path,
9076  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
9077  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
9078  */
9079  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
9080  prepStmt.clearParameters();
9081  prepStmt.setLong(1, newFileId); // obj_id
9082 
9083  // If the parent is part of a file system, grab its file system ID
9084  Long fileSystemObjectId;
9085  if (0 != parent.getId()) {
9086  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
9087  if (fileSystemObjectId != -1) {
9088  prepStmt.setLong(2, fileSystemObjectId);
9089  } else {
9090  prepStmt.setNull(2, java.sql.Types.BIGINT);
9091  fileSystemObjectId = null;
9092  }
9093  } else {
9094  prepStmt.setNull(2, java.sql.Types.BIGINT);
9095  fileSystemObjectId = null;
9096  }
9097  prepStmt.setString(3, fileName); // name
9098  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
9099  prepStmt.setShort(5, (short) 0); // has_path
9100  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
9101  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
9102  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
9103  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
9104  //prevent negative size
9105  long savedSize = size < 0 ? 0 : size;
9106  prepStmt.setLong(10, savedSize); // size
9107  prepStmt.setLong(11, ctime); // ctime
9108  prepStmt.setLong(12, crtime); // crtime
9109  prepStmt.setLong(13, atime); // atime
9110  prepStmt.setLong(14, mtime); // mtime
9111  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
9112  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
9113  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
9114 
9115  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
9116  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
9117  prepStmt.setString(20, parentPath); // parent path
9118  prepStmt.setLong(21, parent.getDataSource().getId()); // data_source_obj_id
9119 
9120  prepStmt.setString(22, extractExtension(fileName)); //extension
9121 
9122  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
9123  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
9124  prepStmt.setLong(25, TskData.CollectedStatus.UNKNOWN.getType()); // collected
9125 
9126  connection.executeUpdate(prepStmt);
9127 
9128  /*
9129  * Insert a row in the tsk_layout_file table for each chunk of the
9130  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
9131  * byte_len, sequence) VALUES (?, ?, ?, ?)
9132  */
9133  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
9134  for (TskFileRange tskFileRange : fileRanges) {
9135  prepStmt.clearParameters();
9136  prepStmt.setLong(1, newFileId); // obj_id
9137  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
9138  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
9139  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
9140  connection.executeUpdate(prepStmt);
9141  }
9142 
9143  /*
9144  * Create a layout file representation of the carved file.
9145  */
9146  LayoutFile layoutFile = new LayoutFile(this,
9147  newFileId,
9148  parent.getDataSource().getId(),
9149  fileSystemObjectId,
9150  fileName,
9154  dirFlag,
9155  metaFlag.getValue(),
9156  savedSize,
9157  ctime, crtime, atime, mtime,
9158  null, null, null,
9160  parentPath,
9161  null,
9162  OsAccount.NO_OWNER_ID,
9163  OsAccount.NO_ACCOUNT);
9164 
9165  transaction.commit();
9166  transaction = null;
9167  return layoutFile;
9168 
9169  } catch (SQLException ex) {
9170  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
9171  } finally {
9172  closeResultSet(resultSet);
9173  closeStatement(statement);
9174 
9175  if (null != transaction) {
9176  try {
9177  transaction.rollback();
9178  } catch (TskCoreException ex2) {
9179  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
9180  }
9181  }
9182  }
9183  }
9184 
9194  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
9195  if (content == null) {
9196  throw new TskCoreException("Null Content parameter given");
9197  }
9198  if (content instanceof AbstractFile) {
9199  return ((AbstractFile) content).getDataSourceObjectId();
9200  } else {
9201  return getDataSourceObjectId(connection, content.getId());
9202  }
9203  }
9204 
9217  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
9219  Statement statement = null;
9220  ResultSet resultSet = null;
9221  try {
9222  statement = connection.createStatement();
9223  long dataSourceObjId;
9224  long ancestorId = objectId;
9225  do {
9226  dataSourceObjId = ancestorId;
9227  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
9228  resultSet = statement.executeQuery(query);
9229  if (resultSet.next()) {
9230  ancestorId = resultSet.getLong("par_obj_id");
9231  } else {
9232  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
9233  }
9234  resultSet.close();
9235  resultSet = null;
9236  } while (0 != ancestorId); // Not NULL
9237  return dataSourceObjId;
9238  } catch (SQLException ex) {
9239  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
9240  } finally {
9241  closeResultSet(resultSet);
9242  closeStatement(statement);
9244  }
9245  }
9246 
9258  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
9259  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
9260  statement.clearParameters();
9261  statement.setLong(1, objId);
9262  statement.setString(2, path);
9263  statement.setInt(3, type.getType());
9264  connection.executeUpdate(statement);
9265  }
9266 
9278  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
9279  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
9280  statement.clearParameters();
9281  statement.setString(1, path);
9282  statement.setInt(2, type.getType());
9283  statement.setLong(3, objId);
9284  connection.executeUpdate(statement);
9285  }
9286 
9300  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
9301  String ext = "";
9302  if (!containsLikeWildcard(fileName)) {
9303  ext = SleuthkitCase.extractExtension(fileName);
9304  }
9305 
9306  CaseDbConnection connection = null;
9307  ResultSet rs = null;
9308  long parentId = parentFile.getId();
9309 
9311  try {
9312  connection = connections.getConnection();
9313 
9314  PreparedStatement statement;
9315  if (ext.isEmpty()) {
9316  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
9317  statement.clearParameters();
9318  statement.setLong(1, parentId);
9319  statement.setString(2, fileName);
9320  } else {
9321  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
9322  statement.clearParameters();
9323  statement.setString(1, ext);
9324  statement.setLong(2, parentId);
9325  statement.setString(3, fileName);
9326  }
9327 
9328  rs = connection.executeQuery(statement);
9329  return resultSetToAbstractFiles(rs, connection);
9330  } catch (SQLException ex) {
9331  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
9332  } finally {
9333  closeResultSet(rs);
9334  closeConnection(connection);
9336  }
9337  }
9338 
9350  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
9351  CaseDbConnection connection = null;
9352  Statement s = null;
9353  ResultSet rs = null;
9355  try {
9356  connection = connections.getConnection();
9357  s = connection.createStatement();
9358  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9359  rs.next();
9360  return rs.getLong("count");
9361  } catch (SQLException e) {
9362  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
9363  } finally {
9364  closeResultSet(rs);
9365  closeStatement(s);
9366  closeConnection(connection);
9368  }
9369  }
9370 
9388  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
9389  CaseDbConnection connection = null;
9390  Statement s = null;
9391  ResultSet rs = null;
9393  try {
9394  connection = connections.getConnection();
9395  s = connection.createStatement();
9396  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9397  return resultSetToAbstractFiles(rs, connection);
9398  } catch (SQLException e) {
9399  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
9400  } finally {
9401  closeResultSet(rs);
9402  closeStatement(s);
9403  closeConnection(connection);
9405  }
9406  }
9407 
9426  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
9427  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";
9429  try (CaseDbConnection connection = connections.getConnection()) {
9430  String query = String.format(queryTemplate, parentId, sqlWhereClause);
9431  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
9432  return resultSetToAbstractFiles(rs, connection);
9433  } catch (SQLException ex) {
9434  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
9435  }
9436  } finally {
9438  }
9439  }
9440 
9453  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
9454  CaseDbConnection connection = null;
9455  Statement s = null;
9456  ResultSet rs = null;
9458  try {
9459  connection = connections.getConnection();
9460  s = connection.createStatement();
9461  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
9462  List<Long> ret = new ArrayList<>();
9463  while (rs.next()) {
9464  ret.add(rs.getLong("obj_id"));
9465  }
9466  return ret;
9467  } catch (SQLException e) {
9468  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
9469  } finally {
9470  closeResultSet(rs);
9471  closeStatement(s);
9472  closeConnection(connection);
9474  }
9475  }
9476 
9488  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
9489 
9490  // get the non-unique path (strip of image and volume path segments, if
9491  // the exist.
9492  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
9493 
9494  // split the file name from the parent path
9495  int lastSlash = path.lastIndexOf('/'); //NON-NLS
9496 
9497  // if the last slash is at the end, strip it off
9498  if (lastSlash == path.length()) {
9499  path = path.substring(0, lastSlash - 1);
9500  lastSlash = path.lastIndexOf('/'); //NON-NLS
9501  }
9502 
9503  String parentPath = path.substring(0, lastSlash);
9504  String fileName = path.substring(lastSlash);
9505 
9506  return findFiles(dataSource, fileName, parentPath);
9507  }
9508 
9519  public List<TskFileRange> getFileRanges(long id) 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_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
9528  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
9529  while (rs.next()) {
9530  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
9531  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
9532  ranges.add(range);
9533  }
9534  return ranges;
9535  } catch (SQLException ex) {
9536  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
9537  } finally {
9538  closeResultSet(rs);
9539  closeStatement(s);
9540  closeConnection(connection);
9542  }
9543  }
9544 
9555  public Image getImageById(long id) throws TskCoreException {
9556  CaseDbConnection connection = null;
9557  Statement s = null;
9558  ResultSet rs = null;
9560  try {
9561  connection = connections.getConnection();
9562  s = connection.createStatement();
9563  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 "
9564  + "FROM tsk_image_info "
9565  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
9566  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
9567  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
9568 
9569  List<String> imagePaths = new ArrayList<>();
9570  long type, ssize, size;
9571  String tzone, md5, sha1, sha256, name, device_id, imagePath;
9572 
9573  if (rs.next()) {
9574  imagePath = rs.getString("name");
9575  if (imagePath != null) {
9576  imagePaths.add(imagePath);
9577  }
9578  type = rs.getLong("type"); //NON-NLS
9579  ssize = rs.getLong("ssize"); //NON-NLS
9580  tzone = rs.getString("tzone"); //NON-NLS
9581  size = rs.getLong("size"); //NON-NLS
9582  md5 = rs.getString("md5"); //NON-NLS
9583  sha1 = rs.getString("sha1"); //NON-NLS
9584  sha256 = rs.getString("sha256"); //NON-NLS
9585  name = rs.getString("display_name");
9586  if (name == null) {
9587  if (imagePaths.size() > 0) {
9588  String path = imagePaths.get(0);
9589  name = (new java.io.File(path)).getName();
9590  } else {
9591  name = "";
9592  }
9593  }
9594  device_id = rs.getString("device_id");
9595  } else {
9596  throw new TskCoreException("No image found for id: " + id);
9597  }
9598 
9599  // image can have multiple paths, therefore there can be multiple rows in the result set
9600  while (rs.next()) {
9601  imagePath = rs.getString("name");
9602  if (imagePath != null) {
9603  imagePaths.add(imagePath);
9604  }
9605  }
9606 
9607  return new Image(this, id, type, device_id, ssize, name,
9608  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
9609  } catch (SQLException ex) {
9610  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
9611  } finally {
9612  closeResultSet(rs);
9613  closeStatement(s);
9614  closeConnection(connection);
9616  }
9617  }
9618 
9630  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
9631  CaseDbConnection connection = null;
9632  Statement s = null;
9633  ResultSet rs = null;
9635  try {
9636  connection = connections.getConnection();
9637  s = connection.createStatement();
9638  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
9639  + "where obj_id = " + id); //NON-NLS
9640  if (rs.next()) {
9641  long type = rs.getLong("vs_type"); //NON-NLS
9642  long imgOffset = rs.getLong("img_offset"); //NON-NLS
9643  long blockSize = rs.getLong("block_size"); //NON-NLS
9644  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
9645  vs.setParent(parent);
9646  return vs;
9647  } else {
9648  throw new TskCoreException("No volume system found for id:" + id);
9649  }
9650  } catch (SQLException ex) {
9651  throw new TskCoreException("Error getting Volume System by ID.", ex);
9652  } finally {
9653  closeResultSet(rs);
9654  closeStatement(s);
9655  closeConnection(connection);
9657  }
9658  }
9659 
9668  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
9669  VolumeSystem vs = getVolumeSystemById(id, null);
9670  vs.setParentId(parentId);
9671  return vs;
9672  }
9673 
9685  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
9686  return getFileSystemByIdHelper(id, parent);
9687  }
9688 
9697  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
9698  Volume vol = null;
9699  FileSystem fs = getFileSystemById(id, vol);
9700  fs.setParentId(parentId);
9701  return fs;
9702  }
9703 
9715  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
9716  return getFileSystemByIdHelper(id, parent);
9717  }
9718 
9730  Pool getPoolById(long id, Content parent) throws TskCoreException {
9731  return getPoolByIdHelper(id, parent);
9732  }
9733 
9742  Pool getPoolById(long id, long parentId) throws TskCoreException {
9743  Pool pool = getPoolById(id, null);
9744  pool.setParentId(parentId);
9745  return pool;
9746  }
9747 
9759  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9760 
9762  try (CaseDbConnection connection = connections.getConnection();
9763  Statement s = connection.createStatement();
9764  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9765  + "where obj_id = " + id);) { //NON-NLS
9766  if (rs.next()) {
9767  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9768  pool.setParent(parent);
9769 
9770  return pool;
9771  } else {
9772  throw new TskCoreException("No pool found for ID:" + id);
9773  }
9774  } catch (SQLException ex) {
9775  throw new TskCoreException("Error getting Pool by ID", ex);
9776  } finally {
9778  }
9779  }
9780 
9792  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9793  // see if we already have it
9794  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9795  // but it should be the same...
9796  synchronized (fileSystemIdMap) {
9797  if (fileSystemIdMap.containsKey(id)) {
9798  return fileSystemIdMap.get(id);
9799  }
9800  }
9801  CaseDbConnection connection = null;
9802  Statement s = null;
9803  ResultSet rs = null;
9805  try {
9806  connection = connections.getConnection();
9807  s = connection.createStatement();
9808  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9809  + "where obj_id = " + id); //NON-NLS
9810  if (rs.next()) {
9811  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9812  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9813  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9814  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9815  fs.setParent(parent);
9816  // save it for the next call
9817  synchronized (fileSystemIdMap) {
9818  fileSystemIdMap.put(id, fs);
9819  }
9820  return fs;
9821  } else {
9822  throw new TskCoreException("No file system found for id:" + id);
9823  }
9824  } catch (SQLException ex) {
9825  throw new TskCoreException("Error getting File System by ID", ex);
9826  } finally {
9827  closeResultSet(rs);
9828  closeStatement(s);
9829  closeConnection(connection);
9831  }
9832  }
9833 
9845  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9846  CaseDbConnection connection = null;
9847  Statement s = null;
9848  ResultSet rs = null;
9850  try {
9851  connection = connections.getConnection();
9852  s = connection.createStatement();
9853  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9854  + "where obj_id = " + id); //NON-NLS
9855  if (rs.next()) {
9863  String description;
9864  try {
9865  description = rs.getString("desc");
9866  } catch (Exception ex) {
9867  description = rs.getString("descr");
9868  }
9869  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9870  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9871  description);
9872  vol.setParent(parent);
9873  return vol;
9874  } else {
9875  throw new TskCoreException("No volume found for id:" + id);
9876  }
9877  } catch (SQLException ex) {
9878  throw new TskCoreException("Error getting Volume by ID", ex);
9879  } finally {
9880  closeResultSet(rs);
9881  closeStatement(s);
9882  closeConnection(connection);
9884  }
9885  }
9886 
9895  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9896  Volume vol = getVolumeById(id, null);
9897  vol.setParentId(parentId);
9898  return vol;
9899  }
9900 
9912  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9913  CaseDbConnection connection = null;
9914  Statement s = null;
9915  ResultSet rs = null;
9917  try {
9918  connection = connections.getConnection();
9919  s = connection.createStatement();
9920  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9921  + "WHERE obj_id = " + id);
9922  Directory temp = null; //NON-NLS
9923  if (rs.next()) {
9924  final short type = rs.getShort("type"); //NON-NLS
9925  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9926  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9927  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9928  temp = directory(rs, parentFs);
9929  }
9930  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9931  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9932  }
9933  } else {
9934  throw new TskCoreException("No Directory found for id:" + id);
9935  }
9936  return temp;
9937  } catch (SQLException ex) {
9938  throw new TskCoreException("Error getting Directory by ID", ex);
9939  } finally {
9940  closeResultSet(rs);
9941  closeStatement(s);
9942  closeConnection(connection);
9944  }
9945  }
9946 
9956  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9957  List<FileSystem> fileSystems = new ArrayList<>();
9958  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9959 
9960  CaseDbConnection connection = null;
9961  Statement s = null;
9962  ResultSet rs = null;
9964  try {
9965  connection = connections.getConnection();
9966  s = connection.createStatement();
9967  rs = connection.executeQuery(s, queryStr); //NON-NLS
9968  while (rs.next()) {
9969  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9970  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9971  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9972  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9973  fs.setParent(null);
9974  fileSystems.add(fs);
9975  }
9976  } catch (SQLException ex) {
9977  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9978  } finally {
9979  closeResultSet(rs);
9980  closeStatement(s);
9981  closeConnection(connection);
9983  }
9984  return fileSystems;
9985  }
9986 
9997  List<Content> getImageChildren(Image img) throws TskCoreException {
9998  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9999  List<Content> children = new ArrayList<Content>();
10000  for (ObjectInfo info : childInfos) {
10001  if (null != info.type) {
10002  switch (info.type) {
10003  case VS:
10004  children.add(getVolumeSystemById(info.id, img));
10005  break;
10006  case POOL:
10007  children.add(getPoolById(info.id, img));
10008  break;
10009  case FS:
10010  children.add(getFileSystemById(info.id, img));
10011  break;
10012  case ABSTRACTFILE:
10013  AbstractFile f = getAbstractFileById(info.id);
10014  if (f != null) {
10015  children.add(f);
10016  }
10017  break;
10018  case ARTIFACT:
10019  BlackboardArtifact art = getArtifactById(info.id);
10020  if (art != null) {
10021  children.add(art);
10022  }
10023  break;
10024  case REPORT:
10025  // Do nothing for now - see JIRA-3673
10026  break;
10027  default:
10028  throw new TskCoreException("Image has child of invalid type: " + info.type);
10029  }
10030  }
10031  }
10032  return children;
10033  }
10034 
10045  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
10046  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
10047  List<Long> children = new ArrayList<Long>();
10048  for (ObjectInfo info : childInfos) {
10049  if (info.type == ObjectType.VS
10050  || info.type == ObjectType.POOL
10051  || info.type == ObjectType.FS
10052  || info.type == ObjectType.ABSTRACTFILE
10053  || info.type == ObjectType.ARTIFACT) {
10054  children.add(info.id);
10055  } else if (info.type == ObjectType.REPORT) {
10056  // Do nothing for now - see JIRA-3673
10057  } else {
10058  throw new TskCoreException("Image has child of invalid type: " + info.type);
10059  }
10060  }
10061  return children;
10062  }
10063 
10074  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
10075  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
10076  List<Content> children = new ArrayList<Content>();
10077  for (ObjectInfo info : childInfos) {
10078  if (null != info.type) {
10079  switch (info.type) {
10080  case VS:
10081  children.add(getVolumeSystemById(info.id, pool));
10082  break;
10083  case ABSTRACTFILE:
10084  AbstractFile f = getAbstractFileById(info.id);
10085  if (f != null) {
10086  children.add(f);
10087  }
10088  break;
10089  case ARTIFACT:
10090  BlackboardArtifact art = getArtifactById(info.id);
10091  if (art != null) {
10092  children.add(art);
10093  }
10094  break;
10095  default:
10096  throw new TskCoreException("Pool has child of invalid type: " + info.type);
10097  }
10098  }
10099  }
10100  return children;
10101  }
10102 
10113  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
10114  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
10115  List<Long> children = new ArrayList<Long>();
10116  for (ObjectInfo info : childInfos) {
10117  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
10118  children.add(info.id);
10119  } else {
10120  throw new TskCoreException("Pool has child of invalid type: " + info.type);
10121  }
10122  }
10123  return children;
10124  }
10125 
10136  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
10137  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
10138  List<Content> children = new ArrayList<Content>();
10139  for (ObjectInfo info : childInfos) {
10140  if (null != info.type) {
10141  switch (info.type) {
10142  case VOL:
10143  children.add(getVolumeById(info.id, vs));
10144  break;
10145  case ABSTRACTFILE:
10146  AbstractFile f = getAbstractFileById(info.id);
10147  if (f != null) {
10148  children.add(f);
10149  }
10150  break;
10151  case ARTIFACT:
10152  BlackboardArtifact art = getArtifactById(info.id);
10153  if (art != null) {
10154  children.add(art);
10155  }
10156  break;
10157  default:
10158  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
10159  }
10160  }
10161  }
10162  return children;
10163  }
10164 
10175  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
10176  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
10177  List<Long> children = new ArrayList<Long>();
10178  for (ObjectInfo info : childInfos) {
10179  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
10180  children.add(info.id);
10181  } else {
10182  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
10183  }
10184  }
10185  return children;
10186  }
10187 
10198  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
10199  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
10200  List<Content> children = new ArrayList<Content>();
10201  for (ObjectInfo info : childInfos) {
10202  if (null != info.type) {
10203  switch (info.type) {
10204  case POOL:
10205  children.add(getPoolById(info.id, vol));
10206  break;
10207  case FS:
10208  children.add(getFileSystemById(info.id, vol));
10209  break;
10210  case ABSTRACTFILE:
10211  AbstractFile f = getAbstractFileById(info.id);
10212  if (f != null) {
10213  children.add(f);
10214  }
10215  break;
10216  case ARTIFACT:
10217  BlackboardArtifact art = getArtifactById(info.id);
10218  if (art != null) {
10219  children.add(art);
10220  }
10221  break;
10222  default:
10223  throw new TskCoreException("Volume has child of invalid type: " + info.type);
10224  }
10225  }
10226  }
10227  return children;
10228  }
10229 
10240  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
10241  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
10242  final List<Long> children = new ArrayList<Long>();
10243  for (ObjectInfo info : childInfos) {
10244  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
10245  children.add(info.id);
10246  } else {
10247  throw new TskCoreException("Volume has child of invalid type: " + info.type);
10248  }
10249  }
10250  return children;
10251  }
10252 
10266  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
10267  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
10268  }
10269 
10284  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
10285  return addImageInfo(deviceObjId, imageFilePaths, timeZone, host, null);
10286  }
10287 
10288 
10304  @Beta
10305  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host, String password) throws TskCoreException {
10306  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, password, this);
10307  return getImageById(imageId);
10308  }
10309 
10319  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
10320  CaseDbConnection connection = null;
10321  Statement s1 = null;
10322  ResultSet rs1 = null;
10324  try {
10325  connection = connections.getConnection();
10326  s1 = connection.createStatement();
10327  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
10328  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
10329  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
10330  while (rs1.next()) {
10331  long obj_id = rs1.getLong("obj_id"); //NON-NLS
10332  String name = rs1.getString("name"); //NON-NLS
10333  List<String> imagePaths = imgPaths.get(obj_id);
10334  if (imagePaths == null) {
10335  List<String> paths = new ArrayList<String>();
10336  if (name != null) {
10337  paths.add(name);
10338  }
10339  imgPaths.put(obj_id, paths);
10340  } else {
10341  if (name != null) {
10342  imagePaths.add(name);
10343  }
10344  }
10345  }
10346  return imgPaths;
10347  } catch (SQLException ex) {
10348  throw new TskCoreException("Error getting image paths.", ex);
10349  } finally {
10350  closeResultSet(rs1);
10351  closeStatement(s1);
10352  closeConnection(connection);
10354  }
10355  }
10356 
10368  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
10369  List<String> imagePaths = new ArrayList<>();
10371  Statement statement = null;
10372  ResultSet resultSet = null;
10373  try {
10374  statement = connection.createStatement();
10375  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
10376  while (resultSet.next()) {
10377  imagePaths.add(resultSet.getString("name"));
10378  }
10379  } catch (SQLException ex) {
10380  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
10381  } finally {
10382  closeResultSet(resultSet);
10383  closeStatement(statement);
10385  }
10386 
10387  return imagePaths;
10388  }
10389 
10396  public List<Image> getImages() throws TskCoreException {
10397  CaseDbConnection connection = null;
10398  Statement s = null;
10399  ResultSet rs = null;
10401  try {
10402  connection = connections.getConnection();
10403  s = connection.createStatement();
10404  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
10405  Collection<Long> imageIDs = new ArrayList<Long>();
10406  while (rs.next()) {
10407  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
10408  }
10409  List<Image> images = new ArrayList<Image>();
10410  for (long id : imageIDs) {
10411  images.add(getImageById(id));
10412  }
10413  return images;
10414  } catch (SQLException ex) {
10415  throw new TskCoreException("Error retrieving images.", ex);
10416  } finally {
10417  closeResultSet(rs);
10418  closeStatement(s);
10419  closeConnection(connection);
10421  }
10422  }
10423 
10434  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
10435  CaseDbTransaction transaction = beginTransaction();
10436  try {
10437  setImagePaths(obj_id, paths, transaction);
10438  transaction.commit();
10439  transaction = null;
10440  } finally {
10441  if (transaction != null) {
10442  transaction.rollback();
10443  }
10444  }
10445  }
10446 
10458  @Beta
10459  public void setImagePaths(long objId, List<String> paths, CaseDbTransaction trans) throws TskCoreException {
10460  try {
10461  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
10462  statement.clearParameters();
10463  statement.setLong(1, objId);
10464  trans.getConnection().executeUpdate(statement);
10465  for (int i = 0; i < paths.size(); i++) {
10466  statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
10467  statement.clearParameters();
10468  statement.setLong(1, objId);
10469  statement.setString(2, paths.get(i));
10470  statement.setLong(3, i);
10471  trans.getConnection().executeUpdate(statement);
10472  }
10473  } catch (SQLException ex) {
10474  throw new TskCoreException("Error updating image paths.", ex);
10475  }
10476  }
10477 
10478 
10490  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
10491 
10492  // Check if this data source is the only one associated with its host. If so,
10493  // we will delete the host and other associated data.
10494  // Note that the cascading deletes were only added in schema 9.1, so we
10495  // would get an error trying to delete a host from older cases.
10496  Host hostToDelete = null;
10498  int major = version.getMajor();
10499  int minor = version.getMinor();
10500  if (major > 9 || (major == 9 && minor >= 1)) {
10501  hostToDelete = getHostManager().getHostByDataSource(dataSourceObjectId);
10502  if (getHostManager().getDataSourcesForHost(hostToDelete).size() != 1) {
10503  hostToDelete = null;
10504  }
10505  }
10506 
10507  CaseDbConnection connection = null;
10508  Statement statement;
10510  try {
10511  connection = connections.getConnection();
10512  statement = connection.createStatement();
10513  connection.beginTransaction();
10514  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
10515  // all associated rows from tsk_object and its children. For large data sources this may take some time.
10516  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
10517  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
10518  // associated rows from accounts table and its children.
10519  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
10520  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
10521  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
10522  statement.execute(accountSql);
10523 
10524  // Now delete any host that was only associated with this data source. This will cascade to delete
10525  // realms, os accounts, and os account attributes that were associated with the host.
10526  if (hostToDelete != null) {
10527  statement.execute("DELETE FROM tsk_hosts WHERE id = " + hostToDelete.getHostId());
10528 
10529  // Clean up any stray OS Account objects
10530  String deleteOsAcctObjectsQuery = "DELETE FROM tsk_objects "
10531  + "WHERE type=" + TskData.ObjectType.OS_ACCOUNT.getObjectType() + " "
10532  + "AND obj_id NOT IN (SELECT os_account_obj_id FROM tsk_os_accounts WHERE os_account_obj_id IS NOT NULL)";
10533  statement.execute(deleteOsAcctObjectsQuery);
10534  }
10535 
10536  connection.commitTransaction();
10537  } catch (SQLException ex) {
10538  rollbackTransaction(connection);
10539  throw new TskCoreException("Error deleting data source.", ex);
10540  } finally {
10541  closeConnection(connection);
10543  }
10544  }
10545 
10571  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
10572  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
10573  try {
10574  while (rs.next()) {
10575  final short type = rs.getShort("type"); //NON-NLS
10576  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
10577  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
10578  FsContent result;
10579  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
10580  result = directory(rs, null);
10581  } else {
10582  result = file(rs, null);
10583  }
10584  results.add(result);
10585  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
10586  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
10587  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
10588  results.add(virtDir);
10589  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
10590  final LocalDirectory localDir = localDirectory(rs);
10591  results.add(localDir);
10592  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
10593  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
10594  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
10595  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
10596  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
10597  String parentPath = rs.getString("parent_path"); //NON-NLS
10598  if (parentPath == null) {
10599  parentPath = "/"; //NON-NLS
10600  }
10601 
10602  Long osAccountObjId = rs.getLong("os_account_obj_id");
10603  if (rs.wasNull()) {
10604  osAccountObjId = null;
10605  }
10606 
10607  LayoutFile lf = new LayoutFile(this,
10608  rs.getLong("obj_id"), //NON-NLS
10609  rs.getLong("data_source_obj_id"),
10610  rs.getLong("fs_obj_id"),
10611  rs.getString("name"), //NON-NLS
10612  atype,
10613  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10614  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10615  rs.getLong("size"), //NON-NLS
10616  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10617  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10618  FileKnown.valueOf(rs.getByte("known")), parentPath,
10619  rs.getString("mime_type"),
10620  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10621  results.add(lf);
10622  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
10623  final DerivedFile df;
10624  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
10625  results.add(df);
10626  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
10627  final LocalFile lf;
10628  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
10629  results.add(lf);
10630  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
10631  final SlackFile sf = slackFile(rs, null);
10632  results.add(sf);
10633  }
10634  } //end for each resultSet
10635  } catch (SQLException e) {
10636  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
10637  }
10638 
10639  return results;
10640  }
10641 
10642  // This following methods generate AbstractFile objects from a ResultSet
10654  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
10655  Long osAccountObjId = rs.getLong("os_account_obj_id");
10656  if (rs.wasNull()) {
10657  osAccountObjId = null;
10658  }
10659 
10660  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
10661  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10662  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10663  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10664  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10665  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10666  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10667  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10668  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10669  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10670  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10671  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10672  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"),
10673  osAccountObjId, TskData.CollectedStatus.valueOf(rs.getInt("collected")), Collections.emptyList()); //NON-NLS
10674  f.setFileSystem(fs);
10675  return f;
10676  }
10677 
10689  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
10690  Long osAccountObjId = rs.getLong("os_account_obj_id");
10691  if (rs.wasNull()) {
10692  osAccountObjId = null;
10693  }
10694 
10695  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10696  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10697  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10698  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10699  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10700  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10701  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10702  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10703  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10704  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10705  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10706  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10707  dir.setFileSystem(fs);
10708  return dir;
10709  }
10710 
10721  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
10722  String parentPath = rs.getString("parent_path"); //NON-NLS
10723  if (parentPath == null) {
10724  parentPath = "";
10725  }
10726 
10727  long objId = rs.getLong("obj_id");
10728  long dsObjId = rs.getLong("data_source_obj_id");
10729  if (objId == dsObjId) { // virtual directory is a data source
10730 
10731  String deviceId = "";
10732  String timeZone = "";
10733  Statement s = null;
10734  ResultSet rsDataSourceInfo = null;
10735 
10737  try {
10738  s = connection.createStatement();
10739  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
10740  if (rsDataSourceInfo.next()) {
10741  deviceId = rsDataSourceInfo.getString("device_id");
10742  timeZone = rsDataSourceInfo.getString("time_zone");
10743  }
10744  } catch (SQLException ex) {
10745  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
10746  } finally {
10747  closeResultSet(rsDataSourceInfo);
10748  closeStatement(s);
10750  }
10751 
10752  return new LocalFilesDataSource(this,
10753  objId, dsObjId,
10754  deviceId,
10755  rs.getString("name"),
10756  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10757  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10758  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
10759  rs.getShort("meta_flags"),
10760  timeZone,
10761  rs.getString("md5"),
10762  rs.getString("sha256"),
10763  rs.getString("sha1"),
10764  FileKnown.valueOf(rs.getByte("known")),
10765  parentPath);
10766  } else {
10767  final VirtualDirectory vd = new VirtualDirectory(this,
10768  objId, dsObjId,
10769  rs.getLong("fs_obj_id"),
10770  rs.getString("name"), //NON-NLS
10771  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10772  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10773  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10774  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10775  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10776  return vd;
10777  }
10778  }
10779 
10789  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
10790  String parentPath = rs.getString("parent_path"); //NON-NLS
10791  if (parentPath == null) {
10792  parentPath = "";
10793  }
10794  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
10795  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
10796  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10797  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10798  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10799  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10800  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10801  return ld;
10802  }
10803 
10817  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10818  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10819  long objId = rs.getLong("obj_id"); //NON-NLS
10820  String localPath = null;
10821  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10822  if (hasLocalPath) {
10823  ResultSet rsFilePath = null;
10825  try {
10826  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10827  statement.clearParameters();
10828  statement.setLong(1, objId);
10829  rsFilePath = connection.executeQuery(statement);
10830  if (rsFilePath.next()) {
10831  localPath = rsFilePath.getString("path");
10832  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10833  }
10834  } catch (SQLException ex) {
10835  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10836  } finally {
10837  closeResultSet(rsFilePath);
10839  }
10840  }
10841  String parentPath = rs.getString("parent_path"); //NON-NLS
10842  if (parentPath == null) {
10843  parentPath = "";
10844  }
10845 
10846  Long osAccountObjId = rs.getLong("os_account_obj_id");
10847  if (rs.wasNull()) {
10848  osAccountObjId = null;
10849  }
10850 
10851  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10852  rs.getLong("fs_obj_id"),
10853  rs.getString("name"), //NON-NLS
10854  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10855  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10856  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10857  rs.getLong("size"), //NON-NLS
10858  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10859  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10860  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10861  parentPath, localPath, parentId, rs.getString("mime_type"),
10862  encodingType, rs.getString("extension"),
10863  rs.getString("owner_uid"), osAccountObjId);
10864  return df;
10865  }
10866 
10880  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10881  long objId = rs.getLong("obj_id"); //NON-NLS
10882  String localPath = null;
10883  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10884  if (rs.getBoolean("has_path")) {
10885  ResultSet rsFilePath = null;
10887  try {
10888  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10889  statement.clearParameters();
10890  statement.setLong(1, objId);
10891  rsFilePath = connection.executeQuery(statement);
10892  if (rsFilePath.next()) {
10893  localPath = rsFilePath.getString("path");
10894  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10895  }
10896  } catch (SQLException ex) {
10897  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10898  } finally {
10899  closeResultSet(rsFilePath);
10901  }
10902  }
10903  String parentPath = rs.getString("parent_path"); //NON-NLS
10904  if (null == parentPath) {
10905  parentPath = "";
10906  }
10907  Long osAccountObjId = rs.getLong("os_account_obj_id");
10908  if (rs.wasNull()) {
10909  osAccountObjId = null;
10910  }
10911 
10912  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10913  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10914  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10915  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10916  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10917  rs.getLong("size"), //NON-NLS
10918  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10919  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10920  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10921  parentId, parentPath, rs.getLong("data_source_obj_id"),
10922  localPath, encodingType, rs.getString("extension"),
10923  rs.getString("owner_uid"), osAccountObjId);
10924  return file;
10925  }
10926 
10938  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10939  Long osAccountObjId = rs.getLong("os_account_obj_id");
10940  if (rs.wasNull()) {
10941  osAccountObjId = null;
10942  }
10943  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10944  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10945  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10946  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10947  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10948  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10949  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10950  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10951  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10952  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10953  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10954  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10955  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10956  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10957  f.setFileSystem(fs);
10958  return f;
10959  }
10960 
10972  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10973  List<Content> children = new ArrayList<Content>();
10974 
10975  while (rs.next()) {
10976  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10977 
10978  if (null != type) {
10979  switch (type) {
10980  case FS:
10981  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10982  FsContent result;
10983  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10984  result = directory(rs, null);
10985  } else {
10986  result = file(rs, null);
10987  }
10988  children.add(result);
10989  } else {
10990  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10991  children.add(virtDir);
10992  }
10993  break;
10994  case VIRTUAL_DIR:
10995  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10996  children.add(virtDir);
10997  break;
10998  case LOCAL_DIR:
10999  LocalDirectory localDir = localDirectory(rs);
11000  children.add(localDir);
11001  break;
11002  case UNALLOC_BLOCKS:
11003  case UNUSED_BLOCKS:
11004  case CARVED:
11005  case LAYOUT_FILE: {
11006  String parentPath = rs.getString("parent_path");
11007  if (parentPath == null) {
11008  parentPath = "";
11009  }
11010  Long osAccountObjId = rs.getLong("os_account_obj_id");
11011  if (rs.wasNull()) {
11012  osAccountObjId = null;
11013  }
11014  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
11015  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"),
11016  rs.getString("name"), type,
11017  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
11018  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
11019  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
11020  rs.getLong("size"),
11021  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
11022  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
11023  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
11024  rs.getString("owner_uid"), osAccountObjId);
11025  children.add(lf);
11026  break;
11027  }
11028  case DERIVED:
11029  final DerivedFile df = derivedFile(rs, connection, parentId);
11030  children.add(df);
11031  break;
11032  case LOCAL: {
11033  final LocalFile lf = localFile(rs, connection, parentId);
11034  children.add(lf);
11035  break;
11036  }
11037  case SLACK: {
11038  final SlackFile sf = slackFile(rs, null);
11039  children.add(sf);
11040  break;
11041  }
11042  default:
11043  break;
11044  }
11045  }
11046  }
11047  return children;
11048  }
11049 
11071  public CaseDbQuery executeQuery(String query) throws TskCoreException {
11072  return new CaseDbQuery(query);
11073  }
11074 
11096  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
11097  return new CaseDbQuery(query, true);
11098  }
11099 
11107  CaseDbConnection getConnection() throws TskCoreException {
11108  return connections.getConnection();
11109  }
11110 
11118  String getCaseHandleIdentifier() {
11119  return caseHandleIdentifier;
11120  }
11121 
11122  @SuppressWarnings("deprecation")
11123  @Override
11124  protected void finalize() throws Throwable {
11125  try {
11126  close();
11127  } finally {
11128  super.finalize();
11129  }
11130  }
11131 
11135  public synchronized void close() {
11137 
11138  try {
11139  connections.close();
11140  } catch (TskCoreException ex) {
11141  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
11142  }
11143 
11144  fileSystemIdMap.clear();
11145 
11146  try {
11147  if (this.caseHandle != null) {
11148  this.caseHandle.free();
11149  this.caseHandle = null;
11150  }
11151  } catch (TskCoreException ex) {
11152  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
11153  } finally {
11155  }
11156 
11157  if (this.lockResources != null) {
11158  try {
11159  this.lockResources.close();
11160  } catch (Exception ex) {
11161  logger.log(Level.SEVERE, "Error closing lock resources.", ex); //NON-NLS
11162  }
11163  }
11164  }
11165 
11178  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
11179  long id = file.getId();
11180  FileKnown currentKnown = file.getKnown();
11181  if (currentKnown.compareTo(fileKnown) > 0) {
11182  return false;
11183  }
11185  try (CaseDbConnection connection = connections.getConnection();
11186  Statement statement = connection.createStatement();) {
11187  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
11188  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
11189  + "WHERE obj_id=" + id); //NON-NLS
11190 
11191  file.setKnown(fileKnown);
11192  } catch (SQLException ex) {
11193  throw new TskCoreException("Error setting Known status.", ex);
11194  } finally {
11196  }
11197  return true;
11198  }
11199 
11208  void setFileName(String name, long objId) throws TskCoreException {
11210  try (CaseDbConnection connection = connections.getConnection();) {
11211  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
11212  preparedStatement.clearParameters();
11213  preparedStatement.setString(1, name);
11214  preparedStatement.setLong(2, objId);
11215  connection.executeUpdate(preparedStatement);
11216  } catch (SQLException ex) {
11217  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
11218  } finally {
11220  }
11221  }
11222 
11231  void setImageName(String name, long objId) throws TskCoreException {
11233  try (CaseDbConnection connection = connections.getConnection();) {
11234  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
11235  preparedStatement.clearParameters();
11236  preparedStatement.setString(1, name);
11237  preparedStatement.setLong(2, objId);
11238  connection.executeUpdate(preparedStatement);
11239  } catch (SQLException ex) {
11240  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
11241  } finally {
11243  }
11244  }
11245 
11260  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
11261 
11263  try (CaseDbConnection connection = connections.getConnection();) {
11264  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
11265  preparedStatement.clearParameters();
11266  preparedStatement.setLong(1, totalSize);
11267  preparedStatement.setLong(2, sectorSize);
11268  preparedStatement.setLong(3, image.getId());
11269  connection.executeUpdate(preparedStatement);
11270  } catch (SQLException ex) {
11271  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);
11272  } finally {
11274  }
11275  }
11276 
11291  @Beta
11292  public void updateFile(long fileObjId, long size, long mtime, long atime, long ctime, long crtime, String userSid, Long osAcctObjId) throws TskCoreException {
11293 
11294  String updateString = "UPDATE tsk_files SET size = ?, mtime = ?, atime = ?, ctime = ?, crtime = ?, "
11295  + " owner_uid = ?, os_account_obj_id = ? WHERE obj_id = ?";
11296 
11298  try (CaseDbConnection connection = connections.getConnection();
11299  PreparedStatement preparedStatement = connection.getPreparedStatement(updateString, Statement.NO_GENERATED_KEYS);) {
11300 
11301  preparedStatement.clearParameters();
11302 
11303  preparedStatement.setLong(1, size);
11304  preparedStatement.setLong(2, mtime);
11305  preparedStatement.setLong(3, atime);
11306  preparedStatement.setLong(4, ctime);
11307  preparedStatement.setLong(5, crtime);
11308  preparedStatement.setString(6, userSid);
11309 
11310  if (osAcctObjId != null) {
11311  preparedStatement.setLong(7, osAcctObjId);
11312  } else {
11313  preparedStatement.setNull(7, java.sql.Types.BIGINT);
11314  }
11315 
11316  preparedStatement.setLong(8, fileObjId);
11317 
11318  connection.executeUpdate(preparedStatement);
11319  } catch (SQLException ex) {
11320  throw new TskCoreException(String.format("Error updating file (obj_id = %s)", fileObjId), ex);
11321  } finally {
11323  }
11324  }
11325 
11335  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
11337  try (CaseDbConnection connection = connections.getConnection();
11338  Statement statement = connection.createStatement()) {
11339  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
11340  file.setMIMEType(mimeType);
11341  } catch (SQLException ex) {
11342  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
11343  } finally {
11345  }
11346  }
11347 
11358  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
11359 
11360  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
11361  short metaFlag = file.getMetaFlagsAsInt();
11362  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
11363  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
11364  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
11365 
11366  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
11367  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
11368 
11370  try (CaseDbConnection connection = connections.getConnection();
11371  Statement statement = connection.createStatement();) {
11372  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
11373 
11374  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
11375  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
11376 
11377  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
11378 
11379  } catch (SQLException ex) {
11380  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
11381  } finally {
11383  }
11384  }
11385 
11395  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
11396  if (md5Hash == null) {
11397  return;
11398  }
11399  long id = file.getId();
11401  try (CaseDbConnection connection = connections.getConnection();) {
11402  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
11403  statement.clearParameters();
11404  statement.setString(1, md5Hash.toLowerCase());
11405  statement.setLong(2, id);
11406  connection.executeUpdate(statement);
11407  file.setMd5Hash(md5Hash.toLowerCase());
11408  } catch (SQLException ex) {
11409  throw new TskCoreException("Error setting MD5 hash", ex);
11410  } finally {
11412  }
11413  }
11414 
11424  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
11425  if (md5Hash == null) {
11426  return;
11427  }
11428  long id = img.getId();
11430  try (CaseDbConnection connection = connections.getConnection();) {
11431  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
11432  statement.clearParameters();
11433  statement.setString(1, md5Hash.toLowerCase());
11434  statement.setLong(2, id);
11435  connection.executeUpdate(statement);
11436  } catch (SQLException ex) {
11437  throw new TskCoreException("Error setting MD5 hash", ex);
11438  } finally {
11440  }
11441  }
11442 
11453  String getMd5ImageHash(Image img) throws TskCoreException {
11454  long id = img.getId();
11455  CaseDbConnection connection = null;
11456  ResultSet rs = null;
11457  String hash = "";
11459  try {
11460  connection = connections.getConnection();
11461 
11462  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
11463  statement.clearParameters();
11464  statement.setLong(1, id);
11465  rs = connection.executeQuery(statement);
11466  if (rs.next()) {
11467  hash = rs.getString("md5");
11468  }
11469  return hash;
11470  } catch (SQLException ex) {
11471  throw new TskCoreException("Error getting MD5 hash", ex);
11472  } finally {
11473  closeResultSet(rs);
11474  closeConnection(connection);
11476  }
11477  }
11478 
11488  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
11489  if (sha1Hash == null) {
11490  return;
11491  }
11492  long id = img.getId();
11494  try (CaseDbConnection connection = connections.getConnection();) {
11495  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
11496  statement.clearParameters();
11497  statement.setString(1, sha1Hash.toLowerCase());
11498  statement.setLong(2, id);
11499  connection.executeUpdate(statement);
11500  } catch (SQLException ex) {
11501  throw new TskCoreException("Error setting SHA1 hash", ex);
11502  } finally {
11504  }
11505  }
11506 
11517  String getSha1ImageHash(Image img) throws TskCoreException {
11518  long id = img.getId();
11519  CaseDbConnection connection = null;
11520  ResultSet rs = null;
11521  String hash = "";
11523  try {
11524  connection = connections.getConnection();
11525 
11526  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
11527  statement.clearParameters();
11528  statement.setLong(1, id);
11529  rs = connection.executeQuery(statement);
11530  if (rs.next()) {
11531  hash = rs.getString("sha1");
11532  }
11533  return hash;
11534  } catch (SQLException ex) {
11535  throw new TskCoreException("Error getting SHA1 hash", ex);
11536  } finally {
11537  closeResultSet(rs);
11538  closeConnection(connection);
11540  }
11541  }
11542 
11552  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
11553  if (sha256Hash == null) {
11554  return;
11555  }
11556  long id = img.getId();
11558  try (CaseDbConnection connection = connections.getConnection();) {
11559  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
11560  statement.clearParameters();
11561  statement.setString(1, sha256Hash.toLowerCase());
11562  statement.setLong(2, id);
11563  connection.executeUpdate(statement);
11564  } catch (SQLException ex) {
11565  throw new TskCoreException("Error setting SHA256 hash", ex);
11566  } finally {
11568  }
11569  }
11570 
11581  String getSha256ImageHash(Image img) throws TskCoreException {
11582  long id = img.getId();
11583  CaseDbConnection connection = null;
11584  ResultSet rs = null;
11585  String hash = "";
11587  try {
11588  connection = connections.getConnection();
11589 
11590  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
11591  statement.clearParameters();
11592  statement.setLong(1, id);
11593  rs = connection.executeQuery(statement);
11594  if (rs.next()) {
11595  hash = rs.getString("sha256");
11596  }
11597  return hash;
11598  } catch (SQLException ex) {
11599  throw new TskCoreException("Error setting SHA256 hash", ex);
11600  } finally {
11601  closeResultSet(rs);
11602  closeConnection(connection);
11604  }
11605  }
11606 
11615  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
11616 
11617  long id = datasource.getId();
11619  try (CaseDbConnection connection = connections.getConnection();) {
11620  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11621  statement.clearParameters();
11622  statement.setString(1, details);
11623  statement.setLong(2, id);
11624  connection.executeUpdate(statement);
11625  } catch (SQLException ex) {
11626  throw new TskCoreException("Error setting acquisition details", ex);
11627  } finally {
11629  }
11630  }
11631 
11643  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
11644 
11645  long id = datasource.getId();
11647  try (CaseDbConnection connection = connections.getConnection();) {
11648  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
11649  statement.clearParameters();
11650  statement.setString(1, settings);
11651  statement.setString(2, name);
11652  statement.setString(3, version);
11653  statement.setLong(4, id);
11654  connection.executeUpdate(statement);
11655  } catch (SQLException ex) {
11656  throw new TskCoreException("Error setting acquisition details", ex);
11657  } finally {
11659  }
11660  }
11661 
11671  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
11672  try {
11673  CaseDbConnection connection = trans.getConnection();
11674  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11675  statement.clearParameters();
11676  statement.setString(1, details);
11677  statement.setLong(2, dataSourceId);
11678  connection.executeUpdate(statement);
11679  } catch (SQLException ex) {
11680  throw new TskCoreException("Error setting acquisition details", ex);
11681  }
11682  }
11683 
11693  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
11694  long id = datasource.getId();
11695  CaseDbConnection connection = null;
11696  ResultSet rs = null;
11697  String hash = "";
11699  try {
11700  connection = connections.getConnection();
11701 
11702  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
11703  statement.clearParameters();
11704  statement.setLong(1, id);
11705  rs = connection.executeQuery(statement);
11706  if (rs.next()) {
11707  hash = rs.getString("acquisition_details");
11708  }
11709  return hash;
11710  } catch (SQLException ex) {
11711  throw new TskCoreException("Error setting acquisition details", ex);
11712  } finally {
11713  closeResultSet(rs);
11714  closeConnection(connection);
11716  }
11717  }
11718 
11729  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
11730  long id = datasource.getId();
11731  CaseDbConnection connection = null;
11732  ResultSet rs = null;
11733  String returnValue = "";
11735  try {
11736  connection = connections.getConnection();
11737 
11738  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11739  statement.clearParameters();
11740  statement.setLong(1, id);
11741  rs = connection.executeQuery(statement);
11742  if (rs.next()) {
11743  returnValue = rs.getString(columnName);
11744  }
11745  return returnValue;
11746  } catch (SQLException ex) {
11747  throw new TskCoreException("Error setting acquisition details", ex);
11748  } finally {
11749  closeResultSet(rs);
11750  closeConnection(connection);
11752  }
11753  }
11754 
11765  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
11766  long id = datasource.getId();
11767  CaseDbConnection connection = null;
11768  ResultSet rs = null;
11769  Long returnValue = null;
11771  try {
11772  connection = connections.getConnection();
11773 
11774  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11775  statement.clearParameters();
11776  statement.setLong(1, id);
11777  rs = connection.executeQuery(statement);
11778  if (rs.next()) {
11779  returnValue = rs.getLong(columnName);
11780  }
11781  return returnValue;
11782  } catch (SQLException ex) {
11783  throw new TskCoreException("Error setting acquisition details", ex);
11784  } finally {
11785  closeResultSet(rs);
11786  closeConnection(connection);
11788  }
11789  }
11790 
11801  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
11802  if (newStatus == null) {
11803  return;
11804  }
11806  try (CaseDbConnection connection = connections.getConnection();
11807  Statement statement = connection.createStatement();) {
11808  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
11809  + " SET review_status_id=" + newStatus.getID()
11810  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
11811  } catch (SQLException ex) {
11812  throw new TskCoreException("Error setting review status", ex);
11813  } finally {
11815  }
11816  }
11817 
11828  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
11829  CaseDbConnection connection = null;
11830  Statement s = null;
11831  ResultSet rs = null;
11833  try {
11834  connection = connections.getConnection();
11835  s = connection.createStatement();
11836  Short contentShort = contentType.getValue();
11837  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
11838  int count = 0;
11839  if (rs.next()) {
11840  count = rs.getInt("count");
11841  }
11842  return count;
11843  } catch (SQLException ex) {
11844  throw new TskCoreException("Error getting number of objects.", ex);
11845  } finally {
11846  closeResultSet(rs);
11847  closeStatement(s);
11848  closeConnection(connection);
11850  }
11851  }
11852 
11861  public static String escapeSingleQuotes(String text) {
11862  String escapedText = null;
11863  if (text != null) {
11864  escapedText = text.replaceAll("'", "''");
11865  }
11866  return escapedText;
11867  }
11868 
11876  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11877  if (md5Hash == null) {
11878  return Collections.<AbstractFile>emptyList();
11879  }
11880 
11881  CaseDbConnection connection = null;
11882  Statement s = null;
11883  ResultSet rs = null;
11885  try {
11886  connection = connections.getConnection();
11887  s = connection.createStatement();
11888  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11889  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11890  + "AND size > 0"); //NON-NLS
11891  return resultSetToAbstractFiles(rs, connection);
11892  } catch (SQLException | TskCoreException ex) {
11893  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11894  } finally {
11895  closeResultSet(rs);
11896  closeStatement(s);
11897  closeConnection(connection);
11899  }
11900  return Collections.<AbstractFile>emptyList();
11901  }
11902 
11909  public boolean allFilesMd5Hashed() {
11910  boolean allFilesAreHashed = false;
11911 
11912  CaseDbConnection connection = null;
11913  Statement s = null;
11914  ResultSet rs = null;
11916  try {
11917  connection = connections.getConnection();
11918  s = connection.createStatement();
11919  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11920  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11921  + "AND md5 IS NULL " //NON-NLS
11922  + "AND size > '0'"); //NON-NLS
11923  if (rs.next() && rs.getInt("count") == 0) {
11924  allFilesAreHashed = true;
11925  }
11926  } catch (SQLException | TskCoreException ex) {
11927  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11928  } finally {
11929  closeResultSet(rs);
11930  closeStatement(s);
11931  closeConnection(connection);
11933  }
11934  return allFilesAreHashed;
11935  }
11936 
11942  public int countFilesMd5Hashed() {
11943  int count = 0;
11944 
11946  CaseDbConnection connection = null;
11947  Statement s = null;
11948  ResultSet rs = null;
11949  try {
11950  connection = connections.getConnection();
11951  s = connection.createStatement();
11952  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11953  + "WHERE md5 IS NOT NULL " //NON-NLS
11954  + "AND size > '0'"); //NON-NLS
11955  if (rs.next()) {
11956  count = rs.getInt("count");
11957  }
11958  } catch (SQLException | TskCoreException ex) {
11959  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11960  } finally {
11961  closeResultSet(rs);
11962  closeStatement(s);
11963  closeConnection(connection);
11965  }
11966  return count;
11967 
11968  }
11969 
11978  public List<TagName> getAllTagNames() throws TskCoreException {
11979  CaseDbConnection connection = null;
11980  ResultSet resultSet = null;
11982  try {
11983  connection = connections.getConnection();
11984 
11985  // SELECT * FROM tag_names
11986  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11987  resultSet = connection.executeQuery(statement);
11988  ArrayList<TagName> tagNames = new ArrayList<>();
11989  while (resultSet.next()) {
11990  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11991  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11992  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11993  }
11994  return tagNames;
11995  } catch (SQLException ex) {
11996  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11997  } finally {
11998  closeResultSet(resultSet);
11999  closeConnection(connection);
12001  }
12002  }
12003 
12014  public List<TagName> getTagNamesInUse() throws TskCoreException {
12015  CaseDbConnection connection = null;
12016  ResultSet resultSet = null;
12018  try {
12019  connection = connections.getConnection();
12020 
12021  // 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)
12022  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
12023  resultSet = connection.executeQuery(statement);
12024  ArrayList<TagName> tagNames = new ArrayList<>();
12025  while (resultSet.next()) {
12026  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12027  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12028  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
12029  }
12030  return tagNames;
12031  } catch (SQLException ex) {
12032  throw new TskCoreException("Error selecting rows from tag_names table", ex);
12033  } finally {
12034  closeResultSet(resultSet);
12035  closeConnection(connection);
12037  }
12038  }
12039 
12052  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
12053 
12054  ArrayList<TagName> tagNames = new ArrayList<>();
12055  // SELECT * FROM tag_names WHERE tag_name_id IN
12056  // ( 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 = ? "
12057  // UNION
12058  // 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 = ? )
12059  // )
12060  CaseDbConnection connection = null;
12061  ResultSet resultSet = null;
12063  try {
12064  connection = connections.getConnection();
12065 
12066  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
12067  statement.setLong(1, dsObjId);
12068  statement.setLong(2, dsObjId);
12069  resultSet = connection.executeQuery(statement); //NON-NLS
12070  while (resultSet.next()) {
12071  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12072  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12073  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
12074  }
12075  return tagNames;
12076  } catch (SQLException ex) {
12077  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
12078  } finally {
12079  closeResultSet(resultSet);
12080  closeConnection(connection);
12082  }
12083  }
12084 
12098  @Deprecated
12099  @SuppressWarnings("deprecation")
12100  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
12101  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
12102  }
12103 
12120  @Deprecated
12121  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
12122  return getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
12123  }
12124 
12139  @Deprecated
12140  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
12141  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
12142  }
12143 
12144  /*
12145  * Deletes a row from the content_tags table in the case database. @param
12146  * tag A ContentTag data transfer object (DTO) for the row to delete.
12147  * @throws TskCoreException
12148  */
12149  public void deleteContentTag(ContentTag tag) throws TskCoreException {
12151  try {
12152  // DELETE FROM content_tags WHERE tag_id = ?
12153  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
12154  statement.clearParameters();
12155  statement.setLong(1, tag.getId());
12156  trans.getConnection().executeUpdate(statement);
12157 
12158  // update the aggregate score for the content
12159  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
12160  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
12161  ? tag.getContent().getDataSource().getId()
12162  : null;
12163 
12164  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
12165 
12166  trans.commit();
12167  trans = null;
12168  } catch (SQLException ex) {
12169  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
12170  } finally {
12171  if (trans != null) {
12172  trans.rollback();
12173  }
12174  }
12175  }
12176 
12185  public List<ContentTag> getAllContentTags() throws TskCoreException {
12186  CaseDbConnection connection = null;
12187  ResultSet resultSet = null;
12189  try {
12190  connection = connections.getConnection();
12191 
12192  // 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
12193  // FROM content_tags
12194  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
12195  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12196  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
12197  resultSet = connection.executeQuery(statement);
12198  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12199  while (resultSet.next()) {
12200  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12201  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12202  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12203  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
12204  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
12205  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
12206  }
12207  return tags;
12208  } catch (SQLException ex) {
12209  throw new TskCoreException("Error selecting rows from content_tags table", ex);
12210  } finally {
12211  closeResultSet(resultSet);
12212  closeConnection(connection);
12214  }
12215  }
12216 
12227  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
12228  if (tagName.getId() == Tag.ID_NOT_SET) {
12229  throw new TskCoreException("TagName object is invalid, id not set");
12230  }
12231  CaseDbConnection connection = null;
12232  ResultSet resultSet = null;
12234  try {
12235  connection = connections.getConnection();
12236 
12237  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
12238  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
12239  statement.clearParameters();
12240  statement.setLong(1, tagName.getId());
12241  resultSet = connection.executeQuery(statement);
12242  if (resultSet.next()) {
12243  return resultSet.getLong("count");
12244  } else {
12245  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
12246  }
12247  } catch (SQLException ex) {
12248  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
12249  } finally {
12250  closeResultSet(resultSet);
12251  closeConnection(connection);
12253  }
12254  }
12255 
12271  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12272 
12273  if (tagName.getId() == Tag.ID_NOT_SET) {
12274  throw new TskCoreException("TagName object is invalid, id not set");
12275  }
12276 
12277  CaseDbConnection connection = null;
12278  ResultSet resultSet = null;
12280  try {
12281  connection = connections.getConnection();
12282 
12283  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
12284  // + " AND content_tags.tag_name_id = ? "
12285  // + " AND tsk_files.data_source_obj_id = ? "
12286  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12287  statement.clearParameters();
12288  statement.setLong(1, tagName.getId());
12289  statement.setLong(2, dsObjId);
12290 
12291  resultSet = connection.executeQuery(statement);
12292  if (resultSet.next()) {
12293  return resultSet.getLong("count");
12294  } else {
12295  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
12296  }
12297  } catch (SQLException ex) {
12298  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12299  } finally {
12300  closeResultSet(resultSet);
12301  closeConnection(connection);
12303  }
12304  }
12305 
12316  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
12317 
12318  CaseDbConnection connection = null;
12319  ResultSet resultSet = null;
12320  ContentTag tag = null;
12322  try {
12323  connection = connections.getConnection();
12324 
12325  // 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
12326  // FROM content_tags
12327  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
12328  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12329  // WHERE tag_id = ?
12330  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
12331  statement.clearParameters();
12332  statement.setLong(1, contentTagID);
12333  resultSet = connection.executeQuery(statement);
12334 
12335  while (resultSet.next()) {
12336  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12337  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12338  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12339  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
12340  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
12341  }
12342  resultSet.close();
12343 
12344  } catch (SQLException ex) {
12345  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
12346  } finally {
12347  closeResultSet(resultSet);
12348  closeConnection(connection);
12350  }
12351  return tag;
12352  }
12353 
12365  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
12366  if (tagName.getId() == Tag.ID_NOT_SET) {
12367  throw new TskCoreException("TagName object is invalid, id not set");
12368  }
12369  CaseDbConnection connection = null;
12370  ResultSet resultSet = null;
12372  try {
12373  connection = connections.getConnection();
12374 
12375  // 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
12376  // FROM content_tags
12377  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12378  // WHERE tag_name_id = ?
12379  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
12380  statement.clearParameters();
12381  statement.setLong(1, tagName.getId());
12382  resultSet = connection.executeQuery(statement);
12383  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12384  while (resultSet.next()) {
12385  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
12386  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12387  tags.add(tag);
12388  }
12389  resultSet.close();
12390  return tags;
12391  } catch (SQLException ex) {
12392  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
12393  } finally {
12394  closeResultSet(resultSet);
12395  closeConnection(connection);
12397  }
12398  }
12399 
12414  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12415 
12416  CaseDbConnection connection = null;
12417  ResultSet resultSet = null;
12419  try {
12420  connection = connections.getConnection();
12421 
12422  // NOTE: Getting all content tags by tag name for a given data source includes
12423  // looking up all Content objects that have entries in tsk_files, as well as
12424  // all OsAccounts. OsAccounts do not have corresponding entries in tsk_files so we
12425  // have to do a separate query to look them up, and then do a UNION of the results.
12426 
12427 // "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 "
12428 // + "FROM content_tags "
12429 // + "JOIN tsk_os_accounts acc ON content_tags.obj_id = acc.os_account_obj_id "
12430 // + "JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12431 // + "JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12432 // + "WHERE content_tags.tag_name_id = ? "
12433 // + "AND acc.os_account_obj_id IN (SELECT os_account_obj_id FROM tsk_os_account_instances WHERE data_source_obj_id = ?) "
12434 // + "AND acc.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
12435 // + " UNION "
12436 // + "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 "
12437 // + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
12438 // + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id "
12439 // + "AND content_tags.obj_id = tsk_files.obj_id "
12440 // + "AND content_tags.tag_name_id = tag_names.tag_name_id "
12441 // + "AND content_tags.tag_name_id = ? "
12442 // + "AND tsk_files.data_source_obj_id = ? "
12443 
12444  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12445  statement.clearParameters();
12446  statement.setLong(1, tagName.getId());
12447  statement.setLong(2, dsObjId);
12448  statement.setLong(3, tagName.getId());
12449  statement.setLong(4, dsObjId);
12450  resultSet = connection.executeQuery(statement);
12451  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12452  while (resultSet.next()) {
12453  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
12454  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12455  tags.add(tag);
12456  }
12457  resultSet.close();
12458  return tags;
12459  } catch (SQLException ex) {
12460  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
12461  } finally {
12462  closeResultSet(resultSet);
12463  closeConnection(connection);
12465  }
12466  }
12467 
12479  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
12480  CaseDbConnection connection = null;
12481  ResultSet resultSet = null;
12483  try {
12484  connection = connections.getConnection();
12485 
12486  // 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
12487  // FROM content_tags
12488  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
12489  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
12490  // WHERE content_tags.obj_id = ?
12491  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
12492  statement.clearParameters();
12493  statement.setLong(1, content.getId());
12494  resultSet = connection.executeQuery(statement);
12495  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
12496  while (resultSet.next()) {
12497  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12498  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12499  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12500  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
12501  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
12502  tags.add(tag);
12503  }
12504  return tags;
12505  } catch (SQLException ex) {
12506  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
12507  } finally {
12508  closeResultSet(resultSet);
12509  closeConnection(connection);
12511  }
12512  }
12513 
12528  @Deprecated
12529  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
12530  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
12531  }
12532 
12533  /*
12534  * Deletes a row from the blackboard_artifact_tags table in the case
12535  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
12536  * representing the row to delete. @throws TskCoreException
12537  */
12538  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
12540  try {
12541  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
12542  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
12543  statement.clearParameters();
12544  statement.setLong(1, tag.getId());
12545  trans.getConnection().executeUpdate(statement);
12546 
12547  // update the aggregate score for the artifact
12548  Long artifactObjId = tag.getArtifact().getId();
12549  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
12550  ? tag.getContent().getDataSource().getId()
12551  : null;
12552 
12553  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
12554 
12555  trans.commit();
12556  trans = null;
12557  } catch (SQLException ex) {
12558  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
12559  } finally {
12560  if (trans != null) {
12561  trans.rollback();
12562  }
12563  }
12564  }
12565 
12575  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
12576  CaseDbConnection connection = null;
12577  ResultSet resultSet = null;
12579  try {
12580  connection = connections.getConnection();
12581 
12582  // 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
12583  // FROM blackboard_artifact_tags
12584  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12585  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12586  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
12587  resultSet = connection.executeQuery(statement);
12588  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12589  while (resultSet.next()) {
12590  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12591  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12592  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12593  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12594  Content content = getContentById(artifact.getObjectID());
12595  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12596  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12597  tags.add(tag);
12598  }
12599  return tags;
12600  } catch (SQLException ex) {
12601  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
12602  } finally {
12603  closeResultSet(resultSet);
12604  closeConnection(connection);
12606  }
12607  }
12608 
12619  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
12620  if (tagName.getId() == Tag.ID_NOT_SET) {
12621  throw new TskCoreException("TagName object is invalid, id not set");
12622  }
12623  CaseDbConnection connection = null;
12624  ResultSet resultSet = null;
12626  try {
12627  connection = connections.getConnection();
12628 
12629  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
12630  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
12631  statement.clearParameters();
12632  statement.setLong(1, tagName.getId());
12633  resultSet = connection.executeQuery(statement);
12634  if (resultSet.next()) {
12635  return resultSet.getLong("count");
12636  } else {
12637  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
12638  }
12639  } catch (SQLException ex) {
12640  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
12641  } finally {
12642  closeResultSet(resultSet);
12643  closeConnection(connection);
12645  }
12646  }
12647 
12662  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12663 
12664  if (tagName.getId() == Tag.ID_NOT_SET) {
12665  throw new TskCoreException("TagName object is invalid, id not set");
12666  }
12667 
12668  CaseDbConnection connection = null;
12669  ResultSet resultSet = null;
12671  try {
12672  connection = connections.getConnection();
12673 
12674  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
12675  // + " AND artifact_tags.tag_name_id = ?"
12676  // + " AND arts.data_source_obj_id = ? "
12677  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
12678  statement.clearParameters();
12679  statement.setLong(1, tagName.getId());
12680  statement.setLong(2, dsObjId);
12681  resultSet = connection.executeQuery(statement);
12682  if (resultSet.next()) {
12683  return resultSet.getLong("count");
12684  } else {
12685  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
12686  }
12687  } catch (SQLException ex) {
12688  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12689  } finally {
12690  closeResultSet(resultSet);
12691  closeConnection(connection);
12693  }
12694  }
12695 
12707  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
12708  if (tagName.getId() == Tag.ID_NOT_SET) {
12709  throw new TskCoreException("TagName object is invalid, id not set");
12710  }
12711  CaseDbConnection connection = null;
12712  ResultSet resultSet = null;
12714  try {
12715  connection = connections.getConnection();
12716 
12717  // 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
12718  // FROM blackboard_artifact_tags
12719  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12720  // WHERE tag_name_id = ?
12721  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
12722  statement.clearParameters();
12723  statement.setLong(1, tagName.getId());
12724  resultSet = connection.executeQuery(statement);
12725  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12726  while (resultSet.next()) {
12727  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12728  Content content = getContentById(artifact.getObjectID());
12729  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12730  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12731  tags.add(tag);
12732  }
12733  return tags;
12734  } catch (SQLException ex) {
12735  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
12736  } finally {
12737  closeResultSet(resultSet);
12738  closeConnection(connection);
12740  }
12741  }
12742 
12757  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12758 
12759  if (tagName.getId() == Tag.ID_NOT_SET) {
12760  throw new TskCoreException("TagName object is invalid, id not set");
12761  }
12762 
12763  CaseDbConnection connection = null;
12764  ResultSet resultSet = null;
12766  try {
12767  connection = connections.getConnection();
12768 
12769  // 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
12770  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
12771  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
12772  // WHERE artifact_tags.artifact_id = arts.artifact_id
12773  // AND artifact_tags.tag_name_id = ?
12774  // AND arts.data_source_obj_id = ?
12775  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12776  statement.clearParameters();
12777  statement.setLong(1, tagName.getId());
12778  statement.setLong(2, dsObjId);
12779  resultSet = connection.executeQuery(statement);
12780  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12781  while (resultSet.next()) {
12782  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12783  Content content = getContentById(artifact.getObjectID());
12784  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12785  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12786  tags.add(tag);
12787  }
12788  return tags;
12789  } catch (SQLException ex) {
12790  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12791  } finally {
12792  closeResultSet(resultSet);
12793  closeConnection(connection);
12795  }
12796 
12797  }
12798 
12810  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
12811 
12812  CaseDbConnection connection = null;
12813  ResultSet resultSet = null;
12814  BlackboardArtifactTag tag = null;
12816  try {
12817  connection = connections.getConnection();
12818 
12819  //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
12820  // FROM blackboard_artifact_tags
12821  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12822  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12823  // WHERE blackboard_artifact_tags.tag_id = ?
12824  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
12825  statement.clearParameters();
12826  statement.setLong(1, artifactTagID);
12827  resultSet = connection.executeQuery(statement);
12828 
12829  while (resultSet.next()) {
12830  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12831  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12832  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12833  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12834  Content content = getContentById(artifact.getObjectID());
12835  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12836  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
12837  }
12838  resultSet.close();
12839 
12840  } catch (SQLException ex) {
12841  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12842  } finally {
12843  closeResultSet(resultSet);
12844  closeConnection(connection);
12846  }
12847  return tag;
12848  }
12849 
12862  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12863  CaseDbConnection connection = null;
12864  ResultSet resultSet = null;
12866  try {
12867  connection = connections.getConnection();
12868 
12869  // 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
12870  // FROM blackboard_artifact_tags
12871  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12872  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12873  // WHERE blackboard_artifact_tags.artifact_id = ?
12874  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12875  statement.clearParameters();
12876  statement.setLong(1, artifact.getArtifactID());
12877  resultSet = connection.executeQuery(statement);
12878  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12879  while (resultSet.next()) {
12880  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12881  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12882  TskData.TagType.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12883  Content content = getContentById(artifact.getObjectID());
12884  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12885  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12886  tags.add(tag);
12887  }
12888  return tags;
12889  } catch (SQLException ex) {
12890  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12891  } finally {
12892  closeResultSet(resultSet);
12893  closeConnection(connection);
12895  }
12896  }
12897 
12906  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12908  try (CaseDbConnection connection = connections.getConnection();) {
12909  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12910  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12911  statement.clearParameters();
12912  statement.setString(1, newPath);
12913  statement.setLong(2, objectId);
12914  connection.executeUpdate(statement);
12915  } catch (SQLException ex) {
12916  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12917  } finally {
12919  }
12920  }
12921 
12935  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12936  return addReport(localPath, sourceModuleName, reportName, null);
12937  }
12938 
12954  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12955  // Make sure the local path of the report is in the database directory
12956  // or one of its subdirectories.
12957  String relativePath = ""; //NON-NLS
12958  long createTime = 0;
12959  String localPathLower = localPath.toLowerCase();
12960 
12961  if (localPathLower.startsWith("http")) {
12962  relativePath = localPathLower;
12963  createTime = System.currentTimeMillis() / 1000;
12964  } else {
12965  /*
12966  * Note: The following call to .relativize() may be dangerous in
12967  * case-sensitive operating systems and should be looked at. For
12968  * now, we are simply relativizing the paths as all lower case, then
12969  * using the length of the result to pull out the appropriate number
12970  * of characters from the localPath String.
12971  */
12972  try {
12973  String casePathLower = getDbDirPath().toLowerCase();
12974  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12975  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12976  } catch (IllegalArgumentException ex) {
12977  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12978  throw new TskCoreException(errorMessage, ex);
12979  }
12980  try {
12981  // get its file time
12982  java.io.File tempFile = new java.io.File(localPath);
12983  // Convert to UNIX epoch (seconds, not milliseconds).
12984  createTime = tempFile.lastModified() / 1000;
12985  } catch (Exception ex) {
12986  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12987  }
12988  }
12989 
12990  // Write the report data to the database.
12992  try (CaseDbConnection connection = connections.getConnection();) {
12993  // Insert a row for the report into the tsk_objects table.
12994  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12995  long parentObjId = 0;
12996  if (parent != null) {
12997  parentObjId = parent.getId();
12998  }
12999  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
13000 
13001  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
13002  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
13003  statement.clearParameters();
13004  statement.setLong(1, objectId);
13005  statement.setString(2, relativePath);
13006  statement.setLong(3, createTime);
13007  statement.setString(4, sourceModuleName);
13008  statement.setString(5, reportName);
13009  connection.executeUpdate(statement);
13010  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
13011  } catch (SQLException ex) {
13012  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
13013  } finally {
13015  }
13016  }
13017 
13026  public List<Report> getAllReports() throws TskCoreException {
13027  CaseDbConnection connection = null;
13028  ResultSet resultSet = null;
13029  ResultSet parentResultSet = null;
13030  PreparedStatement statement = null;
13031  Statement parentStatement = null;
13033  try {
13034  connection = connections.getConnection();
13035 
13036  // SELECT * FROM reports
13037  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
13038  parentStatement = connection.createStatement();
13039  resultSet = connection.executeQuery(statement);
13040  ArrayList<Report> reports = new ArrayList<Report>();
13041  while (resultSet.next()) {
13042  String localpath = resultSet.getString("path");
13043  if (localpath.toLowerCase().startsWith("http") == false) {
13044  // make path absolute
13045  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
13046  }
13047 
13048  // get the report parent
13049  Content parent = null;
13050  long reportId = resultSet.getLong("obj_id"); // NON-NLS
13051  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
13052  parentResultSet = parentStatement.executeQuery(parentQuery);
13053  if (parentResultSet.next()) {
13054  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
13055  parent = this.getContentById(parentId);
13056  }
13057  parentResultSet.close();
13058 
13059  reports.add(new Report(this,
13060  reportId,
13061  localpath,
13062  resultSet.getLong("crtime"), //NON-NLS
13063  resultSet.getString("src_module_name"), //NON-NLS
13064  resultSet.getString("report_name"),
13065  parent)); //NON-NLS
13066  }
13067  return reports;
13068  } catch (SQLException ex) {
13069  throw new TskCoreException("Error querying reports table", ex);
13070  } finally {
13071  closeResultSet(resultSet);
13072  closeResultSet(parentResultSet);
13073  closeStatement(statement);
13074  closeStatement(parentStatement);
13075 
13076  closeConnection(connection);
13078  }
13079  }
13080 
13090  public Report getReportById(long id) throws TskCoreException {
13091  CaseDbConnection connection = null;
13092  PreparedStatement statement = null;
13093  Statement parentStatement = null;
13094  ResultSet resultSet = null;
13095  ResultSet parentResultSet = null;
13096  Report report = null;
13098  try {
13099  connection = connections.getConnection();
13100 
13101  // SELECT * FROM reports WHERE obj_id = ?
13102  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
13103  parentStatement = connection.createStatement();
13104  statement.clearParameters();
13105  statement.setLong(1, id);
13106  resultSet = connection.executeQuery(statement);
13107 
13108  if (resultSet.next()) {
13109  // get the report parent
13110  Content parent = null;
13111  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
13112  parentResultSet = parentStatement.executeQuery(parentQuery);
13113  if (parentResultSet.next()) {
13114  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
13115  parent = this.getContentById(parentId);
13116  }
13117 
13118  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
13119  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
13120  resultSet.getLong("crtime"), //NON-NLS
13121  resultSet.getString("src_module_name"), //NON-NLS
13122  resultSet.getString("report_name"),
13123  parent); //NON-NLS
13124  } else {
13125  throw new TskCoreException("No report found for id: " + id);
13126  }
13127  } catch (SQLException ex) {
13128  throw new TskCoreException("Error querying reports table for id: " + id, ex);
13129  } finally {
13130  closeResultSet(resultSet);
13131  closeResultSet(parentResultSet);
13132  closeStatement(statement);
13133  closeStatement(parentStatement);
13134  closeConnection(connection);
13136  }
13137 
13138  return report;
13139  }
13140 
13148  public void deleteReport(Report report) throws TskCoreException {
13150  try (CaseDbConnection connection = connections.getConnection();) {
13151  // DELETE FROM reports WHERE reports.obj_id = ?
13152  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
13153  statement.setLong(1, report.getId());
13154  connection.executeUpdate(statement);
13155  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
13156  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
13157  statement.setLong(1, report.getId());
13158  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
13159  connection.executeUpdate(statement);
13160  } catch (SQLException ex) {
13161  throw new TskCoreException("Error querying reports table", ex);
13162  } finally {
13164  }
13165  }
13166 
13167  static void closeResultSet(ResultSet resultSet) {
13168  if (resultSet != null) {
13169  try {
13170  resultSet.close();
13171  } catch (SQLException ex) {
13172  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
13173  }
13174  }
13175  }
13176 
13177  static void closeStatement(Statement statement) {
13178  if (statement != null) {
13179  try {
13180  statement.close();
13181  } catch (SQLException ex) {
13182  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
13183 
13184  }
13185  }
13186  }
13187 
13188  static void closeConnection(CaseDbConnection connection) {
13189  if (connection != null) {
13190  connection.close();
13191  }
13192  }
13193 
13194  private static void rollbackTransaction(CaseDbConnection connection) {
13195  if (connection != null) {
13196  connection.rollbackTransaction();
13197  }
13198  }
13199 
13208  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
13210  try (CaseDbConnection connection = connections.getConnection();) {
13211  Statement statement = connection.createStatement();
13212  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
13213  } catch (SQLException ex) {
13214  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
13215  } finally {
13217  }
13218  }
13219 
13220  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
13222  try (CaseDbConnection connection = connections.getConnection();
13223  Statement statement = connection.createStatement();) {
13224  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
13225  } catch (SQLException ex) {
13226  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
13227  } finally {
13229  }
13230  }
13231 
13248  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
13249  CaseDbConnection connection = null;
13251  ResultSet resultSet = null;
13252  Statement statement;
13253  try {
13254  connection = connections.getConnection();
13255  connection.beginTransaction();
13256  statement = connection.createStatement();
13257  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
13258  insertStatement.setLong(1, dataSource.getId());
13259  insertStatement.setString(2, hostName);
13260  insertStatement.setLong(3, jobStart.getTime());
13261  insertStatement.setLong(4, jobEnd.getTime());
13262  insertStatement.setInt(5, status.ordinal());
13263  insertStatement.setString(6, settingsDir);
13264  connection.executeUpdate(insertStatement);
13265  resultSet = insertStatement.getGeneratedKeys();
13266  resultSet.next();
13267  long id = resultSet.getLong(1); //last_insert_rowid()
13268  for (int i = 0; i < ingestModules.size(); i++) {
13269  IngestModuleInfo ingestModule = ingestModules.get(i);
13270  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
13271  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
13272  }
13273  resultSet.close();
13274  resultSet = null;
13275  connection.commitTransaction();
13276  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
13277  } catch (SQLException ex) {
13278  rollbackTransaction(connection);
13279  throw new TskCoreException("Error adding the ingest job.", ex);
13280  } finally {
13281  closeResultSet(resultSet);
13282  closeConnection(connection);
13284  }
13285  }
13286 
13300  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
13301  CaseDbConnection connection = null;
13302  ResultSet resultSet = null;
13303  Statement statement = null;
13304  String uniqueName = factoryClassName + "-" + displayName + "-" + version;
13306  try {
13307  connection = connections.getConnection();
13308  statement = connection.createStatement();
13309  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
13310  if (!resultSet.next()) {
13311  resultSet.close();
13312  resultSet = null;
13313  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
13314  insertStatement.setString(1, displayName);
13315  insertStatement.setString(2, uniqueName);
13316  insertStatement.setInt(3, type.ordinal());
13317  insertStatement.setString(4, version);
13318  connection.executeUpdate(insertStatement);
13319  resultSet = insertStatement.getGeneratedKeys();
13320  resultSet.next();
13321  long id = resultSet.getLong(1); //last_insert_rowid()
13322  resultSet.close();
13323  resultSet = null;
13324  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
13325  } else {
13326  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
13327  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
13328  }
13329  } catch (SQLException ex) {
13330  try {
13331  closeStatement(statement);
13332  if (connection != null) {
13333  statement = connection.createStatement();
13334  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
13335  if (resultSet.next()) {
13336  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
13337  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
13338  }
13339  }
13340  throw new TskCoreException("Couldn't add new module to database.", ex);
13341  } catch (SQLException ex1) {
13342  throw new TskCoreException("Couldn't add new module to database.", ex1);
13343  }
13344  } finally {
13345  closeResultSet(resultSet);
13346  closeStatement(statement);
13347  closeConnection(connection);
13349  }
13350  }
13351 
13359  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
13360  CaseDbConnection connection = null;
13361  ResultSet resultSet = null;
13362  Statement statement = null;
13363  List<IngestJobInfo> ingestJobs = new ArrayList<>();
13365  try {
13366  connection = connections.getConnection();
13367  statement = connection.createStatement();
13368  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
13369  while (resultSet.next()) {
13370  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
13371  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
13372  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
13373  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
13374  }
13375  return ingestJobs;
13376  } catch (SQLException ex) {
13377  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
13378  } finally {
13379  closeResultSet(resultSet);
13380  closeStatement(statement);
13381  closeConnection(connection);
13383  }
13384  }
13385 
13396  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
13397  ResultSet resultSet = null;
13398  Statement statement = null;
13399  List<IngestModuleInfo> ingestModules = new ArrayList<>();
13401  try {
13402  statement = connection.createStatement();
13403  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
13404  + "ingest_job_modules.pipeline_position AS pipeline_position, "
13405  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
13406  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
13407  + "FROM ingest_job_modules, ingest_modules "
13408  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
13409  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
13410  + "ORDER BY (ingest_job_modules.pipeline_position);");
13411  while (resultSet.next()) {
13412  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
13413  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
13414  }
13415  return ingestModules;
13416  } finally {
13417  closeResultSet(resultSet);
13418  closeStatement(statement);
13420 
13421  }
13422  }
13423 
13433  String getInsertOrIgnoreSQL(String sql) {
13434  switch (getDatabaseType()) {
13435  case POSTGRESQL:
13436  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
13437  case SQLITE:
13438  return " INSERT OR IGNORE " + sql; //NON-NLS
13439  default:
13440  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
13441  }
13442  }
13443 
13464  private List<? extends BlackboardArtifact> getArtifactsForValues(BlackboardArtifact.Category category, String dbColumn, List<? extends Number> values, CaseDbConnection connection) throws TskCoreException {
13465  String where = "";
13466  // This look creates the OR statement with the following format:
13467  // <dbColumn> = <value> OR <dbColumn> = <value2> OR ...
13468  for (Number value : values) {
13469  if (!where.isEmpty()) {
13470  where += " OR ";
13471  }
13472  where += dbColumn + " = " + value;
13473  }
13474 
13475  // Base on the category pass the OR statement to the approprate method
13476  // that will retrieve the artifacts.
13477  if (category == BlackboardArtifact.Category.DATA_ARTIFACT) {
13478  return blackboard.getDataArtifactsWhere(where, connection);
13479  } else {
13480  return blackboard.getAnalysisResultsWhere(where, connection);
13481  }
13482  }
13483 
13487  static class ObjectInfo {
13488 
13489  private long id;
13490  private TskData.ObjectType type;
13491 
13492  ObjectInfo(long id, ObjectType type) {
13493  this.id = id;
13494  this.type = type;
13495  }
13496 
13497  long getId() {
13498  return id;
13499  }
13500 
13501  TskData.ObjectType getType() {
13502  return type;
13503  }
13504  }
13505 
13506  private interface DbCommand {
13507 
13508  void execute() throws SQLException;
13509  }
13510 
13511  private enum PREPARED_STATEMENT {
13512 
13513  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
13514  + "WHERE artifact_type_id = ?"), //NON-NLS
13515  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
13516  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
13517  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
13518  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
13519  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
13520  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13521  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13522  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
13523  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
13524  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
13525  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13526  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13527  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
13528  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13529  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13530  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13531  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13532  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
13533  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13534  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13535  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
13536  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13537  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13538  + "WHERE tsk_files.extension = ? AND "
13539  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
13540  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
13541  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
13542  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13543  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13544  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13545  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
13546  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
13547  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
13548  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
13549  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
13550  + "AND tsk_files.type = ? )"), //NON-NLS
13551  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
13552  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13553  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
13554  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
13555  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
13556  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13557  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
13558  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
13559  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
13560  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13561  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
13562  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13563  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
13564  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13565  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
13566  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13567  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
13568  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13569  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
13570  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
13571  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
13572  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
13573  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
13574  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
13575  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
13576  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
13577  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13578  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
13579  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
13580  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
13581  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13582  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13583  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
13584  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
13585  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
13586  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
13587  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
13588  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
13589  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
13590  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
13591  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13592  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
13593  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
13594  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
13595  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
13596  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
13597  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
13598  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
13599  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)"
13600  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
13601  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
13602  + "WHERE obj_id = ?"), //NON-NLS
13603  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
13604  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13605  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
13606  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
13607  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
13608  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
13609  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
13610  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
13611  + "WHERE tag_name_id IN " //NON-NLS
13612  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
13613  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
13614  + "WHERE tag_name_id IN "
13615  + "( SELECT content_tags.tag_name_id as tag_name_id "
13616  + "FROM content_tags as content_tags, tsk_files as tsk_files"
13617  + " WHERE content_tags.obj_id = tsk_files.obj_id"
13618  + " AND tsk_files.data_source_obj_id = ?"
13619  + " UNION "
13620  + "SELECT artifact_tags.tag_name_id as tag_name_id "
13621  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
13622  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
13623  + " AND arts.data_source_obj_id = ?"
13624  + " )"),
13625  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
13626  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13627  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
13628  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
13629  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
13630  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
13631  + " AND content_tags.tag_name_id = ? "
13632  + " AND tsk_files.data_source_obj_id = ? "
13633  ),
13634  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 "
13635  + "FROM content_tags "
13636  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13637  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13638  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 "
13639  + "FROM content_tags "
13640  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13641  + "WHERE tag_name_id = ?"), //NON-NLS
13642  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 "
13643  + "FROM content_tags "
13644  + "JOIN tsk_os_accounts acc ON content_tags.obj_id = acc.os_account_obj_id "
13645  + "JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13646  + "JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13647  + "WHERE content_tags.tag_name_id = ? "
13648  + "AND acc.os_account_obj_id IN (SELECT os_account_obj_id FROM tsk_os_account_instances WHERE data_source_obj_id = ?) "
13649  + "AND acc.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
13650  + " UNION "
13651  + "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 "
13652  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
13653  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id "
13654  + "AND content_tags.obj_id = tsk_files.obj_id "
13655  + "AND content_tags.tag_name_id = tag_names.tag_name_id "
13656  + "AND content_tags.tag_name_id = ? "
13657  + "AND tsk_files.data_source_obj_id = ? "), //NON-NLS
13658  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 "
13659  + "FROM content_tags "
13660  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13661  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13662  + "WHERE tag_id = ?"), //NON-NLS
13663  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 "
13664  + "FROM content_tags "
13665  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
13666  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
13667  + "WHERE content_tags.obj_id = ?"), //NON-NLS
13668  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
13669  + "VALUES (?, ?, ?, ?)"), //NON-NLS
13670  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
13671  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 "
13672  + "FROM blackboard_artifact_tags "
13673  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13674  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
13675  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
13676  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"
13677  + " AND artifact_tags.tag_name_id = ?"
13678  + " AND arts.data_source_obj_id = ? "),
13679  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 "
13680  + "FROM blackboard_artifact_tags "
13681  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13682  + "WHERE tag_name_id = ?"), //NON-NLS
13683  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 "
13684  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
13685  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
13686  + " AND artifact_tags.artifact_id = arts.artifact_id"
13687  + " AND artifact_tags.tag_name_id = ? "
13688  + " AND arts.data_source_obj_id = ? "),
13689  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 "
13690  + "FROM blackboard_artifact_tags "
13691  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13692  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13693  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
13694  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 "
13695  + "FROM blackboard_artifact_tags "
13696  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13697  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13698  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
13699  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
13700  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
13701  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
13702  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
13703  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
13704  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13705  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
13706  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
13707  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
13708  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
13709  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
13710  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
13711  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
13712  + "WHERE (tsk_objects.par_obj_id = ?)"),
13713  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
13714  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
13715  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
13716  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
13717  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
13718  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
13719  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
13720  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
13721  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
13722  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
13723  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13724  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id, acquisition_tool_settings) VALUES (?, ?, ?, ?, ?, ?)"),
13725  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
13726  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13727  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13728  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
13729  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)"
13730  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13731  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?");
13732 
13733  private final String sql;
13734 
13735  private PREPARED_STATEMENT(String sql) {
13736  this.sql = sql;
13737  }
13738 
13739  String getSQL() {
13740  return sql;
13741  }
13742  }
13743 
13749  abstract private class ConnectionPool {
13750 
13751  private PooledDataSource pooledDataSource;
13752 
13753  public ConnectionPool() {
13754  pooledDataSource = null;
13755  }
13756 
13757  CaseDbConnection getConnection() throws TskCoreException {
13758  if (pooledDataSource == null) {
13759  throw new TskCoreException("Error getting case database connection - case is closed");
13760  }
13761  try {
13762  return getPooledConnection();
13763  } catch (SQLException exp) {
13764  throw new TskCoreException(exp.getMessage());
13765  }
13766  }
13767 
13768  void close() throws TskCoreException {
13769  if (pooledDataSource != null) {
13770  try {
13771  pooledDataSource.close();
13772  } catch (SQLException exp) {
13773  throw new TskCoreException(exp.getMessage());
13774  } finally {
13775  pooledDataSource = null;
13776  }
13777  }
13778  }
13779 
13780  abstract CaseDbConnection getPooledConnection() throws SQLException;
13781 
13782  public PooledDataSource getPooledDataSource() {
13783  return pooledDataSource;
13784  }
13785 
13786  public void setPooledDataSource(PooledDataSource pooledDataSource) {
13787  this.pooledDataSource = pooledDataSource;
13788  }
13789  }
13790 
13795  private final class SQLiteConnections extends ConnectionPool {
13796 
13797  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
13798 
13799  SQLiteConnections(String dbPath) throws SQLException {
13800  configurationOverrides.put("acquireIncrement", "2");
13801  configurationOverrides.put("initialPoolSize", "5");
13802  configurationOverrides.put("minPoolSize", "5");
13803  /*
13804  * NOTE: max pool size and max statements are related. If you
13805  * increase max pool size, then also increase statements.
13806  */
13807  configurationOverrides.put("maxPoolSize", "20");
13808  configurationOverrides.put("maxStatements", "200");
13809  configurationOverrides.put("maxStatementsPerConnection", "20");
13810 
13811  SQLiteConfig config = new SQLiteConfig();
13812  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
13813  config.setReadUncommitted(true);
13814  config.enforceForeignKeys(true); // Enforce foreign key constraints.
13815  SQLiteDataSource unpooled = new SQLiteDataSource(config);
13816  unpooled.setUrl("jdbc:sqlite:" + dbPath);
13817  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
13818  }
13819 
13820  @Override
13821  public CaseDbConnection getPooledConnection() throws SQLException {
13822  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
13823  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
13824  // Temporarily filter out Image Gallery threads
13825  if (!Thread.currentThread().getName().contains("ImageGallery")) {
13826  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());
13827  }
13828  }
13829  return new SQLiteConnection(getPooledDataSource().getConnection());
13830  }
13831  }
13832 
13837  private final class PostgreSQLConnections extends ConnectionPool {
13838 
13839  PostgreSQLConnections(CaseDbConnectionInfo info, String dbName) throws PropertyVetoException, UnsupportedEncodingException {
13840 
13841  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
13842  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
13843 
13844  String connectionURL = "jdbc:postgresql://" + info.getHost() + ":" + Integer.valueOf(info.getPort()) + "/"
13845  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString());
13846  if (info.isSslEnabled()) {
13847  if (info.isSslVerify()) {
13848  if (info.getCustomSslValidationClassName().isBlank()) {
13849  connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL;
13850  } else {
13851  // use custom SSL certificate validation class
13852  connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName());
13853  }
13854  } else {
13855  connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL;
13856  }
13857  }
13858  comboPooledDataSource.setJdbcUrl(connectionURL);
13859  comboPooledDataSource.setUser(info.getUserName());
13860  comboPooledDataSource.setPassword(info.getPassword());
13861  comboPooledDataSource.setAcquireIncrement(2);
13862  comboPooledDataSource.setInitialPoolSize(5);
13863  comboPooledDataSource.setMinPoolSize(5);
13864  /*
13865  * NOTE: max pool size and max statements are related. If you
13866  * increase max pool size, then also increase statements.
13867  */
13868  comboPooledDataSource.setMaxPoolSize(20);
13869  comboPooledDataSource.setMaxStatements(200);
13870  comboPooledDataSource.setMaxStatementsPerConnection(20);
13871  setPooledDataSource(comboPooledDataSource);
13872  }
13873 
13874  @Override
13875  public CaseDbConnection getPooledConnection() throws SQLException {
13876  return new PostgreSQLConnection(getPooledDataSource().getConnection());
13877  }
13878  }
13879 
13883  abstract class CaseDbConnection implements AutoCloseable {
13884 
13885  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
13886  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
13887 
13888  private class CreateStatement implements DbCommand {
13889 
13890  private final Connection connection;
13891  private Statement statement = null;
13892 
13893  CreateStatement(Connection connection) {
13894  this.connection = connection;
13895  }
13896 
13897  Statement getStatement() {
13898  return statement;
13899  }
13900 
13901  @Override
13902  public void execute() throws SQLException {
13903  statement = connection.createStatement();
13904  }
13905  }
13906 
13907  private class SetAutoCommit implements DbCommand {
13908 
13909  private final Connection connection;
13910  private final boolean mode;
13911 
13912  SetAutoCommit(Connection connection, boolean mode) {
13913  this.connection = connection;
13914  this.mode = mode;
13915  }
13916 
13917  @Override
13918  public void execute() throws SQLException {
13919  connection.setAutoCommit(mode);
13920  }
13921  }
13922 
13923  private class Commit implements DbCommand {
13924 
13925  private final Connection connection;
13926 
13927  Commit(Connection connection) {
13928  this.connection = connection;
13929  }
13930 
13931  @Override
13932  public void execute() throws SQLException {
13933  connection.commit();
13934  }
13935  }
13936 
13945  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13946 
13947  private final Connection connection;
13948 
13949  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13950  this.connection = connection;
13951  }
13952 
13953  @Override
13954  public void execute() throws SQLException {
13955  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13956  preparedStatement.execute();
13957 
13958  }
13959  }
13960 
13961  private class ExecuteQuery implements DbCommand {
13962 
13963  private final Statement statement;
13964  private final String query;
13965  private ResultSet resultSet;
13966 
13967  ExecuteQuery(Statement statement, String query) {
13968  this.statement = statement;
13969  this.query = query;
13970  }
13971 
13972  ResultSet getResultSet() {
13973  return resultSet;
13974  }
13975 
13976  @Override
13977  public void execute() throws SQLException {
13978  resultSet = statement.executeQuery(query);
13979  }
13980  }
13981 
13982  private class ExecutePreparedStatementQuery implements DbCommand {
13983 
13984  private final PreparedStatement preparedStatement;
13985  private ResultSet resultSet;
13986 
13987  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13988  this.preparedStatement = preparedStatement;
13989  }
13990 
13991  ResultSet getResultSet() {
13992  return resultSet;
13993  }
13994 
13995  @Override
13996  public void execute() throws SQLException {
13997  resultSet = preparedStatement.executeQuery();
13998  }
13999  }
14000 
14001  private class ExecutePreparedStatementUpdate implements DbCommand {
14002 
14003  private final PreparedStatement preparedStatement;
14004 
14005  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
14006  this.preparedStatement = preparedStatement;
14007  }
14008 
14009  @Override
14010  public void execute() throws SQLException {
14011  preparedStatement.executeUpdate();
14012  }
14013  }
14014 
14015  private class ExecuteStatementUpdate implements DbCommand {
14016 
14017  private final Statement statement;
14018  private final String updateCommand;
14019 
14020  ExecuteStatementUpdate(Statement statement, String updateCommand) {
14021  this.statement = statement;
14022  this.updateCommand = updateCommand;
14023  }
14024 
14025  @Override
14026  public void execute() throws SQLException {
14027  statement.executeUpdate(updateCommand);
14028  }
14029  }
14030 
14031  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
14032 
14033  private final Statement statement;
14034  private final int generateKeys;
14035  private final String updateCommand;
14036 
14037  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
14038  this.statement = statement;
14039  this.generateKeys = generateKeys;
14040  this.updateCommand = updateCommand;
14041  }
14042 
14043  @Override
14044  public void execute() throws SQLException {
14045  statement.executeUpdate(updateCommand, generateKeys);
14046  }
14047  }
14048 
14049  private class PrepareStatement implements DbCommand {
14050 
14051  private final Connection connection;
14052  private final String input;
14053  private PreparedStatement preparedStatement = null;
14054 
14055  PrepareStatement(Connection connection, String input) {
14056  this.connection = connection;
14057  this.input = input;
14058  }
14059 
14060  PreparedStatement getPreparedStatement() {
14061  return preparedStatement;
14062  }
14063 
14064  @Override
14065  public void execute() throws SQLException {
14066  preparedStatement = connection.prepareStatement(input);
14067  }
14068  }
14069 
14070  private class PrepareStatementGenerateKeys implements DbCommand {
14071 
14072  private final Connection connection;
14073  private final String input;
14074  private final int generateKeys;
14075  private PreparedStatement preparedStatement = null;
14076 
14077  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
14078  this.connection = connection;
14079  this.input = input;
14080  this.generateKeys = generateKeysInput;
14081  }
14082 
14083  PreparedStatement getPreparedStatement() {
14084  return preparedStatement;
14085  }
14086 
14087  @Override
14088  public void execute() throws SQLException {
14089  preparedStatement = connection.prepareStatement(input, generateKeys);
14090  }
14091  }
14092 
14093  abstract void executeCommand(DbCommand command) throws SQLException;
14094 
14095  private final Connection connection;
14096  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
14097  private final Map<String, PreparedStatement> adHocPreparedStatements;
14098 
14099  CaseDbConnection(Connection connection) {
14100  this.connection = connection;
14101  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
14102  adHocPreparedStatements = new HashMap<>();
14103  }
14104 
14105  boolean isOpen() {
14106  return this.connection != null;
14107  }
14108 
14109  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
14110  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
14111  }
14112 
14113  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
14114  // Lazy statement preparation.
14115  PreparedStatement statement;
14116  if (this.preparedStatements.containsKey(statementKey)) {
14117  statement = this.preparedStatements.get(statementKey);
14118  } else {
14119  statement = prepareStatement(statementKey.getSQL(), generateKeys);
14120  this.preparedStatements.put(statementKey, statement);
14121  }
14122  return statement;
14123  }
14124 
14136  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
14137  PreparedStatement statement;
14138  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
14139  if (adHocPreparedStatements.containsKey(statementKey) && !adHocPreparedStatements.get(statementKey).isClosed()) {
14140  statement = this.adHocPreparedStatements.get(statementKey);
14141  } else {
14142  statement = prepareStatement(sqlStatement, generateKeys);
14143  this.adHocPreparedStatements.put(statementKey, statement);
14144  }
14145  return statement;
14146  }
14147 
14148  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
14149  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
14150  executeCommand(prepareStatement);
14151  return prepareStatement.getPreparedStatement();
14152  }
14153 
14154  Statement createStatement() throws SQLException {
14155  CreateStatement createStatement = new CreateStatement(this.connection);
14156  executeCommand(createStatement);
14157  return createStatement.getStatement();
14158  }
14159 
14160  void beginTransaction() throws SQLException {
14161  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
14162  executeCommand(setAutoCommit);
14163  }
14164 
14165  void commitTransaction() throws SQLException {
14166  Commit commit = new Commit(connection);
14167  executeCommand(commit);
14168  // You must turn auto commit back on when done with the transaction.
14169  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
14170  executeCommand(setAutoCommit);
14171  }
14172 
14178  void rollbackTransaction() {
14179  try {
14180  connection.rollback();
14181  } catch (SQLException e) {
14182  logger.log(Level.SEVERE, "Error rolling back transaction", e);
14183  }
14184  try {
14185  connection.setAutoCommit(true);
14186  } catch (SQLException e) {
14187  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
14188  }
14189  }
14190 
14198  void rollbackTransactionWithThrow() throws SQLException {
14199  try {
14200  connection.rollback();
14201  } finally {
14202  connection.setAutoCommit(true);
14203  }
14204  }
14205 
14214  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
14215  switch (getDatabaseType()) {
14216  case POSTGRESQL:
14217  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
14218  executeCommand(tableWriteLock);
14219  break;
14220  case SQLITE:
14221  // We do nothing here because we assume the entire SQLite DB is already locked from
14222  // when the analysis results were added/deleted in the same transaction.
14223  break;
14224  default:
14225  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
14226  }
14227  }
14228 
14229  ResultSet executeQuery(Statement statement, String query) throws SQLException {
14230  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
14231  executeCommand(queryCommand);
14232  return queryCommand.getResultSet();
14233  }
14234 
14244  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
14245  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
14246  executeCommand(executePreparedStatementQuery);
14247  return executePreparedStatementQuery.getResultSet();
14248  }
14249 
14250  void executeUpdate(Statement statement, String update) throws SQLException {
14251  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
14252  }
14253 
14254  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
14255  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
14256  executeCommand(executeStatementUpdate);
14257  }
14258 
14259  void executeUpdate(PreparedStatement statement) throws SQLException {
14260  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
14261  executeCommand(executePreparedStatementUpdate);
14262  }
14263 
14267  @Override
14268  public void close() {
14269  try {
14270  for (PreparedStatement stmt : preparedStatements.values()) {
14271  closeStatement(stmt);
14272  }
14273  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
14274  closeStatement(stmt);
14275  }
14276  connection.close();
14277  } catch (SQLException ex) {
14278  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
14279  }
14280  }
14281 
14282  Connection getConnection() {
14283  return this.connection;
14284  }
14285  }
14286 
14290  private final class SQLiteConnection extends CaseDbConnection {
14291 
14292  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
14293  private static final int SQLITE_BUSY_ERROR = 5;
14294 
14295  SQLiteConnection(Connection conn) {
14296  super(conn);
14297  }
14298 
14299  @Override
14300  void executeCommand(DbCommand command) throws SQLException {
14301  int retryCounter = 0;
14302  while (true) {
14303  try {
14304  command.execute(); // Perform the operation
14305  break;
14306  } catch (SQLException ex) {
14307  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
14308  try {
14309 
14310  // We do not notify of error here, as this is not an
14311  // error condition. It is likely a temporary busy or
14312  // locked issue and we will retry.
14313  retryCounter++;
14314  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
14315  } catch (InterruptedException exp) {
14316  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
14317  }
14318  } else {
14319  throw ex;
14320  }
14321  }
14322  }
14323  }
14324  }
14325 
14329  private final class PostgreSQLConnection extends CaseDbConnection {
14330 
14331  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
14332  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
14333  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
14334  private static final int MAX_RETRIES = 3;
14335 
14336  PostgreSQLConnection(Connection conn) {
14337  super(conn);
14338  }
14339 
14340  @Override
14341  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
14342  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
14343  executeCommand(executeStatementUpdateGenerateKeys);
14344  }
14345 
14346  @Override
14347  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
14348  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
14349  executeCommand(prepareStatementGenerateKeys);
14350  return prepareStatementGenerateKeys.getPreparedStatement();
14351  }
14352 
14353  @Override
14354  void executeCommand(DbCommand command) throws SQLException {
14355  SQLException lastException = null;
14356  for (int retries = 0; retries < MAX_RETRIES; retries++) {
14357  try {
14358  command.execute();
14359  lastException = null; // reset since we had a successful execution
14360  break;
14361  } catch (SQLException ex) {
14362  lastException = ex;
14363  String sqlState = ex.getSQLState();
14364  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
14365  try {
14366  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
14367  } catch (InterruptedException exp) {
14368  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
14369  }
14370  } else {
14371  throw ex;
14372  }
14373  }
14374  }
14375 
14376  // rethrow the exception if we bailed because of too many retries
14377  if (lastException != null) {
14378  throw lastException;
14379  }
14380  }
14381  }
14382 
14414  public static final class CaseDbTransaction {
14415 
14416  private final CaseDbConnection connection;
14417  private SleuthkitCase sleuthkitCase;
14418 
14419  /* This class can store information about what was
14420  * inserted as part of the transaction so that we can
14421  * fire events after the data has been persisted. */
14422 
14423  // Score changes are stored as a map keyed by objId to prevent duplicates.
14424  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
14425  private List<Host> hostsAdded = new ArrayList<>();
14426  private List<TimelineEventAddedEvent> timelineEvents = new ArrayList<>();
14427  private List<OsAccount> accountsChanged = new ArrayList<>();
14428  private List<OsAccount> accountsAdded = new ArrayList<>();
14429  private List<TskEvent.MergedAccountsPair> accountsMerged = new ArrayList<>();
14430 
14431  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
14432  private List<Long> deletedResultObjectIds = new ArrayList<>();
14433 
14434  // Keep track of which threads have connections to debug deadlocks
14435  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
14436  private static final Object threadsWithOpenTransactionLock = new Object();
14437 
14438  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
14439  this.sleuthkitCase = sleuthkitCase;
14440 
14441  sleuthkitCase.acquireSingleUserCaseWriteLock();
14442  this.connection = sleuthkitCase.getConnection();
14443  try {
14444  synchronized (threadsWithOpenTransactionLock) {
14445  this.connection.beginTransaction();
14446  threadsWithOpenTransaction.add(Thread.currentThread().getId());
14447  }
14448  } catch (SQLException ex) {
14449  sleuthkitCase.releaseSingleUserCaseWriteLock();
14450  throw new TskCoreException("Failed to create transaction on case database", ex);
14451  }
14452 
14453  }
14454 
14462  CaseDbConnection getConnection() {
14463  return this.connection;
14464  }
14465 
14471  void registerScoreChange(ScoreChange scoreChange) {
14472  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
14473  }
14474 
14479  void registerTimelineEvent(TimelineEventAddedEvent timelineEvent) {
14480  if (timelineEvent != null) {
14481  timelineEvents.add(timelineEvent);
14482  }
14483  }
14484 
14490  void registerAddedHost(Host host) {
14491  if (host != null) {
14492  this.hostsAdded.add(host);
14493  }
14494  }
14495 
14501  void registerChangedOsAccount(OsAccount account) {
14502  if (account != null) {
14503  accountsChanged.add(account);
14504  }
14505  }
14506 
14512  void registerDeletedOsAccount(long osAccountObjId) {
14513  deletedOsAccountObjectIds.add(osAccountObjId);
14514  }
14515 
14521  void registerAddedOsAccount(OsAccount account) {
14522  if (account != null) {
14523  accountsAdded.add(account);
14524  }
14525  }
14526 
14533  void registerMergedOsAccount(long sourceOsAccountObjId, long destinationOsAccountObjId) {
14534  accountsMerged.add(new TskEvent.MergedAccountsPair(sourceOsAccountObjId, destinationOsAccountObjId));
14535  }
14536 
14543  void registerDeletedAnalysisResult(long analysisResultObjId) {
14544  this.deletedResultObjectIds.add(analysisResultObjId);
14545  }
14546 
14555  private static boolean hasOpenTransaction(long threadId) {
14556  synchronized (threadsWithOpenTransactionLock) {
14557  return threadsWithOpenTransaction.contains(threadId);
14558  }
14559  }
14560 
14567  public void commit() throws TskCoreException {
14568  try {
14569  this.connection.commitTransaction();
14570  } catch (SQLException ex) {
14571  throw new TskCoreException("Failed to commit transaction on case database", ex);
14572  } finally {
14573  close();
14574 
14575  if (!scoreChangeMap.isEmpty()) {
14576  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
14577  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
14578  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
14579  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
14580  }
14581  }
14582  if (!timelineEvents.isEmpty()) {
14583  for (TimelineEventAddedEvent evt : timelineEvents) {
14584  sleuthkitCase.fireTSKEvent(evt);
14585  }
14586  }
14587  if (!hostsAdded.isEmpty()) {
14588  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
14589  }
14590  if (!accountsAdded.isEmpty()) {
14591  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
14592  }
14593  if (!accountsChanged.isEmpty()) {
14594  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
14595  }
14596  if (!accountsMerged.isEmpty()) {
14597  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsMergedTskEvent(accountsMerged));
14598  }
14599  if (!deletedOsAccountObjectIds.isEmpty()) {
14600  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
14601  }
14602  if (!deletedResultObjectIds.isEmpty()) {
14603  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
14604  }
14605  }
14606  }
14607 
14614  public void rollback() throws TskCoreException {
14615  try {
14616  this.connection.rollbackTransactionWithThrow();
14617  } catch (SQLException ex) {
14618  throw new TskCoreException("Case database transaction rollback failed", ex);
14619  } finally {
14620  close();
14621  }
14622  }
14623 
14628  void close() {
14629  this.connection.close();
14630  sleuthkitCase.releaseSingleUserCaseWriteLock();
14631  synchronized (threadsWithOpenTransactionLock) {
14632  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
14633  }
14634  }
14635  }
14636 
14646  public final class CaseDbQuery implements AutoCloseable {
14647 
14648  private ResultSet resultSet;
14649  private CaseDbConnection connection;
14650 
14651  private CaseDbQuery(String query) throws TskCoreException {
14652  this(query, false);
14653  }
14654 
14655  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
14656  if (!allowWriteQuery) {
14657  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
14658  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
14659  }
14660  }
14661 
14663  try {
14664  connection = connections.getConnection();
14665  resultSet = connection.executeQuery(connection.createStatement(), query);
14666  } catch (SQLException ex) {
14668  throw new TskCoreException("Error executing query: ", ex);
14669  } catch (TskCoreException ex) {
14671  throw ex;
14672  }
14673  }
14674 
14680  public ResultSet getResultSet() {
14681  return resultSet;
14682  }
14683 
14684  @Override
14685  public void close() throws TskCoreException {
14686  try {
14687  if (resultSet != null) {
14688  final Statement statement = resultSet.getStatement();
14689  if (statement != null) {
14690  statement.close();
14691  }
14692  resultSet.close();
14693  }
14694  closeConnection(connection);
14695  } catch (SQLException ex) {
14696  throw new TskCoreException("Error closing query: ", ex);
14697  } finally {
14699  }
14700  }
14701  }
14702 
14710  @Deprecated
14711  public void addErrorObserver(ErrorObserver observer) {
14712  sleuthkitCaseErrorObservers.add(observer);
14713  }
14714 
14722  @Deprecated
14723  public void removeErrorObserver(ErrorObserver observer) {
14724  int i = sleuthkitCaseErrorObservers.indexOf(observer);
14725  if (i >= 0) {
14726  sleuthkitCaseErrorObservers.remove(i);
14727  }
14728  }
14729 
14738  @Deprecated
14739  public void submitError(String context, String errorMessage) {
14740  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
14741  if (observer != null) {
14742  try {
14743  observer.receiveError(context, errorMessage);
14744  } catch (Exception ex) {
14745  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
14746 
14747  }
14748  }
14749  }
14750  }
14751 
14757  @Deprecated
14758  public interface ErrorObserver {
14759 
14766  public enum Context {
14767 
14771  IMAGE_READ_ERROR("Image File Read Error"),
14775  DATABASE_READ_ERROR("Database Read Error");
14776 
14777  private final String contextString;
14778 
14779  private Context(String context) {
14780  this.contextString = context;
14781  }
14782 
14783  public String getContextString() {
14784  return contextString;
14785  }
14786  };
14787 
14788  void receiveError(String context, String errorMessage);
14789  }
14790 
14801  @Deprecated
14802  long getDataSourceObjectId(long objectId) {
14803  try {
14804  CaseDbConnection connection = connections.getConnection();
14805  try {
14806  return getDataSourceObjectId(connection, objectId);
14807  } finally {
14808  closeConnection(connection);
14809  }
14810  } catch (TskCoreException ex) {
14811  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
14812  return 0;
14813  }
14814  }
14815 
14825  @Deprecated
14826  public long getLastObjectId() throws TskCoreException {
14827  CaseDbConnection connection = null;
14828  ResultSet rs = null;
14830  try {
14831  connection = connections.getConnection();
14832 
14833  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
14834  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
14835  rs = connection.executeQuery(statement);
14836  long id = -1;
14837  if (rs.next()) {
14838  id = rs.getLong("max_obj_id");
14839  }
14840  return id;
14841  } catch (SQLException e) {
14842  throw new TskCoreException("Error getting last object id", e);
14843  } finally {
14844  closeResultSet(rs);
14845  closeConnection(connection);
14847  }
14848  }
14849 
14863  @Deprecated
14864  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
14865  CaseDbConnection connection = null;
14866  Statement s = null;
14867  ResultSet rs = null;
14869  try {
14870  connection = connections.getConnection();
14871  s = connection.createStatement();
14872  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
14873  List<FsContent> results = new ArrayList<FsContent>();
14874  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
14875  for (AbstractFile f : temp) {
14876  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
14877  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
14878  results.add((FsContent) f);
14879  }
14880  }
14881  return results;
14882  } catch (SQLException e) {
14883  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
14884  } finally {
14885  closeResultSet(rs);
14886  closeStatement(s);
14887  closeConnection(connection);
14889  }
14890  }
14891 
14903  @Deprecated
14904  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
14905  CaseDbConnection connection = null;
14906  Statement s = null;
14907  ResultSet rs = null;
14909  try {
14910  connection = connections.getConnection();
14911  s = connection.createStatement();
14912  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
14913  int typeId = -1;
14914  if (rs.next()) {
14915  typeId = rs.getInt("artifact_type_id");
14916  }
14917  return typeId;
14918  } catch (SQLException ex) {
14919  throw new TskCoreException("Error getting artifact type id", ex);
14920  } finally {
14921  closeResultSet(rs);
14922  closeStatement(s);
14923  closeConnection(connection);
14925  }
14926  }
14927 
14937  @Deprecated
14938  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
14939  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
14940  }
14941 
14955  @Deprecated
14956  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14957  try {
14958  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14959  } catch (TskDataException ex) {
14960  throw new TskCoreException("Failed to add artifact type.", ex);
14961  }
14962  }
14963 
14977  @Deprecated
14978  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14979  try {
14980  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14981  } catch (TskDataException ex) {
14982  throw new TskCoreException("Couldn't add new attribute type");
14983  }
14984  }
14985 
14996  @Deprecated
14997  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14998  CaseDbConnection connection = null;
14999  Statement s = null;
15000  ResultSet rs = null;
15002  try {
15003  connection = connections.getConnection();
15004  s = connection.createStatement();
15005  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
15006  int typeId = -1;
15007  if (rs.next()) {
15008  typeId = rs.getInt("attribute_type_id");
15009  }
15010  return typeId;
15011  } catch (SQLException ex) {
15012  throw new TskCoreException("Error getting attribute type id", ex);
15013  } finally {
15014  closeResultSet(rs);
15015  closeStatement(s);
15016  closeConnection(connection);
15018  }
15019  }
15020 
15033  @Deprecated
15034  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
15035  CaseDbConnection connection = null;
15036  Statement s = null;
15037  ResultSet rs = null;
15039  try {
15040  connection = connections.getConnection();
15041  s = connection.createStatement();
15042  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
15043  if (rs.next()) {
15044  return rs.getString("type_name");
15045  } else {
15046  throw new TskCoreException("No type with that id");
15047  }
15048  } catch (SQLException ex) {
15049  throw new TskCoreException("Error getting or creating a attribute type name", ex);
15050  } finally {
15051  closeResultSet(rs);
15052  closeStatement(s);
15053  closeConnection(connection);
15055  }
15056  }
15057 
15070  @Deprecated
15071  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
15072  CaseDbConnection connection = null;
15073  Statement s = null;
15074  ResultSet rs = null;
15076  try {
15077  connection = connections.getConnection();
15078  s = connection.createStatement();
15079  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
15080  if (rs.next()) {
15081  return rs.getString("display_name");
15082  } else {
15083  throw new TskCoreException("No type with that id");
15084  }
15085  } catch (SQLException ex) {
15086  throw new TskCoreException("Error getting or creating a attribute type name", ex);
15087  } finally {
15088  closeResultSet(rs);
15089  closeStatement(s);
15090  closeConnection(connection);
15092  }
15093  }
15094 
15104  @Deprecated
15105  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
15106  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
15107  }
15108 
15124  @Deprecated
15125  public ResultSet runQuery(String query) throws SQLException {
15126  CaseDbConnection connection = null;
15128  try {
15129  connection = connections.getConnection();
15130  return connection.executeQuery(connection.createStatement(), query);
15131  } catch (TskCoreException ex) {
15132  throw new SQLException("Error getting connection for ad hoc query", ex);
15133  } finally {
15134  //TODO unlock should be done in closeRunQuery()
15135  //but currently not all code calls closeRunQuery - need to fix this
15136  closeConnection(connection);
15138  }
15139  }
15140 
15150  @Deprecated
15151  public void closeRunQuery(ResultSet resultSet) throws SQLException {
15152  final Statement statement = resultSet.getStatement();
15153  resultSet.close();
15154  if (statement != null) {
15155  statement.close();
15156  }
15157  }
15158 
15175  @Deprecated
15176  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
15177  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
15178  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
15179  files.add(carvedFile);
15180  CarvingResult carvingResult;
15181  Content parent = getContentById(containerId);
15182  if (parent instanceof FileSystem
15183  || parent instanceof Volume
15184  || parent instanceof Image) {
15185  carvingResult = new CarvingResult(parent, files);
15186  } else {
15187  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
15188  }
15189  return addCarvedFiles(carvingResult).get(0);
15190  }
15191 
15205  @Deprecated
15206  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
15207  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
15208  for (CarvedFileContainer container : filesToAdd) {
15209  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
15210  carvedFiles.add(carvedFile);
15211  }
15212  CarvingResult carvingResult;
15213  Content parent = getContentById(filesToAdd.get(0).getId());
15214  if (parent instanceof FileSystem
15215  || parent instanceof Volume
15216  || parent instanceof Image) {
15217  carvingResult = new CarvingResult(parent, carvedFiles);
15218  } else {
15219  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
15220  }
15221  return addCarvedFiles(carvingResult);
15222  }
15223 
15253  @Deprecated
15254  public DerivedFile addDerivedFile(String fileName, String localPath,
15255  long size, long ctime, long crtime, long atime, long mtime,
15256  boolean isFile, AbstractFile parentFile,
15257  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
15258  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
15259  isFile, parentFile, rederiveDetails, toolName, toolVersion,
15260  otherDetails, TskData.EncodingType.NONE);
15261  }
15262 
15292  @Deprecated
15293  public LocalFile addLocalFile(String fileName, String localPath,
15294  long size, long ctime, long crtime, long atime, long mtime,
15295  String md5, FileKnown known, String mimeType,
15296  boolean isFile, TskData.EncodingType encodingType,
15297  Content parent, CaseDbTransaction transaction) throws TskCoreException {
15298 
15299  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
15300  md5, null, known, mimeType, isFile, encodingType,
15301  parent, transaction);
15302  }
15303 
15328  @Deprecated
15329  public LocalFile addLocalFile(String fileName, String localPath,
15330  long size, long ctime, long crtime, long atime, long mtime,
15331  boolean isFile,
15332  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
15333  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
15334  TskData.EncodingType.NONE, parent, transaction);
15335  }
15336 
15356  @Deprecated
15357  public LocalFile addLocalFile(String fileName, String localPath,
15358  long size, long ctime, long crtime, long atime, long mtime,
15359  boolean isFile,
15360  AbstractFile parent) throws TskCoreException {
15361  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
15362  isFile, TskData.EncodingType.NONE, parent);
15363  }
15364 
15381  @Deprecated
15382  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
15383  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", null, this);
15384  }
15385 
15396  @Deprecated
15397  public Collection<FileSystem> getFileSystems(Image image) {
15398  try {
15399  return getImageFileSystems(image);
15400  } catch (TskCoreException ex) {
15401  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
15402  return new ArrayList<>();
15403  }
15404  }
15405 
15423  @Deprecated
15424  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
15425  return findFilesInFolder(fileName, parentFile);
15426  }
15427 
15435  @Deprecated
15436  public void acquireExclusiveLock() {
15438  }
15439 
15447  @Deprecated
15448  public void releaseExclusiveLock() {
15450  }
15451 
15459  @Deprecated
15460  public void acquireSharedLock() {
15462  }
15463 
15471  @Deprecated
15472  public void releaseSharedLock() {
15474  }
15475 };
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:695
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)
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, String password, CaseDbTransaction transaction)
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)
static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider, String lockingApplicationName)
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)
static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider, String lockingApplicationName)
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)
AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath, String password)
LAYOUT_FILE
Set of blocks from an image that have been designated as a file.
Definition: TskData.java:704
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)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone, Host host, String password)
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:698
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:696
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:641
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:703
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:640
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 TagType valueOf(byte type)
Definition: TskData.java:922
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:644
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:697
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:699
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:679
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:802
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:701
static SleuthkitCase newCase(String dbPath)
void updateFile(long fileObjId, long size, long mtime, long atime, long ctime, long crtime, String userSid, Long osAcctObjId)
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:642
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:639
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:638
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:158
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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