Sleuth Kit Java Bindings (JNI)  4.11.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-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.cache.Cache;
23 import com.google.common.cache.CacheBuilder;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.eventbus.EventBus;
26 import com.mchange.v2.c3p0.ComboPooledDataSource;
27 import com.mchange.v2.c3p0.DataSources;
28 import com.mchange.v2.c3p0.PooledDataSource;
29 import com.zaxxer.sparsebits.SparseBitSet;
30 import java.beans.PropertyVetoException;
31 import java.io.BufferedInputStream;
32 import java.io.BufferedOutputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.io.UnsupportedEncodingException;
40 import java.net.InetAddress;
41 import java.net.URLEncoder;
42 import java.nio.charset.StandardCharsets;
43 import java.nio.file.Paths;
44 import java.sql.Connection;
45 import java.sql.DriverManager;
46 import java.sql.PreparedStatement;
47 import java.sql.ResultSet;
48 import java.sql.SQLException;
49 import java.sql.Statement;
50 import java.text.SimpleDateFormat;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.Collections;
55 import java.util.concurrent.atomic.AtomicBoolean;
56 import java.util.concurrent.atomic.AtomicInteger;
57 import java.util.Date;
58 import java.util.EnumMap;
59 import java.util.HashMap;
60 import java.util.HashSet;
61 import java.util.LinkedHashMap;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.MissingResourceException;
65 import java.util.Objects;
66 import java.util.Properties;
67 import java.util.ResourceBundle;
68 import java.util.Set;
69 import java.util.UUID;
70 import java.util.concurrent.TimeUnit;
71 import java.util.concurrent.locks.ReentrantReadWriteLock;
72 import java.util.logging.Level;
73 import java.util.logging.Logger;
74 import java.util.stream.Collectors;
75 import org.apache.commons.lang3.StringUtils;
76 import org.postgresql.util.PSQLState;
94 import org.sqlite.SQLiteConfig;
95 import org.sqlite.SQLiteDataSource;
96 import org.sqlite.SQLiteJDBCLoader;
97 
102 public class SleuthkitCase {
103 
104  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
105 
106  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
107  = new CaseDbSchemaVersionNumber(9, 3);
108 
109  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
110  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
111  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
112  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
113  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
114  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
115  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
116  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
117  private static final String SQL_ERROR_LIMIT_GROUP = "54";
118  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
119 
120  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
121  "tsk_events",
122  "tsk_event_descriptions",
123  "tsk_event_types",
124  "tsk_db_info",
125  "tsk_objects",
126  "tsk_image_info",
127  "tsk_image_names",
128  "tsk_vs_info",
129  "tsk_vs_parts",
130  "tsk_fs_info",
131  "tsk_file_layout",
132  "tsk_files",
133  "tsk_files_path",
134  "tsk_files_derived",
135  "tsk_files_derived_method",
136  "tag_names",
137  "content_tags",
138  "blackboard_artifact_tags",
139  "blackboard_artifacts",
140  "blackboard_attributes",
141  "blackboard_artifact_types",
142  "blackboard_attribute_types",
143  "data_source_info",
144  "file_encoding_types",
145  "ingest_module_types",
146  "ingest_job_status_types",
147  "ingest_modules",
148  "ingest_jobs",
149  "ingest_job_modules",
150  "account_types",
151  "accounts",
152  "account_relationships",
153  "review_statuses",
154  "reports,");
155 
156  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
157  "parObjId",
158  "layout_objID",
159  "artifact_objID",
160  "artifact_artifact_objID",
161  "artifact_typeID",
162  "attrsArtifactID",
163  "mime_type",
164  "file_extension",
165  "relationships_account1",
166  "relationships_account2",
167  "relationships_relationship_source_obj_id",
168  "relationships_date_time",
169  "relationships_relationship_type",
170  "relationships_data_source_obj_id",
171  "events_time",
172  "events_type",
173  "events_data_source_obj_id",
174  "events_file_obj_id",
175  "events_artifact_id");
176 
177  private static final String TSK_VERSION_KEY = "TSK_VER";
178  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
179  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
180  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
181  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
182 
183  private final ConnectionPool connections;
184  private final Object carvedFileDirsLock = new Object();
185  private final static int MAX_CARVED_FILES_PER_FOLDER = 2000;
186  private final Map<Long, CarvedFileDirInfo> rootIdsToCarvedFileDirs = new HashMap<>();
187  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
188  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
189  private final String databaseName;
190  private final String dbPath;
191  private final DbType dbType;
192  private final String caseDirPath;
193  private SleuthkitJNI.CaseDbHandle caseHandle;
194  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
195  private String dbBackupPath;
196  private AtomicBoolean timelineEventsDisabled = new AtomicBoolean(false);
197 
198  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
199 
200  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
201  private final Object rootDirectoryMapLock = new Object();
202  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
203  private final Cache<Long, Boolean> isRootDirectoryCache
204  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
205 
206  /*
207  * First parameter is used to specify the SparseBitSet to use, as object IDs
208  * can be larger than the max size of a SparseBitSet
209  */
210  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
211 
212  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
213  // This read/write lock is used to implement a layer of locking on top of
214  // the locking protocol provided by the underlying SQLite database. The Java
215  // locking protocol improves performance for reasons that are not currently
216  // understood. Note that the lock is contructed to use a fairness policy.
217  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
218 
219  private CommunicationsManager communicationsMgr;
220  private TimelineManager timelineMgr;
221  private Blackboard blackboard;
222  private CaseDbAccessManager dbAccessManager;
223  private FileManager fileManager;
224  private TaggingManager taggingMgr;
225  private ScoringManager scoringManager;
226  private OsAccountRealmManager osAccountRealmManager;
227  private OsAccountManager osAccountManager;
228  private HostManager hostManager;
229  private PersonManager personManager;
230  private HostAddressManager hostAddressManager;
231 
232  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
233 
234  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
235 
236  public void registerForEvents(Object listener) {
237  eventBus.register(listener);
238  }
239 
240  public void unregisterForEvents(Object listener) {
241  eventBus.unregister(listener);
242  }
243 
244  void fireTSKEvent(Object event) {
245  eventBus.post(event);
246  }
247 
248  // Cache of frequently used content objects (e.g. data source, file system).
249  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
250 
251  private Examiner cachedCurrentExaminer = null;
252 
253  static {
254  Properties p = new Properties(System.getProperties());
255  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
256  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
257  System.setProperties(p);
258  }
259 
274  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
275  // Check if we can talk to the database.
276  if (info.getHost() == null || info.getHost().isEmpty()) {
277  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
278  } else if (info.getPort() == null || info.getPort().isEmpty()) {
279  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
280  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
281  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
282  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
283  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
284  }
285 
286  try {
287  Class.forName("org.postgresql.Driver"); //NON-NLS
288  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
289  if (conn != null) {
290  conn.close();
291  }
292  } catch (SQLException ex) {
293  String result;
294  String sqlState = ex.getSQLState().toLowerCase();
295  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
296  try {
297  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
298  // if we can reach the host, then it's probably port problem
299  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
300  } else {
301  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
302  }
303  } catch (IOException | MissingResourceException any) {
304  // it may be anything
305  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
306  }
307  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
308  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
309  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
310  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
311  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
312  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
313  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
314  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
315  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
316  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
317  } else {
318  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
319  }
320  throw new TskCoreException(result);
321  } catch (ClassNotFoundException ex) {
322  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
323  }
324  }
325 
337  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
338  Class.forName("org.sqlite.JDBC");
339  this.dbPath = dbPath;
340  this.dbType = dbType;
341  File dbFile = new File(dbPath);
342  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
343  this.databaseName = dbFile.getName();
344  this.connections = new SQLiteConnections(dbPath);
345  this.caseHandle = caseHandle;
346  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
347  init();
348  logSQLiteJDBCDriverInfo();
349  }
350 
368  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
369  this.dbPath = "";
370  this.databaseName = dbName;
371  this.dbType = dbType;
372  this.caseDirPath = caseDirPath;
373  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
374  this.caseHandle = caseHandle;
375  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
376  init();
377  }
378 
379  private void init() throws Exception {
380  blackboard = new Blackboard(this);
381  updateDatabaseSchema(null);
382  try (CaseDbConnection connection = connections.getConnection()) {
383  blackboard.initBlackboardArtifactTypes(connection);
384  blackboard.initBlackboardAttributeTypes(connection);
385  initNextArtifactId(connection);
386  initIngestModuleTypes(connection);
387  initIngestStatusTypes(connection);
388  initReviewStatuses(connection);
389  initEncodingTypes(connection);
390  populateHasChildrenMap(connection);
391  updateExaminers(connection);
392  initDBSchemaCreationVersion(connection);
393  }
394 
395  fileManager = new FileManager(this);
396  communicationsMgr = new CommunicationsManager(this);
397  timelineMgr = new TimelineManager(this);
398  dbAccessManager = new CaseDbAccessManager(this);
399  taggingMgr = new TaggingManager(this);
400  scoringManager = new ScoringManager(this);
401  osAccountRealmManager = new OsAccountRealmManager(this);
402  osAccountManager = new OsAccountManager(this);
403  hostManager = new HostManager(this);
404  personManager = new PersonManager(this);
405  hostAddressManager = new HostAddressManager(this);
406  }
407 
413  static Set<String> getCoreTableNames() {
414  return Collections.unmodifiableSet(CORE_TABLE_NAMES);
415  }
416 
422  static Set<String> getCoreIndexNames() {
423  return Collections.unmodifiableSet(CORE_INDEX_NAMES);
424  }
425 
434  boolean getHasChildren(Content content) {
435  long objId = content.getId();
436  long mapIndex = objId / Integer.MAX_VALUE;
437  int mapValue = (int) (objId % Integer.MAX_VALUE);
438 
439  synchronized (hasChildrenBitSetMap) {
440  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
441  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
442  }
443  return false;
444  }
445  }
446 
452  private void setHasChildren(Long objId) {
453  long mapIndex = objId / Integer.MAX_VALUE;
454  int mapValue = (int) (objId % Integer.MAX_VALUE);
455 
456  synchronized (hasChildrenBitSetMap) {
457  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
458  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
459  } else {
460  SparseBitSet bitSet = new SparseBitSet();
461  bitSet.set(mapValue);
462  hasChildrenBitSetMap.put(mapIndex, bitSet);
463  }
464  }
465  }
466 
475  return communicationsMgr;
476  }
477 
484  return blackboard;
485  }
486 
493  return fileManager;
494  }
495 
504  return timelineMgr;
505  }
506 
507  /*
508  * Gets the case database access manager for this case.
509  *
510  * @return The per case CaseDbAccessManager object.
511  *
512  * @throws org.sleuthkit.datamodel.TskCoreException
513  */
515  return dbAccessManager;
516  }
517 
523  public synchronized TaggingManager getTaggingManager() {
524  return taggingMgr;
525  }
526 
535  return scoringManager;
536  }
537 
546  return osAccountRealmManager;
547  }
548 
557  return osAccountManager;
558  }
559 
568  return hostManager;
569  }
570 
579  return personManager;
580  }
581 
590  return hostAddressManager;
591  }
592 
602  private void initNextArtifactId(CaseDbConnection connection) throws SQLException {
604  try (Statement statement = connection.createStatement()) {
605  ResultSet resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
606  resultSet.next();
607  nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
608  if (nextArtifactId == 1) {
609  nextArtifactId = BASE_ARTIFACT_ID;
610  }
611  } finally {
613  }
614  }
615 
623  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
624  Statement statement = null;
625  ResultSet resultSet = null;
627  try {
628  statement = connection.createStatement();
629  for (IngestModuleType type : IngestModuleType.values()) {
630  try {
631  String query = "INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
632  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
633  query += " ON CONFLICT ON CONSTRAINT ingest_module_types_pkey DO NOTHING"; // NON-NLS
634  }
635  statement.execute(query);
636  } catch (SQLException ex) {
637  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
638  resultSet.next();
639  if (resultSet.getLong("count") == 0) {
640  throw ex;
641  }
642  resultSet.close();
643  resultSet = null;
644  }
645  }
646  } finally {
647  closeResultSet(resultSet);
648  closeStatement(statement);
650  }
651  }
652 
660  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
661  Statement statement = null;
662  ResultSet resultSet = null;
664  try {
665  statement = connection.createStatement();
666  for (IngestJobStatusType type : IngestJobStatusType.values()) {
667  try {
668  String query = "INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "')"; // NON-NLS
669  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
670  query += " ON CONFLICT ON CONSTRAINT ingest_job_status_types_pkey DO NOTHING"; // NON-NLS
671  }
672  statement.execute(query);
673  } catch (SQLException ex) {
674  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
675  resultSet.next();
676  if (resultSet.getLong("count") == 0) {
677  throw ex;
678  }
679  resultSet.close();
680  resultSet = null;
681  }
682  }
683  } finally {
684  closeResultSet(resultSet);
685  closeStatement(statement);
687  }
688  }
689 
696  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
697  Statement statement = null;
698  ResultSet resultSet = null;
700  try {
701  statement = connection.createStatement();
702  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
703  try {
704  String query = "INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
705  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')";
706  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
707  query += " ON CONFLICT ON CONSTRAINT review_statuses_pkey DO NOTHING"; // NON-NLS
708  }
709  statement.execute(query);
710  } catch (SQLException ex) {
711  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
712  resultSet.next();
713  if (resultSet.getLong("count") == 0) {
714  throw ex;
715  }
716  resultSet.close();
717  resultSet = null;
718  }
719  }
720  } finally {
721  closeResultSet(resultSet);
722  closeStatement(statement);
724  }
725  }
726 
734  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
735  Statement statement = null;
736  ResultSet resultSet = null;
738  try {
739  statement = connection.createStatement();
740  for (TskData.EncodingType type : TskData.EncodingType.values()) {
741  try {
742  String query = "INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"; // NON-NLS
743  if (getDatabaseType().equals(DbType.POSTGRESQL)) {
744  query += " ON CONFLICT ON CONSTRAINT file_encoding_types_pkey DO NOTHING"; // NON-NLS
745  }
746  statement.execute(query);
747  } catch (SQLException ex) {
748  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
749  resultSet.next();
750  if (resultSet.getLong("count") == 0) {
751  throw ex;
752  }
753  resultSet.close();
754  resultSet = null;
755  }
756  }
757  } finally {
758  closeResultSet(resultSet);
759  closeStatement(statement);
761  }
762  }
763 
772  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
773 
774  String loginName = System.getProperty("user.name");
775  if (loginName.isEmpty()) {
776  logger.log(Level.SEVERE, "Cannot determine logged in user name");
777  return;
778  }
779 
781  try {
782  PreparedStatement statement;
783  switch (getDatabaseType()) {
784  case POSTGRESQL:
785  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
786  break;
787  case SQLITE:
788  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
789  break;
790  default:
791  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
792  }
793  statement.clearParameters();
794  statement.setString(1, loginName);
795  connection.executeUpdate(statement);
796  } catch (SQLException ex) {
797  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
798  } finally {
800  }
801  }
802 
810  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
811  long timestamp = System.currentTimeMillis();
812 
813  Statement statement = null;
814  ResultSet resultSet = null;
816  try {
817  statement = connection.createStatement();
818  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
819 
820  synchronized (hasChildrenBitSetMap) {
821  while (resultSet.next()) {
822  setHasChildren(resultSet.getLong("par_obj_id"));
823  }
824  }
825  long delay = System.currentTimeMillis() - timestamp;
826  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
827  } catch (SQLException ex) {
828  throw new TskCoreException("Error populating parent node cache", ex);
829  } finally {
830  closeResultSet(resultSet);
831  closeStatement(statement);
833  }
834  }
835 
842  void addDataSourceToHasChildrenMap() throws TskCoreException {
843 
844  CaseDbConnection connection = connections.getConnection();
845  try {
846  populateHasChildrenMap(connection);
847  } finally {
848  closeConnection(connection);
849  }
850  }
851 
861  private void updateDatabaseSchema(String dbPath) throws Exception {
862  CaseDbConnection connection = null;
863  ResultSet resultSet = null;
864  Statement statement = null;
866  try {
867  connection = connections.getConnection();
868  connection.beginTransaction();
869 
870  boolean hasMinorVersion = false;
871  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
872  while (columns.next()) {
873  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
874  hasMinorVersion = true;
875  }
876  }
877 
878  // Get the schema version number of the case database from the tsk_db_info table.
879  int dbSchemaMajorVersion;
880  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
881 
882  statement = connection.createStatement();
883  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
884  + (hasMinorVersion ? ", schema_minor_ver" : "")
885  + " FROM tsk_db_info"); //NON-NLS
886  if (resultSet.next()) {
887  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
888  if (hasMinorVersion) {
889  //if there is a minor version column, use it, else default to zero.
890  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
891  }
892  } else {
893  throw new TskCoreException();
894  }
895  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
896 
897  resultSet.close();
898  resultSet = null;
899  statement.close();
900  statement = null;
901  //check schema compatibility
902  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
903  //we cannot open a db with a major schema version higher than the current one.
904  throw new TskUnsupportedSchemaVersionException(
905  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
906  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
907  //The schema version is compatible,possibly after upgrades.
908 
909  if (null != dbPath) {
910  // Make a backup copy of the database. Client code can get the path of the backup
911  // using the getBackupDatabasePath() method.
912  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
913  copyCaseDB(backupFilePath);
914  dbBackupPath = backupFilePath;
915  }
916 
917  // ***CALL SCHEMA UPDATE METHODS HERE***
918  // Each method should examine the schema version passed to it and either:
919  // a. do nothing and return the schema version unchanged, or
920  // b. upgrade the database and return the schema version that the db was upgraded to.
921  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
922  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
923  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
924  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
925  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
926  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
927  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
928  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
929  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
930  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
931  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
932  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
933  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
934  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
935  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
936  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
937  dbSchemaVersion = updateFromSchema9dot1toSchema9dot2(dbSchemaVersion, connection);
938  dbSchemaVersion = updateFromSchema9dot2toSchema9dot3(dbSchemaVersion, connection);
939 
940 
941 
942  statement = connection.createStatement();
943  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
944  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
945  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
946  statement.close();
947  statement = null;
948  }
949 
950  connection.commitTransaction();
951  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
952  rollbackTransaction(connection);
953  throw ex;
954  } finally {
955  closeResultSet(resultSet);
956  closeStatement(statement);
957  closeConnection(connection);
959  }
960  }
961 
969  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
970 
971  Statement statement = null;
972  ResultSet resultSet = null;
973  String createdSchemaMajorVersion = "0";
974  String createdSchemaMinorVersion = "0";
976  try {
977  statement = connection.createStatement();
978  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
979  while (resultSet.next()) {
980  String name = resultSet.getString("name");
981  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
982  createdSchemaMajorVersion = resultSet.getString("value");
983  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
984  createdSchemaMinorVersion = resultSet.getString("value");
985  }
986  }
987 
988  } finally {
989  closeResultSet(resultSet);
990  closeStatement(statement);
992  }
993 
994  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
995  }
996 
1006  public void copyCaseDB(String newDBPath) throws IOException {
1007  if (dbPath.isEmpty()) {
1008  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1009  }
1010  InputStream in = null;
1011  OutputStream out = null;
1013  try {
1014  InputStream inFile = new FileInputStream(dbPath);
1015  in = new BufferedInputStream(inFile);
1016  OutputStream outFile = new FileOutputStream(newDBPath);
1017  out = new BufferedOutputStream(outFile);
1018  int bytesRead = in.read();
1019  while (bytesRead != -1) {
1020  out.write(bytesRead);
1021  bytesRead = in.read();
1022  }
1023  } finally {
1024  try {
1025  if (in != null) {
1026  in.close();
1027  }
1028  if (out != null) {
1029  out.flush();
1030  out.close();
1031  }
1032  } catch (IOException e) {
1033  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1034  }
1036  }
1037  }
1038 
1042  private void logSQLiteJDBCDriverInfo() {
1043  try {
1044  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1045  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1046  ? "native" : "pure-java")); //NON-NLS
1047  } catch (Exception ex) {
1048  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1049  }
1050  }
1051 
1065  @SuppressWarnings("deprecation")
1066  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1067  if (schemaVersion.getMajor() != 2) {
1068  return schemaVersion;
1069  }
1070  Statement statement = null;
1071  Statement statement2 = null;
1072  Statement updateStatement = null;
1073  ResultSet resultSet = null;
1075  try {
1076  statement = connection.createStatement();
1077  statement2 = connection.createStatement();
1078 
1079  // Add new tables for tags.
1080  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
1081  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
1082  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
1083 
1084  // Add a new table for reports.
1085  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
1086 
1087  // Add new columns to the image info table.
1088  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1089  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1090  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1091 
1092  // Add a new column to the file system info table.
1093  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1094 
1095  // Add a new column to the file table.
1096  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1097 
1098  // Add new columns and indexes to the attributes table and populate the
1099  // new column. Note that addition of the new column is a denormalization
1100  // to optimize attribute queries.
1101  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1102  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1103  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1104  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1105  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1106  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1107  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1108  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1109  + "FROM blackboard_attributes AS attrs " //NON-NLS
1110  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1111  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1112  updateStatement = connection.createStatement();
1113  while (resultSet.next()) {
1114  long artifactId = resultSet.getLong("artifact_id");
1115  int artifactTypeId = resultSet.getInt("artifact_type_id");
1116  updateStatement.executeUpdate(
1117  "UPDATE blackboard_attributes " //NON-NLS
1118  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1119  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1120  }
1121  resultSet.close();
1122 
1123  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1124  Map<String, Long> tagNames = new HashMap<>();
1125  long tagNameCounter = 1;
1126 
1127  // Convert file tags.
1128  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1129  resultSet = statement.executeQuery("SELECT * FROM \n"
1130  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1131  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1132  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1133  + "WHERE blackboard_artifacts.artifact_type_id = "
1134  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1135  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1136  + ") AS tagNames \n"
1137  + "INNER JOIN \n"
1138  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1139  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1140  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1141  + "ON tagNames.objId = fileData.objId2 \n"
1142  + "LEFT JOIN \n"
1143  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1144  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1145  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1146 
1147  while (resultSet.next()) {
1148  long objId = resultSet.getLong("objId");
1149  long fileSize = resultSet.getLong("fileSize");
1150  String tagName = resultSet.getString("name");
1151  String tagComment = resultSet.getString("comment");
1152  if (tagComment == null) {
1153  tagComment = "";
1154  }
1155 
1156  if (tagName != null && !tagName.isEmpty()) {
1157  // Get the index for the tag name, adding it to the database if needed.
1158  long tagNameIndex;
1159  if (tagNames.containsKey(tagName)) {
1160  tagNameIndex = tagNames.get(tagName);
1161  } else {
1162  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1163  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1164  tagNames.put(tagName, tagNameCounter);
1165  tagNameIndex = tagNameCounter;
1166  tagNameCounter++;
1167  }
1168 
1169  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1170  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1171  }
1172  }
1173  resultSet.close();
1174 
1175  // Convert artifact tags.
1176  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1177  resultSet = statement.executeQuery("SELECT * FROM \n"
1178  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1179  + "blackboard_attributes.value_text AS name\n"
1180  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1181  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1182  + "WHERE blackboard_artifacts.artifact_type_id = "
1183  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1184  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1185  + ") AS tagNames \n"
1186  + "INNER JOIN \n"
1187  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1188  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1189  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1190  + "LEFT JOIN \n"
1191  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1192  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1193  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1194 
1195  while (resultSet.next()) {
1196  long artifactId = resultSet.getLong("taggedArtifactId");
1197  String tagName = resultSet.getString("name");
1198  String tagComment = resultSet.getString("comment");
1199  if (tagComment == null) {
1200  tagComment = "";
1201  }
1202  if (tagName != null && !tagName.isEmpty()) {
1203  // Get the index for the tag name, adding it to the database if needed.
1204  long tagNameIndex;
1205  if (tagNames.containsKey(tagName)) {
1206  tagNameIndex = tagNames.get(tagName);
1207  } else {
1208  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1209  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1210  tagNames.put(tagName, tagNameCounter);
1211  tagNameIndex = tagNameCounter;
1212  tagNameCounter++;
1213  }
1214 
1215  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1216  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1217  }
1218  }
1219  resultSet.close();
1220 
1221  statement.execute(
1222  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1223  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1224  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1225  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1226  statement.execute(
1227  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1228  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1229  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1230 
1231  return new CaseDbSchemaVersionNumber(3, 0);
1232  } finally {
1233  closeStatement(updateStatement);
1234  closeResultSet(resultSet);
1235  closeStatement(statement);
1236  closeStatement(statement2);
1238  }
1239  }
1240 
1254  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1255  if (schemaVersion.getMajor() != 3) {
1256  return schemaVersion;
1257  }
1258 
1259  Statement statement = null;
1260  ResultSet resultSet = null;
1261  Statement queryStatement = null;
1262  ResultSet queryResultSet = null;
1263  Statement updateStatement = null;
1265  try {
1266  // Add mime_type column to tsk_files table. Populate with general
1267  // info artifact file signature data.
1268  statement = connection.createStatement();
1269  updateStatement = connection.createStatement();
1270  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1271  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1272  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1273  + "WHERE files.obj_id = arts.obj_id AND "
1274  + "arts.artifact_id = attrs.artifact_id AND "
1275  + "arts.artifact_type_id = 1 AND "
1276  + "attrs.attribute_type_id = 62");
1277  while (resultSet.next()) {
1278  updateStatement.executeUpdate(
1279  "UPDATE tsk_files " //NON-NLS
1280  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1281  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1282  }
1283  resultSet.close();
1284 
1285  // Add value_type column to blackboard_attribute_types table.
1286  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1287  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1288  while (resultSet.next()) {
1289  int attributeTypeId = resultSet.getInt("attribute_type_id");
1290  String attributeLabel = resultSet.getString("type_name");
1291  if (attributeTypeId < Blackboard.MIN_USER_DEFINED_TYPE_ID) {
1292  updateStatement.executeUpdate(
1293  "UPDATE blackboard_attribute_types " //NON-NLS
1294  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1295  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1296  }
1297  }
1298  resultSet.close();
1299 
1300  // Add a data_sources_info table.
1301  queryStatement = connection.createStatement();
1302  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));");
1303  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1304  while (resultSet.next()) {
1305  long objectId = resultSet.getLong("obj_id");
1306  String timeZone = "";
1307  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1308  if (queryResultSet.next()) {
1309  timeZone = queryResultSet.getString("tzone");
1310  }
1311  queryResultSet.close();
1312  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1313  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1314  }
1315  resultSet.close();
1316 
1317  // Add data_source_obj_id column to the tsk_files table.
1318  //
1319  // NOTE: A new case database will have the following FK constraint:
1320  //
1321  // REFERENCES data_source_info (obj_id)
1322  //
1323  // The constraint is sacrificed here to avoid having to create and
1324  // populate a new tsk_files table.
1325  //
1326  // TODO: Do this right.
1327  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1328  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");
1329  while (resultSet.next()) {
1330  long fileId = resultSet.getLong("obj_id");
1331  long dataSourceId = getDataSourceObjectId(connection, fileId);
1332  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1333  }
1334  resultSet.close();
1335  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1336  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1337  if (this.dbType.equals(DbType.SQLITE)) {
1338  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
1339  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
1340  } else {
1341  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
1342  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
1343  }
1344 
1345  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
1346  initIngestModuleTypes(connection);
1347  initIngestStatusTypes(connection);
1348 
1349  return new CaseDbSchemaVersionNumber(4, 0);
1350 
1351  } finally {
1352  closeResultSet(queryResultSet);
1353  closeStatement(queryStatement);
1354  closeStatement(updateStatement);
1355  closeResultSet(resultSet);
1356  closeStatement(statement);
1358  }
1359  }
1360 
1374  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1375  if (schemaVersion.getMajor() != 4) {
1376  return schemaVersion;
1377  }
1378 
1379  Statement statement = null;
1381  try {
1382  // Add the review_statuses lookup table.
1383  statement = connection.createStatement();
1384  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1385 
1386  /*
1387  * Add review_status_id column to artifacts table.
1388  *
1389  * NOTE: For DBs created with schema 5 we define a foreign key
1390  * constraint on the review_status_column. We don't bother with this
1391  * for DBs updated to schema 5 because of limitations of the SQLite
1392  * ALTER TABLE command.
1393  */
1394  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1395 
1396  // Add the encoding table
1397  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1398  initEncodingTypes(connection);
1399 
1400  /*
1401  * This needs to be done due to a Autopsy/TSK out of synch problem.
1402  * Without this, it is possible to upgrade from version 4 to 5 and
1403  * then 5 to 6, but not from 4 to 6.
1404  */
1405  initReviewStatuses(connection);
1406 
1407  // Add encoding type column to tsk_files_path
1408  // This should really have the FOREIGN KEY constraint but there are problems
1409  // getting that to work, so we don't add it on this upgrade path.
1410  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1411 
1412  return new CaseDbSchemaVersionNumber(5, 0);
1413 
1414  } finally {
1415  closeStatement(statement);
1417  }
1418  }
1419 
1433  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1434  if (schemaVersion.getMajor() != 5) {
1435  return schemaVersion;
1436  }
1437 
1438  /*
1439  * This upgrade fixes a bug where some releases had artifact review
1440  * status support in the case database and others did not.
1441  */
1442  Statement statement = null;
1443  ResultSet resultSet = null;
1445  try {
1446  /*
1447  * Add the review_statuses lookup table, if missing.
1448  */
1449  statement = connection.createStatement();
1450  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)");
1451 
1452  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1453  resultSet.next();
1454  if (resultSet.getLong("count") == 0) {
1455  /*
1456  * Add review_status_id column to artifacts table.
1457  *
1458  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1459  * key constraint on the review_status_column. We don't bother
1460  * with this for DBs updated to schema 5 or 6 because of
1461  * limitations of the SQLite ALTER TABLE command.
1462  */
1463  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1464  }
1465 
1466  return new CaseDbSchemaVersionNumber(6, 0);
1467 
1468  } finally {
1469  closeResultSet(resultSet);
1470  closeStatement(statement);
1472  }
1473  }
1474 
1488  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1489  if (schemaVersion.getMajor() != 6) {
1490  return schemaVersion;
1491  }
1492 
1493  /*
1494  * This upgrade adds an indexed extension column to the tsk_files table.
1495  */
1496  Statement statement = null;
1497  Statement updstatement = null;
1498  ResultSet resultSet = null;
1500  try {
1501  statement = connection.createStatement();
1502  updstatement = connection.createStatement();
1503  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1504 
1505  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1506  while (resultSet.next()) {
1507  long objID = resultSet.getLong("obj_id");
1508  String name = resultSet.getString("name");
1509  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1510  + "WHERE obj_id = " + objID);
1511  }
1512 
1513  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1514 
1515  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1516  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1517 
1518  return new CaseDbSchemaVersionNumber(7, 0);
1519 
1520  } finally {
1521  closeResultSet(resultSet);
1522  closeStatement(statement);
1523  closeStatement(updstatement);
1525  }
1526  }
1527 
1541  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1542  if (schemaVersion.getMajor() != 7) {
1543  return schemaVersion;
1544  }
1545 
1546  if (schemaVersion.getMinor() != 0) {
1547  return schemaVersion;
1548  }
1549 
1550  /*
1551  * This upgrade adds a minor version number column.
1552  */
1553  Statement statement = null;
1554  ResultSet resultSet = null;
1556  try {
1557  statement = connection.createStatement();
1558 
1559  //add the schema minor version number column.
1560  if (schemaVersion.getMinor() == 0) {
1561  //add the schema minor version number column.
1562  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1563  }
1564  return new CaseDbSchemaVersionNumber(7, 1);
1565 
1566  } finally {
1567  closeResultSet(resultSet);
1568  closeStatement(statement);
1570  }
1571  }
1572 
1586  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1587  if (schemaVersion.getMajor() != 7) {
1588  return schemaVersion;
1589  }
1590 
1591  if (schemaVersion.getMinor() != 1) {
1592  return schemaVersion;
1593  }
1594 
1595  Statement statement = null;
1596  Statement updstatement = null;
1597  ResultSet resultSet = null;
1599  try {
1600  //add the data_source_obj_id column to blackboard_artifacts.
1601  statement = connection.createStatement();
1602  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1603 
1604  // populate data_source_obj_id for each artifact
1605  updstatement = connection.createStatement();
1606  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1607  while (resultSet.next()) {
1608  long artifact_id = resultSet.getLong("artifact_id");
1609  long obj_id = resultSet.getLong("obj_id");
1610  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1611  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1612  + "WHERE artifact_id = " + artifact_id);
1613  }
1614  closeResultSet(resultSet);
1615  closeStatement(statement);
1616  closeStatement(updstatement);
1617 
1618  /*
1619  * Add a knownStatus column to the tag_names table.
1620  */
1621  statement = connection.createStatement();
1622  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1623 
1624  // Create account_types, accounts, and account_relationships table
1625  if (this.dbType.equals(DbType.SQLITE)) {
1626  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1627  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))");
1628  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))");
1629  } else {
1630  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1631  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))");
1632  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))");
1633  }
1634 
1635  // Create indexes
1636  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1637  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1638  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1639  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1640  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1641  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1642  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1643 
1644  return new CaseDbSchemaVersionNumber(7, 2);
1645  } finally {
1646  closeResultSet(resultSet);
1647  closeStatement(statement);
1648  closeStatement(updstatement);
1650  }
1651  }
1652 
1666  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1667  if (schemaVersion.getMajor() != 7) {
1668  return schemaVersion;
1669  }
1670 
1671  if (schemaVersion.getMinor() != 2) {
1672  return schemaVersion;
1673  }
1674 
1675  Statement updateSchemaStatement = connection.createStatement();
1676  Statement getExistingReportsStatement = connection.createStatement();
1677  ResultSet resultSet = null;
1678  ResultSet existingReports = null;
1679 
1681  try {
1682  // Update the schema to turn report_id into an object id.
1683 
1684  // Unfortunately, SQLite doesn't support adding a constraint
1685  // to an existing table so we have to rename the old...
1686  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1687 
1688  // ...create the new...
1689  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))");
1690 
1691  // ...add the existing report records back...
1692  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1693  while (existingReports.next()) {
1694  String path = existingReports.getString(2);
1695  long crtime = existingReports.getInt(3);
1696  String sourceModule = existingReports.getString(4);
1697  String reportName = existingReports.getString(5);
1698 
1699  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1700  insertObjectStatement.clearParameters();
1701  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1702  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1703  connection.executeUpdate(insertObjectStatement);
1704  resultSet = insertObjectStatement.getGeneratedKeys();
1705  if (!resultSet.next()) {
1706  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1707  }
1708  long objectId = resultSet.getLong(1); //last_insert_rowid()
1709 
1710  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1711  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1712  insertReportStatement.clearParameters();
1713  insertReportStatement.setLong(1, objectId);
1714  insertReportStatement.setString(2, path);
1715  insertReportStatement.setLong(3, crtime);
1716  insertReportStatement.setString(4, sourceModule);
1717  insertReportStatement.setString(5, reportName);
1718  connection.executeUpdate(insertReportStatement);
1719  }
1720 
1721  // ...and drop the old table.
1722  updateSchemaStatement.execute("DROP TABLE old_reports");
1723 
1724  return new CaseDbSchemaVersionNumber(8, 0);
1725  } finally {
1726  closeResultSet(resultSet);
1727  closeResultSet(existingReports);
1728  closeStatement(updateSchemaStatement);
1729  closeStatement(getExistingReportsStatement);
1731  }
1732  }
1733 
1747  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1748  if (schemaVersion.getMajor() != 8) {
1749  return schemaVersion;
1750  }
1751 
1752  if (schemaVersion.getMinor() != 0) {
1753  return schemaVersion;
1754  }
1755 
1757 
1758  try (Statement statement = connection.createStatement();) {
1759  // create examiners table
1760  if (this.dbType.equals(DbType.SQLITE)) {
1761  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1762  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1763  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1764  } else {
1765  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1766  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1767  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1768  }
1769 
1770  return new CaseDbSchemaVersionNumber(8, 1);
1771  } finally {
1773  }
1774  }
1775 
1789  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1790  if (schemaVersion.getMajor() != 8) {
1791  return schemaVersion;
1792  }
1793 
1794  if (schemaVersion.getMinor() != 1) {
1795  return schemaVersion;
1796  }
1797 
1799 
1800  try (Statement statement = connection.createStatement();) {
1801  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1802  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1803 
1804  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1805 
1806  /*
1807  * Add new tsk_db_extended_info table with TSK version, creation
1808  * time schema and schema version numbers as the initial data. The
1809  * creation time schema version is set to 0, 0 to indicate that it
1810  * is not known.
1811  */
1812  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1813  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1814  result.next();
1815  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1816  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1817  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1818  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1819  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1820 
1821  String primaryKeyType;
1822  switch (getDatabaseType()) {
1823  case POSTGRESQL:
1824  primaryKeyType = "BIGSERIAL";
1825  break;
1826  case SQLITE:
1827  primaryKeyType = "INTEGER";
1828  break;
1829  default:
1830  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1831  }
1832 
1833  //create and initialize tsk_event_types tables
1834  statement.execute("CREATE TABLE tsk_event_types ("
1835  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1836  + " display_name TEXT UNIQUE NOT NULL, "
1837  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1838  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1839  + " values( 0, 'Event Types', null)");
1840  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1841  + " values(1, 'File System', 0)");
1842  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1843  + " values(2, 'Web Activity', 0)");
1844  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1845  + " values(3, 'Misc Types', 0)");
1846  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1847  + " values(4, 'Modified', 1)");
1848  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1849  + " values(5, 'Accessed', 1)");
1850  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1851  + " values(6, 'Created', 1)");
1852  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1853  + " values(7, 'Changed', 1)");
1854 
1855  //create tsk_events tables
1856  statement.execute("CREATE TABLE tsk_event_descriptions ("
1857  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1858  + " full_description TEXT NOT NULL, "
1859  + " med_description TEXT, "
1860  + " short_description TEXT,"
1861  + " data_source_obj_id BIGINT NOT NULL, "
1862  + " file_obj_id BIGINT NOT NULL, "
1863  + " artifact_id BIGINT, "
1864  + " hash_hit INTEGER NOT NULL, " //boolean
1865  + " tagged INTEGER NOT NULL, " //boolean
1866  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1867  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1868  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1869  );
1870 
1871  statement.execute("CREATE TABLE tsk_events ( "
1872  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1873  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1874  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1875  + " time INTEGER NOT NULL) "
1876  );
1877 
1878  //create tsk_events indices
1879  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1880  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1881  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1882  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1883  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1884  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1885  return new CaseDbSchemaVersionNumber(8, 2);
1886 
1887  } finally {
1889  }
1890  }
1891 
1905  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1906  if (schemaVersion.getMajor() != 8) {
1907  return schemaVersion;
1908  }
1909 
1910  if (schemaVersion.getMinor() != 2) {
1911  return schemaVersion;
1912  }
1913 
1915 
1916  ResultSet resultSet = null;
1917 
1918  try (Statement statement = connection.createStatement();) {
1919 
1920  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1921  // Unfortunately, SQLite doesn't support adding a constraint
1922  // to an existing table so we have to rename the old...
1923  String primaryKeyType;
1924  switch (getDatabaseType()) {
1925  case POSTGRESQL:
1926  primaryKeyType = "BIGSERIAL";
1927  break;
1928  case SQLITE:
1929  primaryKeyType = "INTEGER";
1930  break;
1931  default:
1932  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1933  }
1934 
1935  //create and initialize tsk_event_types tables which may or may not exist
1936  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
1937  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1938  + " display_name TEXT UNIQUE NOT NULL, "
1939  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1940 
1941  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
1942 
1943  // If there is something in resultSet then the table must have previously
1944  // existing therefore there is not need to populate
1945  if (!resultSet.next()) {
1946 
1947  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1948  + " values( 0, 'Event Types', null)");
1949  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1950  + " values(1, 'File System', 0)");
1951  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1952  + " values(2, 'Web Activity', 0)");
1953  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1954  + " values(3, 'Misc Types', 0)");
1955  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1956  + " values(4, 'Modified', 1)");
1957  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1958  + " values(5, 'Accessed', 1)");
1959  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1960  + " values(6, 'Created', 1)");
1961  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1962  + " values(7, 'Changed', 1)");
1963  }
1964 
1965  // Delete the old table that may have been created with the upgrade
1966  // from 8.1 to 8.2.
1967  statement.execute("DROP TABLE IF EXISTS tsk_events");
1968 
1969  // Delete the old table that may have been created with the upgrade
1970  // from 8.1 to 8.2
1971  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
1972 
1973  //create new tsk_event_description table
1974  statement.execute("CREATE TABLE tsk_event_descriptions ("
1975  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1976  + " full_description TEXT NOT NULL, "
1977  + " med_description TEXT, "
1978  + " short_description TEXT,"
1979  + " data_source_obj_id BIGINT NOT NULL, "
1980  + " file_obj_id BIGINT NOT NULL, "
1981  + " artifact_id BIGINT, "
1982  + " hash_hit INTEGER NOT NULL, " //boolean
1983  + " tagged INTEGER NOT NULL, " //boolean
1984  + " UNIQUE(full_description, file_obj_id, artifact_id), "
1985  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1986  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1987  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1988  );
1989 
1990  // create a new table
1991  statement.execute("CREATE TABLE tsk_events ( "
1992  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1993  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1994  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1995  + " time INTEGER NOT NULL, "
1996  + " UNIQUE (event_type_id, event_description_id, time))"
1997  );
1998 
1999  // Fix mistakenly set names in tsk_db_info_extended
2000  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2001  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2002 
2003  return new CaseDbSchemaVersionNumber(8, 3);
2004  } finally {
2005  closeResultSet(resultSet);
2007  }
2008  }
2009 
2031  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2032  if (schemaVersion.getMajor() != 8) {
2033  return schemaVersion;
2034  }
2035 
2036  if (schemaVersion.getMinor() != 3) {
2037  return schemaVersion;
2038  }
2039 
2040  Statement statement = connection.createStatement();
2041  ResultSet results = null;
2042 
2044  try {
2045  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2046  // the previous update code.
2047  if (null == getDatabaseType()) {
2048  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2049  }
2050 
2051  switch (getDatabaseType()) {
2052  case POSTGRESQL:
2053  // Check if the misnamed column is present
2054  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2055  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2056  if (results.next()) {
2057  // In PostgreSQL we can rename the column if it exists
2058  statement.execute("ALTER TABLE tsk_event_descriptions "
2059  + "RENAME COLUMN file_obj_id TO content_obj_id");
2060 
2061  // 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
2062  // Fix the schema, preserving any data if exists.
2063  statement.execute("CREATE TABLE temp_tsk_events ( "
2064  + " event_id BIGSERIAL PRIMARY KEY, "
2065  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2066  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2067  + " time BIGINT NOT NULL, "
2068  + " UNIQUE (event_type_id, event_description_id, time))"
2069  );
2070 
2071  // Copy the data
2072  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2073  + "event_description_id, time) SELECT * FROM tsk_events");
2074 
2075  // Drop the old table
2076  statement.execute("DROP TABLE tsk_events");
2077 
2078  // Rename the new table
2079  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2080 
2081  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2082  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2083  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2084  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2085  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2086  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2087  }
2088  break;
2089  case SQLITE:
2090  boolean hasMisnamedColumn = false;
2091  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2092  while (results.next()) {
2093  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2094  hasMisnamedColumn = true;
2095  break;
2096  }
2097  }
2098 
2099  if (hasMisnamedColumn) {
2100  // Since we can't rename the column we'll need to make new tables and copy the data
2101  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2102  + " event_description_id INTEGER PRIMARY KEY, "
2103  + " full_description TEXT NOT NULL, "
2104  + " med_description TEXT, "
2105  + " short_description TEXT,"
2106  + " data_source_obj_id BIGINT NOT NULL, "
2107  + " content_obj_id BIGINT NOT NULL, "
2108  + " artifact_id BIGINT, "
2109  + " hash_hit INTEGER NOT NULL, " //boolean
2110  + " tagged INTEGER NOT NULL, " //boolean
2111  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2112  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2113  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2114  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2115  );
2116 
2117  statement.execute("CREATE TABLE temp_tsk_events ( "
2118  + " event_id INTEGER PRIMARY KEY, "
2119  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2120  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2121  + " time INTEGER NOT NULL, "
2122  + " UNIQUE (event_type_id, event_description_id, time))"
2123  );
2124 
2125  // Copy the data
2126  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2127  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2128  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2129 
2130  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2131  + "event_description_id, time) SELECT * FROM tsk_events");
2132 
2133  // Drop the old tables
2134  statement.execute("DROP TABLE tsk_events");
2135  statement.execute("DROP TABLE tsk_event_descriptions");
2136 
2137  // Rename the new tables
2138  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2139  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2140 
2141  //create tsk_events indices
2142  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2143  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2144  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2145  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2146  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2147  }
2148  break;
2149  default:
2150  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2151  }
2152 
2153  // create pool info table
2154  if (this.dbType.equals(DbType.SQLITE)) {
2155  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)");
2156  } else {
2157  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)");
2158  }
2159 
2160  // Add new account types for newly supported messaging applications, if they dont exists already.
2161  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2162  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2163  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2164  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2165  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2166  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2167  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2168  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2169  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2170  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2171 
2172  return new CaseDbSchemaVersionNumber(8, 4);
2173  } finally {
2174  closeResultSet(results);
2175  closeStatement(statement);
2177  }
2178  }
2179 
2180  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2181  if (schemaVersion.getMajor() != 8) {
2182  return schemaVersion;
2183  }
2184 
2185  if (schemaVersion.getMinor() != 4) {
2186  return schemaVersion;
2187  }
2188 
2189  Statement statement = connection.createStatement();
2191  try {
2192  switch (getDatabaseType()) {
2193  case POSTGRESQL:
2194  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2195  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2196  break;
2197  case SQLITE:
2198  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2199  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2200  break;
2201  }
2202 
2203  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2204 
2205  /*
2206  * Update existing Project Vic tag names (from Image Gallery in
2207  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2208  * date and will not work with the Project VIC Report module. New
2209  * cases will get the new names from Image Gallery.
2210  */
2211  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2212  if (getDatabaseType() == DbType.POSTGRESQL) {
2213  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2214  } else {
2215  statement.execute(insertStmt);
2216  }
2217  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2218  if (resultSet != null && resultSet.next()) {
2219  int tagSetId = resultSet.getInt(1);
2220 
2221  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2222  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2223  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2224  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2225  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2226  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2227 
2228  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')";
2229  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')";
2230  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2231  statement.executeUpdate(deleteContentTag);
2232  statement.executeUpdate(deleteArtifactTag);
2233  statement.executeUpdate(deleteCat0);
2234 
2235  } else {
2236  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2237  }
2238  }
2239 
2240  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2241  // this column will have a foreign key constraint on the data_source_info table.
2242  // There does not seem to be a reasonable way to do this in an upgrade,
2243  // so upgraded cases will be missing the foreign key.
2244  switch (getDatabaseType()) {
2245  case POSTGRESQL:
2246  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2247  break;
2248  case SQLITE:
2249  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2250  break;
2251  }
2252  Statement updateStatement = connection.createStatement();
2253  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2254  while (resultSet.next()) {
2255  long fsId = resultSet.getLong("obj_id");
2256  long dataSourceId = getDataSourceObjectId(connection, fsId);
2257  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2258  }
2259  } finally {
2260  closeStatement(updateStatement);
2261  }
2262 
2263  return new CaseDbSchemaVersionNumber(8, 5);
2264 
2265  } finally {
2266  closeStatement(statement);
2268  }
2269  }
2270 
2271  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2272  if (schemaVersion.getMajor() != 8) {
2273  return schemaVersion;
2274  }
2275 
2276  if (schemaVersion.getMinor() != 5) {
2277  return schemaVersion;
2278  }
2279 
2280  Statement statement = connection.createStatement();
2282  try {
2283  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2284 
2285  return new CaseDbSchemaVersionNumber(8, 6);
2286 
2287  } finally {
2288  closeStatement(statement);
2290  }
2291  }
2292 
2293  @SuppressWarnings("deprecation")
2294  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2295  if (schemaVersion.getMajor() != 8) {
2296  return schemaVersion;
2297  }
2298 
2299  if (schemaVersion.getMinor() != 6) {
2300  return schemaVersion;
2301  }
2302 
2303  Statement statement = connection.createStatement();
2305  try {
2306  String dateDataType = "BIGINT";
2307  String bigIntDataType = "BIGINT";
2308  String blobDataType = "BYTEA";
2309  String primaryKeyType = "BIGSERIAL";
2310 
2311  if (this.dbType.equals(DbType.SQLITE)) {
2312  dateDataType = "INTEGER";
2313  bigIntDataType = "INTEGER";
2314  blobDataType = "BLOB";
2315  primaryKeyType = "INTEGER";
2316  }
2317  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2318  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2319  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2320  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2321 
2322  // Add category type and initialize the types. We use the list of artifact types that
2323  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2324  // case the built-in types change in a later release.
2325  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2326  String analysisTypeObjIdList
2327  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2328  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2329  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2330  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2331  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2332  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2333  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2334  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2335  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2336  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2337  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2338  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2339  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2340  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2341  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2342  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2343  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2344  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2345  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2346 
2347  // Create tsk file attributes table
2348  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2349  + "obj_id " + bigIntDataType + " NOT NULL, "
2350  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2351  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2352  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2353  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2354  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2355 
2356  // create analysis results tables
2357  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2358  + "conclusion TEXT, "
2359  + "significance INTEGER NOT NULL, "
2360  /*
2361  * method_category was a column in a little distributed
2362  * version of 9.0. It was renamed to priority before public
2363  * release. The 9.1 upgrade code will add the priority
2364  * column. This is commented out since it was never used.
2365  */
2366  // + "method_category INTEGER NOT NULL, "
2367  + "configuration TEXT, justification TEXT, "
2368  + "ignore_score INTEGER DEFAULT 0 " // boolean
2369  + ")");
2370 
2371  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2372  + "data_source_obj_id " + bigIntDataType + ", "
2373  + "significance INTEGER NOT NULL, "
2374  // See comment above on why this is commented out
2375  // + "method_category INTEGER NOT NULL, "
2376  + "UNIQUE (obj_id),"
2377  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2378  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2379  + ")");
2380 
2381  // Create person table.
2382  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2383  + "name TEXT NOT NULL, " // person name
2384  + "UNIQUE(name)) ");
2385 
2386  // Create host table.
2387  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2388  + "name TEXT NOT NULL, " // host name
2389  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2390  + "person_id INTEGER, "
2391  + "merged_into " + bigIntDataType + ", "
2392  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2393  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2394  + "UNIQUE(name)) ");
2395 
2396  // Create OS Account and related tables
2397  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2398  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2399  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2400  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2401  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2402  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2403  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2404  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2405  + "UNIQUE(realm_signature), "
2406  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2407  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2408 
2409  // Add host column and create a host for each existing data source.
2410  // We will create a host for each device id so that related data sources will
2411  // be associated with the same host.
2412  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2413  Statement updateStatement = connection.createStatement();
2414  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2415  Map<String, Long> hostMap = new HashMap<>();
2416  long hostIndex = 1;
2417  while (resultSet.next()) {
2418  long objId = resultSet.getLong("obj_id");
2419  String deviceId = resultSet.getString("device_id");
2420 
2421  if (!hostMap.containsKey(deviceId)) {
2422  String hostName = "Host " + hostIndex;
2423  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2424  hostMap.put(deviceId, hostIndex);
2425  hostIndex++;
2426  }
2427  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2428  }
2429  } finally {
2430  closeStatement(updateStatement);
2431  }
2432 
2433  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2434  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2435  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2436  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2437  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2438  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2439  + "status INTEGER, " // enabled/disabled/deleted
2440  + "type INTEGER, " // service/interactive
2441  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2442  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2443  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2444  + "UNIQUE(signature, realm_id), "
2445  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2446  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2447  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2448 
2449  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2450  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2451  + "host_id " + bigIntDataType + ", "
2452  + "source_obj_id " + bigIntDataType + ", "
2453  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2454  + "value_type INTEGER NOT NULL, "
2455  + "value_byte " + bigIntDataType + ", "
2456  + "value_text TEXT, "
2457  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2458  + "value_double NUMERIC(20, 10), "
2459  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2460  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2461  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2462  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2463 
2464  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2465  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2466  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2467  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2468  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2469  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2470  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2471 
2472  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2473  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2474  + "os_account_obj_id " + bigIntDataType + ", "
2475  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2476 
2477  // add owner_uid & os_account_obj_id columns to tsk_files
2478  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2479  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2480 
2481  // create host address tables
2482  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2483  + "address_type INTEGER NOT NULL, "
2484  + "address TEXT NOT NULL, "
2485  + "UNIQUE(address_type, address)) ");
2486 
2487  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2488  + "host_id " + bigIntDataType + " NOT NULL, "
2489  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2490  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2491  + "time " + bigIntDataType + ", " // time at which the mapping existed
2492  + "UNIQUE(host_id, addr_obj_id, time), "
2493  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2494  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2495  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2496 
2497  // stores associations between DNS name and IP address
2498  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2499  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2500  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2501  + "source_obj_id " + bigIntDataType + ", "
2502  + "time " + bigIntDataType + ", " // time at which the mapping existed
2503  + "UNIQUE(dns_address_id, ip_address_id, time), "
2504  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2505  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2506  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2507 
2508  // maps an address to an artifact using it
2509  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2510  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2511  + "obj_id " + bigIntDataType + " NOT NULL, "
2512  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2513  + "UNIQUE(addr_obj_id, obj_id), "
2514  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2515  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2516 
2517  return new CaseDbSchemaVersionNumber(9, 0);
2518 
2519  } finally {
2520  closeStatement(statement);
2522  }
2523  }
2524 
2525  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2526  if (schemaVersion.getMajor() != 9) {
2527  return schemaVersion;
2528  }
2529 
2530  if (schemaVersion.getMinor() != 0) {
2531  return schemaVersion;
2532  }
2533 
2534  Statement statement = connection.createStatement();
2535  ResultSet results = null;
2537  try {
2538  // The 9.0 schema contained method_category columns that were renamed to priority.
2539  switch (getDatabaseType()) {
2540  case POSTGRESQL:
2541  // Check if the misnamed column is present. We'll assume here that the column will exist
2542  // in both tables if present in one.
2543  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2544  + "WHERE table_name='tsk_analysis_results' and column_name='method_category'");
2545  if (results.next()) {
2546  // In PostgreSQL we can delete the column
2547  statement.execute("ALTER TABLE tsk_analysis_results "
2548  + "DROP COLUMN method_category");
2549  statement.execute("ALTER TABLE tsk_aggregate_score "
2550  + "DROP COLUMN method_category");
2551  }
2552  break;
2553  case SQLITE:
2554  // Check if the misnamed column is present. We'll assume here that the column will exist
2555  // in both tables if present in one.
2556  boolean hasMisnamedColumn = false;
2557  results = statement.executeQuery("pragma table_info('tsk_analysis_results')");
2558  while (results.next()) {
2559  if (results.getString("name") != null && results.getString("name").equals("method_category")) {
2560  hasMisnamedColumn = true;
2561  break;
2562  }
2563  }
2564 
2565  if (hasMisnamedColumn) {
2566  // Since we can't rename the column we'll need to make a new table and copy the data.
2567  // We'll add the priority column later.
2568  statement.execute("CREATE TABLE temp_tsk_analysis_results (artifact_obj_id INTEGER PRIMARY KEY, "
2569  + "conclusion TEXT, "
2570  + "significance INTEGER NOT NULL, "
2571  + "configuration TEXT, justification TEXT, "
2572  + "ignore_score INTEGER DEFAULT 0 " // boolean
2573  + ")");
2574  statement.execute("CREATE TABLE temp_tsk_aggregate_score( obj_id INTEGER PRIMARY KEY, "
2575  + "data_source_obj_id INTEGER, "
2576  + "significance INTEGER NOT NULL, "
2577  + "UNIQUE (obj_id),"
2578  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2579  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2580  + ")");
2581 
2582  // Copy the data
2583  statement.execute("INSERT INTO temp_tsk_analysis_results(artifact_obj_id, "
2584  + "conclusion, justification, significance, configuration, ignore_score) "
2585  + "SELECT artifact_obj_id, conclusion, justification, significance, configuration, ignore_score FROM tsk_analysis_results");
2586  statement.execute("INSERT INTO temp_tsk_aggregate_score(obj_id, "
2587  + "data_source_obj_id, significance) "
2588  + "SELECT obj_id, data_source_obj_id, significance FROM tsk_aggregate_score");
2589 
2590  // Drop the old tables
2591  statement.execute("DROP TABLE tsk_analysis_results");
2592  statement.execute("DROP TABLE tsk_aggregate_score");
2593 
2594  // Rename the new tables
2595  statement.execute("ALTER TABLE temp_tsk_analysis_results RENAME TO tsk_analysis_results");
2596  statement.execute("ALTER TABLE temp_tsk_aggregate_score RENAME TO tsk_aggregate_score");
2597 
2598  }
2599  break;
2600  default:
2601  throw new TskCoreException("Unsupported database type: " + getDatabaseType().toString());
2602  }
2603 
2604  // add an index on tsk_file_attributes table.
2605  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2606 
2607  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2608  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2609 
2610  statement.execute("UPDATE blackboard_artifact_types SET category_type = 1 WHERE artifact_type_id = 16");
2611 
2612  return new CaseDbSchemaVersionNumber(9, 1);
2613  } finally {
2614  closeResultSet(results);
2615  closeStatement(statement);
2617  }
2618  }
2619 
2633  private CaseDbSchemaVersionNumber updateFromSchema9dot1toSchema9dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2634  if (schemaVersion.getMajor() != 9) {
2635  return schemaVersion;
2636  }
2637 
2638  if (schemaVersion.getMinor() != 1) {
2639  return schemaVersion;
2640  }
2641 
2642  Statement updateSchemaStatement = connection.createStatement();
2643  ResultSet results = null;
2645  try {
2646 
2647  String bigIntDataType = "BIGINT";
2648  String primaryKeyType = "BIGSERIAL";
2649 
2650  if (this.dbType.equals(DbType.SQLITE)) {
2651  bigIntDataType = "INTEGER";
2652  primaryKeyType = "INTEGER";
2653  }
2654 
2655  // In 9.2 we modified the UNIQUE constraint on tsk_os_account_instances to include instance_type column.
2656  // Since SQLite does not allow to drop or alter constraints, we will create a new table, copy the data and delete the old table.
2657  // Rename existing table
2658  updateSchemaStatement.execute("ALTER TABLE tsk_os_account_instances RENAME TO old_tsk_os_account_instances");
2659 
2660  // New table
2661  updateSchemaStatement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2662  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2663  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2664  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2665  + "UNIQUE(os_account_obj_id, data_source_obj_id, instance_type), "
2666  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id) ON DELETE CASCADE, "
2667  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE ) ");
2668 
2669  // Copy the data from old table, order by id preserves the primary key.
2670  updateSchemaStatement.execute("INSERT INTO tsk_os_account_instances(os_account_obj_id, "
2671  + "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");
2672 
2673  // delete old table
2674  updateSchemaStatement.execute("DROP TABLE old_tsk_os_account_instances");
2675 
2676  return new CaseDbSchemaVersionNumber(9, 2);
2677  } finally {
2678  closeResultSet(results);
2679  closeStatement(updateSchemaStatement);
2681  }
2682  }
2683 
2684  private CaseDbSchemaVersionNumber updateFromSchema9dot2toSchema9dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2685  if (schemaVersion.getMajor() != 9) {
2686  return schemaVersion;
2687  }
2688 
2689  if (schemaVersion.getMinor() != 2) {
2690  return schemaVersion;
2691  }
2692 
2693  Statement statement = connection.createStatement();
2695  try {
2696  // add a new column 'sha1' to tsk_files
2697  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha1 TEXT");
2698 
2699 
2700  return new CaseDbSchemaVersionNumber(9, 3);
2701 
2702  } finally {
2703  closeStatement(statement);
2705  }
2706  }
2707 
2719  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2720 
2721  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2722  switch (getDatabaseType()) {
2723  case POSTGRESQL:
2724  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2725  break;
2726  case SQLITE:
2727  insertSQL = "INSERT OR IGNORE " + insertSQL;
2728  break;
2729  default:
2730  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2731  }
2732  statement.execute(insertSQL); //NON-NLS
2733  }
2734 
2742  static String extractExtension(final String fileName) {
2743  String ext;
2744  int i = fileName.lastIndexOf(".");
2745  // > 0 because we assume it's not an extension if period is the first character
2746  if ((i > 0) && ((i + 1) < fileName.length())) {
2747  ext = fileName.substring(i + 1);
2748  } else {
2749  return "";
2750  }
2751  // we added this at one point to deal with files that had crazy names based on URLs
2752  // it's too hard though to clean those up and not mess up basic extensions though.
2753  // We need to add '-' to the below if we use it again
2754  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2755  // if (findNonAlphanumeric.length > 1) {
2756  // ext = findNonAlphanumeric[0];
2757  // }
2758  return ext.toLowerCase();
2759  }
2760 
2771  @Deprecated
2772  public int getSchemaVersion() {
2773  return getDBSchemaVersion().getMajor();
2774  }
2775 
2782  return CURRENT_DB_SCHEMA_VERSION;
2783  }
2784 
2792  return caseDBSchemaCreationVersion;
2793  }
2794 
2801  return this.dbType;
2802  }
2803 
2810  public String getBackupDatabasePath() {
2811  return dbBackupPath;
2812  }
2813 
2828  public CaseDbTransaction beginTransaction() throws TskCoreException {
2829  return new CaseDbTransaction(this);
2830  }
2831 
2837  public String getDatabaseName() {
2838  return databaseName;
2839  }
2840 
2847  public String getDbDirPath() {
2848  return caseDirPath;
2849  }
2850 
2857  if (dbType == DbType.SQLITE) {
2858  rwLock.writeLock().lock();
2859  }
2860  }
2861 
2868  if (dbType == DbType.SQLITE) {
2869  rwLock.writeLock().unlock();
2870  }
2871  }
2872 
2879  if (dbType == DbType.SQLITE) {
2880  rwLock.readLock().lock();
2881  }
2882  }
2883 
2890  if (dbType == DbType.SQLITE) {
2891  rwLock.readLock().unlock();
2892  }
2893  }
2894 
2904  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2905  try {
2906  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2907  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2909  //don't wrap in new TskCoreException
2910  throw ex;
2911  } catch (Exception ex) {
2912  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
2913  }
2914  }
2915 
2927  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
2928  try {
2929  /*
2930  * The flow of this method involves trying to open case and if
2931  * successful, return that case. If unsuccessful, an exception is
2932  * thrown. We catch any exceptions, and use tryConnect() to attempt
2933  * to obtain further information about the error. If tryConnect() is
2934  * unable to successfully connect, tryConnect() will throw a
2935  * TskCoreException with a message containing user-level error
2936  * reporting. If tryConnect() is able to connect, flow continues and
2937  * we rethrow the original exception obtained from trying to create
2938  * the case. In this way, we obtain more detailed information if we
2939  * are able, but do not lose any information if unable.
2940  */
2941  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2942  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
2943  } catch (PropertyVetoException exp) {
2944  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2945  throw new TskCoreException(exp.getMessage(), exp);
2947  //don't wrap in new TskCoreException
2948  throw ex;
2949  } catch (Exception exp) {
2950  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2951  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2952  }
2953  }
2954 
2964  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
2965  try {
2966  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
2967  factory.createCaseDatabase();
2968 
2969  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2970  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2971  } catch (Exception ex) {
2972  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
2973  }
2974  }
2975 
2991  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
2992  String databaseName = createCaseDataBaseName(caseName);
2993  try {
3006  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
3007  factory.createCaseDatabase();
3008 
3009  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
3010  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
3011  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
3012  } catch (PropertyVetoException exp) {
3013  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
3014  throw new TskCoreException(exp.getMessage(), exp);
3015  } catch (Exception exp) {
3016  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
3017  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
3018  }
3019  }
3020 
3030  private static String createCaseDataBaseName(String candidateDbName) {
3031  String dbName;
3032  if (!candidateDbName.isEmpty()) {
3033  /*
3034  * Replace all non-ASCII characters.
3035  */
3036  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
3037 
3038  /*
3039  * Replace all control characters.
3040  */
3041  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
3042 
3043  /*
3044  * Replace /, \, :, ?, space, ' ".
3045  */
3046  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
3047 
3048  /*
3049  * Make it all lowercase.
3050  */
3051  dbName = dbName.toLowerCase();
3052 
3053  /*
3054  * Must start with letter or underscore. If not, prepend an
3055  * underscore.
3056  */
3057  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
3058  dbName = "_" + dbName;
3059  }
3060 
3061  /*
3062  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
3063  * uniqueness.
3064  */
3065  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
3066  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
3067  }
3068 
3069  } else {
3070  /*
3071  * Must start with letter or underscore.
3072  */
3073  dbName = "_";
3074  }
3075  /*
3076  * Add the time stmap.
3077  */
3078  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
3079  Date date = new Date();
3080  dbName = dbName + "_" + dateFormat.format(date);
3081 
3082  return dbName;
3083  }
3084 
3090  @Beta
3092  timelineEventsDisabled.set(true);
3093  }
3094 
3102  public Examiner getCurrentExaminer() throws TskCoreException {
3103 
3104  // return cached value if there's one
3105  if (cachedCurrentExaminer != null) {
3106  return cachedCurrentExaminer;
3107  }
3108  String loginName = System.getProperty("user.name");
3109  if (loginName == null || loginName.isEmpty()) {
3110  throw new TskCoreException("Failed to determine logged in user name.");
3111  }
3112 
3113  ResultSet resultSet = null;
3114  CaseDbConnection connection = null;
3116  try {
3117  connection = connections.getConnection();
3118  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3119  statement.clearParameters();
3120  statement.setString(1, loginName);
3121  resultSet = connection.executeQuery(statement);
3122  if (resultSet.next()) {
3123  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3124  return cachedCurrentExaminer;
3125  } else {
3126  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3127  }
3128 
3129  } catch (SQLException ex) {
3130  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3131  } finally {
3132  closeResultSet(resultSet);
3133  closeConnection(connection);
3135  }
3136 
3137  }
3138 
3148  Examiner getExaminerById(long id) throws TskCoreException {
3149 
3150  CaseDbConnection connection = null;
3151  ResultSet resultSet = null;
3153  try {
3154  connection = connections.getConnection();
3155  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3156  statement.clearParameters();
3157  statement.setLong(1, id);
3158  resultSet = connection.executeQuery(statement);
3159  if (resultSet.next()) {
3160  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3161  } else {
3162  throw new TskCoreException("Error getting examaminer for id = " + id);
3163  }
3164  } catch (SQLException ex) {
3165  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3166  } finally {
3167  closeResultSet(resultSet);
3168  closeConnection(connection);
3170  }
3171  }
3172 
3190  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3191  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
3192  }
3193 
3202  public List<Content> getRootObjects() throws TskCoreException {
3203  CaseDbConnection connection = null;
3204  Statement s = null;
3205  ResultSet rs = null;
3207  try {
3208  connection = connections.getConnection();
3209  s = connection.createStatement();
3210  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
3211  + "WHERE par_obj_id IS NULL"); //NON-NLS
3212  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3213  while (rs.next()) {
3214  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3215  }
3216 
3217  List<Content> rootObjs = new ArrayList<Content>();
3218  for (ObjectInfo i : infos) {
3219  if (null != i.type) {
3220  switch (i.type) {
3221  case IMG:
3222  rootObjs.add(getImageById(i.id));
3223  break;
3224  case ABSTRACTFILE:
3225  // Check if virtual dir for local files.
3226  AbstractFile af = getAbstractFileById(i.id);
3227  if (af instanceof VirtualDirectory) {
3228  rootObjs.add(af);
3229  } else {
3230  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3231  }
3232  break;
3233  case REPORT:
3234  break;
3235  case OS_ACCOUNT:
3236  break;
3237  case HOST_ADDRESS:
3238  break;
3239  case UNSUPPORTED:
3240  break;
3241  default:
3242  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3243  }
3244  }
3245  }
3246  return rootObjs;
3247  } catch (SQLException ex) {
3248  throw new TskCoreException("Error getting root objects", ex);
3249  } finally {
3250  closeResultSet(rs);
3251  closeStatement(s);
3252  closeConnection(connection);
3254  }
3255  }
3256 
3268  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3269 
3270  // check cached map first
3271  synchronized (deviceIdToDatasourceObjIdMap) {
3272  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3273  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3274  }
3275 
3276  CaseDbConnection connection = null;
3277  Statement s = null;
3278  ResultSet rs = null;
3280  try {
3281  connection = connections.getConnection();
3282  s = connection.createStatement();
3283  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3284  List<Long> dataSourceObjIds = new ArrayList<Long>();
3285  while (rs.next()) {
3286  dataSourceObjIds.add(rs.getLong("obj_id"));
3287 
3288  // Add to map of deviceID to data_source_obj_id.
3289  long ds_obj_id = rs.getLong("obj_id");
3290  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3291  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3292  } else {
3293  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3294  }
3295  }
3296  return dataSourceObjIds;
3297  } catch (SQLException ex) {
3298  throw new TskCoreException("Error getting data sources", ex);
3299  } finally {
3300  closeResultSet(rs);
3301  closeStatement(s);
3302  closeConnection(connection);
3304  }
3305  }
3306  }
3307 
3324  public List<DataSource> getDataSources() throws TskCoreException {
3325  CaseDbConnection connection = null;
3326  Statement statement = null;
3327  ResultSet resultSet = null;
3328  Statement statement2 = null;
3329  ResultSet resultSet2 = null;
3331  try {
3332  connection = connections.getConnection();
3333  statement = connection.createStatement();
3334  statement2 = connection.createStatement();
3335  resultSet = connection.executeQuery(statement,
3336  "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 "
3337  + "FROM data_source_info AS ds "
3338  + "LEFT JOIN tsk_image_info AS img "
3339  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3340 
3341  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3342  Map<Long, List<String>> imagePathsMap = getImagePaths();
3343 
3344  while (resultSet.next()) {
3345  DataSource dataSource;
3346  Long objectId = resultSet.getLong("obj_id");
3347  String deviceId = resultSet.getString("device_id");
3348  String timezone = resultSet.getString("time_zone");
3349  String type = resultSet.getString("type");
3350 
3351  if (type == null) {
3352  /*
3353  * No data found in 'tsk_image_info', so we build a
3354  * LocalFilesDataSource.
3355  */
3356 
3357  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3358  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3359  resultSet2.close();
3360 
3364  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3365  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3366  String parentPath = "/"; //NON-NLS
3367  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3368  } else {
3369  /*
3370  * Data found in 'tsk_image_info', so we build an Image.
3371  */
3372  Long ssize = resultSet.getLong("ssize");
3373  Long size = resultSet.getLong("size");
3374  String md5 = resultSet.getString("md5");
3375  String sha1 = resultSet.getString("sha1");
3376  String sha256 = resultSet.getString("sha256");
3377  String name = resultSet.getString("display_name");
3378 
3379  List<String> imagePaths = imagePathsMap.get(objectId);
3380  if (name == null) {
3381  if (imagePaths.size() > 0) {
3382  String path = imagePaths.get(0);
3383  name = (new java.io.File(path)).getName();
3384  } else {
3385  name = "";
3386  }
3387  }
3388 
3389  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3390  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3391  }
3392 
3393  dataSourceList.add(dataSource);
3394  }
3395 
3396  return dataSourceList;
3397 
3398  } catch (SQLException ex) {
3399  throw new TskCoreException("Error getting data sources", ex);
3400  } finally {
3401  closeResultSet(resultSet);
3402  closeStatement(statement);
3403  closeResultSet(resultSet2);
3404  closeStatement(statement2);
3405  closeConnection(connection);
3407  }
3408  }
3409 
3429  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3430  DataSource dataSource = null;
3431  CaseDbConnection connection = null;
3432  Statement statement = null;
3433  ResultSet resultSet = null;
3434  Statement statement2 = null;
3435  ResultSet resultSet2 = null;
3437  try {
3438  connection = connections.getConnection();
3439  statement = connection.createStatement();
3440  statement2 = connection.createStatement();
3441  resultSet = connection.executeQuery(statement,
3442  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3443  + "FROM data_source_info AS ds "
3444  + "LEFT JOIN tsk_image_info AS img "
3445  + "ON ds.obj_id = img.obj_id "
3446  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3447  if (resultSet.next()) {
3448  String deviceId = resultSet.getString("device_id");
3449  String timezone = resultSet.getString("time_zone");
3450  String type = resultSet.getString("type");
3451 
3452  if (type == null) {
3453  /*
3454  * No data found in 'tsk_image_info', so we build an
3455  * LocalFilesDataSource.
3456  */
3457 
3458  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3459  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3460 
3464  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3465  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3466  String parentPath = "/"; //NON-NLS
3467  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, null, FileKnown.UNKNOWN, parentPath);
3468  } else {
3469  /*
3470  * Data found in 'tsk_image_info', so we build an Image.
3471  */
3472  Long ssize = resultSet.getLong("ssize");
3473  Long size = resultSet.getLong("size");
3474  String md5 = resultSet.getString("md5");
3475  String sha1 = resultSet.getString("sha1");
3476  String sha256 = resultSet.getString("sha256");
3477  String name = resultSet.getString("display_name");
3478 
3479  List<String> imagePaths = getImagePathsById(objectId, connection);
3480  if (name == null) {
3481  if (imagePaths.size() > 0) {
3482  String path = imagePaths.get(0);
3483  name = (new java.io.File(path)).getName();
3484  } else {
3485  name = "";
3486  }
3487  }
3488 
3489  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3490  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3491  }
3492  } else {
3493  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3494  }
3495  } catch (SQLException ex) {
3496  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3497  } finally {
3498  closeResultSet(resultSet);
3499  closeStatement(statement);
3500  closeResultSet(resultSet2);
3501  closeStatement(statement2);
3502  closeConnection(connection);
3504  }
3505 
3506  return dataSource;
3507  }
3508 
3521  @Deprecated
3522  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3523  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3524  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactTypeID)));
3525  return artifacts;
3526  }
3527 
3538  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3539  CaseDbConnection connection = null;
3540  ResultSet rs = null;
3542  try {
3543  connection = connections.getConnection();
3544 
3545  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3546  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3547  statement.clearParameters();
3548  statement.setLong(1, objId);
3549  rs = connection.executeQuery(statement);
3550  long count = 0;
3551  if (rs.next()) {
3552  count = rs.getLong("count");
3553  }
3554  return count;
3555  } catch (SQLException ex) {
3556  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3557  } finally {
3558  closeResultSet(rs);
3559  closeConnection(connection);
3561  }
3562  }
3563 
3574  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3575  CaseDbConnection connection = null;
3576  ResultSet rs = null;
3578  try {
3579  connection = connections.getConnection();
3580 
3581  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3582  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3583  statement.clearParameters();
3584  statement.setInt(1, artifactTypeID);
3585  rs = connection.executeQuery(statement);
3586  long count = 0;
3587  if (rs.next()) {
3588  count = rs.getLong("count");
3589  }
3590  return count;
3591  } catch (SQLException ex) {
3592  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3593  } finally {
3594  closeResultSet(rs);
3595  closeConnection(connection);
3597  }
3598  }
3599 
3611  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3612  CaseDbConnection connection = null;
3613  ResultSet rs = null;
3615  try {
3616  connection = connections.getConnection();
3617 
3618  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3619  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3620  statement.clearParameters();
3621  statement.setInt(2, artifactTypeID);
3622  statement.setLong(1, dataSourceID);
3623  rs = connection.executeQuery(statement);
3624  long count = 0;
3625  if (rs.next()) {
3626  count = rs.getLong("count");
3627  }
3628  return count;
3629  } catch (SQLException ex) {
3630  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3631  } finally {
3632  closeResultSet(rs);
3633  closeConnection(connection);
3635  }
3636  }
3637 
3654  @Deprecated
3655  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3657  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3658  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3659  + "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, "
3660  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3661  + " arts.review_status_id AS review_status_id " //NON-NLS
3662  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3663  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3664  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3665  + " AND attrs.value_text = '" + value + "'"
3666  + " AND types.artifact_type_id=arts.artifact_type_id"
3667  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) { //NON-NLS
3668 
3669  List<Long> analysisArtifactObjIds = new ArrayList<>();
3670  List<Long> dataArtifactObjIds = new ArrayList<>();
3671  while (resultSet.next()) {
3672  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3673  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3674  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3675  } else {
3676  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3677  }
3678  }
3679 
3680  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3681  if (!analysisArtifactObjIds.isEmpty()) {
3682  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3683  }
3684 
3685  if (!dataArtifactObjIds.isEmpty()) {
3686  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3687  }
3688  return artifacts;
3689  } catch (SQLException ex) {
3690  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3691  } finally {
3693  }
3694  }
3695 
3714  @Deprecated
3715  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3716  String valSubStr = "%" + subString; //NON-NLS
3717  if (startsWith == false) {
3718  valSubStr += "%"; //NON-NLS
3719  }
3720 
3722  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3723  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3724  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.artifact_type_id AS artifact_type_id, " //NON-NLS
3725  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3726  + " arts.review_status_id AS review_status_id " //NON-NLS
3727  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3728  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3729  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3730  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3731  + " AND types.artifact_type_id=arts.artifact_type_id "
3732  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3733  List<Long> analysisArtifactObjIds = new ArrayList<>();
3734  List<Long> dataArtifactObjIds = new ArrayList<>();
3735  while (resultSet.next()) {
3736  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3737  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3738  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3739  } else {
3740  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3741  }
3742  }
3743 
3744  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3745  if (!analysisArtifactObjIds.isEmpty()) {
3746  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3747  }
3748 
3749  if (!dataArtifactObjIds.isEmpty()) {
3750  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3751  }
3752  return artifacts;
3753  } catch (SQLException ex) {
3754  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3755  } finally {
3757  }
3758  }
3759 
3775  @Deprecated
3776  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3778  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3779  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3780  + " 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, "
3781  + " types.type_name AS type_name, types.display_name AS display_name, "
3782  + " arts.review_status_id AS review_status_id "//NON-NLS
3783  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3784  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3785  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3786  + " AND attrs.value_int32 = " + value //NON-NLS
3787  + " AND types.artifact_type_id=arts.artifact_type_id "
3788  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3789  List<Long> analysisArtifactObjIds = new ArrayList<>();
3790  List<Long> dataArtifactObjIds = new ArrayList<>();
3791  while (resultSet.next()) {
3792  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3793  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3794  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3795  } else {
3796  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3797  }
3798  }
3799 
3800  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3801  if (!analysisArtifactObjIds.isEmpty()) {
3802  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3803  }
3804 
3805  if (!dataArtifactObjIds.isEmpty()) {
3806  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3807  }
3808  return artifacts;
3809  } catch (SQLException ex) {
3810  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3811  } finally {
3813  }
3814  }
3815 
3832  @Deprecated
3833  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3835  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3836  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3837  + " 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, "
3838  + " types.type_name AS type_name, types.display_name AS display_name, "
3839  + " arts.review_status_id AS review_status_id "//NON-NLS
3840  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3841  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3842  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3843  + " AND attrs.value_int64 = " + value //NON-NLS
3844  + " AND types.artifact_type_id=arts.artifact_type_id "
3845  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3846  List<Long> analysisArtifactObjIds = new ArrayList<>();
3847  List<Long> dataArtifactObjIds = new ArrayList<>();
3848  while (resultSet.next()) {
3849  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3850  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3851  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3852  } else {
3853  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3854  }
3855  }
3856 
3857  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3858  if (!analysisArtifactObjIds.isEmpty()) {
3859  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3860  }
3861 
3862  if (!dataArtifactObjIds.isEmpty()) {
3863  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3864  }
3865  return artifacts;
3866  } catch (SQLException ex) {
3867  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3868  } finally {
3870  }
3871  }
3872 
3889  @Deprecated
3890  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3892  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3893  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3894  + " 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, "
3895  + " types.type_name AS type_name, types.display_name AS display_name, "
3896  + " arts.review_status_id AS review_status_id "//NON-NLS
3897  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3898  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3899  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3900  + " AND attrs.value_double = " + value //NON-NLS
3901  + " AND types.artifact_type_id=arts.artifact_type_id "
3902  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3903  List<Long> analysisArtifactObjIds = new ArrayList<>();
3904  List<Long> dataArtifactObjIds = new ArrayList<>();
3905  while (resultSet.next()) {
3906  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3907  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3908  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3909  } else {
3910  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3911  }
3912  }
3913 
3914  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3915  if (!analysisArtifactObjIds.isEmpty()) {
3916  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3917  }
3918 
3919  if (!dataArtifactObjIds.isEmpty()) {
3920  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3921  }
3922  return artifacts;
3923  } catch (SQLException ex) {
3924  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3925  } finally {
3927  }
3928  }
3929 
3946  @Deprecated
3947  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3948 
3950  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3951  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3952  + " 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, "
3953  + " types.type_name AS type_name, types.display_name AS display_name, "
3954  + " arts.review_status_id AS review_status_id "//NON-NLS
3955  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3956  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3957  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3958  + " AND attrs.value_byte = " + value //NON-NLS
3959  + " AND types.artifact_type_id=arts.artifact_type_id "
3960  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3961  List<Long> analysisArtifactObjIds = new ArrayList<>();
3962  List<Long> dataArtifactObjIds = new ArrayList<>();
3963  while (resultSet.next()) {
3964  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
3965  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3966  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3967  } else {
3968  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3969  }
3970  }
3971 
3972  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3973  if (!analysisArtifactObjIds.isEmpty()) {
3974  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3975  }
3976 
3977  if (!dataArtifactObjIds.isEmpty()) {
3978  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3979  }
3980  return artifacts;
3981  } catch (SQLException ex) {
3982  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3983  } finally {
3985  }
3986  }
3987 
3995  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3996  CaseDbConnection connection = null;
3997  Statement s = null;
3998  ResultSet rs = null;
4000  try {
4001  connection = connections.getConnection();
4002  s = connection.createStatement();
4003  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
4004  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
4005  while (rs.next()) {
4006  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4007  rs.getString("type_name"), rs.getString("display_name"),
4008  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4009  }
4010  return artifactTypes;
4011  } catch (SQLException ex) {
4012  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
4013  } finally {
4014  closeResultSet(rs);
4015  closeStatement(s);
4016  closeConnection(connection);
4018  }
4019  }
4020 
4029  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
4030  String typeIdList = "";
4031  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
4032  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
4033  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
4034  typeIdList += ", ";
4035  }
4036  }
4037  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
4038  + "WHERE artifact_type_id IN (" + typeIdList + ")";
4039  CaseDbConnection connection = null;
4040  Statement s = null;
4041  ResultSet rs = null;
4043  try {
4044  connection = connections.getConnection();
4045  s = connection.createStatement();
4046  rs = connection.executeQuery(s, query);
4047  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
4048  while (rs.next()) {
4049  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
4050  }
4051  return usedArts;
4052  } catch (SQLException ex) {
4053  throw new TskCoreException("Error getting artifact types in use", ex);
4054  } finally {
4055  closeResultSet(rs);
4056  closeStatement(s);
4057  closeConnection(connection);
4059  }
4060  }
4061 
4072  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
4073  CaseDbConnection connection = null;
4074  Statement s = null;
4075  ResultSet rs = null;
4077  try {
4078  connection = connections.getConnection();
4079  s = connection.createStatement();
4080  rs = connection.executeQuery(s,
4081  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
4082  + "types.type_name AS type_name, "
4083  + "types.display_name AS display_name, "
4084  + "types.category_type AS category_type "
4085  + "FROM blackboard_artifact_types AS types "
4086  + "INNER JOIN blackboard_artifacts AS arts "
4087  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
4088  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
4089  while (rs.next()) {
4090  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4091  rs.getString("type_name"), rs.getString("display_name"),
4092  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4093  }
4094  return uniqueArtifactTypes;
4095  } catch (SQLException ex) {
4096  throw new TskCoreException("Error getting attribute types", ex);
4097  } finally {
4098  closeResultSet(rs);
4099  closeStatement(s);
4100  closeConnection(connection);
4102  }
4103  }
4104 
4112  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
4113  CaseDbConnection connection = null;
4114  Statement s = null;
4115  ResultSet rs = null;
4117  try {
4118  connection = connections.getConnection();
4119  s = connection.createStatement();
4120  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
4121  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
4122  while (rs.next()) {
4123  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4124  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
4125  }
4126  return attribute_types;
4127  } catch (SQLException ex) {
4128  throw new TskCoreException("Error getting attribute types", ex);
4129  } finally {
4130  closeResultSet(rs);
4131  closeStatement(s);
4132  closeConnection(connection);
4134  }
4135  }
4136 
4148  public int getBlackboardAttributeTypesCount() throws TskCoreException {
4149  CaseDbConnection connection = null;
4150  Statement s = null;
4151  ResultSet rs = null;
4153  try {
4154  connection = connections.getConnection();
4155  s = connection.createStatement();
4156  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4157  int count = 0;
4158  if (rs.next()) {
4159  count = rs.getInt("count");
4160  }
4161  return count;
4162  } catch (SQLException ex) {
4163  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4164  } finally {
4165  closeResultSet(rs);
4166  closeStatement(s);
4167  closeConnection(connection);
4169  }
4170  }
4171 
4184  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4185  CaseDbConnection connection = null;
4186  ResultSet rs = null;
4188  try {
4189  connection = connections.getConnection();
4190 
4191  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4192  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4193  statement.clearParameters();
4194  statement.setLong(1, obj_id);
4195  statement.setInt(2, artifactTypeID);
4196  rs = connection.executeQuery(statement);
4197  long count = 0;
4198  if (rs.next()) {
4199  count = rs.getLong("count");
4200  }
4201  return count;
4202  } catch (SQLException ex) {
4203  throw new TskCoreException("Error getting blackboard artifact count", ex);
4204  } finally {
4205  closeResultSet(rs);
4206  closeConnection(connection);
4208  }
4209  }
4210 
4223  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4224  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4225  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeName), obj_id));
4226  return artifacts;
4227  }
4228 
4241  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4242  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4243  artifacts.addAll(blackboard.getArtifactsBySourceId(blackboard.getArtifactType(artifactTypeID), obj_id));
4244  return artifacts;
4245  }
4246 
4259  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4260  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4261  }
4262 
4275  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4276  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4277  if (artifactTypeID == -1) {
4278  return 0;
4279  }
4280  return getArtifactsCountHelper(artifactTypeID, obj_id);
4281  }
4282 
4295  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4296  return getArtifactsCountHelper(artifactTypeID, obj_id);
4297  }
4298 
4311  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4312  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4313  }
4314 
4326  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4327  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4328  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeName)));
4329  return artifacts;
4330  }
4331 
4343  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4344  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4345  artifacts.addAll(blackboard.getArtifactsByType(blackboard.getArtifactType(artifactType.getTypeID())));
4346  return artifacts;
4347  }
4348 
4364  @Deprecated
4365  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4366 
4367  String dataArtifactJoin = "tsk_data_artifacts AS datarts ON datarts.artifact_obj_id = arts.artifact_obj_id";
4368  String analysisResultJoin = "tsk_analysis_results AS anresult ON anresult.artifact_obj_id = arts.artifact_obj_id";
4369  String dataArtifactColumns = ", datarts.os_account_obj_id AS os_account_obj_id";
4370  String analysResultColumns = ", anresult.conclusion AS conclusion, anresult.significance AS significance, anresult.priority AS priority, anresult.configuration AS configuration, anresult.justification AS justification ";
4371 
4372  String formatQuery = "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4373  + "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, "
4374  + "types.type_name AS type_name, types.display_name AS display_name,"
4375  + "arts.review_status_id AS review_status_id %s "//NON-NLS
4376  + "FROM blackboard_artifacts AS arts "
4377  + "JOIN blackboard_attributes AS attrs ON arts.artifact_id = attrs.artifact_id "
4378  + "JOIN blackboard_artifact_types AS types ON types.artifact_type_id = arts.artifact_type_id " //NON-NLS
4379  + "LEFT JOIN %s "
4380  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4381  + "AND attrs.attribute_type_id = %d "
4382  + " AND arts.artifact_type_id = %d "
4383  + " AND attrs.value_text = '%s' " //NON-NLS
4384  + " AND types.artifact_type_id=arts.artifact_type_id "
4385  + " AND arts.review_status_id != %d";
4386 
4387  String query = String.format(formatQuery,
4388  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysResultColumns : dataArtifactColumns),
4389  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysisResultJoin : dataArtifactJoin),
4390  attrType.getTypeID(),
4391  artifactType.getTypeID(),
4392  value,
4394 
4396  try (CaseDbConnection connection = connections.getConnection(); Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
4397  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4398  while (rs.next()) {
4399  if (artifactType.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
4400  Long osAccountObjId = rs.getLong("os_account_obj_id");
4401  if (rs.wasNull()) {
4402  osAccountObjId = null;
4403  }
4404 
4405  artifacts.add(new DataArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4406  rs.getLong("artifact_obj_id"),
4407  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4408  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4409  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")), osAccountObjId, false));
4410  } else {
4411  artifacts.add(new AnalysisResult(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4412  rs.getLong("artifact_obj_id"),
4413  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4414  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4415  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")),
4416  new Score(Score.Significance.fromID(rs.getInt("significance")), Score.Priority.fromID(rs.getInt("priority"))),
4417  rs.getString("conclusion"), rs.getString("configuration"), rs.getString("justification")));
4418  }
4419  }
4420  return artifacts;
4421  } catch (SQLException ex) {
4422  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4423  } finally {
4425  }
4426  }
4427 
4439  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4440  List<DataArtifact> dataArtifacts = blackboard.getDataArtifactsWhere("artifacts.artifact_id = " + artifactID);
4441  if (!dataArtifacts.isEmpty()) {
4442  return dataArtifacts.get(0);
4443  }
4444 
4445  List<AnalysisResult> analysisResults = blackboard.getAnalysisResultsWhere("artifacts.artifact_id = " + artifactID);
4446  if (!analysisResults.isEmpty()) {
4447  return analysisResults.get(0);
4448  }
4449 
4450  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4451  }
4452 
4461  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4463  try (CaseDbConnection connection = connections.getConnection();) {
4464  addBlackBoardAttribute(attr, artifactTypeId, connection);
4465  } catch (SQLException ex) {
4466  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4467  } finally {
4469  }
4470  }
4471 
4481  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4482  CaseDbConnection connection = null;
4484  try {
4485  connection = connections.getConnection();
4486  connection.beginTransaction();
4487  for (final BlackboardAttribute attr : attributes) {
4488  addBlackBoardAttribute(attr, artifactTypeId, connection);
4489  }
4490  connection.commitTransaction();
4491  } catch (SQLException ex) {
4492  rollbackTransaction(connection);
4493  throw new TskCoreException("Error adding blackboard attributes", ex);
4494  } finally {
4495  closeConnection(connection);
4497  }
4498  }
4499 
4500  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4501  PreparedStatement statement;
4502  switch (attr.getAttributeType().getValueType()) {
4503  case STRING:
4504  case JSON:
4505  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4506  statement.clearParameters();
4507  statement.setString(7, attr.getValueString());
4508  break;
4509  case BYTE:
4510  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4511  statement.clearParameters();
4512  statement.setBytes(7, attr.getValueBytes());
4513  break;
4514  case INTEGER:
4515  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4516  statement.clearParameters();
4517  statement.setInt(7, attr.getValueInt());
4518  break;
4519  case LONG:
4520  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4521  statement.clearParameters();
4522  statement.setLong(7, attr.getValueLong());
4523  break;
4524  case DOUBLE:
4525  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4526  statement.clearParameters();
4527  statement.setDouble(7, attr.getValueDouble());
4528  break;
4529  case DATETIME:
4530  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4531  statement.clearParameters();
4532  statement.setLong(7, attr.getValueLong());
4533  break;
4534  default:
4535  throw new TskCoreException("Unrecognized artifact attribute value type");
4536  }
4537  statement.setLong(1, attr.getArtifactID());
4538  statement.setInt(2, artifactTypeId);
4539  statement.setString(3, attr.getSourcesCSV());
4540  statement.setString(4, "");
4541  statement.setInt(5, attr.getAttributeType().getTypeID());
4542  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4543  connection.executeUpdate(statement);
4544  }
4545 
4546  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4547  PreparedStatement statement;
4548  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4549  statement.clearParameters();
4550 
4551  statement.setLong(1, attr.getAttributeParentId());
4552  statement.setInt(2, attr.getAttributeType().getTypeID());
4553  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4554 
4555  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4556  statement.setBytes(4, attr.getValueBytes());
4557  } else {
4558  statement.setBytes(4, null);
4559  }
4560 
4561  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4562  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4563  statement.setString(5, attr.getValueString());
4564  } else {
4565  statement.setString(5, null);
4566  }
4567  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4568  statement.setInt(6, attr.getValueInt());
4569  } else {
4570  statement.setNull(6, java.sql.Types.INTEGER);
4571  }
4572 
4573  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4574  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4575  statement.setLong(7, attr.getValueLong());
4576  } else {
4577  statement.setNull(7, java.sql.Types.BIGINT);
4578  }
4579 
4580  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4581  statement.setDouble(8, attr.getValueDouble());
4582  } else {
4583  statement.setNull(8, java.sql.Types.DOUBLE);
4584  }
4585 
4586  connection.executeUpdate(statement);
4587  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4588  if (!resultSet.next()) {
4589  throw new TskCoreException(String.format("Failed to insert file attribute "
4590  + "with id=%d. The expected key was not generated", attr.getId()));
4591  }
4592 
4593  attr.setId(resultSet.getLong(1));
4594  }
4595  }
4596 
4607  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
4608  /*
4609  * WARNING: This is a temporary implementation that is not safe and
4610  * denormalizes the case datbase.
4611  *
4612  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
4613  * the sources of artifact attributes.
4614  */
4615  if (null == source || source.isEmpty()) {
4616  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
4617  }
4618  CaseDbConnection connection = null;
4620  Statement queryStmt = null;
4621  Statement updateStmt = null;
4622  ResultSet result = null;
4623  String newSources = "";
4624  try {
4625  connection = connections.getConnection();
4626  connection.beginTransaction();
4627  String valueClause = "";
4628  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
4629  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4630  switch (valueType) {
4631  case STRING:
4632  case JSON:
4633  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
4634  break;
4635  case INTEGER:
4636  valueClause = " value_int32 = " + attr.getValueInt();
4637  break;
4638  case LONG:
4639  case DATETIME:
4640  valueClause = " value_int64 = " + attr.getValueLong();
4641  break;
4642  case DOUBLE:
4643  valueClause = " value_double = " + attr.getValueDouble();
4644  break;
4645  default:
4646  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4647  }
4648  String query = "SELECT source FROM blackboard_attributes WHERE"
4649  + " artifact_id = " + attr.getArtifactID()
4650  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4651  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4652  + " AND " + valueClause + ";";
4653  queryStmt = connection.createStatement();
4654  updateStmt = connection.createStatement();
4655  result = connection.executeQuery(queryStmt, query);
4656  } else {
4657  /*
4658  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4659  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4660  * = ?
4661  */
4662  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4663  statement.clearParameters();
4664  statement.setLong(1, attr.getArtifactID());
4665  statement.setLong(2, attr.getAttributeType().getTypeID());
4666  statement.setBytes(3, attr.getValueBytes());
4667  result = connection.executeQuery(statement);
4668  }
4669  while (result.next()) {
4670  String oldSources = result.getString("source");
4671  if (null != oldSources && !oldSources.isEmpty()) {
4672  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4673  if (!uniqueSources.contains(source)) {
4674  newSources = oldSources + "," + source;
4675  } else {
4676  newSources = oldSources;
4677  }
4678  } else {
4679  newSources = source;
4680  }
4681  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4682  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4683  + " artifact_id = " + attr.getArtifactID()
4684  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4685  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4686  + " AND " + valueClause + ";";
4687  connection.executeUpdate(updateStmt, update);
4688  } else {
4689  /*
4690  * UPDATE blackboard_attributes SET source = ? WHERE
4691  * artifact_id = ? AND attribute_type_id = ? AND value_type
4692  * = 4 AND value_byte = ?
4693  */
4694  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4695  statement.clearParameters();
4696  statement.setString(1, newSources);
4697  statement.setLong(2, attr.getArtifactID());
4698  statement.setLong(3, attr.getAttributeType().getTypeID());
4699  statement.setBytes(4, attr.getValueBytes());
4700  connection.executeUpdate(statement);
4701  }
4702  }
4703  connection.commitTransaction();
4704  return newSources;
4705  } catch (SQLException ex) {
4706  rollbackTransaction(connection);
4707  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4708  } finally {
4709  closeResultSet(result);
4710  closeStatement(updateStmt);
4711  closeStatement(queryStmt);
4712  closeConnection(connection);
4714  }
4715  }
4716 
4731  @Deprecated
4732  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4733  try {
4734  return blackboard.getOrAddAttributeType(attrTypeString, valueType, displayName);
4735  } catch (BlackboardException ex) {
4736  throw new TskCoreException("Error adding artifact type: " + attrTypeString, ex);
4737  }
4738  }
4739 
4751  @Deprecated
4752  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4753  return blackboard.getAttributeType(attrTypeName);
4754  }
4755 
4767  @Deprecated
4768  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4769  return blackboard.getArtifactType(artTypeName);
4770  }
4771 
4788  @Deprecated
4789  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4790  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
4791  }
4792 
4808  @Deprecated
4809  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
4810  try {
4811  return blackboard.getOrAddArtifactType(displayName, displayName, category);
4812  } catch (BlackboardException ex) {
4813  throw new TskCoreException("Error getting or adding artifact type with name: " + artifactTypeName, ex);
4814  }
4815  }
4816 
4828  @Deprecated
4829  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4830  return blackboard.getBlackboardAttributes(artifact);
4831  }
4832 
4833 
4846  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
4847  CaseDbConnection connection = null;
4848  Statement s = null;
4849  ResultSet rs = null;
4851  try {
4852  connection = connections.getConnection();
4853  s = connection.createStatement();
4854  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
4855  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
4856  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
4857  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
4858  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
4859  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
4860  + "FROM blackboard_attributes " + whereClause); //NON-NLS
4861  ArrayList<BlackboardAttribute> matches = new ArrayList<>();
4862  while (rs.next()) {
4864  // attribute type is cached, so this does not necessarily call to the db
4865  type = blackboard.getAttributeType(rs.getInt("attribute_type_id"));
4867  rs.getLong("artifact_id"),
4868  type,
4869  rs.getString("source"),
4870  rs.getString("context"),
4871  rs.getInt("value_int32"),
4872  rs.getLong("value_int64"),
4873  rs.getDouble("value_double"),
4874  rs.getString("value_text"),
4875  rs.getBytes("value_byte"), this
4876  );
4877  matches.add(attr);
4878  }
4879  return matches;
4880  } catch (SQLException ex) {
4881  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4882  } finally {
4883  closeResultSet(rs);
4884  closeStatement(s);
4885  closeConnection(connection);
4887  }
4888  }
4889 
4901  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
4902  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
4903  + "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, "
4904  + "blackboard_artifacts.review_status_id AS review_status_id "
4905  + "FROM blackboard_artifacts " + whereClause;
4907  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
4908 
4909  List<Long> analysisArtifactObjIds = new ArrayList<>();
4910  List<Long> dataArtifactObjIds = new ArrayList<>();
4911  while (resultSet.next()) {
4912  BlackboardArtifact.Type type = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
4913  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
4914  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4915  } else {
4916  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
4917  }
4918  }
4919 
4920  ArrayList<BlackboardArtifact> matches = new ArrayList<>();
4921  if (!analysisArtifactObjIds.isEmpty()) {
4922  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
4923  }
4924 
4925  if (!dataArtifactObjIds.isEmpty()) {
4926  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
4927  }
4928 
4929  return matches;
4930  } catch (SQLException ex) {
4931  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
4932  } finally {
4934  }
4935  }
4936 
4951  @Deprecated
4952  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
4953  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
4954  if (type == null) {
4955  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
4956  }
4957 
4958  Category category = type.getCategory();
4959  if (category == null) {
4960  throw new TskCoreException(String.format("No category for %s (id: %d)",
4961  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
4962  type.getTypeID()));
4963  }
4964 
4965  Content content = getContentById(obj_id);
4966  if (content == null) {
4967  throw new TskCoreException("No content found for object id: " + obj_id);
4968  }
4969 
4970  switch (category) {
4971  case ANALYSIS_RESULT:
4972  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
4973  .getAnalysisResult();
4974  case DATA_ARTIFACT:
4975  return content.newDataArtifact(type, Collections.emptyList());
4976  default:
4977  throw new TskCoreException("Unknown category type: " + category.getName());
4978  }
4979  }
4980 
4993  @Deprecated
4994  @SuppressWarnings("deprecation")
4995  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4996  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
4997  }
4998 
5014  @Deprecated
5015  @SuppressWarnings("deprecation")
5016  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5017  BlackboardArtifact.Type type = blackboard.getArtifactType(artifactTypeID);
5018  try (CaseDbConnection connection = connections.getConnection()) {
5019  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5020  }
5021  }
5022 
5023  @Deprecated
5024  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5025  try (CaseDbConnection connection = connections.getConnection()) {
5026  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5027  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5028  }
5029  }
5030 
5031  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5032 
5033  PreparedStatement statement;
5034  if (dbType == DbType.POSTGRESQL) {
5035  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5036  statement.clearParameters();
5037  statement.setLong(1, obj_id);
5038  statement.setLong(2, artifact_obj_id);
5039  statement.setLong(3, data_source_obj_id);
5040  statement.setInt(4, artifact_type_id);
5041  } else {
5042  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5043  statement.clearParameters();
5044  this.nextArtifactId++;
5045  statement.setLong(1, this.nextArtifactId);
5046  statement.setLong(2, obj_id);
5047  statement.setLong(3, artifact_obj_id);
5048  statement.setLong(4, data_source_obj_id);
5049  statement.setInt(5, artifact_type_id);
5050  }
5051 
5052  return statement;
5053  }
5054 
5071  @Deprecated
5072  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5073  BlackboardArtifact.Type type = blackboard.getArtifactType(artifact_type_id);
5074  try {
5075  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5076  return blackboard.newAnalysisResult(type, obj_id, data_source_obj_id, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList()).getAnalysisResult();
5077  } else {
5078  return blackboard.newDataArtifact(type, obj_id, data_source_obj_id, Collections.emptyList(), null);
5079  }
5080  } catch (BlackboardException ex) {
5081  throw new TskCoreException("Error creating a blackboard artifact", ex);
5082  }
5083  }
5084 
5103  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5104 
5105  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5106  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5107  }
5108 
5109  long artifactID;
5111  try {
5112  // add a row in tsk_objects
5113  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5114 
5115  // add a row in blackboard_artifacts table
5116  PreparedStatement insertArtifactstatement;
5117  ResultSet resultSet = null;
5118  try {
5119  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5120  connection.executeUpdate(insertArtifactstatement);
5121  resultSet = insertArtifactstatement.getGeneratedKeys();
5122  resultSet.next();
5123  artifactID = resultSet.getLong(1); //last_insert_rowid()
5124 
5125  // add a row in tsk_analysis_results if any data for it is set
5126  if (score.getSignificance() != Score.Significance.UNKNOWN
5127  || !StringUtils.isBlank(conclusion)
5128  || !StringUtils.isBlank(configuration)
5129  || !StringUtils.isBlank(justification)) {
5130 
5131  PreparedStatement analysisResultsStatement;
5132 
5133  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5134  analysisResultsStatement.clearParameters();
5135 
5136  analysisResultsStatement.setLong(1, artifactObjId);
5137  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5138  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5139  analysisResultsStatement.setInt(4, score.getPriority().getId());
5140  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5141  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5142 
5143  connection.executeUpdate(analysisResultsStatement);
5144  }
5145 
5146  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5147  artifactType.getTypeName(), artifactType.getDisplayName(),
5148  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5149  score, (conclusion != null) ? conclusion : "",
5150  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5151 
5152  } finally {
5153  closeResultSet(resultSet);
5154  }
5155 
5156  } catch (SQLException ex) {
5157  throw new TskCoreException("Error creating a analysis result", ex);
5158  } finally {
5160  }
5161  }
5162 
5175  boolean getContentHasChildren(Content content) throws TskCoreException {
5176  CaseDbConnection connection = null;
5177  ResultSet rs = null;
5179  try {
5180  connection = connections.getConnection();
5181 
5182  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5183  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5184  statement.clearParameters();
5185  statement.setLong(1, content.getId());
5186  rs = connection.executeQuery(statement);
5187  boolean hasChildren = false;
5188  if (rs.next()) {
5189  hasChildren = rs.getInt("count") > 0;
5190  }
5191  return hasChildren;
5192  } catch (SQLException e) {
5193  throw new TskCoreException("Error checking for children of parent " + content, e);
5194  } finally {
5195  closeResultSet(rs);
5196  closeConnection(connection);
5198  }
5199  }
5200 
5213  int getContentChildrenCount(Content content) throws TskCoreException {
5214 
5215  if (!this.getHasChildren(content)) {
5216  return 0;
5217  }
5218 
5219  CaseDbConnection connection = null;
5220  ResultSet rs = null;
5222  try {
5223  connection = connections.getConnection();
5224 
5225  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5226  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5227  statement.clearParameters();
5228  statement.setLong(1, content.getId());
5229  rs = connection.executeQuery(statement);
5230  int countChildren = -1;
5231  if (rs.next()) {
5232  countChildren = rs.getInt("count");
5233  }
5234  return countChildren;
5235  } catch (SQLException e) {
5236  throw new TskCoreException("Error checking for children of parent " + content, e);
5237  } finally {
5238  closeResultSet(rs);
5239  closeConnection(connection);
5241  }
5242  }
5243 
5255  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5256  CaseDbConnection connection = null;
5257  ResultSet rs = null;
5259  try {
5260  connection = connections.getConnection();
5261 
5262  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5263  statement.clearParameters();
5264  long parentId = parent.getId();
5265  statement.setLong(1, parentId);
5266  statement.setShort(2, type.getFileType());
5267  rs = connection.executeQuery(statement);
5268  return fileChildren(rs, connection, parentId);
5269  } catch (SQLException ex) {
5270  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5271  } finally {
5272  closeResultSet(rs);
5273  closeConnection(connection);
5275  }
5276  }
5277 
5287  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5288  CaseDbConnection connection = null;
5289  ResultSet rs = null;
5291  try {
5292  connection = connections.getConnection();
5293 
5294  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5295  statement.clearParameters();
5296  long parentId = parent.getId();
5297  statement.setLong(1, parentId);
5298  rs = connection.executeQuery(statement);
5299  return fileChildren(rs, connection, parentId);
5300  } catch (SQLException ex) {
5301  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5302  } finally {
5303  closeResultSet(rs);
5304  closeConnection(connection);
5306  }
5307  }
5308 
5320  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5321  CaseDbConnection connection = null;
5322  ResultSet rs = null;
5324  try {
5325  connection = connections.getConnection();
5326 
5327  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5328  statement.clearParameters();
5329  statement.setLong(1, parent.getId());
5330  statement.setShort(2, type.getFileType());
5331  rs = connection.executeQuery(statement);
5332  List<Long> children = new ArrayList<Long>();
5333  while (rs.next()) {
5334  children.add(rs.getLong("obj_id"));
5335  }
5336  return children;
5337  } catch (SQLException ex) {
5338  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5339  } finally {
5340  closeResultSet(rs);
5341  closeConnection(connection);
5343  }
5344  }
5345 
5355  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5356  CaseDbConnection connection = null;
5357  ResultSet rs = null;
5359  try {
5360  connection = connections.getConnection();
5361 
5362  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5363  statement.clearParameters();
5364  statement.setLong(1, parent.getId());
5365  rs = connection.executeQuery(statement);
5366  List<Long> children = new ArrayList<Long>();
5367  while (rs.next()) {
5368  children.add(rs.getLong("obj_id"));
5369  }
5370  return children;
5371  } catch (SQLException ex) {
5372  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5373  } finally {
5374  closeResultSet(rs);
5375  closeConnection(connection);
5377  }
5378  }
5379 
5390  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5391  CaseDbConnection connection = null;
5392  ResultSet rs = null;
5394  try {
5395  connection = connections.getConnection();
5396 
5397  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5398  statement.clearParameters();
5399  statement.setLong(1, parent.getId());
5400  rs = connection.executeQuery(statement);
5401  List<Long> children = new ArrayList<Long>();
5402  while (rs.next()) {
5403  children.add(rs.getLong("obj_id"));
5404  }
5405  return children;
5406  } catch (SQLException ex) {
5407  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5408  } finally {
5409  closeResultSet(rs);
5410  closeConnection(connection);
5412  }
5413  }
5414 
5424  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5425  long parentId = parent.getId();
5426  List<Content> lc = new ArrayList<>();
5427  lc.addAll(blackboard.getAnalysisResults(parentId));
5428  lc.addAll(blackboard.getDataArtifactsBySource(parentId));
5429  return lc;
5430  }
5431 
5440  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5441  CaseDbConnection connection = null;
5442  Statement s = null;
5443  ResultSet rs = null;
5445  try {
5446  connection = connections.getConnection();
5447  s = connection.createStatement();
5448  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5449  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5450  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5451  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5452  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5453  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5454  while (rs.next()) {
5455  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5456  }
5457  return infos;
5458  } catch (SQLException ex) {
5459  throw new TskCoreException("Error getting Children Info for Content", ex);
5460  } finally {
5461  closeResultSet(rs);
5462  closeStatement(s);
5463  closeConnection(connection);
5465  }
5466  }
5467 
5478  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5479  return getParentInfo(c.getId());
5480  }
5481 
5492  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5494  CaseDbConnection connection = null;
5495  Statement s = null;
5496  ResultSet rs = null;
5497  try {
5498  connection = connections.getConnection();
5499  s = connection.createStatement();
5500  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5501  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5502  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5503  + "WHERE child.obj_id = " + contentId); //NON-NLS
5504  if (rs.next()) {
5505  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5506  } else {
5507  return null;
5508  }
5509  } catch (SQLException ex) {
5510  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5511  } finally {
5512  closeResultSet(rs);
5513  closeStatement(s);
5514  closeConnection(connection);
5516  }
5517  }
5518 
5529  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5530  if (fsc.isRoot()) {
5531  // Given FsContent is a root object and can't have parent directory
5532  return null;
5533  } else {
5534  ObjectInfo parentInfo = getParentInfo(fsc);
5535  if (parentInfo == null) {
5536  return null;
5537  }
5538  Directory parent = null;
5539  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
5540  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
5541  } else {
5542  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
5543  }
5544  return parent;
5545  }
5546  }
5547 
5559  public Content getContentById(long id) throws TskCoreException {
5560  // First check to see if this exists in our frequently used content cache.
5561  Content content = frequentlyUsedContentMap.get(id);
5562  if (null != content) {
5563  return content;
5564  }
5565 
5566  long parentId;
5567  TskData.ObjectType type;
5568 
5569  CaseDbConnection connection = null;
5570  Statement s = null;
5571  ResultSet rs = null;
5573  try {
5574  connection = connections.getConnection();
5575  s = connection.createStatement();
5576  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
5577  if (!rs.next()) {
5578  return null;
5579  }
5580  parentId = rs.getLong("par_obj_id"); //NON-NLS
5581  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
5582  } catch (SQLException ex) {
5583  throw new TskCoreException("Error getting Content by ID.", ex);
5584  } finally {
5585  closeResultSet(rs);
5586  closeStatement(s);
5587  closeConnection(connection);
5589  }
5590 
5591  // Construct the object
5592  switch (type) {
5593  case IMG:
5594  content = getImageById(id);
5595  frequentlyUsedContentMap.put(id, content);
5596  break;
5597  case VS:
5598  content = getVolumeSystemById(id, parentId);
5599  break;
5600  case VOL:
5601  content = getVolumeById(id, parentId);
5602  frequentlyUsedContentMap.put(id, content);
5603  break;
5604  case POOL:
5605  content = getPoolById(id, parentId);
5606  break;
5607  case FS:
5608  content = getFileSystemById(id, parentId);
5609  frequentlyUsedContentMap.put(id, content);
5610  break;
5611  case ABSTRACTFILE:
5612  content = getAbstractFileById(id);
5613 
5614  // Add virtual and root directories to frequently used map.
5615  // Calling isRoot() on local directories goes up the entire directory structure
5616  // and they can only be the root of portable cases, so skip trying to add
5617  // them to the cache.
5618  if (((AbstractFile) content).isVirtual()
5619  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5620  frequentlyUsedContentMap.put(id, content);
5621  }
5622  break;
5623  case ARTIFACT:
5624  content = getArtifactById(id);
5625  break;
5626  case REPORT:
5627  content = getReportById(id);
5628  break;
5629  case OS_ACCOUNT:
5630  content = this.osAccountManager.getOsAccountByObjectId(id);
5631  break;
5632  case HOST_ADDRESS:
5633  content = hostAddressManager.getHostAddress(id);
5634  break;
5635  default:
5636  content = new UnsupportedContent(this, id);
5637  }
5638 
5639  return content;
5640  }
5641 
5649  String getFilePath(long id) {
5650 
5651  String filePath = null;
5652  CaseDbConnection connection = null;
5653  ResultSet rs = null;
5655  try {
5656  connection = connections.getConnection();
5657 
5658  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5659  statement.clearParameters();
5660  statement.setLong(1, id);
5661  rs = connection.executeQuery(statement);
5662  if (rs.next()) {
5663  filePath = rs.getString("path");
5664  }
5665  } catch (SQLException | TskCoreException ex) {
5666  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5667  } finally {
5668  closeResultSet(rs);
5669  closeConnection(connection);
5671  }
5672  return filePath;
5673  }
5674 
5682  TskData.EncodingType getEncodingType(long id) {
5683 
5684  TskData.EncodingType type = TskData.EncodingType.NONE;
5685  CaseDbConnection connection = null;
5686  ResultSet rs = null;
5688  try {
5689  connection = connections.getConnection();
5690  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5691  statement.clearParameters();
5692  statement.setLong(1, id);
5693  rs = connection.executeQuery(statement);
5694  if (rs.next()) {
5695  type = TskData.EncodingType.valueOf(rs.getInt(1));
5696  }
5697  } catch (SQLException | TskCoreException ex) {
5698  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5699  } finally {
5700  closeResultSet(rs);
5701  closeConnection(connection);
5703  }
5704  return type;
5705  }
5706 
5715  String getFileParentPath(long objectId, CaseDbConnection connection) {
5716  String parentPath = null;
5718  ResultSet rs = null;
5719  try {
5720  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5721  statement.clearParameters();
5722  statement.setLong(1, objectId);
5723  rs = connection.executeQuery(statement);
5724  if (rs.next()) {
5725  parentPath = rs.getString("parent_path");
5726  }
5727  } catch (SQLException ex) {
5728  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5729  } finally {
5730  closeResultSet(rs);
5732  }
5733  return parentPath;
5734  }
5735 
5744  String getFileName(long objectId, CaseDbConnection connection) {
5745  String fileName = null;
5747  ResultSet rs = null;
5748  try {
5749  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5750  statement.clearParameters();
5751  statement.setLong(1, objectId);
5752  rs = connection.executeQuery(statement);
5753  if (rs.next()) {
5754  fileName = rs.getString("name");
5755  }
5756  } catch (SQLException ex) {
5757  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5758  } finally {
5759  closeResultSet(rs);
5761  }
5762  return fileName;
5763  }
5764 
5775  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5776 
5777  DerivedFile.DerivedMethod method = null;
5778  CaseDbConnection connection = null;
5779  ResultSet rs1 = null;
5780  ResultSet rs2 = null;
5782  try {
5783  connection = connections.getConnection();
5784 
5785  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5786  statement.clearParameters();
5787  statement.setLong(1, id);
5788  rs1 = connection.executeQuery(statement);
5789  if (rs1.next()) {
5790  int method_id = rs1.getInt("derived_id");
5791  String rederive = rs1.getString("rederive");
5792  method = new DerivedFile.DerivedMethod(method_id, rederive);
5793  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5794  statement.clearParameters();
5795  statement.setInt(1, method_id);
5796  rs2 = connection.executeQuery(statement);
5797  if (rs2.next()) {
5798  method.setToolName(rs2.getString("tool_name"));
5799  method.setToolVersion(rs2.getString("tool_version"));
5800  method.setOther(rs2.getString("other"));
5801  }
5802  }
5803  } catch (SQLException e) {
5804  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5805  } finally {
5806  closeResultSet(rs2);
5807  closeResultSet(rs1);
5808  closeConnection(connection);
5810  }
5811  return method;
5812  }
5813 
5824  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
5825  CaseDbConnection connection = connections.getConnection();
5826  try {
5827  return getAbstractFileById(id, connection);
5828  } finally {
5829  closeConnection(connection);
5830  }
5831  }
5832 
5845  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
5847  ResultSet rs = null;
5848  try {
5849  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
5850  statement.clearParameters();
5851  statement.setLong(1, objectId);
5852  rs = connection.executeQuery(statement);
5853  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
5854  if (files.size() > 0) {
5855  return files.get(0);
5856  } else {
5857  return null;
5858  }
5859  } catch (SQLException ex) {
5860  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
5861  } finally {
5862  closeResultSet(rs);
5864  }
5865  }
5866 
5878  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
5879 
5880  CaseDbConnection connection = null;
5881  ResultSet rs = null;
5883  try {
5884  connection = connections.getConnection();
5885 
5886  // get the artifact type.
5887  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
5888  statement.clearParameters();
5889  statement.setLong(1, id);
5890 
5891  rs = connection.executeQuery(statement);
5892  if (!rs.next()) {
5893  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
5894  }
5895 
5896  // based on the artifact type category, get the analysis result or the data artifact
5897  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(rs.getInt("artifact_type_id"));
5898  switch (artifactType.getCategory()) {
5899  case ANALYSIS_RESULT:
5900  return blackboard.getAnalysisResultById(id);
5901  case DATA_ARTIFACT:
5902  return blackboard.getDataArtifactById(id);
5903  default:
5904  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
5905  }
5906 
5907  } catch (SQLException ex) {
5908  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
5909  } finally {
5910  closeResultSet(rs);
5911  closeConnection(connection);
5913  }
5914  }
5915 
5929  @Deprecated
5930  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
5931  String query = "SELECT artifact_type_id, artifact_obj_id FROM blackboard_artifacts WHERE artifact_id = " + id;
5933 
5934  try (CaseDbConnection connection = connections.getConnection();
5935  Statement statement = connection.createStatement();
5936  ResultSet resultSet = statement.executeQuery(query);) {
5937  if (resultSet != null && resultSet.next()) {
5938  BlackboardArtifact.Type artifactType = blackboard.getArtifactType(resultSet.getInt("artifact_type_id"));
5939  long artifactObjId = resultSet.getLong("artifact_obj_id");
5940  switch (artifactType.getCategory()) {
5941  case ANALYSIS_RESULT:
5942  return blackboard.getAnalysisResultById(artifactObjId);
5943  case DATA_ARTIFACT:
5944  return blackboard.getDataArtifactById(artifactObjId);
5945  }
5946  }
5947  return null;
5948  } catch (SQLException ex) {
5949  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
5950  } finally {
5952  }
5953  }
5954 
5967  private long getFileSystemId(long fileId, CaseDbConnection connection) {
5969  ResultSet rs = null;
5970  long ret = -1;
5971  try {
5972  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
5973  statement.clearParameters();
5974  statement.setLong(1, fileId);
5975  rs = connection.executeQuery(statement);
5976  if (rs.next()) {
5977  ret = rs.getLong("fs_obj_id");
5978  if (ret == 0) {
5979  ret = -1;
5980  }
5981  }
5982  } catch (SQLException e) {
5983  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
5984  } finally {
5985  closeResultSet(rs);
5987  }
5988  return ret;
5989  }
5990 
6002  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6003  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
6004  CaseDbConnection connection = null;
6005  Statement statement = null;
6006  ResultSet resultSet = null;
6008  try {
6009  connection = connections.getConnection();
6010  statement = connection.createStatement();
6011  resultSet = connection.executeQuery(statement, query);
6012  resultSet.next();
6013  return (resultSet.getLong("count") > 0L);
6014  } catch (SQLException ex) {
6015  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6016  } finally {
6017  closeResultSet(resultSet);
6018  closeStatement(statement);
6019  closeConnection(connection);
6021  }
6022  }
6023 
6033  private static boolean containsLikeWildcard(String str) {
6034  if (str == null) {
6035  return false;
6036  } else {
6037  return str.contains("%") || str.contains("_");
6038  }
6039  }
6040 
6052  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6053  String ext = "";
6054  if (!containsLikeWildcard(fileName)) {
6055  ext = SleuthkitCase.extractExtension(fileName);
6056  }
6057 
6058  List<AbstractFile> files = new ArrayList<>();
6059  CaseDbConnection connection = null;
6060  ResultSet resultSet = null;
6062  try {
6063  connection = connections.getConnection();
6064 
6065  PreparedStatement statement;
6066  if (ext.isEmpty()) {
6067  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6068  statement.clearParameters();
6069  statement.setString(1, fileName.toLowerCase());
6070  statement.setLong(2, dataSource.getId());
6071  } else {
6072  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6073  statement.clearParameters();
6074  statement.setString(1, ext);
6075  statement.setString(2, fileName.toLowerCase());
6076  statement.setLong(3, dataSource.getId());
6077  }
6078 
6079  resultSet = connection.executeQuery(statement);
6080  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6081  } catch (SQLException e) {
6082  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6083  } finally {
6084  closeResultSet(resultSet);
6085  closeConnection(connection);
6087  }
6088  return files;
6089  }
6090 
6104  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6105  String ext = "";
6106  if (!containsLikeWildcard(fileName)) {
6107  ext = SleuthkitCase.extractExtension(fileName);
6108  }
6109 
6110  List<AbstractFile> files = new ArrayList<>();
6111  CaseDbConnection connection = null;
6112  ResultSet resultSet = null;
6114  try {
6115  connection = connections.getConnection();
6116  PreparedStatement statement;
6117  if (ext.isEmpty()) {
6118  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6119  statement.clearParameters();
6120  statement.setString(1, fileName.toLowerCase());
6121  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6122  statement.setLong(3, dataSource.getId());
6123  } else {
6124  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6125  statement.clearParameters();
6126  statement.setString(1, ext);
6127  statement.setString(2, fileName.toLowerCase());
6128  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6129  statement.setLong(4, dataSource.getId());
6130  }
6131 
6132  resultSet = connection.executeQuery(statement);
6133  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6134  } catch (SQLException e) {
6135  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6136  } finally {
6137  closeResultSet(resultSet);
6138  closeConnection(connection);
6140  }
6141  return files;
6142  }
6143 
6155  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6156  CaseDbTransaction localTrans = beginTransaction();
6157  try {
6158  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6159  localTrans.commit();
6160  localTrans = null;
6161  return newVD;
6162  } finally {
6163  if (null != localTrans) {
6164  try {
6165  localTrans.rollback();
6166  } catch (TskCoreException ex2) {
6167  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6168  }
6169  }
6170  }
6171  }
6172 
6185  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6186  ResultSet resultSet = null;
6188  try {
6189  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6190  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6191  statement.clearParameters();
6192  if (parentId != 0) {
6193  statement.setLong(1, parentId);
6194  } else {
6195  statement.setNull(1, java.sql.Types.BIGINT);
6196  }
6197  statement.setInt(2, objectType);
6198  connection.executeUpdate(statement);
6199  resultSet = statement.getGeneratedKeys();
6200 
6201  if (resultSet.next()) {
6202  if (parentId != 0) {
6203  setHasChildren(parentId);
6204  }
6205  return resultSet.getLong(1); //last_insert_rowid()
6206  } else {
6207  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6208  }
6209  } finally {
6210  closeResultSet(resultSet);
6212  }
6213  }
6214 
6232  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6233  if (transaction == null) {
6234  throw new TskCoreException("Passed null CaseDbTransaction");
6235  }
6236 
6237  ResultSet resultSet = null;
6238  try {
6239  // Get the parent path.
6240  CaseDbConnection connection = transaction.getConnection();
6241 
6242  String parentPath;
6243  Content parent = this.getAbstractFileById(parentId, connection);
6244  if (parent instanceof AbstractFile) {
6245  if (isRootDirectory((AbstractFile) parent, transaction)) {
6246  if (parent.getName().isEmpty()) {
6247  parentPath = "/";
6248  } else {
6249  parentPath = "/" + parent.getName() + "/";
6250  }
6251  } else {
6252  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6253  }
6254  } else {
6255  // The parent was either null or not an abstract file
6256  parentPath = "/";
6257  }
6258 
6259  // Insert a row for the virtual directory into the tsk_objects table.
6260  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6261 
6262  // Insert a row for the virtual directory into the tsk_files table.
6263  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6264  // 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)
6265  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)
6266  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6267  statement.clearParameters();
6268  statement.setLong(1, newObjId);
6269 
6270  // If the parent is part of a file system, grab its file system ID
6271  Long fileSystemObjectId = null;
6272  if (0 != parentId) {
6273  fileSystemObjectId = this.getFileSystemId(parentId, connection);
6274  if (fileSystemObjectId != -1) {
6275  statement.setLong(2, fileSystemObjectId);
6276  } else {
6277  statement.setNull(2, java.sql.Types.BIGINT);
6278  fileSystemObjectId = null;
6279  }
6280  } else {
6281  statement.setNull(2, java.sql.Types.BIGINT);
6282  }
6283 
6284  // name
6285  statement.setString(3, directoryName);
6286 
6287  //type
6288  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6289  statement.setShort(5, (short) 1);
6290 
6291  //flags
6293  statement.setShort(6, dirType.getValue());
6295  statement.setShort(7, metaType.getValue());
6296 
6297  //allocated
6299  statement.setShort(8, dirFlag.getValue());
6300  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6301  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6302  statement.setShort(9, metaFlags);
6303 
6304  //size
6305  statement.setLong(10, 0);
6306 
6307  // nulls for params 11-14
6308  statement.setNull(11, java.sql.Types.BIGINT);
6309  statement.setNull(12, java.sql.Types.BIGINT);
6310  statement.setNull(13, java.sql.Types.BIGINT);
6311  statement.setNull(14, java.sql.Types.BIGINT);
6312 
6313  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6314  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6315  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6316 
6317  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6318  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6319 
6320  // parent path
6321  statement.setString(20, parentPath);
6322 
6323  // data source object id (same as object id if this is a data source)
6324  long dataSourceObjectId;
6325  if (0 == parentId) {
6326  dataSourceObjectId = newObjId;
6327  } else {
6328  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6329  }
6330  statement.setLong(21, dataSourceObjectId);
6331 
6332  //extension, since this is not really file we just set it to null
6333  statement.setString(22, null);
6334 
6335  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6336  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6337 
6338  connection.executeUpdate(statement);
6339 
6340  return new VirtualDirectory(this, newObjId, dataSourceObjectId, fileSystemObjectId, directoryName, dirType,
6341  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6342  parentPath);
6343  } catch (SQLException e) {
6344  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6345  } finally {
6346  closeResultSet(resultSet);
6347  }
6348  }
6349 
6362  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6363  CaseDbTransaction localTrans = beginTransaction();
6364  try {
6365  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6366  localTrans.commit();
6367  return newLD;
6368  } catch (TskCoreException ex) {
6369  try {
6370  localTrans.rollback();
6371  } catch (TskCoreException ex2) {
6372  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6373  }
6374  throw ex;
6375  }
6376  }
6377 
6395  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6396  if (transaction == null) {
6397  throw new TskCoreException("Passed null CaseDbTransaction");
6398  }
6399 
6400  ResultSet resultSet = null;
6401  try {
6402  // Get the parent path.
6403  CaseDbConnection connection = transaction.getConnection();
6404  AbstractFile parent = getAbstractFileById(parentId, connection);
6405  String parentPath;
6406  if ((parent == null) || isRootDirectory(parent, transaction)) {
6407  parentPath = "/";
6408  } else {
6409  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6410  }
6411 
6412  // Insert a row for the local directory into the tsk_objects table.
6413  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6414 
6415  // Insert a row for the local directory into the tsk_files table.
6416  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6417  // 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)
6418  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6419  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6420  statement.clearParameters();
6421  statement.setLong(1, newObjId);
6422 
6423  // The parent of a local directory will never be a file system
6424  statement.setNull(2, java.sql.Types.BIGINT);
6425 
6426  // name
6427  statement.setString(3, directoryName);
6428 
6429  //type
6430  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6431  statement.setShort(5, (short) 1);
6432 
6433  //flags
6435  statement.setShort(6, dirType.getValue());
6437  statement.setShort(7, metaType.getValue());
6438 
6439  //allocated
6441  statement.setShort(8, dirFlag.getValue());
6442  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6443  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6444  statement.setShort(9, metaFlags);
6445 
6446  //size
6447  statement.setLong(10, 0);
6448 
6449  // nulls for params 11-14
6450  statement.setNull(11, java.sql.Types.BIGINT);
6451  statement.setNull(12, java.sql.Types.BIGINT);
6452  statement.setNull(13, java.sql.Types.BIGINT);
6453  statement.setNull(14, java.sql.Types.BIGINT);
6454 
6455  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6456  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6457  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6458 
6459  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6460  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6461 
6462  // parent path
6463  statement.setString(20, parentPath);
6464 
6465  // data source object id
6466  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6467  statement.setLong(21, dataSourceObjectId);
6468 
6469  //extension, since this is a directory we just set it to null
6470  statement.setString(22, null);
6471 
6472  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6473  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6474 
6475  connection.executeUpdate(statement);
6476 
6477  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6478  metaType, dirFlag, metaFlags, null, null, null, FileKnown.UNKNOWN,
6479  parentPath);
6480  } catch (SQLException e) {
6481  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6482  } finally {
6483  closeResultSet(resultSet);
6484  }
6485  }
6486 
6506  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6507  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6508  }
6509 
6530  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6531 
6532  Statement statement = null;
6533  try {
6534  CaseDbConnection connection = transaction.getConnection();
6535 
6536  // Insert a row for the root virtual directory of the data source
6537  // into the tsk_objects table.
6538  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6539 
6540  // If no host was supplied, make one
6541  if (host == null) {
6542  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
6543  }
6544 
6545  // Insert a row for the virtual directory of the data source into
6546  // the data_source_info table.
6547  statement = connection.createStatement();
6548  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
6549  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
6550 
6551  // Insert a row for the root virtual directory of the data source
6552  // into the tsk_files table. Note that its data source object id is
6553  // its own object id.
6554  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
6555  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
6556  // atime, mtime, md5, sha256, sha1, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6557  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
6558  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6559  preparedStatement.clearParameters();
6560  preparedStatement.setLong(1, newObjId);
6561  preparedStatement.setNull(2, java.sql.Types.BIGINT);
6562  preparedStatement.setString(3, rootDirectoryName);
6563  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6564  preparedStatement.setShort(5, (short) 1);
6566  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
6568  preparedStatement.setShort(7, metaType.getValue());
6570  preparedStatement.setShort(8, dirFlag.getValue());
6571  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6572  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6573  preparedStatement.setShort(9, metaFlags);
6574  preparedStatement.setLong(10, 0);
6575  preparedStatement.setNull(11, java.sql.Types.BIGINT);
6576  preparedStatement.setNull(12, java.sql.Types.BIGINT);
6577  preparedStatement.setNull(13, java.sql.Types.BIGINT);
6578  preparedStatement.setNull(14, java.sql.Types.BIGINT);
6579  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
6580  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6581  preparedStatement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
6582  preparedStatement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6583  preparedStatement.setNull(19, java.sql.Types.VARCHAR); // MIME type
6584  String parentPath = "/"; //NON-NLS
6585  preparedStatement.setString(20, parentPath);
6586  preparedStatement.setLong(21, newObjId);
6587  preparedStatement.setString(22, null); //extension, just set it to null
6588  preparedStatement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
6589  preparedStatement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
6590 
6591 
6592  connection.executeUpdate(preparedStatement);
6593 
6594  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, null, FileKnown.UNKNOWN, parentPath);
6595 
6596  } catch (SQLException ex) {
6597  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
6598  } finally {
6599  closeStatement(statement);
6600  }
6601  }
6602 
6622  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6623  String timezone, String md5, String sha1, String sha256,
6624  String deviceId,
6625  CaseDbTransaction transaction) throws TskCoreException {
6626  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
6627  }
6628 
6649  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6650  String timezone, String md5, String sha1, String sha256,
6651  String deviceId, Host host,
6652  CaseDbTransaction transaction) throws TskCoreException {
6653  Statement statement = null;
6654  try {
6655  // Insert a row for the Image into the tsk_objects table.
6656  CaseDbConnection connection = transaction.getConnection();
6657  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
6658 
6659  // Add a row to tsk_image_info
6660  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
6661  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
6662  preparedStatement.clearParameters();
6663  preparedStatement.setLong(1, newObjId);
6664  preparedStatement.setShort(2, (short) type.getValue());
6665  preparedStatement.setLong(3, sectorSize);
6666  preparedStatement.setString(4, timezone);
6667  //prevent negative size
6668  long savedSize = size < 0 ? 0 : size;
6669  preparedStatement.setLong(5, savedSize);
6670  preparedStatement.setString(6, md5);
6671  preparedStatement.setString(7, sha1);
6672  preparedStatement.setString(8, sha256);
6673  preparedStatement.setString(9, displayName);
6674  connection.executeUpdate(preparedStatement);
6675 
6676  // If there are paths, add them to tsk_image_names
6677  for (int i = 0; i < imagePaths.size(); i++) {
6678  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
6679  preparedStatement.clearParameters();
6680  preparedStatement.setLong(1, newObjId);
6681  preparedStatement.setString(2, imagePaths.get(i));
6682  preparedStatement.setLong(3, i);
6683  connection.executeUpdate(preparedStatement);
6684  }
6685 
6686  // Create the display name
6687  String name = displayName;
6688  if (name == null || name.isEmpty()) {
6689  if (imagePaths.size() > 0) {
6690  String path = imagePaths.get(0);
6691  name = (new java.io.File(path)).getName();
6692  } else {
6693  name = "";
6694  }
6695  }
6696 
6697  // Create a host if needed
6698  if (host == null) {
6699  if (name.isEmpty()) {
6700  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
6701  } else {
6702  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
6703  }
6704  }
6705 
6706  // Add a row to data_source_info
6707  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
6708  statement = connection.createStatement();
6709  preparedStatement.setLong(1, newObjId);
6710  preparedStatement.setString(2, deviceId);
6711  preparedStatement.setString(3, timezone);
6712  preparedStatement.setLong(4, new Date().getTime());
6713  preparedStatement.setLong(5, host.getHostId());
6714  connection.executeUpdate(preparedStatement);
6715 
6716  // Create the new Image object
6717  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
6718  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
6719  } catch (SQLException ex) {
6720  if (!imagePaths.isEmpty()) {
6721  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
6722  } else {
6723  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
6724  }
6725  } finally {
6726  closeStatement(statement);
6727  }
6728  }
6729 
6743  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
6744  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
6745  try {
6746  // Insert a row for the VolumeSystem into the tsk_objects table.
6747  CaseDbConnection connection = transaction.getConnection();
6748  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
6749 
6750  // Add a row to tsk_vs_info
6751  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
6752  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
6753  preparedStatement.clearParameters();
6754  preparedStatement.setLong(1, newObjId);
6755  preparedStatement.setShort(2, (short) type.getVsType());
6756  preparedStatement.setLong(3, imgOffset);
6757  preparedStatement.setLong(4, blockSize);
6758  connection.executeUpdate(preparedStatement);
6759 
6760  // Create the new VolumeSystem object
6761  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
6762  } catch (SQLException ex) {
6763  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
6764  parentObjId, imgOffset), ex);
6765  }
6766  }
6767 
6783  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
6784  long flags, CaseDbTransaction transaction) throws TskCoreException {
6785  try {
6786  // Insert a row for the Volume into the tsk_objects table.
6787  CaseDbConnection connection = transaction.getConnection();
6788  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
6789 
6790  // Add a row to tsk_vs_parts
6791  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
6792  PreparedStatement preparedStatement;
6793  if (this.dbType == DbType.POSTGRESQL) {
6794  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
6795  } else {
6796  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
6797  }
6798  preparedStatement.clearParameters();
6799  preparedStatement.setLong(1, newObjId);
6800  preparedStatement.setLong(2, addr);
6801  preparedStatement.setLong(3, start);
6802  preparedStatement.setLong(4, length);
6803  preparedStatement.setString(5, desc);
6804  preparedStatement.setShort(6, (short) flags);
6805  connection.executeUpdate(preparedStatement);
6806 
6807  // Create the new Volume object
6808  return new Volume(this, newObjId, addr, start, length, flags, desc);
6809  } catch (SQLException ex) {
6810  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
6811  }
6812  }
6813 
6825  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
6826  try {
6827  // Insert a row for the Pool into the tsk_objects table.
6828  CaseDbConnection connection = transaction.getConnection();
6829  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
6830 
6831  // Add a row to tsk_pool_info
6832  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
6833  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
6834  preparedStatement.clearParameters();
6835  preparedStatement.setLong(1, newObjId);
6836  preparedStatement.setShort(2, type.getValue());
6837  connection.executeUpdate(preparedStatement);
6838 
6839  // Create the new Pool object
6840  return new Pool(this, newObjId, type.getName(), type.getValue());
6841  } catch (SQLException ex) {
6842  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
6843  }
6844  }
6845 
6864  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
6865  long rootInum, long firstInum, long lastInum, String displayName,
6866  CaseDbTransaction transaction) throws TskCoreException {
6867  try {
6868  // Insert a row for the FileSystem into the tsk_objects table.
6869  CaseDbConnection connection = transaction.getConnection();
6870  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
6871 
6872  // Get the data source object ID
6873  long dataSourceId = getDataSourceObjectId(connection, newObjId);
6874 
6875  // Add a row to tsk_fs_info
6876  // 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)
6877  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
6878  preparedStatement.clearParameters();
6879  preparedStatement.setLong(1, newObjId);
6880  preparedStatement.setLong(2, dataSourceId);
6881  preparedStatement.setLong(3, imgOffset);
6882  preparedStatement.setInt(4, type.getValue());
6883  preparedStatement.setLong(5, blockSize);
6884  preparedStatement.setLong(6, blockCount);
6885  preparedStatement.setLong(7, rootInum);
6886  preparedStatement.setLong(8, firstInum);
6887  preparedStatement.setLong(9, lastInum);
6888  preparedStatement.setString(10, displayName);
6889  connection.executeUpdate(preparedStatement);
6890 
6891  // Create the new FileSystem object
6892  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
6893  firstInum, lastInum);
6894  } catch (SQLException ex) {
6895  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
6896  imgOffset, parentObjId), ex);
6897  }
6898  }
6899 
6925  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
6926  String fileName,
6927  long metaAddr, int metaSeq,
6928  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
6929  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
6930  long ctime, long crtime, long atime, long mtime,
6931  boolean isFile, Content parent) throws TskCoreException {
6932 
6933  CaseDbTransaction transaction = beginTransaction();
6934  try {
6935 
6936  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
6937  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
6938  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
6939  OsAccount.NO_OWNER_ID, null,
6940  Collections.emptyList(), transaction);
6941 
6942  transaction.commit();
6943  transaction = null;
6944  return fileSystemFile;
6945  } finally {
6946  if (null != transaction) {
6947  try {
6948  transaction.rollback();
6949  } catch (TskCoreException ex2) {
6950  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6951  }
6952  }
6953  }
6954  }
6955 
6993  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
6994  String fileName,
6995  long metaAddr, int metaSeq,
6996  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
6997  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
6998  long ctime, long crtime, long atime, long mtime,
6999  String md5Hash, String sha256Hash, String mimeType,
7000  boolean isFile, Content parent, String ownerUid,
7001  OsAccount osAccount, List<Attribute> fileAttributes,
7002  CaseDbTransaction transaction) throws TskCoreException {
7003 
7004  return addFileSystemFile(dataSourceObjId, fsObjId,
7005  fileName,
7006  metaAddr, metaSeq,
7007  attrType, attrId,
7008  dirFlag, metaFlags, size,
7009  ctime, crtime, atime, mtime,
7010  md5Hash, sha256Hash, null,
7011  mimeType,
7012  isFile, parent, ownerUid,
7013  osAccount, fileAttributes,
7014  transaction);
7015  }
7016 
7056  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7057  String fileName,
7058  long metaAddr, int metaSeq,
7059  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7060  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7061  long ctime, long crtime, long atime, long mtime,
7062  String md5Hash, String sha256Hash, String sha1Hash,
7063  String mimeType, boolean isFile,
7064  Content parent, String ownerUid,
7065  OsAccount osAccount, List<Attribute> fileAttributes,
7066  CaseDbTransaction transaction) throws TskCoreException {
7067 
7068  TimelineManager timelineManager = getTimelineManager();
7069 
7070  Statement queryStatement = null;
7071  String parentPath = "/";
7072  try {
7073  CaseDbConnection connection = transaction.getConnection();
7074 
7075  // Insert a row for the local/logical file into the tsk_objects table.
7076  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7077  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7078 
7079  if (parent instanceof AbstractFile) {
7080  AbstractFile parentFile = (AbstractFile) parent;
7081  if (isRootDirectory(parentFile, transaction)) {
7082  parentPath = "/";
7083  } else {
7084  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7085  }
7086  } else {
7087  parentPath = "/";
7088  }
7089 
7090  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7091  statement.clearParameters();
7092  statement.setLong(1, objectId); // obj_is
7093  statement.setLong(2, fsObjId); // fs_obj_id
7094  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7095  statement.setShort(4, (short) attrType.getValue()); // attr_type
7096  statement.setInt(5, attrId); // attr_id
7097  statement.setString(6, fileName); // name
7098  statement.setLong(7, metaAddr); // meta_addr
7099  statement.setInt(8, metaSeq); // meta_addr
7100  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7101  statement.setShort(10, (short) 1); // has_path
7103  statement.setShort(11, dirType.getValue()); // dir_type
7105  statement.setShort(12, metaType.getValue()); // meta_type
7106  statement.setShort(13, dirFlag.getValue()); // dir_flags
7107  statement.setShort(14, metaFlags); // meta_flags
7108  statement.setLong(15, size < 0 ? 0 : size);
7109  statement.setLong(16, ctime);
7110  statement.setLong(17, crtime);
7111  statement.setLong(18, atime);
7112  statement.setLong(19, mtime);
7113  statement.setString(20, md5Hash);
7114  statement.setString(21, sha256Hash);
7115  statement.setString(22, sha1Hash);
7116  statement.setString(23, mimeType);
7117  statement.setString(24, parentPath);
7118  final String extension = extractExtension(fileName);
7119  statement.setString(25, extension);
7120  statement.setString(26, ownerUid);
7121  if (null != osAccount) {
7122  statement.setLong(27, osAccount.getId());
7123  } else {
7124  statement.setNull(27, java.sql.Types.BIGINT); // osAccountObjId
7125  }
7126 
7127  connection.executeUpdate(statement);
7128 
7129  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7130  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7131  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, sha1Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7132 
7133  if (!timelineEventsDisabled.get()) {
7134  timelineManager.addEventsForNewFile(derivedFile, connection);
7135  }
7136 
7137  for (Attribute fileAttribute : fileAttributes) {
7138  fileAttribute.setAttributeParentId(objectId);
7139  fileAttribute.setCaseDatabase(this);
7140  addFileAttribute(fileAttribute, connection);
7141  }
7142 
7143  if (osAccount != null) {
7144  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
7145  }
7146 
7147  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7148  attrType, attrId, fileName, metaAddr, metaSeq,
7149  dirType, metaType, dirFlag, metaFlags,
7150  size, ctime, crtime, atime, mtime,
7151  (short) 0, 0, 0, md5Hash, sha256Hash, sha1Hash, null, parentPath, mimeType,
7152  extension, ownerUid, osAccountId, fileAttributes);
7153 
7154  } catch (SQLException ex) {
7155  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);
7156  } finally {
7157  closeStatement(queryStatement);
7158  }
7159  }
7160 
7169  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7170  CaseDbConnection connection = null;
7171  Statement s = null;
7172  ResultSet rs = null;
7174  try {
7175  connection = connections.getConnection();
7176  s = connection.createStatement();
7177  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7178  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7179  + " AND obj_id = data_source_obj_id"
7180  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7181  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7182  while (rs.next()) {
7183  virtDirRootIds.add(virtualDirectory(rs, connection));
7184  }
7185  return virtDirRootIds;
7186  } catch (SQLException ex) {
7187  throw new TskCoreException("Error getting local files virtual folder id", ex);
7188  } finally {
7189  closeResultSet(rs);
7190  closeStatement(s);
7191  closeConnection(connection);
7193  }
7194  }
7195 
7208  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7209  assert (null != fileRanges);
7210  if (null == fileRanges) {
7211  throw new TskCoreException("TskFileRange object is null");
7212  }
7213 
7214  assert (null != parent);
7215  if (null == parent) {
7216  throw new TskCoreException("Conent is null");
7217  }
7218 
7219  String parentPath;
7220  if (parent instanceof AbstractFile) {
7221  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
7222  } else {
7223  parentPath = "/";
7224  }
7225 
7226  CaseDbTransaction transaction = null;
7227  Statement statement = null;
7228  ResultSet resultSet = null;
7229 
7230  try {
7231  transaction = beginTransaction();
7232  CaseDbConnection connection = transaction.getConnection();
7233 
7234  // If the parent is part of a file system, grab its file system ID
7235  Long fileSystemObjectId;
7236  if (0 != parent.getId()) {
7237  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
7238  if (fileSystemObjectId == -1) {
7239  fileSystemObjectId = null;
7240  }
7241  } else {
7242  fileSystemObjectId = null;
7243  }
7244 
7245  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<>();
7246  for (TskFileRange fileRange : fileRanges) {
7247  /*
7248  * Insert a row for the Tsk file range into the tsk_objects
7249  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7250  * ?)
7251  */
7252  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7253  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7254  /*
7255  * Insert a row for the Tsk file range into the tsk_files table:
7256  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7257  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7258  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7259  * parent_path, data_source_obj_id,extension, owner_uid,
7260  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7261  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
7262  */
7263  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7264  prepStmt.clearParameters();
7265  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7266  if (fileSystemObjectId != null) {
7267  prepStmt.setLong(2, fileSystemObjectId);// fs_obj_id
7268  } else {
7269  prepStmt.setNull(2, java.sql.Types.BIGINT);
7270  }
7271  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]
7272  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7273  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7274  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7275  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7276  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7277  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7278  prepStmt.setLong(10, fileRange.getByteLen()); // size
7279  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7280  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7281  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7282  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7283  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7284  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7285  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7286 
7287  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7288  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7289  prepStmt.setString(20, parentPath); // parent path
7290  prepStmt.setLong(21, parent.getId()); // data_source_obj_id
7291 
7292  //extension, since this is not a FS file we just set it to null
7293  prepStmt.setString(22, null);
7294 
7295  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7296  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7297 
7298  connection.executeUpdate(prepStmt);
7299 
7300  /*
7301  * Insert a row in the tsk_layout_file table for each chunk of
7302  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7303  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7304  */
7305  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7306  prepStmt.clearParameters();
7307  prepStmt.setLong(1, fileRangeId); // obj_id
7308  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7309  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7310  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7311  connection.executeUpdate(prepStmt);
7312 
7313  /*
7314  * Create a layout file representation of the carved file.
7315  */
7316  fileRangeLayoutFiles.add(new LayoutFile(this,
7317  fileRangeId,
7318  parent.getId(),
7319  fileSystemObjectId,
7320  Long.toString(fileRange.getSequence()),
7325  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7326  fileRange.getByteLen(),
7327  0L, 0L, 0L, 0L,
7328  null, null, null,
7330  parent.getUniquePath(),
7331  null,
7332  OsAccount.NO_OWNER_ID,
7333  OsAccount.NO_ACCOUNT));
7334  }
7335 
7336  transaction.commit();
7337  transaction = null;
7338  return fileRangeLayoutFiles;
7339 
7340  } catch (SQLException ex) {
7341  throw new TskCoreException("Failed to add layout files to case database", ex);
7342  } finally {
7343  closeResultSet(resultSet);
7344  closeStatement(statement);
7345 
7346  if (null != transaction) {
7347  try {
7348  transaction.rollback();
7349  } catch (TskCoreException ex2) {
7350  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7351  }
7352  }
7353  }
7354  }
7355 
7362  private class CarvedFileDirInfo {
7363 
7364  final VirtualDirectory currentFolder;
7365  AtomicInteger count;
7366 
7367  CarvedFileDirInfo(VirtualDirectory currentFolder) {
7368  this.currentFolder = currentFolder;
7369  count = new AtomicInteger(0);
7370  }
7371 
7372  CarvedFileDirInfo(VirtualDirectory currentFolder, int count) {
7373  this.currentFolder = currentFolder;
7374  this.count = new AtomicInteger(count);
7375  }
7376 
7383  boolean isFull() {
7384  return count.get() >= MAX_CARVED_FILES_PER_FOLDER;
7385  }
7386 
7390  void incrementFileCounter() {
7391  count.incrementAndGet();
7392  }
7393  }
7394 
7404  private CarvedFileDirInfo getMostRecentCarvedDirInfo(VirtualDirectory carvedFilesBaseDir) throws TskCoreException {
7405  VirtualDirectory mostRecentDir = null;
7406  for (Content child : carvedFilesBaseDir.getChildren()) {
7407  if (isValidCarvedFileSubfolder(child)) {
7408  if (mostRecentDir == null
7409  || (mostRecentDir.getId() < child.getId())) {
7410  mostRecentDir = (VirtualDirectory) child;
7411  }
7412  }
7413  }
7414 
7415  if (mostRecentDir != null) {
7416  return new CarvedFileDirInfo(mostRecentDir, mostRecentDir.getChildrenCount());
7417  }
7418  return null;
7419  }
7420 
7429  private boolean isValidCarvedFileSubfolder(Content subfolder) {
7430  if (!(subfolder instanceof VirtualDirectory)) {
7431  return false;
7432  }
7433  return subfolder.getName().matches("^[0-9]+$");
7434  }
7435 
7449  private CarvedFileDirInfo createCarvedFilesSubfolder(Content carvedFilesBaseDir, CarvedFileDirInfo currentSubfolderInfo) throws TskCoreException {
7450  int nextIndex = 1;
7451  if (currentSubfolderInfo != null) {
7452  try {
7453  int currentIndex = Integer.parseInt(currentSubfolderInfo.currentFolder.getName());
7454  nextIndex = currentIndex + 1;
7455  } catch (NumberFormatException ex) {
7456  throw new TskCoreException("Unexpected name format for carved files subdirectory with ID: " + currentSubfolderInfo.currentFolder.getId() + " (" + currentSubfolderInfo.currentFolder.getName() + ")", ex);
7457  }
7458  }
7459 
7460  VirtualDirectory carvedFilesSubdir = addVirtualDirectory(carvedFilesBaseDir.getId(), Integer.toString(nextIndex));
7461  return new CarvedFileDirInfo(carvedFilesSubdir);
7462  }
7463 
7475  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
7476  assert (null != carvingResult);
7477  if (null == carvingResult) {
7478  throw new TskCoreException("Carving is null");
7479  }
7480  assert (null != carvingResult.getParent());
7481  if (null == carvingResult.getParent()) {
7482  throw new TskCoreException("Carving result has null parent");
7483  }
7484  assert (null != carvingResult.getCarvedFiles());
7485  if (null == carvingResult.getCarvedFiles()) {
7486  throw new TskCoreException("Carving result has null carved files");
7487  }
7488  CaseDbTransaction transaction = null;
7489  Statement statement = null;
7490  ResultSet resultSet = null;
7491  try {
7492 
7493  /*
7494  * Carved files are "re-parented" as children of the $CarvedFiles
7495  * virtual directory of the root file system, volume, or image
7496  * ancestor of the carved files parent, but if no such ancestor is
7497  * found, then the parent specified in the carving result is used.
7498  */
7499  Content root = carvingResult.getParent();
7500  while (null != root) {
7501  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
7502  break;
7503  }
7504  root = root.getParent();
7505  }
7506  if (null == root) {
7507  root = carvingResult.getParent();
7508  }
7509 
7510  /*
7511  * Get or create the $CarvedFiles virtual directory for the root
7512  * ancestor.
7513  */
7514  CarvedFileDirInfo carvedFilesDirInfo = null;
7515  synchronized (carvedFileDirsLock) {
7516  // Get the subfolder currently in use (if there is one)
7517  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7518  if (carvedFilesDirInfo != null) {
7519  carvedFilesDirInfo.incrementFileCounter();
7520 
7521  // If the current folder is full, create a new one.
7522  if (carvedFilesDirInfo.isFull()) {
7523  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesDirInfo.currentFolder.getParent(), carvedFilesDirInfo);
7524  }
7525  }
7526 
7527  if (null == carvedFilesDirInfo) {
7528  List<Content> rootChildren;
7529  if (root instanceof FileSystem) {
7530  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
7531  } else {
7532  rootChildren = root.getChildren();
7533  }
7534  for (Content child : rootChildren) {
7535  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
7536 
7537  VirtualDirectory baseDir = (VirtualDirectory) child;
7538 
7539  // Get the most recent subfolder in the carved files folder.
7540  carvedFilesDirInfo = getMostRecentCarvedDirInfo(baseDir);
7541 
7542  // If there are no subfolders, create one.
7543  if (carvedFilesDirInfo == null) {
7544  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, null);
7545  }
7546 
7547  // If there are already too many files in the subfolder, create a new one.
7548  if (carvedFilesDirInfo.isFull()) {
7549  carvedFilesDirInfo = createCarvedFilesSubfolder(baseDir, carvedFilesDirInfo);
7550  }
7551 
7552  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7553  break;
7554  }
7555  }
7556  if (carvedFilesDirInfo == null) {
7557  // If we get here, we didn't have a carved files base folder in the case, so we need to make that and
7558  // the first subfolder.
7559 
7560  long parId = root.getId();
7561  // $CarvedFiles should be a child of the root directory, not the file system
7562  if (root instanceof FileSystem) {
7563  Content rootDir = ((FileSystem) root).getRootDirectory();
7564  parId = rootDir.getId();
7565  }
7566  VirtualDirectory carvedFilesBaseDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
7567  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, null);
7568  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7569  }
7570  }
7571  }
7572 
7573  /*
7574  * Add the carved files to the database as children of the
7575  * $CarvedFile directory of the root ancestor.
7576  */
7577  VirtualDirectory carvedFilesBaseDir = (VirtualDirectory) carvedFilesDirInfo.currentFolder.getParent();
7578  transaction = beginTransaction();
7579  CaseDbConnection connection = transaction.getConnection();
7580  String parentPath = getFileParentPath(carvedFilesDirInfo.currentFolder.getId(), connection) + carvedFilesDirInfo.currentFolder.getName() + "/";
7581  List<LayoutFile> carvedFiles = new ArrayList<>();
7582  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
7583 
7584  /*
7585  * Check if we need to change to a new subfolder.
7586  */
7587  VirtualDirectory carvedFilesDir = carvedFilesDirInfo.currentFolder;
7588  if (carvedFilesDirInfo.isFull()) {
7589  // To prevent deadlocks involving the case write lock and the carvedFileDirsLock,
7590  // commit the current transaction and then start a new one
7591  // after switching to the new folder.
7592  transaction.commit();
7593 
7594  synchronized (carvedFileDirsLock) {
7595  // Get the current copy from the map - another thread may have just created a new folder.
7596  carvedFilesDirInfo = rootIdsToCarvedFileDirs.get(root.getId());
7597  if (carvedFilesDirInfo.isFull()) {
7598  carvedFilesDirInfo = createCarvedFilesSubfolder(carvedFilesBaseDir, carvedFilesDirInfo);
7599  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDirInfo);
7600  carvedFilesDir = carvedFilesDirInfo.currentFolder;
7601  }
7602  }
7603 
7604  // Start a new transaction.
7605  transaction = beginTransaction();
7606  connection = transaction.getConnection();
7607  parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
7608 
7609  }
7610  carvedFilesDirInfo.incrementFileCounter();
7611 
7612  /*
7613  * Insert a row for the carved file into the tsk_objects table:
7614  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7615  */
7616  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7617 
7618 
7619  /*
7620  * Insert a row for the carved file into the tsk_files table:
7621  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7622  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7623  * ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
7624  * parent_path, data_source_obj_id,extenion, owner_uid,
7625  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7626  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7627  */
7628  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7629  prepStmt.clearParameters();
7630  prepStmt.setLong(1, carvedFileId); // obj_id
7631  Long fileSystemObjectId;
7632  if (root instanceof FileSystem) {
7633  prepStmt.setLong(2, root.getId()); // fs_obj_id
7634  fileSystemObjectId = root.getId();
7635  } else {
7636  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7637  fileSystemObjectId = null;
7638  }
7639  prepStmt.setString(3, carvedFile.getName()); // name
7640  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
7641  prepStmt.setShort(5, (short) 1); // has_path
7642  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7643  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7644  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7645  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7646  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
7647  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7648  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7649  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7650  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7651  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7652  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7653  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7654 
7655  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7656  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
7657  prepStmt.setString(20, parentPath); // parent path
7658  prepStmt.setLong(21, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
7659  prepStmt.setString(22, extractExtension(carvedFile.getName())); //extension
7660 
7661  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7662  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7663 
7664  connection.executeUpdate(prepStmt);
7665 
7666  /*
7667  * Insert a row in the tsk_layout_file table for each chunk of
7668  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7669  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7670  */
7671  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7672  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
7673  prepStmt.clearParameters();
7674  prepStmt.setLong(1, carvedFileId); // obj_id
7675  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7676  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7677  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7678  connection.executeUpdate(prepStmt);
7679  }
7680 
7681  /*
7682  * Create a layout file representation of the carved file.
7683  */
7684  carvedFiles.add(new LayoutFile(this,
7685  carvedFileId,
7686  carvedFilesDir.getDataSourceObjectId(),
7687  fileSystemObjectId,
7688  carvedFile.getName(),
7693  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7694  carvedFile.getSizeInBytes(),
7695  0L, 0L, 0L, 0L,
7696  null, null, null,
7698  parentPath,
7699  null,
7700  OsAccount.NO_OWNER_ID,
7701  OsAccount.NO_ACCOUNT));
7702  }
7703 
7704  transaction.commit();
7705  transaction = null;
7706  return carvedFiles;
7707 
7708  } catch (SQLException ex) {
7709  throw new TskCoreException("Failed to add carved files to case database", ex);
7710  } finally {
7711  closeResultSet(resultSet);
7712  closeStatement(statement);
7713 
7714  if (null != transaction) {
7715  try {
7716  transaction.rollback();
7717  } catch (TskCoreException ex2) {
7718  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7719  }
7720  }
7721  }
7722  }
7723 
7754  public DerivedFile addDerivedFile(String fileName, String localPath,
7755  long size, long ctime, long crtime, long atime, long mtime,
7756  boolean isFile, Content parentObj,
7757  String rederiveDetails, String toolName, String toolVersion,
7758  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7759  CaseDbTransaction transaction = beginTransaction();
7760  try {
7761  DerivedFile df = addDerivedFile(fileName, localPath,
7762  size, ctime, crtime, atime, mtime,
7763  isFile, parentObj,
7764  rederiveDetails, toolName, toolVersion,
7765  otherDetails, encodingType, transaction);
7766  transaction.commit();
7767  return df;
7768  } catch (TskCoreException ex) {
7769  transaction.rollback();
7770  throw ex;
7771  }
7772  }
7773 
7774  public DerivedFile addDerivedFile(String fileName, String localPath,
7775  long size, long ctime, long crtime, long atime, long mtime,
7776  boolean isFile, Content parentObj,
7777  String rederiveDetails, String toolName, String toolVersion,
7778  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
7779  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7780  localPath = localPath.replaceAll("^[/\\\\]+", "");
7781 
7782  TimelineManager timelineManager = getTimelineManager();
7783 
7784  CaseDbConnection connection = transaction.getConnection();
7785  try {
7786  final long parentId = parentObj.getId();
7787  String parentPath = "";
7788  if (parentObj instanceof BlackboardArtifact) {
7789  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7790  } else if (parentObj instanceof AbstractFile) {
7791  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7792  }
7793 
7794  // Insert a row for the derived file into the tsk_objects table.
7795  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7796  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7797 
7798  // Insert a row for the virtual directory into the tsk_files table.
7799  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
7800  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
7801  // parent_path, data_source_obj_id, extension)
7802  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
7803  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7804  statement.clearParameters();
7805  statement.setLong(1, newObjId);
7806 
7807  // If the parentFile is part of a file system, use its file system object ID.
7808  Long fsObjId = this.getFileSystemId(parentId, connection);
7809  if (fsObjId != -1) {
7810  statement.setLong(2, fsObjId);
7811  } else {
7812  fsObjId = null;
7813  statement.setNull(2, java.sql.Types.BIGINT);
7814  }
7815  statement.setString(3, fileName);
7816 
7817  //type, has_path
7818  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7819  statement.setShort(5, (short) 1);
7820 
7821  //flags
7823  statement.setShort(6, dirType.getValue());
7825  statement.setShort(7, metaType.getValue());
7826 
7827  //note: using alloc under assumption that derived files derive from alloc files
7829  statement.setShort(8, dirFlag.getValue());
7830  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7831  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7832  statement.setShort(9, metaFlags);
7833 
7834  //size
7835  //prevent negative size
7836  long savedSize = size < 0 ? 0 : size;
7837  statement.setLong(10, savedSize);
7838 
7839  //mactimes
7840  //long ctime, long crtime, long atime, long mtime,
7841  statement.setLong(11, ctime);
7842  statement.setLong(12, crtime);
7843  statement.setLong(13, atime);
7844  statement.setLong(14, mtime);
7845 
7846  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
7847  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7848  statement.setNull(17, java.sql.Types.VARCHAR); // SHA-1
7849 
7850  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7851  statement.setNull(19, java.sql.Types.VARCHAR); // MIME type
7852 
7853  //parent path
7854  statement.setString(20, parentPath);
7855 
7856  // root data source object id
7857  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
7858  statement.setLong(21, dataSourceObjId);
7859  final String extension = extractExtension(fileName);
7860  //extension
7861  statement.setString(22, extension);
7862 
7863  statement.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
7864  statement.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
7865 
7866  connection.executeUpdate(statement);
7867 
7868  //add localPath
7869  addFilePath(connection, newObjId, localPath, encodingType);
7870 
7871  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fsObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7872  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
7873 
7874  if (!timelineEventsDisabled.get()) {
7875  timelineManager.addEventsForNewFile(derivedFile, connection);
7876  }
7877 
7878  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
7879  return derivedFile;
7880  } catch (SQLException ex) {
7881  throw new TskCoreException("Failed to add derived file to case database", ex);
7882  }
7883  }
7884 
7915  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7916  long size, long ctime, long crtime, long atime, long mtime,
7917  boolean isFile, String mimeType,
7918  String rederiveDetails, String toolName, String toolVersion,
7919  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7920 
7921  CaseDbTransaction trans = null;
7922  try {
7923  Content parentObj = derivedFile.getParent();
7924 
7925  trans = beginTransaction();
7926  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
7927  size, ctime, crtime, atime, mtime,
7928  isFile, mimeType,
7929  rederiveDetails, toolName, toolVersion,
7930  otherDetails, encodingType, parentObj, trans);
7931  trans.commit();
7932  return updatedFile;
7933  } catch (TskCoreException ex) {
7934  if (trans != null) {
7935  trans.rollback();
7936  }
7937  throw ex;
7938  }
7939  }
7940 
7941  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7942  long size, long ctime, long crtime, long atime, long mtime,
7943  boolean isFile, String mimeType,
7944  String rederiveDetails, String toolName, String toolVersion,
7945  String otherDetails, TskData.EncodingType encodingType,
7946  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
7947 
7948  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7949  localPath = localPath.replaceAll("^[/\\\\]+", "");
7950 
7951  ResultSet rs = null;
7952  try {
7953  final long parentId = parentObj.getId();
7954  String parentPath = "";
7955  if (parentObj instanceof BlackboardArtifact) {
7956  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7957  } else if (parentObj instanceof AbstractFile) {
7958  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7959  }
7960  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
7961  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
7962  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
7963  statement.clearParameters();
7964 
7965  //type
7966  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7967 
7968  //flags
7970  statement.setShort(2, dirType.getValue());
7972  statement.setShort(3, metaType.getValue());
7973 
7974  //note: using alloc under assumption that derived files derive from alloc files
7976  statement.setShort(4, dirFlag.getValue());
7977  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7978  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7979  statement.setShort(5, metaFlags);
7980 
7981  //size
7982  //prevent negative size
7983  long savedSize = size < 0 ? 0 : size;
7984  statement.setLong(6, savedSize);
7985 
7986  //mactimes
7987  //long ctime, long crtime, long atime, long mtime,
7988  statement.setLong(7, ctime);
7989  statement.setLong(8, crtime);
7990  statement.setLong(9, atime);
7991  statement.setLong(10, mtime);
7992  statement.setString(11, mimeType);
7993  statement.setString(12, String.valueOf(derivedFile.getId()));
7994  trans.getConnection().executeUpdate(statement);
7995 
7996  //add localPath
7997  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
7998 
7999  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
8000  Long fileSystemObjId = derivedFile.getFileSystemObjectId().orElse(null);
8001  final String extension = extractExtension(derivedFile.getName());
8002  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, fileSystemObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
8003  savedSize, ctime, crtime, atime, mtime, null, null, null, null, parentPath, localPath, parentId, null, encodingType, extension,
8004  derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
8005  } catch (SQLException ex) {
8006  throw new TskCoreException("Failed to add derived file to case database", ex);
8007  } finally {
8008  closeResultSet(rs);
8009  }
8010  }
8011 
8031  public LocalFile addLocalFile(String fileName, String localPath,
8032  long size, long ctime, long crtime, long atime, long mtime,
8033  boolean isFile, TskData.EncodingType encodingType,
8034  AbstractFile parent) throws TskCoreException {
8035 
8036  CaseDbTransaction localTrans = beginTransaction();
8037  try {
8038  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
8039  localTrans.commit();
8040  localTrans = null;
8041  return created;
8042  } finally {
8043  if (null != localTrans) {
8044  try {
8045  localTrans.rollback();
8046  } catch (TskCoreException ex2) {
8047  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8048  }
8049  }
8050  }
8051  }
8052 
8077  public LocalFile addLocalFile(String fileName, String localPath,
8078  long size, long ctime, long crtime, long atime, long mtime,
8079  boolean isFile, TskData.EncodingType encodingType,
8080  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8081 
8082  return addLocalFile(fileName, localPath,
8083  size, ctime, crtime, atime, mtime,
8084  null, null, null,
8085  isFile, encodingType,
8086  parent, transaction);
8087  }
8088 
8117  public LocalFile addLocalFile(String fileName, String localPath,
8118  long size, long ctime, long crtime, long atime, long mtime,
8119  String md5, String sha256, FileKnown known, String mimeType,
8120  boolean isFile, TskData.EncodingType encodingType,
8121  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8122 
8123  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8124  md5, sha256, known, mimeType, isFile, encodingType,
8125  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8126 
8127  }
8128 
8159  public LocalFile addLocalFile(String fileName, String localPath,
8160  long size, long ctime, long crtime, long atime, long mtime,
8161  String md5, String sha256, FileKnown known, String mimeType,
8162  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8163  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8164 
8165  return addLocalFile(fileName, localPath,
8166  size, ctime, crtime, atime, mtime,
8167  md5, sha256, null, known, mimeType,
8168  isFile, encodingType, osAccountId, ownerAccount,
8169  parent, transaction);
8170  }
8171 
8172 
8205  public LocalFile addLocalFile(String fileName, String localPath,
8206  long size, long ctime, long crtime, long atime, long mtime,
8207  String md5, String sha256, String sha1Hash, FileKnown known, String mimeType,
8208  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8209  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8210  CaseDbConnection connection = transaction.getConnection();
8211  Statement queryStatement = null;
8212  try {
8213 
8214  // Insert a row for the local/logical file into the tsk_objects table.
8215  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8216  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8217 
8218  // Insert a row for the local/logical file into the tsk_files table.
8219  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8220  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, sha1, known, mime_type,
8221  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8222  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?)
8223  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8224  statement.clearParameters();
8225  statement.setLong(1, objectId);
8226  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8227  statement.setString(3, fileName);
8228  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8229  statement.setShort(5, (short) 1);
8231  statement.setShort(6, dirType.getValue());
8233  statement.setShort(7, metaType.getValue());
8235  statement.setShort(8, dirFlag.getValue());
8236  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8237  statement.setShort(9, metaFlags);
8238  //prevent negative size
8239  long savedSize = size < 0 ? 0 : size;
8240  statement.setLong(10, savedSize);
8241  statement.setLong(11, ctime);
8242  statement.setLong(12, crtime);
8243  statement.setLong(13, atime);
8244  statement.setLong(14, mtime);
8245  statement.setString(15, md5);
8246  statement.setString(16, sha256);
8247  statement.setString(17, sha1Hash); // sha1
8248 
8249  if (known != null) {
8250  statement.setByte(18, known.getFileKnownValue());
8251  } else {
8252  statement.setByte(18, FileKnown.UNKNOWN.getFileKnownValue());
8253  }
8254  statement.setString(19, mimeType);
8255  String parentPath;
8256  long dataSourceObjId;
8257 
8258  if (parent instanceof AbstractFile) {
8259  AbstractFile parentFile = (AbstractFile) parent;
8260  if (isRootDirectory(parentFile, transaction)) {
8261  parentPath = "/";
8262  } else {
8263  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8264  }
8265  dataSourceObjId = parentFile.getDataSourceObjectId();
8266  } else {
8267  parentPath = "/";
8268  dataSourceObjId = getDataSourceObjectId(connection, parent);
8269  }
8270  statement.setString(20, parentPath);
8271  statement.setLong(21, dataSourceObjId);
8272  final String extension = extractExtension(fileName);
8273  statement.setString(22, extension);
8274 
8275  if (ownerAccount != null) {
8276  statement.setString(23, ownerAccount); // ownerUid
8277  } else {
8278  statement.setNull(23, java.sql.Types.VARCHAR);
8279  }
8280 
8281  if (osAccountId != null) {
8282  statement.setLong(24, osAccountId); // osAccountObjId
8283  } else {
8284  statement.setNull(24, java.sql.Types.BIGINT);
8285  }
8286 
8287  connection.executeUpdate(statement);
8288  addFilePath(connection, objectId, localPath, encodingType);
8289  LocalFile localFile = new LocalFile(this,
8290  objectId,
8291  fileName,
8293  dirType,
8294  metaType,
8295  dirFlag,
8296  metaFlags,
8297  savedSize,
8298  ctime, crtime, atime, mtime,
8299  mimeType, md5, sha256, sha1Hash, known,
8300  parent.getId(), parentPath,
8301  dataSourceObjId,
8302  localPath,
8303  encodingType, extension,
8304  ownerAccount, osAccountId);
8305  if (!timelineEventsDisabled.get()) {
8306  getTimelineManager().addEventsForNewFile(localFile, connection);
8307  }
8308  return localFile;
8309 
8310  } catch (SQLException ex) {
8311  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);
8312  } finally {
8313  closeStatement(queryStatement);
8314  }
8315  }
8316 
8322  private class RootDirectoryKey {
8323 
8324  private long dataSourceId;
8325  private Long fileSystemId;
8326 
8327  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8328  this.dataSourceId = dataSourceId;
8329  this.fileSystemId = fileSystemId;
8330  }
8331 
8332  @Override
8333  public int hashCode() {
8334  int hash = 7;
8335  hash = 41 * hash + Objects.hashCode(dataSourceId);
8336  hash = 41 * hash + Objects.hashCode(fileSystemId);
8337  return hash;
8338  }
8339 
8340  @Override
8341  public boolean equals(Object obj) {
8342  if (this == obj) {
8343  return true;
8344  }
8345  if (obj == null) {
8346  return false;
8347  }
8348  if (getClass() != obj.getClass()) {
8349  return false;
8350  }
8351 
8352  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8353  if (dataSourceId != otherKey.dataSourceId) {
8354  return false;
8355  }
8356 
8357  if (fileSystemId != null) {
8358  return fileSystemId.equals(otherKey.fileSystemId);
8359  }
8360  return (otherKey.fileSystemId == null);
8361  }
8362  }
8363 
8376  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8377 
8378  // First check if we know the root directory for this data source and optionally
8379  // file system. There is only one root, so if we know it we can simply compare
8380  // this file ID to the known root directory.
8381  Long fsObjId = null;
8382  if (file instanceof FsContent) {
8383  fsObjId = ((FsContent) file).getFileSystemId();
8384  }
8385  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8386  synchronized (rootDirectoryMapLock) {
8387  if (rootDirectoryMap.containsKey(key)) {
8388  return rootDirectoryMap.get(key).equals(file.getId());
8389  }
8390  }
8391 
8392  // Fallback cache. We store the result of each database lookup
8393  // so it won't be done multiple times in a row. In practice, this will
8394  // only be used if this method was never called on the root directory.
8395  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8396  if (isRoot != null) {
8397  return isRoot;
8398  }
8399 
8400  CaseDbConnection connection = transaction.getConnection();
8401  Statement statement = null;
8402  ResultSet resultSet = null;
8403 
8404  try {
8405  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8406  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8407  + "WHERE ChildRow.obj_id = %s;", file.getId());
8408 
8409  statement = connection.createStatement();
8410  resultSet = statement.executeQuery(query);
8411  if (resultSet.next()) {
8412  long parentId = resultSet.getLong("parent_object_id");
8413  if (parentId == 0) {
8414  return true;
8415  }
8416  int type = resultSet.getInt("parent_type");
8417  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8418  || type == TskData.ObjectType.VS.getObjectType()
8419  || type == TskData.ObjectType.VOL.getObjectType()
8420  || type == TskData.ObjectType.FS.getObjectType();
8421  if (result == true) {
8422  synchronized (rootDirectoryMapLock) {
8423  // This is a root directory so save it
8424  rootDirectoryMap.put(key, file.getId());
8425  }
8426  }
8427  isRootDirectoryCache.put(file.getId(), result);
8428  return result;
8429 
8430  } else {
8431  // This is a root directory so save it
8432  synchronized (rootDirectoryMapLock) {
8433  rootDirectoryMap.put(key, file.getId());
8434  }
8435  isRootDirectoryCache.put(file.getId(), true);
8436 
8437  return true; // The file has no parent
8438 
8439  }
8440  } catch (SQLException ex) {
8441  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
8442  } finally {
8443  closeResultSet(resultSet);
8444  closeStatement(statement);
8445  }
8446  }
8447 
8467  public LayoutFile addLayoutFile(String fileName,
8468  long size,
8469  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
8470  long ctime, long crtime, long atime, long mtime,
8471  List<TskFileRange> fileRanges,
8472  Content parent) throws TskCoreException {
8473 
8474  if (null == parent) {
8475  throw new TskCoreException("Parent can not be null");
8476  }
8477 
8478  String parentPath;
8479  if (parent instanceof AbstractFile) {
8480  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
8481  } else {
8482  parentPath = "/";
8483  }
8484 
8485  CaseDbTransaction transaction = null;
8486  Statement statement = null;
8487  ResultSet resultSet = null;
8488  try {
8489  transaction = beginTransaction();
8490  CaseDbConnection connection = transaction.getConnection();
8491 
8492  /*
8493  * Insert a row for the layout file into the tsk_objects table:
8494  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8495  */
8496  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8497 
8498  /*
8499  * Insert a row for the file into the tsk_files table: INSERT INTO
8500  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
8501  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
8502  * mtime, md5, known, mime_type, parent_path,
8503  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
8504  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8505  */
8506  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8507  prepStmt.clearParameters();
8508  prepStmt.setLong(1, newFileId); // obj_id
8509 
8510  // If the parent is part of a file system, grab its file system ID
8511  Long fileSystemObjectId;
8512  if (0 != parent.getId()) {
8513  fileSystemObjectId = this.getFileSystemId(parent.getId(), connection);
8514  if (fileSystemObjectId != -1) {
8515  prepStmt.setLong(2, fileSystemObjectId);
8516  } else {
8517  prepStmt.setNull(2, java.sql.Types.BIGINT);
8518  fileSystemObjectId = null;
8519  }
8520  } else {
8521  prepStmt.setNull(2, java.sql.Types.BIGINT);
8522  fileSystemObjectId = null;
8523  }
8524  prepStmt.setString(3, fileName); // name
8525  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
8526  prepStmt.setShort(5, (short) 0); // has_path
8527  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8528  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8529  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
8530  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
8531  //prevent negative size
8532  long savedSize = size < 0 ? 0 : size;
8533  prepStmt.setLong(10, savedSize); // size
8534  prepStmt.setLong(11, ctime); // ctime
8535  prepStmt.setLong(12, crtime); // crtime
8536  prepStmt.setLong(13, atime); // atime
8537  prepStmt.setLong(14, mtime); // mtime
8538  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8539  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8540  prepStmt.setNull(17, java.sql.Types.VARCHAR); // SHA-1
8541 
8542  prepStmt.setByte(18, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8543  prepStmt.setNull(19, java.sql.Types.VARCHAR); // MIME type
8544  prepStmt.setString(20, parentPath); // parent path
8545  prepStmt.setLong(21, parent.getDataSource().getId()); // data_source_obj_id
8546 
8547  prepStmt.setString(22, extractExtension(fileName)); //extension
8548 
8549  prepStmt.setString(23, OsAccount.NO_OWNER_ID); // ownerUid
8550  prepStmt.setNull(24, java.sql.Types.BIGINT); // osAccountObjId
8551 
8552  connection.executeUpdate(prepStmt);
8553 
8554  /*
8555  * Insert a row in the tsk_layout_file table for each chunk of the
8556  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
8557  * byte_len, sequence) VALUES (?, ?, ?, ?)
8558  */
8559  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8560  for (TskFileRange tskFileRange : fileRanges) {
8561  prepStmt.clearParameters();
8562  prepStmt.setLong(1, newFileId); // obj_id
8563  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8564  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8565  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8566  connection.executeUpdate(prepStmt);
8567  }
8568 
8569  /*
8570  * Create a layout file representation of the carved file.
8571  */
8572  LayoutFile layoutFile = new LayoutFile(this,
8573  newFileId,
8574  parent.getDataSource().getId(),
8575  fileSystemObjectId,
8576  fileName,
8580  dirFlag,
8581  metaFlag.getValue(),
8582  savedSize,
8583  ctime, crtime, atime, mtime,
8584  null, null, null,
8586  parentPath,
8587  null,
8588  OsAccount.NO_OWNER_ID,
8589  OsAccount.NO_ACCOUNT);
8590 
8591  transaction.commit();
8592  transaction = null;
8593  return layoutFile;
8594 
8595  } catch (SQLException ex) {
8596  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
8597  } finally {
8598  closeResultSet(resultSet);
8599  closeStatement(statement);
8600 
8601  if (null != transaction) {
8602  try {
8603  transaction.rollback();
8604  } catch (TskCoreException ex2) {
8605  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8606  }
8607  }
8608  }
8609  }
8610 
8620  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
8621  if (content == null) {
8622  throw new TskCoreException("Null Content parameter given");
8623  }
8624  if (content instanceof AbstractFile) {
8625  return ((AbstractFile) content).getDataSourceObjectId();
8626  } else {
8627  return getDataSourceObjectId(connection, content.getId());
8628  }
8629  }
8630 
8643  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
8645  Statement statement = null;
8646  ResultSet resultSet = null;
8647  try {
8648  statement = connection.createStatement();
8649  long dataSourceObjId;
8650  long ancestorId = objectId;
8651  do {
8652  dataSourceObjId = ancestorId;
8653  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
8654  resultSet = statement.executeQuery(query);
8655  if (resultSet.next()) {
8656  ancestorId = resultSet.getLong("par_obj_id");
8657  } else {
8658  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
8659  }
8660  resultSet.close();
8661  resultSet = null;
8662  } while (0 != ancestorId); // Not NULL
8663  return dataSourceObjId;
8664  } catch (SQLException ex) {
8665  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
8666  } finally {
8667  closeResultSet(resultSet);
8668  closeStatement(statement);
8670  }
8671  }
8672 
8684  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8685  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
8686  statement.clearParameters();
8687  statement.setLong(1, objId);
8688  statement.setString(2, path);
8689  statement.setInt(3, type.getType());
8690  connection.executeUpdate(statement);
8691  }
8692 
8704  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8705  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
8706  statement.clearParameters();
8707  statement.setString(1, path);
8708  statement.setInt(2, type.getType());
8709  statement.setLong(3, objId);
8710  connection.executeUpdate(statement);
8711  }
8712 
8726  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
8727  String ext = "";
8728  if (!containsLikeWildcard(fileName)) {
8729  ext = SleuthkitCase.extractExtension(fileName);
8730  }
8731 
8732  CaseDbConnection connection = null;
8733  ResultSet rs = null;
8734  long parentId = parentFile.getId();
8735 
8737  try {
8738  connection = connections.getConnection();
8739 
8740  PreparedStatement statement;
8741  if (ext.isEmpty()) {
8742  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
8743  statement.clearParameters();
8744  statement.setLong(1, parentId);
8745  statement.setString(2, fileName);
8746  } else {
8747  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
8748  statement.clearParameters();
8749  statement.setString(1, ext);
8750  statement.setLong(2, parentId);
8751  statement.setString(3, fileName);
8752  }
8753 
8754  rs = connection.executeQuery(statement);
8755  return resultSetToAbstractFiles(rs, connection);
8756  } catch (SQLException ex) {
8757  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
8758  } finally {
8759  closeResultSet(rs);
8760  closeConnection(connection);
8762  }
8763  }
8764 
8776  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
8777  CaseDbConnection connection = null;
8778  Statement s = null;
8779  ResultSet rs = null;
8781  try {
8782  connection = connections.getConnection();
8783  s = connection.createStatement();
8784  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8785  rs.next();
8786  return rs.getLong("count");
8787  } catch (SQLException e) {
8788  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
8789  } finally {
8790  closeResultSet(rs);
8791  closeStatement(s);
8792  closeConnection(connection);
8794  }
8795  }
8796 
8814  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
8815  CaseDbConnection connection = null;
8816  Statement s = null;
8817  ResultSet rs = null;
8819  try {
8820  connection = connections.getConnection();
8821  s = connection.createStatement();
8822  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8823  return resultSetToAbstractFiles(rs, connection);
8824  } catch (SQLException e) {
8825  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
8826  } finally {
8827  closeResultSet(rs);
8828  closeStatement(s);
8829  closeConnection(connection);
8831  }
8832  }
8833 
8852  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
8853  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";
8855  try (CaseDbConnection connection = connections.getConnection()) {
8856  String query = String.format(queryTemplate, parentId, sqlWhereClause);
8857  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
8858  return resultSetToAbstractFiles(rs, connection);
8859  } catch (SQLException ex) {
8860  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
8861  }
8862  } finally {
8864  }
8865  }
8866 
8879  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
8880  CaseDbConnection connection = null;
8881  Statement s = null;
8882  ResultSet rs = null;
8884  try {
8885  connection = connections.getConnection();
8886  s = connection.createStatement();
8887  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8888  List<Long> ret = new ArrayList<>();
8889  while (rs.next()) {
8890  ret.add(rs.getLong("obj_id"));
8891  }
8892  return ret;
8893  } catch (SQLException e) {
8894  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
8895  } finally {
8896  closeResultSet(rs);
8897  closeStatement(s);
8898  closeConnection(connection);
8900  }
8901  }
8902 
8914  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
8915 
8916  // get the non-unique path (strip of image and volume path segments, if
8917  // the exist.
8918  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
8919 
8920  // split the file name from the parent path
8921  int lastSlash = path.lastIndexOf('/'); //NON-NLS
8922 
8923  // if the last slash is at the end, strip it off
8924  if (lastSlash == path.length()) {
8925  path = path.substring(0, lastSlash - 1);
8926  lastSlash = path.lastIndexOf('/'); //NON-NLS
8927  }
8928 
8929  String parentPath = path.substring(0, lastSlash);
8930  String fileName = path.substring(lastSlash);
8931 
8932  return findFiles(dataSource, fileName, parentPath);
8933  }
8934 
8945  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
8946  CaseDbConnection connection = null;
8947  Statement s = null;
8948  ResultSet rs = null;
8950  try {
8951  connection = connections.getConnection();
8952  s = connection.createStatement();
8953  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
8954  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
8955  while (rs.next()) {
8956  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
8957  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
8958  ranges.add(range);
8959  }
8960  return ranges;
8961  } catch (SQLException ex) {
8962  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
8963  } finally {
8964  closeResultSet(rs);
8965  closeStatement(s);
8966  closeConnection(connection);
8968  }
8969  }
8970 
8981  public Image getImageById(long id) throws TskCoreException {
8982  CaseDbConnection connection = null;
8983  Statement s = null;
8984  ResultSet rs = null;
8986  try {
8987  connection = connections.getConnection();
8988  s = connection.createStatement();
8989  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 "
8990  + "FROM tsk_image_info "
8991  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
8992  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
8993  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
8994 
8995  List<String> imagePaths = new ArrayList<>();
8996  long type, ssize, size;
8997  String tzone, md5, sha1, sha256, name, device_id, imagePath;
8998 
8999  if (rs.next()) {
9000  imagePath = rs.getString("name");
9001  if (imagePath != null) {
9002  imagePaths.add(imagePath);
9003  }
9004  type = rs.getLong("type"); //NON-NLS
9005  ssize = rs.getLong("ssize"); //NON-NLS
9006  tzone = rs.getString("tzone"); //NON-NLS
9007  size = rs.getLong("size"); //NON-NLS
9008  md5 = rs.getString("md5"); //NON-NLS
9009  sha1 = rs.getString("sha1"); //NON-NLS
9010  sha256 = rs.getString("sha256"); //NON-NLS
9011  name = rs.getString("display_name");
9012  if (name == null) {
9013  if (imagePaths.size() > 0) {
9014  String path = imagePaths.get(0);
9015  name = (new java.io.File(path)).getName();
9016  } else {
9017  name = "";
9018  }
9019  }
9020  device_id = rs.getString("device_id");
9021  } else {
9022  throw new TskCoreException("No image found for id: " + id);
9023  }
9024 
9025  // image can have multiple paths, therefore there can be multiple rows in the result set
9026  while (rs.next()) {
9027  imagePath = rs.getString("name");
9028  if (imagePath != null) {
9029  imagePaths.add(imagePath);
9030  }
9031  }
9032 
9033  return new Image(this, id, type, device_id, ssize, name,
9034  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
9035  } catch (SQLException ex) {
9036  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
9037  } finally {
9038  closeResultSet(rs);
9039  closeStatement(s);
9040  closeConnection(connection);
9042  }
9043  }
9044 
9056  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
9057  CaseDbConnection connection = null;
9058  Statement s = null;
9059  ResultSet rs = null;
9061  try {
9062  connection = connections.getConnection();
9063  s = connection.createStatement();
9064  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
9065  + "where obj_id = " + id); //NON-NLS
9066  if (rs.next()) {
9067  long type = rs.getLong("vs_type"); //NON-NLS
9068  long imgOffset = rs.getLong("img_offset"); //NON-NLS
9069  long blockSize = rs.getLong("block_size"); //NON-NLS
9070  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
9071  vs.setParent(parent);
9072  return vs;
9073  } else {
9074  throw new TskCoreException("No volume system found for id:" + id);
9075  }
9076  } catch (SQLException ex) {
9077  throw new TskCoreException("Error getting Volume System by ID.", ex);
9078  } finally {
9079  closeResultSet(rs);
9080  closeStatement(s);
9081  closeConnection(connection);
9083  }
9084  }
9085 
9094  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
9095  VolumeSystem vs = getVolumeSystemById(id, null);
9096  vs.setParentId(parentId);
9097  return vs;
9098  }
9099 
9111  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
9112  return getFileSystemByIdHelper(id, parent);
9113  }
9114 
9123  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
9124  Volume vol = null;
9125  FileSystem fs = getFileSystemById(id, vol);
9126  fs.setParentId(parentId);
9127  return fs;
9128  }
9129 
9141  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
9142  return getFileSystemByIdHelper(id, parent);
9143  }
9144 
9156  Pool getPoolById(long id, Content parent) throws TskCoreException {
9157  return getPoolByIdHelper(id, parent);
9158  }
9159 
9168  Pool getPoolById(long id, long parentId) throws TskCoreException {
9169  Pool pool = getPoolById(id, null);
9170  pool.setParentId(parentId);
9171  return pool;
9172  }
9173 
9185  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9186 
9188  try (CaseDbConnection connection = connections.getConnection();
9189  Statement s = connection.createStatement();
9190  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9191  + "where obj_id = " + id);) { //NON-NLS
9192  if (rs.next()) {
9193  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9194  pool.setParent(parent);
9195 
9196  return pool;
9197  } else {
9198  throw new TskCoreException("No pool found for ID:" + id);
9199  }
9200  } catch (SQLException ex) {
9201  throw new TskCoreException("Error getting Pool by ID", ex);
9202  } finally {
9204  }
9205  }
9206 
9218  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9219  // see if we already have it
9220  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9221  // but it should be the same...
9222  synchronized (fileSystemIdMap) {
9223  if (fileSystemIdMap.containsKey(id)) {
9224  return fileSystemIdMap.get(id);
9225  }
9226  }
9227  CaseDbConnection connection = null;
9228  Statement s = null;
9229  ResultSet rs = null;
9231  try {
9232  connection = connections.getConnection();
9233  s = connection.createStatement();
9234  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9235  + "where obj_id = " + id); //NON-NLS
9236  if (rs.next()) {
9237  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9238  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9239  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9240  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9241  fs.setParent(parent);
9242  // save it for the next call
9243  synchronized (fileSystemIdMap) {
9244  fileSystemIdMap.put(id, fs);
9245  }
9246  return fs;
9247  } else {
9248  throw new TskCoreException("No file system found for id:" + id);
9249  }
9250  } catch (SQLException ex) {
9251  throw new TskCoreException("Error getting File System by ID", ex);
9252  } finally {
9253  closeResultSet(rs);
9254  closeStatement(s);
9255  closeConnection(connection);
9257  }
9258  }
9259 
9271  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9272  CaseDbConnection connection = null;
9273  Statement s = null;
9274  ResultSet rs = null;
9276  try {
9277  connection = connections.getConnection();
9278  s = connection.createStatement();
9279  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9280  + "where obj_id = " + id); //NON-NLS
9281  if (rs.next()) {
9289  String description;
9290  try {
9291  description = rs.getString("desc");
9292  } catch (Exception ex) {
9293  description = rs.getString("descr");
9294  }
9295  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9296  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9297  description);
9298  vol.setParent(parent);
9299  return vol;
9300  } else {
9301  throw new TskCoreException("No volume found for id:" + id);
9302  }
9303  } catch (SQLException ex) {
9304  throw new TskCoreException("Error getting Volume by ID", ex);
9305  } finally {
9306  closeResultSet(rs);
9307  closeStatement(s);
9308  closeConnection(connection);
9310  }
9311  }
9312 
9321  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9322  Volume vol = getVolumeById(id, null);
9323  vol.setParentId(parentId);
9324  return vol;
9325  }
9326 
9338  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9339  CaseDbConnection connection = null;
9340  Statement s = null;
9341  ResultSet rs = null;
9343  try {
9344  connection = connections.getConnection();
9345  s = connection.createStatement();
9346  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9347  + "WHERE obj_id = " + id);
9348  Directory temp = null; //NON-NLS
9349  if (rs.next()) {
9350  final short type = rs.getShort("type"); //NON-NLS
9351  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9352  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9353  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9354  temp = directory(rs, parentFs);
9355  }
9356  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9357  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9358  }
9359  } else {
9360  throw new TskCoreException("No Directory found for id:" + id);
9361  }
9362  return temp;
9363  } catch (SQLException ex) {
9364  throw new TskCoreException("Error getting Directory by ID", ex);
9365  } finally {
9366  closeResultSet(rs);
9367  closeStatement(s);
9368  closeConnection(connection);
9370  }
9371  }
9372 
9382  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9383  List<FileSystem> fileSystems = new ArrayList<>();
9384  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9385 
9386  CaseDbConnection connection = null;
9387  Statement s = null;
9388  ResultSet rs = null;
9390  try {
9391  connection = connections.getConnection();
9392  s = connection.createStatement();
9393  rs = connection.executeQuery(s, queryStr); //NON-NLS
9394  while (rs.next()) {
9395  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9396  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9397  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9398  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9399  fs.setParent(null);
9400  fileSystems.add(fs);
9401  }
9402  } catch (SQLException ex) {
9403  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9404  } finally {
9405  closeResultSet(rs);
9406  closeStatement(s);
9407  closeConnection(connection);
9409  }
9410  return fileSystems;
9411  }
9412 
9423  List<Content> getImageChildren(Image img) throws TskCoreException {
9424  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9425  List<Content> children = new ArrayList<Content>();
9426  for (ObjectInfo info : childInfos) {
9427  if (null != info.type) {
9428  switch (info.type) {
9429  case VS:
9430  children.add(getVolumeSystemById(info.id, img));
9431  break;
9432  case POOL:
9433  children.add(getPoolById(info.id, img));
9434  break;
9435  case FS:
9436  children.add(getFileSystemById(info.id, img));
9437  break;
9438  case ABSTRACTFILE:
9439  AbstractFile f = getAbstractFileById(info.id);
9440  if (f != null) {
9441  children.add(f);
9442  }
9443  break;
9444  case ARTIFACT:
9445  BlackboardArtifact art = getArtifactById(info.id);
9446  if (art != null) {
9447  children.add(art);
9448  }
9449  break;
9450  case REPORT:
9451  // Do nothing for now - see JIRA-3673
9452  break;
9453  default:
9454  throw new TskCoreException("Image has child of invalid type: " + info.type);
9455  }
9456  }
9457  }
9458  return children;
9459  }
9460 
9471  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
9472  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9473  List<Long> children = new ArrayList<Long>();
9474  for (ObjectInfo info : childInfos) {
9475  if (info.type == ObjectType.VS
9476  || info.type == ObjectType.POOL
9477  || info.type == ObjectType.FS
9478  || info.type == ObjectType.ABSTRACTFILE
9479  || info.type == ObjectType.ARTIFACT) {
9480  children.add(info.id);
9481  } else if (info.type == ObjectType.REPORT) {
9482  // Do nothing for now - see JIRA-3673
9483  } else {
9484  throw new TskCoreException("Image has child of invalid type: " + info.type);
9485  }
9486  }
9487  return children;
9488  }
9489 
9500  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
9501  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9502  List<Content> children = new ArrayList<Content>();
9503  for (ObjectInfo info : childInfos) {
9504  if (null != info.type) {
9505  switch (info.type) {
9506  case VS:
9507  children.add(getVolumeSystemById(info.id, pool));
9508  break;
9509  case ABSTRACTFILE:
9510  AbstractFile f = getAbstractFileById(info.id);
9511  if (f != null) {
9512  children.add(f);
9513  }
9514  break;
9515  case ARTIFACT:
9516  BlackboardArtifact art = getArtifactById(info.id);
9517  if (art != null) {
9518  children.add(art);
9519  }
9520  break;
9521  default:
9522  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9523  }
9524  }
9525  }
9526  return children;
9527  }
9528 
9539  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
9540  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9541  List<Long> children = new ArrayList<Long>();
9542  for (ObjectInfo info : childInfos) {
9543  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9544  children.add(info.id);
9545  } else {
9546  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9547  }
9548  }
9549  return children;
9550  }
9551 
9562  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
9563  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9564  List<Content> children = new ArrayList<Content>();
9565  for (ObjectInfo info : childInfos) {
9566  if (null != info.type) {
9567  switch (info.type) {
9568  case VOL:
9569  children.add(getVolumeById(info.id, vs));
9570  break;
9571  case ABSTRACTFILE:
9572  AbstractFile f = getAbstractFileById(info.id);
9573  if (f != null) {
9574  children.add(f);
9575  }
9576  break;
9577  case ARTIFACT:
9578  BlackboardArtifact art = getArtifactById(info.id);
9579  if (art != null) {
9580  children.add(art);
9581  }
9582  break;
9583  default:
9584  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9585  }
9586  }
9587  }
9588  return children;
9589  }
9590 
9601  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
9602  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9603  List<Long> children = new ArrayList<Long>();
9604  for (ObjectInfo info : childInfos) {
9605  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9606  children.add(info.id);
9607  } else {
9608  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9609  }
9610  }
9611  return children;
9612  }
9613 
9624  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
9625  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9626  List<Content> children = new ArrayList<Content>();
9627  for (ObjectInfo info : childInfos) {
9628  if (null != info.type) {
9629  switch (info.type) {
9630  case POOL:
9631  children.add(getPoolById(info.id, vol));
9632  break;
9633  case FS:
9634  children.add(getFileSystemById(info.id, vol));
9635  break;
9636  case ABSTRACTFILE:
9637  AbstractFile f = getAbstractFileById(info.id);
9638  if (f != null) {
9639  children.add(f);
9640  }
9641  break;
9642  case ARTIFACT:
9643  BlackboardArtifact art = getArtifactById(info.id);
9644  if (art != null) {
9645  children.add(art);
9646  }
9647  break;
9648  default:
9649  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9650  }
9651  }
9652  }
9653  return children;
9654  }
9655 
9666  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
9667  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9668  final List<Long> children = new ArrayList<Long>();
9669  for (ObjectInfo info : childInfos) {
9670  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9671  children.add(info.id);
9672  } else {
9673  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9674  }
9675  }
9676  return children;
9677  }
9678 
9692  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
9693  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
9694  }
9695 
9710  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
9711  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this);
9712  return getImageById(imageId);
9713  }
9714 
9724  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
9725  CaseDbConnection connection = null;
9726  Statement s1 = null;
9727  ResultSet rs1 = null;
9729  try {
9730  connection = connections.getConnection();
9731  s1 = connection.createStatement();
9732  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
9733  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
9734  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
9735  while (rs1.next()) {
9736  long obj_id = rs1.getLong("obj_id"); //NON-NLS
9737  String name = rs1.getString("name"); //NON-NLS
9738  List<String> imagePaths = imgPaths.get(obj_id);
9739  if (imagePaths == null) {
9740  List<String> paths = new ArrayList<String>();
9741  if (name != null) {
9742  paths.add(name);
9743  }
9744  imgPaths.put(obj_id, paths);
9745  } else {
9746  if (name != null) {
9747  imagePaths.add(name);
9748  }
9749  }
9750  }
9751  return imgPaths;
9752  } catch (SQLException ex) {
9753  throw new TskCoreException("Error getting image paths.", ex);
9754  } finally {
9755  closeResultSet(rs1);
9756  closeStatement(s1);
9757  closeConnection(connection);
9759  }
9760  }
9761 
9773  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
9774  List<String> imagePaths = new ArrayList<>();
9776  Statement statement = null;
9777  ResultSet resultSet = null;
9778  try {
9779  statement = connection.createStatement();
9780  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
9781  while (resultSet.next()) {
9782  imagePaths.add(resultSet.getString("name"));
9783  }
9784  } catch (SQLException ex) {
9785  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
9786  } finally {
9787  closeResultSet(resultSet);
9788  closeStatement(statement);
9790  }
9791 
9792  return imagePaths;
9793  }
9794 
9801  public List<Image> getImages() throws TskCoreException {
9802  CaseDbConnection connection = null;
9803  Statement s = null;
9804  ResultSet rs = null;
9806  try {
9807  connection = connections.getConnection();
9808  s = connection.createStatement();
9809  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
9810  Collection<Long> imageIDs = new ArrayList<Long>();
9811  while (rs.next()) {
9812  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
9813  }
9814  List<Image> images = new ArrayList<Image>();
9815  for (long id : imageIDs) {
9816  images.add(getImageById(id));
9817  }
9818  return images;
9819  } catch (SQLException ex) {
9820  throw new TskCoreException("Error retrieving images.", ex);
9821  } finally {
9822  closeResultSet(rs);
9823  closeStatement(s);
9824  closeConnection(connection);
9826  }
9827  }
9828 
9839  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
9840  CaseDbConnection connection = null;
9842  PreparedStatement statement;
9843  try {
9844  connection = connections.getConnection();
9845  connection.beginTransaction();
9846  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
9847  statement.clearParameters();
9848  statement.setLong(1, obj_id);
9849  connection.executeUpdate(statement);
9850  for (int i = 0; i < paths.size(); i++) {
9851  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
9852  statement.clearParameters();
9853  statement.setLong(1, obj_id);
9854  statement.setString(2, paths.get(i));
9855  statement.setLong(3, i);
9856  connection.executeUpdate(statement);
9857  }
9858  connection.commitTransaction();
9859  } catch (SQLException ex) {
9860  rollbackTransaction(connection);
9861  throw new TskCoreException("Error updating image paths.", ex);
9862  } finally {
9863  closeConnection(connection);
9865  }
9866  }
9867 
9879  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
9880 
9881  // Check if this data source is the only one associated with its host. If so,
9882  // we will delete the host and other associated data.
9883  // Note that the cascading deletes were only added in schema 9.1, so we
9884  // would get an error trying to delete a host from older cases.
9885  Host hostToDelete = null;
9887  int major = version.getMajor();
9888  int minor = version.getMinor();
9889  if (major > 9 || (major == 9 && minor >= 1)) {
9890  hostToDelete = getHostManager().getHostByDataSource(dataSourceObjectId);
9891  if (getHostManager().getDataSourcesForHost(hostToDelete).size() != 1) {
9892  hostToDelete = null;
9893  }
9894  }
9895 
9896  CaseDbConnection connection = null;
9897  Statement statement;
9899  try {
9900  connection = connections.getConnection();
9901  statement = connection.createStatement();
9902  connection.beginTransaction();
9903  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
9904  // all associated rows from tsk_object and its children. For large data sources this may take some time.
9905  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
9906  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
9907  // associated rows from accounts table and its children.
9908  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
9909  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
9910  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
9911  statement.execute(accountSql);
9912 
9913  // Now delete any host that was only associated with this data source. This will cascade to delete
9914  // realms, os accounts, and os account attributes that were associated with the host.
9915  if (hostToDelete != null) {
9916  statement.execute("DELETE FROM tsk_hosts WHERE id = " + hostToDelete.getHostId());
9917 
9918  // Clean up any stray OS Account objects
9919  String deleteOsAcctObjectsQuery = "DELETE FROM tsk_objects "
9920  + "WHERE type=" + TskData.ObjectType.OS_ACCOUNT.getObjectType() + " "
9921  + "AND obj_id NOT IN (SELECT os_account_obj_id FROM tsk_os_accounts WHERE os_account_obj_id IS NOT NULL)";
9922  statement.execute(deleteOsAcctObjectsQuery);
9923  }
9924 
9925  connection.commitTransaction();
9926  } catch (SQLException ex) {
9927  rollbackTransaction(connection);
9928  throw new TskCoreException("Error deleting data source.", ex);
9929  } finally {
9930  closeConnection(connection);
9932  }
9933  }
9934 
9960  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
9961  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
9962  try {
9963  while (rs.next()) {
9964  final short type = rs.getShort("type"); //NON-NLS
9965  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
9966  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
9967  FsContent result;
9968  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
9969  result = directory(rs, null);
9970  } else {
9971  result = file(rs, null);
9972  }
9973  results.add(result);
9974  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
9975  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
9976  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
9977  results.add(virtDir);
9978  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
9979  final LocalDirectory localDir = localDirectory(rs);
9980  results.add(localDir);
9981  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
9982  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
9983  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
9984  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
9985  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
9986  String parentPath = rs.getString("parent_path"); //NON-NLS
9987  if (parentPath == null) {
9988  parentPath = "/"; //NON-NLS
9989  }
9990 
9991  Long osAccountObjId = rs.getLong("os_account_obj_id");
9992  if (rs.wasNull()) {
9993  osAccountObjId = null;
9994  }
9995 
9996  LayoutFile lf = new LayoutFile(this,
9997  rs.getLong("obj_id"), //NON-NLS
9998  rs.getLong("data_source_obj_id"),
9999  rs.getLong("fs_obj_id"),
10000  rs.getString("name"), //NON-NLS
10001  atype,
10002  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10003  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10004  rs.getLong("size"), //NON-NLS
10005  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10006  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10007  FileKnown.valueOf(rs.getByte("known")), parentPath,
10008  rs.getString("mime_type"),
10009  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10010  results.add(lf);
10011  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
10012  final DerivedFile df;
10013  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
10014  results.add(df);
10015  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
10016  final LocalFile lf;
10017  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
10018  results.add(lf);
10019  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
10020  final SlackFile sf = slackFile(rs, null);
10021  results.add(sf);
10022  }
10023  } //end for each resultSet
10024  } catch (SQLException e) {
10025  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
10026  }
10027 
10028  return results;
10029  }
10030 
10031  // This following methods generate AbstractFile objects from a ResultSet
10043  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
10044  Long osAccountObjId = rs.getLong("os_account_obj_id");
10045  if (rs.wasNull()) {
10046  osAccountObjId = null;
10047  }
10048 
10049  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
10050  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10051  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10052  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10053  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10054  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10055  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10056  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10057  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10058  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10059  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10060  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10061  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"),
10062  osAccountObjId, Collections.emptyList()); //NON-NLS
10063  f.setFileSystem(fs);
10064  return f;
10065  }
10066 
10078  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
10079  Long osAccountObjId = rs.getLong("os_account_obj_id");
10080  if (rs.wasNull()) {
10081  osAccountObjId = null;
10082  }
10083 
10084  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10085  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10086  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10087  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10088  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10089  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10090  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10091  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10092  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10093  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10094  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10095  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10096  dir.setFileSystem(fs);
10097  return dir;
10098  }
10099 
10110  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
10111  String parentPath = rs.getString("parent_path"); //NON-NLS
10112  if (parentPath == null) {
10113  parentPath = "";
10114  }
10115 
10116  long objId = rs.getLong("obj_id");
10117  long dsObjId = rs.getLong("data_source_obj_id");
10118  if (objId == dsObjId) { // virtual directory is a data source
10119 
10120  String deviceId = "";
10121  String timeZone = "";
10122  Statement s = null;
10123  ResultSet rsDataSourceInfo = null;
10124 
10126  try {
10127  s = connection.createStatement();
10128  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
10129  if (rsDataSourceInfo.next()) {
10130  deviceId = rsDataSourceInfo.getString("device_id");
10131  timeZone = rsDataSourceInfo.getString("time_zone");
10132  }
10133  } catch (SQLException ex) {
10134  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
10135  } finally {
10136  closeResultSet(rsDataSourceInfo);
10137  closeStatement(s);
10139  }
10140 
10141  return new LocalFilesDataSource(this,
10142  objId, dsObjId,
10143  deviceId,
10144  rs.getString("name"),
10145  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10146  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10147  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
10148  rs.getShort("meta_flags"),
10149  timeZone,
10150  rs.getString("md5"),
10151  rs.getString("sha256"),
10152  rs.getString("sha1"),
10153  FileKnown.valueOf(rs.getByte("known")),
10154  parentPath);
10155  } else {
10156  final VirtualDirectory vd = new VirtualDirectory(this,
10157  objId, dsObjId,
10158  rs.getLong("fs_obj_id"),
10159  rs.getString("name"), //NON-NLS
10160  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10161  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10162  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10163  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10164  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10165  return vd;
10166  }
10167  }
10168 
10178  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
10179  String parentPath = rs.getString("parent_path"); //NON-NLS
10180  if (parentPath == null) {
10181  parentPath = "";
10182  }
10183  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
10184  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
10185  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10186  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10187  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10188  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"), //NON-NLS
10189  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10190  return ld;
10191  }
10192 
10206  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10207  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10208  long objId = rs.getLong("obj_id"); //NON-NLS
10209  String localPath = null;
10210  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10211  if (hasLocalPath) {
10212  ResultSet rsFilePath = null;
10214  try {
10215  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10216  statement.clearParameters();
10217  statement.setLong(1, objId);
10218  rsFilePath = connection.executeQuery(statement);
10219  if (rsFilePath.next()) {
10220  localPath = rsFilePath.getString("path");
10221  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10222  }
10223  } catch (SQLException ex) {
10224  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10225  } finally {
10226  closeResultSet(rsFilePath);
10228  }
10229  }
10230  String parentPath = rs.getString("parent_path"); //NON-NLS
10231  if (parentPath == null) {
10232  parentPath = "";
10233  }
10234 
10235  Long osAccountObjId = rs.getLong("os_account_obj_id");
10236  if (rs.wasNull()) {
10237  osAccountObjId = null;
10238  }
10239 
10240  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10241  rs.getLong("fs_obj_id"),
10242  rs.getString("name"), //NON-NLS
10243  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10244  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10245  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10246  rs.getLong("size"), //NON-NLS
10247  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10248  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10249  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10250  parentPath, localPath, parentId, rs.getString("mime_type"),
10251  encodingType, rs.getString("extension"),
10252  rs.getString("owner_uid"), osAccountObjId);
10253  return df;
10254  }
10255 
10269  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10270  long objId = rs.getLong("obj_id"); //NON-NLS
10271  String localPath = null;
10272  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10273  if (rs.getBoolean("has_path")) {
10274  ResultSet rsFilePath = null;
10276  try {
10277  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10278  statement.clearParameters();
10279  statement.setLong(1, objId);
10280  rsFilePath = connection.executeQuery(statement);
10281  if (rsFilePath.next()) {
10282  localPath = rsFilePath.getString("path");
10283  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10284  }
10285  } catch (SQLException ex) {
10286  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10287  } finally {
10288  closeResultSet(rsFilePath);
10290  }
10291  }
10292  String parentPath = rs.getString("parent_path"); //NON-NLS
10293  if (null == parentPath) {
10294  parentPath = "";
10295  }
10296  Long osAccountObjId = rs.getLong("os_account_obj_id");
10297  if (rs.wasNull()) {
10298  osAccountObjId = null;
10299  }
10300 
10301  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10302  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10303  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10304  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10305  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10306  rs.getLong("size"), //NON-NLS
10307  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10308  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10309  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10310  parentId, parentPath, rs.getLong("data_source_obj_id"),
10311  localPath, encodingType, rs.getString("extension"),
10312  rs.getString("owner_uid"), osAccountObjId);
10313  return file;
10314  }
10315 
10327  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10328  Long osAccountObjId = rs.getLong("os_account_obj_id");
10329  if (rs.wasNull()) {
10330  osAccountObjId = null;
10331  }
10332  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10333  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10334  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10335  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10336  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10337  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10338  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10339  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10340  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10341  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10342  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10343  FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10344  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10345  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10346  f.setFileSystem(fs);
10347  return f;
10348  }
10349 
10361  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10362  List<Content> children = new ArrayList<Content>();
10363 
10364  while (rs.next()) {
10365  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10366 
10367  if (null != type) {
10368  switch (type) {
10369  case FS:
10370  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10371  FsContent result;
10372  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10373  result = directory(rs, null);
10374  } else {
10375  result = file(rs, null);
10376  }
10377  children.add(result);
10378  } else {
10379  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10380  children.add(virtDir);
10381  }
10382  break;
10383  case VIRTUAL_DIR:
10384  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10385  children.add(virtDir);
10386  break;
10387  case LOCAL_DIR:
10388  LocalDirectory localDir = localDirectory(rs);
10389  children.add(localDir);
10390  break;
10391  case UNALLOC_BLOCKS:
10392  case UNUSED_BLOCKS:
10393  case CARVED:
10394  case LAYOUT_FILE: {
10395  String parentPath = rs.getString("parent_path");
10396  if (parentPath == null) {
10397  parentPath = "";
10398  }
10399  Long osAccountObjId = rs.getLong("os_account_obj_id");
10400  if (rs.wasNull()) {
10401  osAccountObjId = null;
10402  }
10403  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
10404  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"),
10405  rs.getString("name"), type,
10406  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
10407  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
10408  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
10409  rs.getLong("size"),
10410  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
10411  rs.getString("md5"), rs.getString("sha256"), rs.getString("sha1"),
10412  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
10413  rs.getString("owner_uid"), osAccountObjId);
10414  children.add(lf);
10415  break;
10416  }
10417  case DERIVED:
10418  final DerivedFile df = derivedFile(rs, connection, parentId);
10419  children.add(df);
10420  break;
10421  case LOCAL: {
10422  final LocalFile lf = localFile(rs, connection, parentId);
10423  children.add(lf);
10424  break;
10425  }
10426  case SLACK: {
10427  final SlackFile sf = slackFile(rs, null);
10428  children.add(sf);
10429  break;
10430  }
10431  default:
10432  break;
10433  }
10434  }
10435  }
10436  return children;
10437  }
10438 
10460  public CaseDbQuery executeQuery(String query) throws TskCoreException {
10461  return new CaseDbQuery(query);
10462  }
10463 
10485  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
10486  return new CaseDbQuery(query, true);
10487  }
10488 
10496  CaseDbConnection getConnection() throws TskCoreException {
10497  return connections.getConnection();
10498  }
10499 
10507  String getCaseHandleIdentifier() {
10508  return caseHandleIdentifier;
10509  }
10510 
10511  @SuppressWarnings("deprecation")
10512  @Override
10513  protected void finalize() throws Throwable {
10514  try {
10515  close();
10516  } finally {
10517  super.finalize();
10518  }
10519  }
10520 
10524  public synchronized void close() {
10526 
10527  try {
10528  connections.close();
10529  } catch (TskCoreException ex) {
10530  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
10531  }
10532 
10533  fileSystemIdMap.clear();
10534 
10535  try {
10536  if (this.caseHandle != null) {
10537  this.caseHandle.free();
10538  this.caseHandle = null;
10539  }
10540  } catch (TskCoreException ex) {
10541  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
10542  } finally {
10544  }
10545  }
10546 
10559  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
10560  long id = file.getId();
10561  FileKnown currentKnown = file.getKnown();
10562  if (currentKnown.compareTo(fileKnown) > 0) {
10563  return false;
10564  }
10566  try (CaseDbConnection connection = connections.getConnection();
10567  Statement statement = connection.createStatement();) {
10568  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
10569  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
10570  + "WHERE obj_id=" + id); //NON-NLS
10571 
10572  file.setKnown(fileKnown);
10573  } catch (SQLException ex) {
10574  throw new TskCoreException("Error setting Known status.", ex);
10575  } finally {
10577  }
10578  return true;
10579  }
10580 
10589  void setFileName(String name, long objId) throws TskCoreException {
10591  try (CaseDbConnection connection = connections.getConnection();) {
10592  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
10593  preparedStatement.clearParameters();
10594  preparedStatement.setString(1, name);
10595  preparedStatement.setLong(2, objId);
10596  connection.executeUpdate(preparedStatement);
10597  } catch (SQLException ex) {
10598  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10599  } finally {
10601  }
10602  }
10603 
10612  void setImageName(String name, long objId) throws TskCoreException {
10614  try (CaseDbConnection connection = connections.getConnection();) {
10615  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
10616  preparedStatement.clearParameters();
10617  preparedStatement.setString(1, name);
10618  preparedStatement.setLong(2, objId);
10619  connection.executeUpdate(preparedStatement);
10620  } catch (SQLException ex) {
10621  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10622  } finally {
10624  }
10625  }
10626 
10641  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
10642 
10644  try (CaseDbConnection connection = connections.getConnection();) {
10645  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
10646  preparedStatement.clearParameters();
10647  preparedStatement.setLong(1, totalSize);
10648  preparedStatement.setLong(2, sectorSize);
10649  preparedStatement.setLong(3, image.getId());
10650  connection.executeUpdate(preparedStatement);
10651  } catch (SQLException ex) {
10652  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);
10653  } finally {
10655  }
10656  }
10657 
10667  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
10669  try (CaseDbConnection connection = connections.getConnection();
10670  Statement statement = connection.createStatement()) {
10671  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
10672  file.setMIMEType(mimeType);
10673  } catch (SQLException ex) {
10674  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
10675  } finally {
10677  }
10678  }
10679 
10690  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
10691 
10692  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
10693  short metaFlag = file.getMetaFlagsAsInt();
10694  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
10695  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
10696  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
10697 
10698  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
10699  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
10700 
10702  try (CaseDbConnection connection = connections.getConnection();
10703  Statement statement = connection.createStatement();) {
10704  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
10705 
10706  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
10707  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
10708 
10709  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
10710 
10711  } catch (SQLException ex) {
10712  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
10713  } finally {
10715  }
10716  }
10717 
10727  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
10728  if (md5Hash == null) {
10729  return;
10730  }
10731  long id = file.getId();
10733  try (CaseDbConnection connection = connections.getConnection();) {
10734  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
10735  statement.clearParameters();
10736  statement.setString(1, md5Hash.toLowerCase());
10737  statement.setLong(2, id);
10738  connection.executeUpdate(statement);
10739  file.setMd5Hash(md5Hash.toLowerCase());
10740  } catch (SQLException ex) {
10741  throw new TskCoreException("Error setting MD5 hash", ex);
10742  } finally {
10744  }
10745  }
10746 
10756  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
10757  if (md5Hash == null) {
10758  return;
10759  }
10760  long id = img.getId();
10762  try (CaseDbConnection connection = connections.getConnection();) {
10763  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
10764  statement.clearParameters();
10765  statement.setString(1, md5Hash.toLowerCase());
10766  statement.setLong(2, id);
10767  connection.executeUpdate(statement);
10768  } catch (SQLException ex) {
10769  throw new TskCoreException("Error setting MD5 hash", ex);
10770  } finally {
10772  }
10773  }
10774 
10785  String getMd5ImageHash(Image img) throws TskCoreException {
10786  long id = img.getId();
10787  CaseDbConnection connection = null;
10788  ResultSet rs = null;
10789  String hash = "";
10791  try {
10792  connection = connections.getConnection();
10793 
10794  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
10795  statement.clearParameters();
10796  statement.setLong(1, id);
10797  rs = connection.executeQuery(statement);
10798  if (rs.next()) {
10799  hash = rs.getString("md5");
10800  }
10801  return hash;
10802  } catch (SQLException ex) {
10803  throw new TskCoreException("Error getting MD5 hash", ex);
10804  } finally {
10805  closeResultSet(rs);
10806  closeConnection(connection);
10808  }
10809  }
10810 
10820  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
10821  if (sha1Hash == null) {
10822  return;
10823  }
10824  long id = img.getId();
10826  try (CaseDbConnection connection = connections.getConnection();) {
10827  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
10828  statement.clearParameters();
10829  statement.setString(1, sha1Hash.toLowerCase());
10830  statement.setLong(2, id);
10831  connection.executeUpdate(statement);
10832  } catch (SQLException ex) {
10833  throw new TskCoreException("Error setting SHA1 hash", ex);
10834  } finally {
10836  }
10837  }
10838 
10849  String getSha1ImageHash(Image img) throws TskCoreException {
10850  long id = img.getId();
10851  CaseDbConnection connection = null;
10852  ResultSet rs = null;
10853  String hash = "";
10855  try {
10856  connection = connections.getConnection();
10857 
10858  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
10859  statement.clearParameters();
10860  statement.setLong(1, id);
10861  rs = connection.executeQuery(statement);
10862  if (rs.next()) {
10863  hash = rs.getString("sha1");
10864  }
10865  return hash;
10866  } catch (SQLException ex) {
10867  throw new TskCoreException("Error getting SHA1 hash", ex);
10868  } finally {
10869  closeResultSet(rs);
10870  closeConnection(connection);
10872  }
10873  }
10874 
10884  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
10885  if (sha256Hash == null) {
10886  return;
10887  }
10888  long id = img.getId();
10890  try (CaseDbConnection connection = connections.getConnection();) {
10891  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
10892  statement.clearParameters();
10893  statement.setString(1, sha256Hash.toLowerCase());
10894  statement.setLong(2, id);
10895  connection.executeUpdate(statement);
10896  } catch (SQLException ex) {
10897  throw new TskCoreException("Error setting SHA256 hash", ex);
10898  } finally {
10900  }
10901  }
10902 
10913  String getSha256ImageHash(Image img) throws TskCoreException {
10914  long id = img.getId();
10915  CaseDbConnection connection = null;
10916  ResultSet rs = null;
10917  String hash = "";
10919  try {
10920  connection = connections.getConnection();
10921 
10922  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
10923  statement.clearParameters();
10924  statement.setLong(1, id);
10925  rs = connection.executeQuery(statement);
10926  if (rs.next()) {
10927  hash = rs.getString("sha256");
10928  }
10929  return hash;
10930  } catch (SQLException ex) {
10931  throw new TskCoreException("Error setting SHA256 hash", ex);
10932  } finally {
10933  closeResultSet(rs);
10934  closeConnection(connection);
10936  }
10937  }
10938 
10947  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
10948 
10949  long id = datasource.getId();
10951  try (CaseDbConnection connection = connections.getConnection();) {
10952  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
10953  statement.clearParameters();
10954  statement.setString(1, details);
10955  statement.setLong(2, id);
10956  connection.executeUpdate(statement);
10957  } catch (SQLException ex) {
10958  throw new TskCoreException("Error setting acquisition details", ex);
10959  } finally {
10961  }
10962  }
10963 
10975  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
10976 
10977  long id = datasource.getId();
10979  try (CaseDbConnection connection = connections.getConnection();) {
10980  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
10981  statement.clearParameters();
10982  statement.setString(1, settings);
10983  statement.setString(2, name);
10984  statement.setString(3, version);
10985  statement.setLong(4, id);
10986  connection.executeUpdate(statement);
10987  } catch (SQLException ex) {
10988  throw new TskCoreException("Error setting acquisition details", ex);
10989  } finally {
10991  }
10992  }
10993 
11003  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
11004  try {
11005  CaseDbConnection connection = trans.getConnection();
11006  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
11007  statement.clearParameters();
11008  statement.setString(1, details);
11009  statement.setLong(2, dataSourceId);
11010  connection.executeUpdate(statement);
11011  } catch (SQLException ex) {
11012  throw new TskCoreException("Error setting acquisition details", ex);
11013  }
11014  }
11015 
11025  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
11026  long id = datasource.getId();
11027  CaseDbConnection connection = null;
11028  ResultSet rs = null;
11029  String hash = "";
11031  try {
11032  connection = connections.getConnection();
11033 
11034  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
11035  statement.clearParameters();
11036  statement.setLong(1, id);
11037  rs = connection.executeQuery(statement);
11038  if (rs.next()) {
11039  hash = rs.getString("acquisition_details");
11040  }
11041  return hash;
11042  } catch (SQLException ex) {
11043  throw new TskCoreException("Error setting acquisition details", ex);
11044  } finally {
11045  closeResultSet(rs);
11046  closeConnection(connection);
11048  }
11049  }
11050 
11061  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
11062  long id = datasource.getId();
11063  CaseDbConnection connection = null;
11064  ResultSet rs = null;
11065  String returnValue = "";
11067  try {
11068  connection = connections.getConnection();
11069 
11070  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11071  statement.clearParameters();
11072  statement.setLong(1, id);
11073  rs = connection.executeQuery(statement);
11074  if (rs.next()) {
11075  returnValue = rs.getString(columnName);
11076  }
11077  return returnValue;
11078  } catch (SQLException ex) {
11079  throw new TskCoreException("Error setting acquisition details", ex);
11080  } finally {
11081  closeResultSet(rs);
11082  closeConnection(connection);
11084  }
11085  }
11086 
11097  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
11098  long id = datasource.getId();
11099  CaseDbConnection connection = null;
11100  ResultSet rs = null;
11101  Long returnValue = null;
11103  try {
11104  connection = connections.getConnection();
11105 
11106  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11107  statement.clearParameters();
11108  statement.setLong(1, id);
11109  rs = connection.executeQuery(statement);
11110  if (rs.next()) {
11111  returnValue = rs.getLong(columnName);
11112  }
11113  return returnValue;
11114  } catch (SQLException ex) {
11115  throw new TskCoreException("Error setting acquisition details", ex);
11116  } finally {
11117  closeResultSet(rs);
11118  closeConnection(connection);
11120  }
11121  }
11122 
11133  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
11134  if (newStatus == null) {
11135  return;
11136  }
11138  try (CaseDbConnection connection = connections.getConnection();
11139  Statement statement = connection.createStatement();) {
11140  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
11141  + " SET review_status_id=" + newStatus.getID()
11142  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
11143  } catch (SQLException ex) {
11144  throw new TskCoreException("Error setting review status", ex);
11145  } finally {
11147  }
11148  }
11149 
11160  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
11161  CaseDbConnection connection = null;
11162  Statement s = null;
11163  ResultSet rs = null;
11165  try {
11166  connection = connections.getConnection();
11167  s = connection.createStatement();
11168  Short contentShort = contentType.getValue();
11169  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
11170  int count = 0;
11171  if (rs.next()) {
11172  count = rs.getInt("count");
11173  }
11174  return count;
11175  } catch (SQLException ex) {
11176  throw new TskCoreException("Error getting number of objects.", ex);
11177  } finally {
11178  closeResultSet(rs);
11179  closeStatement(s);
11180  closeConnection(connection);
11182  }
11183  }
11184 
11193  public static String escapeSingleQuotes(String text) {
11194  String escapedText = null;
11195  if (text != null) {
11196  escapedText = text.replaceAll("'", "''");
11197  }
11198  return escapedText;
11199  }
11200 
11208  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11209  if (md5Hash == null) {
11210  return Collections.<AbstractFile>emptyList();
11211  }
11212 
11213  CaseDbConnection connection = null;
11214  Statement s = null;
11215  ResultSet rs = null;
11217  try {
11218  connection = connections.getConnection();
11219  s = connection.createStatement();
11220  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11221  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11222  + "AND size > 0"); //NON-NLS
11223  return resultSetToAbstractFiles(rs, connection);
11224  } catch (SQLException | TskCoreException ex) {
11225  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11226  } finally {
11227  closeResultSet(rs);
11228  closeStatement(s);
11229  closeConnection(connection);
11231  }
11232  return Collections.<AbstractFile>emptyList();
11233  }
11234 
11241  public boolean allFilesMd5Hashed() {
11242  boolean allFilesAreHashed = false;
11243 
11244  CaseDbConnection connection = null;
11245  Statement s = null;
11246  ResultSet rs = null;
11248  try {
11249  connection = connections.getConnection();
11250  s = connection.createStatement();
11251  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11252  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11253  + "AND md5 IS NULL " //NON-NLS
11254  + "AND size > '0'"); //NON-NLS
11255  if (rs.next() && rs.getInt("count") == 0) {
11256  allFilesAreHashed = true;
11257  }
11258  } catch (SQLException | TskCoreException ex) {
11259  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11260  } finally {
11261  closeResultSet(rs);
11262  closeStatement(s);
11263  closeConnection(connection);
11265  }
11266  return allFilesAreHashed;
11267  }
11268 
11274  public int countFilesMd5Hashed() {
11275  int count = 0;
11276 
11278  CaseDbConnection connection = null;
11279  Statement s = null;
11280  ResultSet rs = null;
11281  try {
11282  connection = connections.getConnection();
11283  s = connection.createStatement();
11284  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11285  + "WHERE md5 IS NOT NULL " //NON-NLS
11286  + "AND size > '0'"); //NON-NLS
11287  if (rs.next()) {
11288  count = rs.getInt("count");
11289  }
11290  } catch (SQLException | TskCoreException ex) {
11291  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11292  } finally {
11293  closeResultSet(rs);
11294  closeStatement(s);
11295  closeConnection(connection);
11297  }
11298  return count;
11299 
11300  }
11301 
11310  public List<TagName> getAllTagNames() throws TskCoreException {
11311  CaseDbConnection connection = null;
11312  ResultSet resultSet = null;
11314  try {
11315  connection = connections.getConnection();
11316 
11317  // SELECT * FROM tag_names
11318  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11319  resultSet = connection.executeQuery(statement);
11320  ArrayList<TagName> tagNames = new ArrayList<>();
11321  while (resultSet.next()) {
11322  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11323  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11324  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11325  }
11326  return tagNames;
11327  } catch (SQLException ex) {
11328  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11329  } finally {
11330  closeResultSet(resultSet);
11331  closeConnection(connection);
11333  }
11334  }
11335 
11346  public List<TagName> getTagNamesInUse() throws TskCoreException {
11347  CaseDbConnection connection = null;
11348  ResultSet resultSet = null;
11350  try {
11351  connection = connections.getConnection();
11352 
11353  // 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)
11354  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
11355  resultSet = connection.executeQuery(statement);
11356  ArrayList<TagName> tagNames = new ArrayList<>();
11357  while (resultSet.next()) {
11358  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11359  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11360  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11361  }
11362  return tagNames;
11363  } catch (SQLException ex) {
11364  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11365  } finally {
11366  closeResultSet(resultSet);
11367  closeConnection(connection);
11369  }
11370  }
11371 
11384  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
11385 
11386  ArrayList<TagName> tagNames = new ArrayList<>();
11387  // SELECT * FROM tag_names WHERE tag_name_id IN
11388  // ( 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 = ? "
11389  // UNION
11390  // 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 = ? )
11391  // )
11392  CaseDbConnection connection = null;
11393  ResultSet resultSet = null;
11395  try {
11396  connection = connections.getConnection();
11397 
11398  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
11399  statement.setLong(1, dsObjId);
11400  statement.setLong(2, dsObjId);
11401  resultSet = connection.executeQuery(statement); //NON-NLS
11402  while (resultSet.next()) {
11403  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11404  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11405  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11406  }
11407  return tagNames;
11408  } catch (SQLException ex) {
11409  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
11410  } finally {
11411  closeResultSet(resultSet);
11412  closeConnection(connection);
11414  }
11415  }
11416 
11430  @Deprecated
11431  @SuppressWarnings("deprecation")
11432  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
11433  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
11434  }
11435 
11452  @Deprecated
11453  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
11454  return getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
11455  }
11456 
11471  @Deprecated
11472  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
11473  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
11474  }
11475 
11476  /*
11477  * Deletes a row from the content_tags table in the case database. @param
11478  * tag A ContentTag data transfer object (DTO) for the row to delete.
11479  * @throws TskCoreException
11480  */
11481  public void deleteContentTag(ContentTag tag) throws TskCoreException {
11483  try {
11484  // DELETE FROM content_tags WHERE tag_id = ?
11485  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
11486  statement.clearParameters();
11487  statement.setLong(1, tag.getId());
11488  trans.getConnection().executeUpdate(statement);
11489 
11490  // update the aggregate score for the content
11491  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
11492  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11493  ? tag.getContent().getDataSource().getId()
11494  : null;
11495 
11496  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
11497 
11498  trans.commit();
11499  trans = null;
11500  } catch (SQLException ex) {
11501  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
11502  } finally {
11503  if (trans != null) {
11504  trans.rollback();
11505  }
11506  }
11507  }
11508 
11517  public List<ContentTag> getAllContentTags() throws TskCoreException {
11518  CaseDbConnection connection = null;
11519  ResultSet resultSet = null;
11521  try {
11522  connection = connections.getConnection();
11523 
11524  // 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
11525  // FROM content_tags
11526  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11527  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11528  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
11529  resultSet = connection.executeQuery(statement);
11530  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11531  while (resultSet.next()) {
11532  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11533  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11534  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11535  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
11536  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
11537  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
11538  }
11539  return tags;
11540  } catch (SQLException ex) {
11541  throw new TskCoreException("Error selecting rows from content_tags table", ex);
11542  } finally {
11543  closeResultSet(resultSet);
11544  closeConnection(connection);
11546  }
11547  }
11548 
11559  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
11560  if (tagName.getId() == Tag.ID_NOT_SET) {
11561  throw new TskCoreException("TagName object is invalid, id not set");
11562  }
11563  CaseDbConnection connection = null;
11564  ResultSet resultSet = null;
11566  try {
11567  connection = connections.getConnection();
11568 
11569  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
11570  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
11571  statement.clearParameters();
11572  statement.setLong(1, tagName.getId());
11573  resultSet = connection.executeQuery(statement);
11574  if (resultSet.next()) {
11575  return resultSet.getLong("count");
11576  } else {
11577  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11578  }
11579  } catch (SQLException ex) {
11580  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11581  } finally {
11582  closeResultSet(resultSet);
11583  closeConnection(connection);
11585  }
11586  }
11587 
11603  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11604 
11605  if (tagName.getId() == Tag.ID_NOT_SET) {
11606  throw new TskCoreException("TagName object is invalid, id not set");
11607  }
11608 
11609  CaseDbConnection connection = null;
11610  ResultSet resultSet = null;
11612  try {
11613  connection = connections.getConnection();
11614 
11615  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11616  // + " AND content_tags.tag_name_id = ? "
11617  // + " AND tsk_files.data_source_obj_id = ? "
11618  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11619  statement.clearParameters();
11620  statement.setLong(1, tagName.getId());
11621  statement.setLong(2, dsObjId);
11622 
11623  resultSet = connection.executeQuery(statement);
11624  if (resultSet.next()) {
11625  return resultSet.getLong("count");
11626  } else {
11627  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11628  }
11629  } catch (SQLException ex) {
11630  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11631  } finally {
11632  closeResultSet(resultSet);
11633  closeConnection(connection);
11635  }
11636  }
11637 
11648  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
11649 
11650  CaseDbConnection connection = null;
11651  ResultSet resultSet = null;
11652  ContentTag tag = null;
11654  try {
11655  connection = connections.getConnection();
11656 
11657  // 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
11658  // FROM content_tags
11659  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11660  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11661  // WHERE tag_id = ?
11662  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
11663  statement.clearParameters();
11664  statement.setLong(1, contentTagID);
11665  resultSet = connection.executeQuery(statement);
11666 
11667  while (resultSet.next()) {
11668  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11669  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11670  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11671  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
11672  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
11673  }
11674  resultSet.close();
11675 
11676  } catch (SQLException ex) {
11677  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
11678  } finally {
11679  closeResultSet(resultSet);
11680  closeConnection(connection);
11682  }
11683  return tag;
11684  }
11685 
11697  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
11698  if (tagName.getId() == Tag.ID_NOT_SET) {
11699  throw new TskCoreException("TagName object is invalid, id not set");
11700  }
11701  CaseDbConnection connection = null;
11702  ResultSet resultSet = null;
11704  try {
11705  connection = connections.getConnection();
11706 
11707  // 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
11708  // FROM content_tags
11709  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11710  // WHERE tag_name_id = ?
11711  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
11712  statement.clearParameters();
11713  statement.setLong(1, tagName.getId());
11714  resultSet = connection.executeQuery(statement);
11715  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11716  while (resultSet.next()) {
11717  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11718  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11719  tags.add(tag);
11720  }
11721  resultSet.close();
11722  return tags;
11723  } catch (SQLException ex) {
11724  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
11725  } finally {
11726  closeResultSet(resultSet);
11727  closeConnection(connection);
11729  }
11730  }
11731 
11744  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11745 
11746  CaseDbConnection connection = null;
11747  ResultSet resultSet = null;
11749  try {
11750  connection = connections.getConnection();
11751 
11752  // 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
11753  // FROM content_tags as content_tags, tsk_files as tsk_files
11754  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11755  // WHERE content_tags.obj_id = tsk_files.obj_id
11756  // AND content_tags.tag_name_id = ?
11757  // AND tsk_files.data_source_obj_id = ?
11758  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11759  statement.clearParameters();
11760  statement.setLong(1, tagName.getId());
11761  statement.setLong(2, dsObjId);
11762  resultSet = connection.executeQuery(statement);
11763  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11764  while (resultSet.next()) {
11765  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11766  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11767  tags.add(tag);
11768  }
11769  resultSet.close();
11770  return tags;
11771  } catch (SQLException ex) {
11772  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
11773  } finally {
11774  closeResultSet(resultSet);
11775  closeConnection(connection);
11777  }
11778  }
11779 
11791  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
11792  CaseDbConnection connection = null;
11793  ResultSet resultSet = null;
11795  try {
11796  connection = connections.getConnection();
11797 
11798  // 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
11799  // FROM content_tags
11800  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11801  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11802  // WHERE content_tags.obj_id = ?
11803  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
11804  statement.clearParameters();
11805  statement.setLong(1, content.getId());
11806  resultSet = connection.executeQuery(statement);
11807  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11808  while (resultSet.next()) {
11809  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11810  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11811  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11812  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
11813  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11814  tags.add(tag);
11815  }
11816  return tags;
11817  } catch (SQLException ex) {
11818  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
11819  } finally {
11820  closeResultSet(resultSet);
11821  closeConnection(connection);
11823  }
11824  }
11825 
11840  @Deprecated
11841  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
11842  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
11843  }
11844 
11845  /*
11846  * Deletes a row from the blackboard_artifact_tags table in the case
11847  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
11848  * representing the row to delete. @throws TskCoreException
11849  */
11850  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
11852  try {
11853  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
11854  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
11855  statement.clearParameters();
11856  statement.setLong(1, tag.getId());
11857  trans.getConnection().executeUpdate(statement);
11858 
11859  // update the aggregate score for the artifact
11860  Long artifactObjId = tag.getArtifact().getId();
11861  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11862  ? tag.getContent().getDataSource().getId()
11863  : null;
11864 
11865  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
11866 
11867  trans.commit();
11868  trans = null;
11869  } catch (SQLException ex) {
11870  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
11871  } finally {
11872  if (trans != null) {
11873  trans.rollback();
11874  }
11875  }
11876  }
11877 
11887  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
11888  CaseDbConnection connection = null;
11889  ResultSet resultSet = null;
11891  try {
11892  connection = connections.getConnection();
11893 
11894  // 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
11895  // FROM blackboard_artifact_tags
11896  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
11897  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11898  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
11899  resultSet = connection.executeQuery(statement);
11900  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
11901  while (resultSet.next()) {
11902  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11903  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11904  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11905  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11906  Content content = getContentById(artifact.getObjectID());
11907  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11908  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11909  tags.add(tag);
11910  }
11911  return tags;
11912  } catch (SQLException ex) {
11913  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
11914  } finally {
11915  closeResultSet(resultSet);
11916  closeConnection(connection);
11918  }
11919  }
11920 
11931  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
11932  if (tagName.getId() == Tag.ID_NOT_SET) {
11933  throw new TskCoreException("TagName object is invalid, id not set");
11934  }
11935  CaseDbConnection connection = null;
11936  ResultSet resultSet = null;
11938  try {
11939  connection = connections.getConnection();
11940 
11941  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
11942  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
11943  statement.clearParameters();
11944  statement.setLong(1, tagName.getId());
11945  resultSet = connection.executeQuery(statement);
11946  if (resultSet.next()) {
11947  return resultSet.getLong("count");
11948  } else {
11949  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11950  }
11951  } catch (SQLException ex) {
11952  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11953  } finally {
11954  closeResultSet(resultSet);
11955  closeConnection(connection);
11957  }
11958  }
11959 
11974  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11975 
11976  if (tagName.getId() == Tag.ID_NOT_SET) {
11977  throw new TskCoreException("TagName object is invalid, id not set");
11978  }
11979 
11980  CaseDbConnection connection = null;
11981  ResultSet resultSet = null;
11983  try {
11984  connection = connections.getConnection();
11985 
11986  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
11987  // + " AND artifact_tags.tag_name_id = ?"
11988  // + " AND arts.data_source_obj_id = ? "
11989  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
11990  statement.clearParameters();
11991  statement.setLong(1, tagName.getId());
11992  statement.setLong(2, dsObjId);
11993  resultSet = connection.executeQuery(statement);
11994  if (resultSet.next()) {
11995  return resultSet.getLong("count");
11996  } else {
11997  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11998  }
11999  } catch (SQLException ex) {
12000  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12001  } finally {
12002  closeResultSet(resultSet);
12003  closeConnection(connection);
12005  }
12006  }
12007 
12019  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
12020  if (tagName.getId() == Tag.ID_NOT_SET) {
12021  throw new TskCoreException("TagName object is invalid, id not set");
12022  }
12023  CaseDbConnection connection = null;
12024  ResultSet resultSet = null;
12026  try {
12027  connection = connections.getConnection();
12028 
12029  // 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
12030  // FROM blackboard_artifact_tags
12031  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12032  // WHERE tag_name_id = ?
12033  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
12034  statement.clearParameters();
12035  statement.setLong(1, tagName.getId());
12036  resultSet = connection.executeQuery(statement);
12037  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12038  while (resultSet.next()) {
12039  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12040  Content content = getContentById(artifact.getObjectID());
12041  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12042  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12043  tags.add(tag);
12044  }
12045  return tags;
12046  } catch (SQLException ex) {
12047  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
12048  } finally {
12049  closeResultSet(resultSet);
12050  closeConnection(connection);
12052  }
12053  }
12054 
12069  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
12070 
12071  if (tagName.getId() == Tag.ID_NOT_SET) {
12072  throw new TskCoreException("TagName object is invalid, id not set");
12073  }
12074 
12075  CaseDbConnection connection = null;
12076  ResultSet resultSet = null;
12078  try {
12079  connection = connections.getConnection();
12080 
12081  // 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
12082  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
12083  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
12084  // WHERE artifact_tags.artifact_id = arts.artifact_id
12085  // AND artifact_tags.tag_name_id = ?
12086  // AND arts.data_source_obj_id = ?
12087  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12088  statement.clearParameters();
12089  statement.setLong(1, tagName.getId());
12090  statement.setLong(2, dsObjId);
12091  resultSet = connection.executeQuery(statement);
12092  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12093  while (resultSet.next()) {
12094  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12095  Content content = getContentById(artifact.getObjectID());
12096  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12097  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12098  tags.add(tag);
12099  }
12100  return tags;
12101  } catch (SQLException ex) {
12102  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12103  } finally {
12104  closeResultSet(resultSet);
12105  closeConnection(connection);
12107  }
12108 
12109  }
12110 
12122  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
12123 
12124  CaseDbConnection connection = null;
12125  ResultSet resultSet = null;
12126  BlackboardArtifactTag tag = null;
12128  try {
12129  connection = connections.getConnection();
12130 
12131  //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
12132  // FROM blackboard_artifact_tags
12133  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12134  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12135  // WHERE blackboard_artifact_tags.tag_id = ?
12136  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
12137  statement.clearParameters();
12138  statement.setLong(1, artifactTagID);
12139  resultSet = connection.executeQuery(statement);
12140 
12141  while (resultSet.next()) {
12142  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12143  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12144  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12145  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12146  Content content = getContentById(artifact.getObjectID());
12147  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12148  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
12149  }
12150  resultSet.close();
12151 
12152  } catch (SQLException ex) {
12153  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12154  } finally {
12155  closeResultSet(resultSet);
12156  closeConnection(connection);
12158  }
12159  return tag;
12160  }
12161 
12174  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12175  CaseDbConnection connection = null;
12176  ResultSet resultSet = null;
12178  try {
12179  connection = connections.getConnection();
12180 
12181  // 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
12182  // FROM blackboard_artifact_tags
12183  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12184  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12185  // WHERE blackboard_artifact_tags.artifact_id = ?
12186  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12187  statement.clearParameters();
12188  statement.setLong(1, artifact.getArtifactID());
12189  resultSet = connection.executeQuery(statement);
12190  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12191  while (resultSet.next()) {
12192  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12193  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12194  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12195  Content content = getContentById(artifact.getObjectID());
12196  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12197  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12198  tags.add(tag);
12199  }
12200  return tags;
12201  } catch (SQLException ex) {
12202  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12203  } finally {
12204  closeResultSet(resultSet);
12205  closeConnection(connection);
12207  }
12208  }
12209 
12218  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12220  try (CaseDbConnection connection = connections.getConnection();) {
12221  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12222  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12223  statement.clearParameters();
12224  statement.setString(1, newPath);
12225  statement.setLong(2, objectId);
12226  connection.executeUpdate(statement);
12227  } catch (SQLException ex) {
12228  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12229  } finally {
12231  }
12232  }
12233 
12247  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12248  return addReport(localPath, sourceModuleName, reportName, null);
12249  }
12250 
12266  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12267  // Make sure the local path of the report is in the database directory
12268  // or one of its subdirectories.
12269  String relativePath = ""; //NON-NLS
12270  long createTime = 0;
12271  String localPathLower = localPath.toLowerCase();
12272 
12273  if (localPathLower.startsWith("http")) {
12274  relativePath = localPathLower;
12275  createTime = System.currentTimeMillis() / 1000;
12276  } else {
12277  /*
12278  * Note: The following call to .relativize() may be dangerous in
12279  * case-sensitive operating systems and should be looked at. For
12280  * now, we are simply relativizing the paths as all lower case, then
12281  * using the length of the result to pull out the appropriate number
12282  * of characters from the localPath String.
12283  */
12284  try {
12285  String casePathLower = getDbDirPath().toLowerCase();
12286  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12287  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12288  } catch (IllegalArgumentException ex) {
12289  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12290  throw new TskCoreException(errorMessage, ex);
12291  }
12292  try {
12293  // get its file time
12294  java.io.File tempFile = new java.io.File(localPath);
12295  // Convert to UNIX epoch (seconds, not milliseconds).
12296  createTime = tempFile.lastModified() / 1000;
12297  } catch (Exception ex) {
12298  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12299  }
12300  }
12301 
12302  // Write the report data to the database.
12304  try (CaseDbConnection connection = connections.getConnection();) {
12305  // Insert a row for the report into the tsk_objects table.
12306  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12307  long parentObjId = 0;
12308  if (parent != null) {
12309  parentObjId = parent.getId();
12310  }
12311  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
12312 
12313  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
12314  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
12315  statement.clearParameters();
12316  statement.setLong(1, objectId);
12317  statement.setString(2, relativePath);
12318  statement.setLong(3, createTime);
12319  statement.setString(4, sourceModuleName);
12320  statement.setString(5, reportName);
12321  connection.executeUpdate(statement);
12322  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
12323  } catch (SQLException ex) {
12324  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
12325  } finally {
12327  }
12328  }
12329 
12338  public List<Report> getAllReports() throws TskCoreException {
12339  CaseDbConnection connection = null;
12340  ResultSet resultSet = null;
12341  ResultSet parentResultSet = null;
12342  PreparedStatement statement = null;
12343  Statement parentStatement = null;
12345  try {
12346  connection = connections.getConnection();
12347 
12348  // SELECT * FROM reports
12349  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
12350  parentStatement = connection.createStatement();
12351  resultSet = connection.executeQuery(statement);
12352  ArrayList<Report> reports = new ArrayList<Report>();
12353  while (resultSet.next()) {
12354  String localpath = resultSet.getString("path");
12355  if (localpath.toLowerCase().startsWith("http") == false) {
12356  // make path absolute
12357  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
12358  }
12359 
12360  // get the report parent
12361  Content parent = null;
12362  long reportId = resultSet.getLong("obj_id"); // NON-NLS
12363  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
12364  parentResultSet = parentStatement.executeQuery(parentQuery);
12365  if (parentResultSet.next()) {
12366  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12367  parent = this.getContentById(parentId);
12368  }
12369  parentResultSet.close();
12370 
12371  reports.add(new Report(this,
12372  reportId,
12373  localpath,
12374  resultSet.getLong("crtime"), //NON-NLS
12375  resultSet.getString("src_module_name"), //NON-NLS
12376  resultSet.getString("report_name"),
12377  parent)); //NON-NLS
12378  }
12379  return reports;
12380  } catch (SQLException ex) {
12381  throw new TskCoreException("Error querying reports table", ex);
12382  } finally {
12383  closeResultSet(resultSet);
12384  closeResultSet(parentResultSet);
12385  closeStatement(statement);
12386  closeStatement(parentStatement);
12387 
12388  closeConnection(connection);
12390  }
12391  }
12392 
12402  public Report getReportById(long id) throws TskCoreException {
12403  CaseDbConnection connection = null;
12404  PreparedStatement statement = null;
12405  Statement parentStatement = null;
12406  ResultSet resultSet = null;
12407  ResultSet parentResultSet = null;
12408  Report report = null;
12410  try {
12411  connection = connections.getConnection();
12412 
12413  // SELECT * FROM reports WHERE obj_id = ?
12414  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
12415  parentStatement = connection.createStatement();
12416  statement.clearParameters();
12417  statement.setLong(1, id);
12418  resultSet = connection.executeQuery(statement);
12419 
12420  if (resultSet.next()) {
12421  // get the report parent
12422  Content parent = null;
12423  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
12424  parentResultSet = parentStatement.executeQuery(parentQuery);
12425  if (parentResultSet.next()) {
12426  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12427  parent = this.getContentById(parentId);
12428  }
12429 
12430  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
12431  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
12432  resultSet.getLong("crtime"), //NON-NLS
12433  resultSet.getString("src_module_name"), //NON-NLS
12434  resultSet.getString("report_name"),
12435  parent); //NON-NLS
12436  } else {
12437  throw new TskCoreException("No report found for id: " + id);
12438  }
12439  } catch (SQLException ex) {
12440  throw new TskCoreException("Error querying reports table for id: " + id, ex);
12441  } finally {
12442  closeResultSet(resultSet);
12443  closeResultSet(parentResultSet);
12444  closeStatement(statement);
12445  closeStatement(parentStatement);
12446  closeConnection(connection);
12448  }
12449 
12450  return report;
12451  }
12452 
12460  public void deleteReport(Report report) throws TskCoreException {
12462  try (CaseDbConnection connection = connections.getConnection();) {
12463  // DELETE FROM reports WHERE reports.obj_id = ?
12464  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
12465  statement.setLong(1, report.getId());
12466  connection.executeUpdate(statement);
12467  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
12468  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
12469  statement.setLong(1, report.getId());
12470  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
12471  connection.executeUpdate(statement);
12472  } catch (SQLException ex) {
12473  throw new TskCoreException("Error querying reports table", ex);
12474  } finally {
12476  }
12477  }
12478 
12479  static void closeResultSet(ResultSet resultSet) {
12480  if (resultSet != null) {
12481  try {
12482  resultSet.close();
12483  } catch (SQLException ex) {
12484  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
12485  }
12486  }
12487  }
12488 
12489  static void closeStatement(Statement statement) {
12490  if (statement != null) {
12491  try {
12492  statement.close();
12493  } catch (SQLException ex) {
12494  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
12495 
12496  }
12497  }
12498  }
12499 
12500  static void closeConnection(CaseDbConnection connection) {
12501  if (connection != null) {
12502  connection.close();
12503  }
12504  }
12505 
12506  private static void rollbackTransaction(CaseDbConnection connection) {
12507  if (connection != null) {
12508  connection.rollbackTransaction();
12509  }
12510  }
12511 
12520  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
12522  try (CaseDbConnection connection = connections.getConnection();) {
12523  Statement statement = connection.createStatement();
12524  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
12525  } catch (SQLException ex) {
12526  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
12527  } finally {
12529  }
12530  }
12531 
12532  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
12534  try (CaseDbConnection connection = connections.getConnection();
12535  Statement statement = connection.createStatement();) {
12536  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
12537  } catch (SQLException ex) {
12538  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
12539  } finally {
12541  }
12542  }
12543 
12560  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
12561  CaseDbConnection connection = null;
12563  ResultSet resultSet = null;
12564  Statement statement;
12565  try {
12566  connection = connections.getConnection();
12567  connection.beginTransaction();
12568  statement = connection.createStatement();
12569  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
12570  insertStatement.setLong(1, dataSource.getId());
12571  insertStatement.setString(2, hostName);
12572  insertStatement.setLong(3, jobStart.getTime());
12573  insertStatement.setLong(4, jobEnd.getTime());
12574  insertStatement.setInt(5, status.ordinal());
12575  insertStatement.setString(6, settingsDir);
12576  connection.executeUpdate(insertStatement);
12577  resultSet = insertStatement.getGeneratedKeys();
12578  resultSet.next();
12579  long id = resultSet.getLong(1); //last_insert_rowid()
12580  for (int i = 0; i < ingestModules.size(); i++) {
12581  IngestModuleInfo ingestModule = ingestModules.get(i);
12582  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
12583  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
12584  }
12585  resultSet.close();
12586  resultSet = null;
12587  connection.commitTransaction();
12588  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
12589  } catch (SQLException ex) {
12590  rollbackTransaction(connection);
12591  throw new TskCoreException("Error adding the ingest job.", ex);
12592  } finally {
12593  closeResultSet(resultSet);
12594  closeConnection(connection);
12596  }
12597  }
12598 
12612  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
12613  CaseDbConnection connection = null;
12614  ResultSet resultSet = null;
12615  Statement statement = null;
12616  String uniqueName = factoryClassName + "-" + displayName + "-" + version;
12618  try {
12619  connection = connections.getConnection();
12620  statement = connection.createStatement();
12621  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12622  if (!resultSet.next()) {
12623  resultSet.close();
12624  resultSet = null;
12625  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
12626  insertStatement.setString(1, displayName);
12627  insertStatement.setString(2, uniqueName);
12628  insertStatement.setInt(3, type.ordinal());
12629  insertStatement.setString(4, version);
12630  connection.executeUpdate(insertStatement);
12631  resultSet = statement.getGeneratedKeys();
12632  resultSet.next();
12633  long id = resultSet.getLong(1); //last_insert_rowid()
12634  resultSet.close();
12635  resultSet = null;
12636  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
12637  } else {
12638  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12639  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12640  }
12641  } catch (SQLException ex) {
12642  try {
12643  closeStatement(statement);
12644  if (connection != null) {
12645  statement = connection.createStatement();
12646  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12647  if (resultSet.next()) {
12648  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12649  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12650  }
12651  }
12652  throw new TskCoreException("Couldn't add new module to database.", ex);
12653  } catch (SQLException ex1) {
12654  throw new TskCoreException("Couldn't add new module to database.", ex1);
12655  }
12656  } finally {
12657  closeResultSet(resultSet);
12658  closeStatement(statement);
12659  closeConnection(connection);
12661  }
12662  }
12663 
12671  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
12672  CaseDbConnection connection = null;
12673  ResultSet resultSet = null;
12674  Statement statement = null;
12675  List<IngestJobInfo> ingestJobs = new ArrayList<>();
12677  try {
12678  connection = connections.getConnection();
12679  statement = connection.createStatement();
12680  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
12681  while (resultSet.next()) {
12682  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
12683  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
12684  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
12685  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
12686  }
12687  return ingestJobs;
12688  } catch (SQLException ex) {
12689  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
12690  } finally {
12691  closeResultSet(resultSet);
12692  closeStatement(statement);
12693  closeConnection(connection);
12695  }
12696  }
12697 
12708  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
12709  ResultSet resultSet = null;
12710  Statement statement = null;
12711  List<IngestModuleInfo> ingestModules = new ArrayList<>();
12713  try {
12714  statement = connection.createStatement();
12715  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
12716  + "ingest_job_modules.pipeline_position AS pipeline_position, "
12717  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
12718  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
12719  + "FROM ingest_job_modules, ingest_modules "
12720  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
12721  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
12722  + "ORDER BY (ingest_job_modules.pipeline_position);");
12723  while (resultSet.next()) {
12724  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12725  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
12726  }
12727  return ingestModules;
12728  } finally {
12729  closeResultSet(resultSet);
12730  closeStatement(statement);
12732 
12733  }
12734  }
12735 
12745  String getInsertOrIgnoreSQL(String sql) {
12746  switch (getDatabaseType()) {
12747  case POSTGRESQL:
12748  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
12749  case SQLITE:
12750  return " INSERT OR IGNORE " + sql; //NON-NLS
12751  default:
12752  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
12753  }
12754  }
12755 
12776  private List<? extends BlackboardArtifact> getArtifactsForValues(BlackboardArtifact.Category category, String dbColumn, List<? extends Number> values, CaseDbConnection connection) throws TskCoreException {
12777  String where = "";
12778  // This look creates the OR statment with the following format:
12779  // <dbColumn> = <value> OR <dbColumn> = <value2> OR ...
12780  for (Number value : values) {
12781  if (!where.isEmpty()) {
12782  where += " OR ";
12783  }
12784  where += dbColumn + " = " + value;
12785  }
12786 
12787  // Base on the category pass the OR statement to the approprate method
12788  // that will retrieve the artifacts.
12789  if (category == BlackboardArtifact.Category.DATA_ARTIFACT) {
12790  return blackboard.getDataArtifactsWhere(where, connection);
12791  } else {
12792  return blackboard.getAnalysisResultsWhere(where, connection);
12793  }
12794  }
12795 
12799  static class ObjectInfo {
12800 
12801  private long id;
12802  private TskData.ObjectType type;
12803 
12804  ObjectInfo(long id, ObjectType type) {
12805  this.id = id;
12806  this.type = type;
12807  }
12808 
12809  long getId() {
12810  return id;
12811  }
12812 
12813  TskData.ObjectType getType() {
12814  return type;
12815  }
12816  }
12817 
12818  private interface DbCommand {
12819 
12820  void execute() throws SQLException;
12821  }
12822 
12823  private enum PREPARED_STATEMENT {
12824 
12825  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
12826  + "WHERE artifact_type_id = ?"), //NON-NLS
12827  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
12828  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
12829  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
12830  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
12831  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
12832  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12833  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12834  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
12835  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
12836  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
12837  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12838  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12839  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
12840  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12841  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12842  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12843  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12844  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
12845  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12846  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12847  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12848  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12849  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12850  + "WHERE tsk_files.extension = ? AND "
12851  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
12852  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12853  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12854  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12855  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12856  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12857  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
12858  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12859  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12860  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12861  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
12862  + "AND tsk_files.type = ? )"), //NON-NLS
12863  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
12864  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12865  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12866  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
12867  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
12868  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12869  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
12870  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12871  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
12872  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12873  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
12874  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12875  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
12876  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12877  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
12878  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12879  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
12880  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12881  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
12882  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12883  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
12884  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
12885  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
12886  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
12887  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
12888  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
12889  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12890  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12891  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
12892  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
12893  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12894  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12895  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12896  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
12897  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
12898  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
12899  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
12900  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
12901  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
12902  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
12903  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12904  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12905  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
12906  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
12907  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
12908  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
12909  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) " //NON-NLS
12910  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
12911  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)"
12912  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
12913  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
12914  + "WHERE obj_id = ?"), //NON-NLS
12915  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
12916  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12917  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
12918  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
12919  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
12920  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
12921  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
12922  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
12923  + "WHERE tag_name_id IN " //NON-NLS
12924  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
12925  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
12926  + "WHERE tag_name_id IN "
12927  + "( SELECT content_tags.tag_name_id as tag_name_id "
12928  + "FROM content_tags as content_tags, tsk_files as tsk_files"
12929  + " WHERE content_tags.obj_id = tsk_files.obj_id"
12930  + " AND tsk_files.data_source_obj_id = ?"
12931  + " UNION "
12932  + "SELECT artifact_tags.tag_name_id as tag_name_id "
12933  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
12934  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
12935  + " AND arts.data_source_obj_id = ?"
12936  + " )"),
12937  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
12938  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12939  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
12940  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
12941  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
12942  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
12943  + " AND content_tags.tag_name_id = ? "
12944  + " AND tsk_files.data_source_obj_id = ? "
12945  ),
12946  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 "
12947  + "FROM content_tags "
12948  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12949  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12950  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 "
12951  + "FROM content_tags "
12952  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12953  + "WHERE tag_name_id = ?"), //NON-NLS
12954  SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE("SELECT content_tags.tag_id, content_tags.obj_id, content_tags.tag_name_id, content_tags.comment, content_tags.begin_byte_offset, content_tags.end_byte_offset, tag_names.display_name, tag_names.description, tag_names.color, tag_names.knownStatus, tsk_examiners.login_name, tag_names.tag_set_id "
12955  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
12956  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
12957  + " AND content_tags.obj_id = tsk_files.obj_id"
12958  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
12959  + " AND content_tags.tag_name_id = ?"
12960  + " AND tsk_files.data_source_obj_id = ? "),
12961  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 "
12962  + "FROM content_tags "
12963  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12964  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12965  + "WHERE tag_id = ?"), //NON-NLS
12966  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 "
12967  + "FROM content_tags "
12968  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12969  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12970  + "WHERE content_tags.obj_id = ?"), //NON-NLS
12971  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
12972  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12973  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
12974  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 "
12975  + "FROM blackboard_artifact_tags "
12976  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12977  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12978  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
12979  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"
12980  + " AND artifact_tags.tag_name_id = ?"
12981  + " AND arts.data_source_obj_id = ? "),
12982  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 "
12983  + "FROM blackboard_artifact_tags "
12984  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12985  + "WHERE tag_name_id = ?"), //NON-NLS
12986  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 "
12987  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
12988  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
12989  + " AND artifact_tags.artifact_id = arts.artifact_id"
12990  + " AND artifact_tags.tag_name_id = ? "
12991  + " AND arts.data_source_obj_id = ? "),
12992  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 "
12993  + "FROM blackboard_artifact_tags "
12994  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12995  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12996  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
12997  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 "
12998  + "FROM blackboard_artifact_tags "
12999  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
13000  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
13001  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
13002  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
13003  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
13004  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
13005  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
13006  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
13007  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
13008  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
13009  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
13010  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
13011  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
13012  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
13013  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
13014  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
13015  + "WHERE (tsk_objects.par_obj_id = ?)"),
13016  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
13017  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
13018  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
13019  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
13020  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
13021  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
13022  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
13023  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
13024  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
13025  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
13026  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13027  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"),
13028  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
13029  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13030  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
13031  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
13032  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)"
13033  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
13034  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?");
13035 
13036  private final String sql;
13037 
13038  private PREPARED_STATEMENT(String sql) {
13039  this.sql = sql;
13040  }
13041 
13042  String getSQL() {
13043  return sql;
13044  }
13045  }
13046 
13052  abstract private class ConnectionPool {
13053 
13054  private PooledDataSource pooledDataSource;
13055 
13056  public ConnectionPool() {
13057  pooledDataSource = null;
13058  }
13059 
13060  CaseDbConnection getConnection() throws TskCoreException {
13061  if (pooledDataSource == null) {
13062  throw new TskCoreException("Error getting case database connection - case is closed");
13063  }
13064  try {
13065  return getPooledConnection();
13066  } catch (SQLException exp) {
13067  throw new TskCoreException(exp.getMessage());
13068  }
13069  }
13070 
13071  void close() throws TskCoreException {
13072  if (pooledDataSource != null) {
13073  try {
13074  pooledDataSource.close();
13075  } catch (SQLException exp) {
13076  throw new TskCoreException(exp.getMessage());
13077  } finally {
13078  pooledDataSource = null;
13079  }
13080  }
13081  }
13082 
13083  abstract CaseDbConnection getPooledConnection() throws SQLException;
13084 
13085  public PooledDataSource getPooledDataSource() {
13086  return pooledDataSource;
13087  }
13088 
13089  public void setPooledDataSource(PooledDataSource pooledDataSource) {
13090  this.pooledDataSource = pooledDataSource;
13091  }
13092  }
13093 
13098  private final class SQLiteConnections extends ConnectionPool {
13099 
13100  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
13101 
13102  SQLiteConnections(String dbPath) throws SQLException {
13103  configurationOverrides.put("acquireIncrement", "2");
13104  configurationOverrides.put("initialPoolSize", "5");
13105  configurationOverrides.put("minPoolSize", "5");
13106  /*
13107  * NOTE: max pool size and max statements are related. If you
13108  * increase max pool size, then also increase statements.
13109  */
13110  configurationOverrides.put("maxPoolSize", "20");
13111  configurationOverrides.put("maxStatements", "200");
13112  configurationOverrides.put("maxStatementsPerConnection", "20");
13113 
13114  SQLiteConfig config = new SQLiteConfig();
13115  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
13116  config.setReadUncommited(true);
13117  config.enforceForeignKeys(true); // Enforce foreign key constraints.
13118  SQLiteDataSource unpooled = new SQLiteDataSource(config);
13119  unpooled.setUrl("jdbc:sqlite:" + dbPath);
13120  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
13121  }
13122 
13123  @Override
13124  public CaseDbConnection getPooledConnection() throws SQLException {
13125  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
13126  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
13127  // Temporarily filter out Image Gallery threads
13128  if (!Thread.currentThread().getName().contains("ImageGallery")) {
13129  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());
13130  }
13131  }
13132  return new SQLiteConnection(getPooledDataSource().getConnection());
13133  }
13134  }
13135 
13140  private final class PostgreSQLConnections extends ConnectionPool {
13141 
13142  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
13143  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
13144  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
13145  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
13146  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
13147  comboPooledDataSource.setUser(userName);
13148  comboPooledDataSource.setPassword(password);
13149  comboPooledDataSource.setAcquireIncrement(2);
13150  comboPooledDataSource.setInitialPoolSize(5);
13151  comboPooledDataSource.setMinPoolSize(5);
13152  /*
13153  * NOTE: max pool size and max statements are related. If you
13154  * increase max pool size, then also increase statements.
13155  */
13156  comboPooledDataSource.setMaxPoolSize(20);
13157  comboPooledDataSource.setMaxStatements(200);
13158  comboPooledDataSource.setMaxStatementsPerConnection(20);
13159  setPooledDataSource(comboPooledDataSource);
13160  }
13161 
13162  @Override
13163  public CaseDbConnection getPooledConnection() throws SQLException {
13164  return new PostgreSQLConnection(getPooledDataSource().getConnection());
13165  }
13166  }
13167 
13171  abstract class CaseDbConnection implements AutoCloseable {
13172 
13173  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
13174  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
13175 
13176  private class CreateStatement implements DbCommand {
13177 
13178  private final Connection connection;
13179  private Statement statement = null;
13180 
13181  CreateStatement(Connection connection) {
13182  this.connection = connection;
13183  }
13184 
13185  Statement getStatement() {
13186  return statement;
13187  }
13188 
13189  @Override
13190  public void execute() throws SQLException {
13191  statement = connection.createStatement();
13192  }
13193  }
13194 
13195  private class SetAutoCommit implements DbCommand {
13196 
13197  private final Connection connection;
13198  private final boolean mode;
13199 
13200  SetAutoCommit(Connection connection, boolean mode) {
13201  this.connection = connection;
13202  this.mode = mode;
13203  }
13204 
13205  @Override
13206  public void execute() throws SQLException {
13207  connection.setAutoCommit(mode);
13208  }
13209  }
13210 
13211  private class Commit implements DbCommand {
13212 
13213  private final Connection connection;
13214 
13215  Commit(Connection connection) {
13216  this.connection = connection;
13217  }
13218 
13219  @Override
13220  public void execute() throws SQLException {
13221  connection.commit();
13222  }
13223  }
13224 
13233  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13234 
13235  private final Connection connection;
13236 
13237  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13238  this.connection = connection;
13239  }
13240 
13241  @Override
13242  public void execute() throws SQLException {
13243  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13244  preparedStatement.execute();
13245 
13246  }
13247  }
13248 
13249  private class ExecuteQuery implements DbCommand {
13250 
13251  private final Statement statement;
13252  private final String query;
13253  private ResultSet resultSet;
13254 
13255  ExecuteQuery(Statement statement, String query) {
13256  this.statement = statement;
13257  this.query = query;
13258  }
13259 
13260  ResultSet getResultSet() {
13261  return resultSet;
13262  }
13263 
13264  @Override
13265  public void execute() throws SQLException {
13266  resultSet = statement.executeQuery(query);
13267  }
13268  }
13269 
13270  private class ExecutePreparedStatementQuery implements DbCommand {
13271 
13272  private final PreparedStatement preparedStatement;
13273  private ResultSet resultSet;
13274 
13275  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13276  this.preparedStatement = preparedStatement;
13277  }
13278 
13279  ResultSet getResultSet() {
13280  return resultSet;
13281  }
13282 
13283  @Override
13284  public void execute() throws SQLException {
13285  resultSet = preparedStatement.executeQuery();
13286  }
13287  }
13288 
13289  private class ExecutePreparedStatementUpdate implements DbCommand {
13290 
13291  private final PreparedStatement preparedStatement;
13292 
13293  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
13294  this.preparedStatement = preparedStatement;
13295  }
13296 
13297  @Override
13298  public void execute() throws SQLException {
13299  preparedStatement.executeUpdate();
13300  }
13301  }
13302 
13303  private class ExecuteStatementUpdate implements DbCommand {
13304 
13305  private final Statement statement;
13306  private final String updateCommand;
13307 
13308  ExecuteStatementUpdate(Statement statement, String updateCommand) {
13309  this.statement = statement;
13310  this.updateCommand = updateCommand;
13311  }
13312 
13313  @Override
13314  public void execute() throws SQLException {
13315  statement.executeUpdate(updateCommand);
13316  }
13317  }
13318 
13319  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
13320 
13321  private final Statement statement;
13322  private final int generateKeys;
13323  private final String updateCommand;
13324 
13325  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
13326  this.statement = statement;
13327  this.generateKeys = generateKeys;
13328  this.updateCommand = updateCommand;
13329  }
13330 
13331  @Override
13332  public void execute() throws SQLException {
13333  statement.executeUpdate(updateCommand, generateKeys);
13334  }
13335  }
13336 
13337  private class PrepareStatement implements DbCommand {
13338 
13339  private final Connection connection;
13340  private final String input;
13341  private PreparedStatement preparedStatement = null;
13342 
13343  PrepareStatement(Connection connection, String input) {
13344  this.connection = connection;
13345  this.input = input;
13346  }
13347 
13348  PreparedStatement getPreparedStatement() {
13349  return preparedStatement;
13350  }
13351 
13352  @Override
13353  public void execute() throws SQLException {
13354  preparedStatement = connection.prepareStatement(input);
13355  }
13356  }
13357 
13358  private class PrepareStatementGenerateKeys implements DbCommand {
13359 
13360  private final Connection connection;
13361  private final String input;
13362  private final int generateKeys;
13363  private PreparedStatement preparedStatement = null;
13364 
13365  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
13366  this.connection = connection;
13367  this.input = input;
13368  this.generateKeys = generateKeysInput;
13369  }
13370 
13371  PreparedStatement getPreparedStatement() {
13372  return preparedStatement;
13373  }
13374 
13375  @Override
13376  public void execute() throws SQLException {
13377  preparedStatement = connection.prepareStatement(input, generateKeys);
13378  }
13379  }
13380 
13381  abstract void executeCommand(DbCommand command) throws SQLException;
13382 
13383  private final Connection connection;
13384  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
13385  private final Map<String, PreparedStatement> adHocPreparedStatements;
13386 
13387  CaseDbConnection(Connection connection) {
13388  this.connection = connection;
13389  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
13390  adHocPreparedStatements = new HashMap<>();
13391  }
13392 
13393  boolean isOpen() {
13394  return this.connection != null;
13395  }
13396 
13397  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
13398  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
13399  }
13400 
13401  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
13402  // Lazy statement preparation.
13403  PreparedStatement statement;
13404  if (this.preparedStatements.containsKey(statementKey)) {
13405  statement = this.preparedStatements.get(statementKey);
13406  } else {
13407  statement = prepareStatement(statementKey.getSQL(), generateKeys);
13408  this.preparedStatements.put(statementKey, statement);
13409  }
13410  return statement;
13411  }
13412 
13424  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
13425  PreparedStatement statement;
13426  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
13427  if (adHocPreparedStatements.containsKey(statementKey) && !adHocPreparedStatements.get(statementKey).isClosed()) {
13428  statement = this.adHocPreparedStatements.get(statementKey);
13429  } else {
13430  statement = prepareStatement(sqlStatement, generateKeys);
13431  this.adHocPreparedStatements.put(statementKey, statement);
13432  }
13433  return statement;
13434  }
13435 
13436  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13437  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
13438  executeCommand(prepareStatement);
13439  return prepareStatement.getPreparedStatement();
13440  }
13441 
13442  Statement createStatement() throws SQLException {
13443  CreateStatement createStatement = new CreateStatement(this.connection);
13444  executeCommand(createStatement);
13445  return createStatement.getStatement();
13446  }
13447 
13448  void beginTransaction() throws SQLException {
13449  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
13450  executeCommand(setAutoCommit);
13451  }
13452 
13453  void commitTransaction() throws SQLException {
13454  Commit commit = new Commit(connection);
13455  executeCommand(commit);
13456  // You must turn auto commit back on when done with the transaction.
13457  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
13458  executeCommand(setAutoCommit);
13459  }
13460 
13466  void rollbackTransaction() {
13467  try {
13468  connection.rollback();
13469  } catch (SQLException e) {
13470  logger.log(Level.SEVERE, "Error rolling back transaction", e);
13471  }
13472  try {
13473  connection.setAutoCommit(true);
13474  } catch (SQLException e) {
13475  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
13476  }
13477  }
13478 
13486  void rollbackTransactionWithThrow() throws SQLException {
13487  try {
13488  connection.rollback();
13489  } finally {
13490  connection.setAutoCommit(true);
13491  }
13492  }
13493 
13502  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
13503  switch (getDatabaseType()) {
13504  case POSTGRESQL:
13505  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
13506  executeCommand(tableWriteLock);
13507  break;
13508  case SQLITE:
13509  // We do nothing here because we assume the entire SQLite DB is already locked from
13510  // when the analysis results were added/deleted in the same transaction.
13511  break;
13512  default:
13513  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
13514  }
13515  }
13516 
13517  ResultSet executeQuery(Statement statement, String query) throws SQLException {
13518  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
13519  executeCommand(queryCommand);
13520  return queryCommand.getResultSet();
13521  }
13522 
13532  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
13533  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
13534  executeCommand(executePreparedStatementQuery);
13535  return executePreparedStatementQuery.getResultSet();
13536  }
13537 
13538  void executeUpdate(Statement statement, String update) throws SQLException {
13539  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
13540  }
13541 
13542  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13543  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
13544  executeCommand(executeStatementUpdate);
13545  }
13546 
13547  void executeUpdate(PreparedStatement statement) throws SQLException {
13548  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
13549  executeCommand(executePreparedStatementUpdate);
13550  }
13551 
13555  @Override
13556  public void close() {
13557  try {
13558  for (PreparedStatement stmt : preparedStatements.values()) {
13559  closeStatement(stmt);
13560  }
13561  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
13562  closeStatement(stmt);
13563  }
13564  connection.close();
13565  } catch (SQLException ex) {
13566  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
13567  }
13568  }
13569 
13570  Connection getConnection() {
13571  return this.connection;
13572  }
13573  }
13574 
13578  private final class SQLiteConnection extends CaseDbConnection {
13579 
13580  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
13581  private static final int SQLITE_BUSY_ERROR = 5;
13582 
13583  SQLiteConnection(Connection conn) {
13584  super(conn);
13585  }
13586 
13587  @Override
13588  void executeCommand(DbCommand command) throws SQLException {
13589  int retryCounter = 0;
13590  while (true) {
13591  try {
13592  command.execute(); // Perform the operation
13593  break;
13594  } catch (SQLException ex) {
13595  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
13596  try {
13597 
13598  // We do not notify of error here, as this is not an
13599  // error condition. It is likely a temporary busy or
13600  // locked issue and we will retry.
13601  retryCounter++;
13602  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13603  } catch (InterruptedException exp) {
13604  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13605  }
13606  } else {
13607  throw ex;
13608  }
13609  }
13610  }
13611  }
13612  }
13613 
13617  private final class PostgreSQLConnection extends CaseDbConnection {
13618 
13619  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
13620  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
13621  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
13622  private static final int MAX_RETRIES = 3;
13623 
13624  PostgreSQLConnection(Connection conn) {
13625  super(conn);
13626  }
13627 
13628  @Override
13629  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13630  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
13631  executeCommand(executeStatementUpdateGenerateKeys);
13632  }
13633 
13634  @Override
13635  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13636  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
13637  executeCommand(prepareStatementGenerateKeys);
13638  return prepareStatementGenerateKeys.getPreparedStatement();
13639  }
13640 
13641  @Override
13642  void executeCommand(DbCommand command) throws SQLException {
13643  SQLException lastException = null;
13644  for (int retries = 0; retries < MAX_RETRIES; retries++) {
13645  try {
13646  command.execute();
13647  lastException = null; // reset since we had a successful execution
13648  break;
13649  } catch (SQLException ex) {
13650  lastException = ex;
13651  String sqlState = ex.getSQLState();
13652  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
13653  try {
13654  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13655  } catch (InterruptedException exp) {
13656  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13657  }
13658  } else {
13659  throw ex;
13660  }
13661  }
13662  }
13663 
13664  // rethrow the exception if we bailed because of too many retries
13665  if (lastException != null) {
13666  throw lastException;
13667  }
13668  }
13669  }
13670 
13702  public static final class CaseDbTransaction {
13703 
13704  private final CaseDbConnection connection;
13705  private SleuthkitCase sleuthkitCase;
13706 
13707  /* This class can store information about what was
13708  * inserted as part of the transaction so that we can
13709  * fire events after the data has been persisted. */
13710 
13711  // Score changes are stored as a map keyed by objId to prevent duplicates.
13712  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
13713  private List<Host> hostsAdded = new ArrayList<>();
13714  private List<OsAccount> accountsChanged = new ArrayList<>();
13715  private List<OsAccount> accountsAdded = new ArrayList<>();
13716 
13717  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
13718  private List<Long> deletedResultObjectIds = new ArrayList<>();
13719 
13720  // Keep track of which threads have connections to debug deadlocks
13721  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
13722  private static final Object threadsWithOpenTransactionLock = new Object();
13723 
13724  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
13725  this.sleuthkitCase = sleuthkitCase;
13726 
13727  sleuthkitCase.acquireSingleUserCaseWriteLock();
13728  this.connection = sleuthkitCase.getConnection();
13729  try {
13730  synchronized (threadsWithOpenTransactionLock) {
13731  this.connection.beginTransaction();
13732  threadsWithOpenTransaction.add(Thread.currentThread().getId());
13733  }
13734  } catch (SQLException ex) {
13735  sleuthkitCase.releaseSingleUserCaseWriteLock();
13736  throw new TskCoreException("Failed to create transaction on case database", ex);
13737  }
13738 
13739  }
13740 
13748  CaseDbConnection getConnection() {
13749  return this.connection;
13750  }
13751 
13757  void registerScoreChange(ScoreChange scoreChange) {
13758  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
13759  }
13760 
13766  void registerAddedHost(Host host) {
13767  if (host != null) {
13768  this.hostsAdded.add(host);
13769  }
13770  }
13771 
13777  void registerChangedOsAccount(OsAccount account) {
13778  if (account != null) {
13779  accountsChanged.add(account);
13780  }
13781  }
13782 
13788  void registerDeletedOsAccount(long osAccountObjId) {
13789  deletedOsAccountObjectIds.add(osAccountObjId);
13790  }
13791 
13797  void registerAddedOsAccount(OsAccount account) {
13798  if (account != null) {
13799  accountsAdded.add(account);
13800  }
13801  }
13802 
13809  void registerDeletedAnalysisResult(long analysisResultObjId) {
13810  this.deletedResultObjectIds.add(analysisResultObjId);
13811  }
13812 
13821  private static boolean hasOpenTransaction(long threadId) {
13822  synchronized (threadsWithOpenTransactionLock) {
13823  return threadsWithOpenTransaction.contains(threadId);
13824  }
13825  }
13826 
13833  public void commit() throws TskCoreException {
13834  try {
13835  this.connection.commitTransaction();
13836  } catch (SQLException ex) {
13837  throw new TskCoreException("Failed to commit transaction on case database", ex);
13838  } finally {
13839  close();
13840 
13841  if (!scoreChangeMap.isEmpty()) {
13842  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
13843  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
13844  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
13845  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
13846  }
13847  }
13848  if (!hostsAdded.isEmpty()) {
13849  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
13850  }
13851  if (!accountsAdded.isEmpty()) {
13852  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
13853  }
13854  if (!accountsChanged.isEmpty()) {
13855  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
13856  }
13857  if (!deletedOsAccountObjectIds.isEmpty()) {
13858  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
13859  }
13860  if (!deletedResultObjectIds.isEmpty()) {
13861  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
13862  }
13863  }
13864  }
13865 
13872  public void rollback() throws TskCoreException {
13873  try {
13874  this.connection.rollbackTransactionWithThrow();
13875  } catch (SQLException ex) {
13876  throw new TskCoreException("Case database transaction rollback failed", ex);
13877  } finally {
13878  close();
13879  }
13880  }
13881 
13886  void close() {
13887  this.connection.close();
13888  sleuthkitCase.releaseSingleUserCaseWriteLock();
13889  synchronized (threadsWithOpenTransactionLock) {
13890  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
13891  }
13892  }
13893  }
13894 
13904  public final class CaseDbQuery implements AutoCloseable {
13905 
13906  private ResultSet resultSet;
13907  private CaseDbConnection connection;
13908 
13909  private CaseDbQuery(String query) throws TskCoreException {
13910  this(query, false);
13911  }
13912 
13913  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
13914  if (!allowWriteQuery) {
13915  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
13916  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
13917  }
13918  }
13919 
13921  try {
13922  connection = connections.getConnection();
13923  resultSet = connection.executeQuery(connection.createStatement(), query);
13924  } catch (SQLException ex) {
13926  throw new TskCoreException("Error executing query: ", ex);
13927  } catch (TskCoreException ex) {
13929  throw ex;
13930  }
13931  }
13932 
13938  public ResultSet getResultSet() {
13939  return resultSet;
13940  }
13941 
13942  @Override
13943  public void close() throws TskCoreException {
13944  try {
13945  if (resultSet != null) {
13946  final Statement statement = resultSet.getStatement();
13947  if (statement != null) {
13948  statement.close();
13949  }
13950  resultSet.close();
13951  }
13952  closeConnection(connection);
13953  } catch (SQLException ex) {
13954  throw new TskCoreException("Error closing query: ", ex);
13955  } finally {
13957  }
13958  }
13959  }
13960 
13968  @Deprecated
13969  public void addErrorObserver(ErrorObserver observer) {
13970  sleuthkitCaseErrorObservers.add(observer);
13971  }
13972 
13980  @Deprecated
13981  public void removeErrorObserver(ErrorObserver observer) {
13982  int i = sleuthkitCaseErrorObservers.indexOf(observer);
13983  if (i >= 0) {
13984  sleuthkitCaseErrorObservers.remove(i);
13985  }
13986  }
13987 
13996  @Deprecated
13997  public void submitError(String context, String errorMessage) {
13998  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
13999  if (observer != null) {
14000  try {
14001  observer.receiveError(context, errorMessage);
14002  } catch (Exception ex) {
14003  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
14004 
14005  }
14006  }
14007  }
14008  }
14009 
14015  @Deprecated
14016  public interface ErrorObserver {
14017 
14024  public enum Context {
14025 
14029  IMAGE_READ_ERROR("Image File Read Error"),
14033  DATABASE_READ_ERROR("Database Read Error");
14034 
14035  private final String contextString;
14036 
14037  private Context(String context) {
14038  this.contextString = context;
14039  }
14040 
14041  public String getContextString() {
14042  return contextString;
14043  }
14044  };
14045 
14046  void receiveError(String context, String errorMessage);
14047  }
14048 
14059  @Deprecated
14060  long getDataSourceObjectId(long objectId) {
14061  try {
14062  CaseDbConnection connection = connections.getConnection();
14063  try {
14064  return getDataSourceObjectId(connection, objectId);
14065  } finally {
14066  closeConnection(connection);
14067  }
14068  } catch (TskCoreException ex) {
14069  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
14070  return 0;
14071  }
14072  }
14073 
14083  @Deprecated
14084  public long getLastObjectId() throws TskCoreException {
14085  CaseDbConnection connection = null;
14086  ResultSet rs = null;
14088  try {
14089  connection = connections.getConnection();
14090 
14091  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
14092  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
14093  rs = connection.executeQuery(statement);
14094  long id = -1;
14095  if (rs.next()) {
14096  id = rs.getLong("max_obj_id");
14097  }
14098  return id;
14099  } catch (SQLException e) {
14100  throw new TskCoreException("Error getting last object id", e);
14101  } finally {
14102  closeResultSet(rs);
14103  closeConnection(connection);
14105  }
14106  }
14107 
14121  @Deprecated
14122  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
14123  CaseDbConnection connection = null;
14124  Statement s = null;
14125  ResultSet rs = null;
14127  try {
14128  connection = connections.getConnection();
14129  s = connection.createStatement();
14130  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
14131  List<FsContent> results = new ArrayList<FsContent>();
14132  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
14133  for (AbstractFile f : temp) {
14134  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
14135  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
14136  results.add((FsContent) f);
14137  }
14138  }
14139  return results;
14140  } catch (SQLException e) {
14141  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
14142  } finally {
14143  closeResultSet(rs);
14144  closeStatement(s);
14145  closeConnection(connection);
14147  }
14148  }
14149 
14161  @Deprecated
14162  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
14163  CaseDbConnection connection = null;
14164  Statement s = null;
14165  ResultSet rs = null;
14167  try {
14168  connection = connections.getConnection();
14169  s = connection.createStatement();
14170  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
14171  int typeId = -1;
14172  if (rs.next()) {
14173  typeId = rs.getInt("artifact_type_id");
14174  }
14175  return typeId;
14176  } catch (SQLException ex) {
14177  throw new TskCoreException("Error getting artifact type id", ex);
14178  } finally {
14179  closeResultSet(rs);
14180  closeStatement(s);
14181  closeConnection(connection);
14183  }
14184  }
14185 
14195  @Deprecated
14196  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
14197  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
14198  }
14199 
14213  @Deprecated
14214  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14215  try {
14216  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14217  } catch (TskDataException ex) {
14218  throw new TskCoreException("Failed to add artifact type.", ex);
14219  }
14220  }
14221 
14235  @Deprecated
14236  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14237  try {
14238  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14239  } catch (TskDataException ex) {
14240  throw new TskCoreException("Couldn't add new attribute type");
14241  }
14242  }
14243 
14254  @Deprecated
14255  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14256  CaseDbConnection connection = null;
14257  Statement s = null;
14258  ResultSet rs = null;
14260  try {
14261  connection = connections.getConnection();
14262  s = connection.createStatement();
14263  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
14264  int typeId = -1;
14265  if (rs.next()) {
14266  typeId = rs.getInt("attribute_type_id");
14267  }
14268  return typeId;
14269  } catch (SQLException ex) {
14270  throw new TskCoreException("Error getting attribute type id", ex);
14271  } finally {
14272  closeResultSet(rs);
14273  closeStatement(s);
14274  closeConnection(connection);
14276  }
14277  }
14278 
14291  @Deprecated
14292  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
14293  CaseDbConnection connection = null;
14294  Statement s = null;
14295  ResultSet rs = null;
14297  try {
14298  connection = connections.getConnection();
14299  s = connection.createStatement();
14300  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14301  if (rs.next()) {
14302  return rs.getString("type_name");
14303  } else {
14304  throw new TskCoreException("No type with that id");
14305  }
14306  } catch (SQLException ex) {
14307  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14308  } finally {
14309  closeResultSet(rs);
14310  closeStatement(s);
14311  closeConnection(connection);
14313  }
14314  }
14315 
14328  @Deprecated
14329  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
14330  CaseDbConnection connection = null;
14331  Statement s = null;
14332  ResultSet rs = null;
14334  try {
14335  connection = connections.getConnection();
14336  s = connection.createStatement();
14337  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14338  if (rs.next()) {
14339  return rs.getString("display_name");
14340  } else {
14341  throw new TskCoreException("No type with that id");
14342  }
14343  } catch (SQLException ex) {
14344  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14345  } finally {
14346  closeResultSet(rs);
14347  closeStatement(s);
14348  closeConnection(connection);
14350  }
14351  }
14352 
14362  @Deprecated
14363  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
14364  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
14365  }
14366 
14382  @Deprecated
14383  public ResultSet runQuery(String query) throws SQLException {
14384  CaseDbConnection connection = null;
14386  try {
14387  connection = connections.getConnection();
14388  return connection.executeQuery(connection.createStatement(), query);
14389  } catch (TskCoreException ex) {
14390  throw new SQLException("Error getting connection for ad hoc query", ex);
14391  } finally {
14392  //TODO unlock should be done in closeRunQuery()
14393  //but currently not all code calls closeRunQuery - need to fix this
14394  closeConnection(connection);
14396  }
14397  }
14398 
14408  @Deprecated
14409  public void closeRunQuery(ResultSet resultSet) throws SQLException {
14410  final Statement statement = resultSet.getStatement();
14411  resultSet.close();
14412  if (statement != null) {
14413  statement.close();
14414  }
14415  }
14416 
14433  @Deprecated
14434  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
14435  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
14436  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
14437  files.add(carvedFile);
14438  CarvingResult carvingResult;
14439  Content parent = getContentById(containerId);
14440  if (parent instanceof FileSystem
14441  || parent instanceof Volume
14442  || parent instanceof Image) {
14443  carvingResult = new CarvingResult(parent, files);
14444  } else {
14445  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
14446  }
14447  return addCarvedFiles(carvingResult).get(0);
14448  }
14449 
14463  @Deprecated
14464  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
14465  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
14466  for (CarvedFileContainer container : filesToAdd) {
14467  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
14468  carvedFiles.add(carvedFile);
14469  }
14470  CarvingResult carvingResult;
14471  Content parent = getContentById(filesToAdd.get(0).getId());
14472  if (parent instanceof FileSystem
14473  || parent instanceof Volume
14474  || parent instanceof Image) {
14475  carvingResult = new CarvingResult(parent, carvedFiles);
14476  } else {
14477  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
14478  }
14479  return addCarvedFiles(carvingResult);
14480  }
14481 
14511  @Deprecated
14512  public DerivedFile addDerivedFile(String fileName, String localPath,
14513  long size, long ctime, long crtime, long atime, long mtime,
14514  boolean isFile, AbstractFile parentFile,
14515  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
14516  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14517  isFile, parentFile, rederiveDetails, toolName, toolVersion,
14518  otherDetails, TskData.EncodingType.NONE);
14519  }
14520 
14550  @Deprecated
14551  public LocalFile addLocalFile(String fileName, String localPath,
14552  long size, long ctime, long crtime, long atime, long mtime,
14553  String md5, FileKnown known, String mimeType,
14554  boolean isFile, TskData.EncodingType encodingType,
14555  Content parent, CaseDbTransaction transaction) throws TskCoreException {
14556 
14557  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14558  md5, null, known, mimeType, isFile, encodingType,
14559  parent, transaction);
14560  }
14561 
14586  @Deprecated
14587  public LocalFile addLocalFile(String fileName, String localPath,
14588  long size, long ctime, long crtime, long atime, long mtime,
14589  boolean isFile,
14590  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
14591  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
14592  TskData.EncodingType.NONE, parent, transaction);
14593  }
14594 
14614  @Deprecated
14615  public LocalFile addLocalFile(String fileName, String localPath,
14616  long size, long ctime, long crtime, long atime, long mtime,
14617  boolean isFile,
14618  AbstractFile parent) throws TskCoreException {
14619  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14620  isFile, TskData.EncodingType.NONE, parent);
14621  }
14622 
14639  @Deprecated
14640  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
14641  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
14642  }
14643 
14654  @Deprecated
14655  public Collection<FileSystem> getFileSystems(Image image) {
14656  try {
14657  return getImageFileSystems(image);
14658  } catch (TskCoreException ex) {
14659  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
14660  return new ArrayList<>();
14661  }
14662  }
14663 
14681  @Deprecated
14682  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
14683  return findFilesInFolder(fileName, parentFile);
14684  }
14685 
14693  @Deprecated
14694  public void acquireExclusiveLock() {
14696  }
14697 
14705  @Deprecated
14706  public void releaseExclusiveLock() {
14708  }
14709 
14717  @Deprecated
14718  public void acquireSharedLock() {
14720  }
14721 
14729  @Deprecated
14730  public void releaseSharedLock() {
14732  }
14733 };
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 Priority fromID(int id)
Definition: Score.java:184
FS
File that can be found in file system tree.
Definition: TskData.java:687
static FileKnown valueOf(byte known)
Definition: TskData.java:812
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
static Significance fromID(int id)
Definition: Score.java:118
BlackboardArtifact getArtifactByArtifactId(long id)
AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans)
BlackboardArtifact getArtifactById(long id)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
Host getHostByDataSource(DataSource dataSource)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType)
LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value)
void addBlackboardAttributes(Collection< BlackboardAttribute > attributes, int artifactTypeId)
Optional< HostAddress > getHostAddress(HostAddress.HostAddressType type, String address)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
static final Score SCORE_UNKNOWN
Definition: Score.java:213
CommunicationsManager getCommunicationsManager()
AnalysisResult getAnalysisResultById(long artifactObjId)
static Set< TSK_FS_META_FLAG_ENUM > valuesOf(short metaFlags)
Definition: TskData.java:247
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails)
OsAccount getOsAccountByObjectId(long osAccountObjId)
boolean isCompatible(CaseDbSchemaVersionNumber dbSchemaVersion)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:206
static TSK_FS_TYPE_ENUM valueOf(int fsTypeValue)
Definition: TskData.java:502
CaseDbSchemaVersionNumber getDBSchemaCreationVersion()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
void addErrorObserver(ErrorObserver observer)
DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType, Content parentObj, CaseDbTransaction trans)
DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, String sha1Hash, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount, Content parent, CaseDbTransaction transaction)
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
void setFileMIMEType(AbstractFile file, String mimeType)
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:207
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount, Content parent, CaseDbTransaction transaction)
void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent, CaseDbTransaction transaction)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
final List< LayoutFile > addLayoutFiles(Content parent, List< TskFileRange > fileRanges)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int addArtifactType(String artifactTypeName, String displayName)
BlackboardArtifactTagChange addArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
synchronized CaseDbAccessManager getCaseDbAccessManager()
DataArtifact getDataArtifactById(long artifactObjId)
BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value)
List< AbstractFile > openFiles(Content dataSource, String filePath)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)
final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version)
long getBlackboardArtifactsCount(String artifactTypeName, long obj_id)
static IngestJobStatusType fromID(int typeId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value)
LAYOUT_FILE
Set of blocks from an image that have been designated as a file.
Definition: TskData.java:696
List< AbstractFile > findAllFilesInFolderWhere(long parentId, String sqlWhereClause)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir)
List< VirtualDirectory > getVirtualDirectoryRoots()
LayoutFile addLayoutFile(String fileName, long size, TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag, long ctime, long crtime, long atime, long mtime, List< TskFileRange > fileRanges, Content parent)
long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypes()
ContentTag getContentTagByID(long contentTagID)
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:690
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:688
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:633
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:208
void unregisterForEvents(Object listener)
LOCAL_DIR
Local directory that was added (not from a disk image)
Definition: TskData.java:695
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:632
void closeRunQuery(ResultSet resultSet)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
int addAttrType(String attrTypeString, String displayName)
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag)
long getContentTagsCountByTagName(TagName tagName, long dsObjId)
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static String escapeSingleQuotes(String text)
String getAttrTypeDisplayName(int attrTypeID)
List< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
List< AbstractFile > findFiles(Content dataSource, String fileName)
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:636
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:689
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:261
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:691
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:671
long getContentTagsCountByTagName(TagName tagName)
FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, String fileName, long metaAddr, int metaSeq, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parent)
Collection< FileSystem > getImageFileSystems(Image image)
void updateImagePath(String newPath, long objectId)
VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset, long blockSize, CaseDbTransaction transaction)
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:793
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:693
static SleuthkitCase newCase(String dbPath)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
List< ContentTag > getContentTagsByContent(Content content)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id)
TagName addTagName(String displayName, String description, TagName.HTML_COLOR color)
int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType)
ABSTRACTFILE
File - see tsk_files for more details.
Definition: TskData.java:634
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)
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:631
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:630
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:157
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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