Sleuth Kit Java Bindings (JNI)  4.10.2
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.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.eventbus.EventBus;
25 import com.mchange.v2.c3p0.ComboPooledDataSource;
26 import com.mchange.v2.c3p0.DataSources;
27 import com.mchange.v2.c3p0.PooledDataSource;
28 import com.zaxxer.sparsebits.SparseBitSet;
29 import java.beans.PropertyVetoException;
30 import java.io.BufferedInputStream;
31 import java.io.BufferedOutputStream;
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.io.UnsupportedEncodingException;
39 import java.net.InetAddress;
40 import java.net.URLEncoder;
41 import java.nio.charset.StandardCharsets;
42 import java.nio.file.Paths;
43 import java.sql.Connection;
44 import java.sql.DriverManager;
45 import java.sql.PreparedStatement;
46 import java.sql.ResultSet;
47 import java.sql.SQLException;
48 import java.sql.Statement;
49 import java.text.SimpleDateFormat;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.Date;
55 import java.util.EnumMap;
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.LinkedHashMap;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.MissingResourceException;
62 import java.util.Objects;
63 import java.util.Properties;
64 import java.util.ResourceBundle;
65 import java.util.Set;
66 import java.util.UUID;
67 import java.util.concurrent.ConcurrentHashMap;
68 import java.util.concurrent.TimeUnit;
69 import java.util.concurrent.locks.ReentrantReadWriteLock;
70 import java.util.logging.Level;
71 import java.util.logging.Logger;
72 import java.util.stream.Collectors;
73 import org.apache.commons.lang3.StringUtils;
74 import org.postgresql.util.PSQLState;
91 import org.sqlite.SQLiteConfig;
92 import org.sqlite.SQLiteDataSource;
93 import org.sqlite.SQLiteJDBCLoader;
94 
99 public class SleuthkitCase {
100 
101  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
102 
107  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
108  = new CaseDbSchemaVersionNumber(9, 1);
109 
110  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
111  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
112  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
113  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
114  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
115  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
116  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
117  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
118  private static final String SQL_ERROR_LIMIT_GROUP = "54";
119  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
120  private static final int MIN_USER_DEFINED_TYPE_ID = 10000;
121 
122  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
123  "tsk_events",
124  "tsk_event_descriptions",
125  "tsk_event_types",
126  "tsk_db_info",
127  "tsk_objects",
128  "tsk_image_info",
129  "tsk_image_names",
130  "tsk_vs_info",
131  "tsk_vs_parts",
132  "tsk_fs_info",
133  "tsk_file_layout",
134  "tsk_files",
135  "tsk_files_path",
136  "tsk_files_derived",
137  "tsk_files_derived_method",
138  "tag_names",
139  "content_tags",
140  "blackboard_artifact_tags",
141  "blackboard_artifacts",
142  "blackboard_attributes",
143  "blackboard_artifact_types",
144  "blackboard_attribute_types",
145  "data_source_info",
146  "file_encoding_types",
147  "ingest_module_types",
148  "ingest_job_status_types",
149  "ingest_modules",
150  "ingest_jobs",
151  "ingest_job_modules",
152  "account_types",
153  "accounts",
154  "account_relationships",
155  "review_statuses",
156  "reports,");
157 
158  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
159  "parObjId",
160  "layout_objID",
161  "artifact_objID",
162  "artifact_artifact_objID",
163  "artifact_typeID",
164  "attrsArtifactID",
165  "mime_type",
166  "file_extension",
167  "relationships_account1",
168  "relationships_account2",
169  "relationships_relationship_source_obj_id",
170  "relationships_date_time",
171  "relationships_relationship_type",
172  "relationships_data_source_obj_id",
173  "events_time",
174  "events_type",
175  "events_data_source_obj_id",
176  "events_file_obj_id",
177  "events_artifact_id");
178 
179  private static final String TSK_VERSION_KEY = "TSK_VER";
180  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
181  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
182  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
183  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
184 
185  private final ConnectionPool connections;
186  private final Object carvedFileDirsLock = new Object();
187  private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<>();
188  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
189  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
190  private final String databaseName;
191  private final String dbPath;
192  private final DbType dbType;
193  private final String caseDirPath;
194  private SleuthkitJNI.CaseDbHandle caseHandle;
195  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
196  private String dbBackupPath;
197  private Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap;
198  private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
199  private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
200  private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
201  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
202 
203  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
204  private final Object rootDirectoryMapLock = new Object();
205  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
206  private final Cache<Long, Boolean> isRootDirectoryCache
207  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
208 
209  /*
210  * First parameter is used to specify the SparseBitSet to use, as object IDs
211  * can be larger than the max size of a SparseBitSet
212  */
213  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
214 
215  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
216  // This read/write lock is used to implement a layer of locking on top of
217  // the locking protocol provided by the underlying SQLite database. The Java
218  // locking protocol improves performance for reasons that are not currently
219  // understood. Note that the lock is contructed to use a fairness policy.
220  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
221 
222  private CommunicationsManager communicationsMgr;
223  private TimelineManager timelineMgr;
224  private Blackboard blackboard;
225  private CaseDbAccessManager dbAccessManager;
226  private FileManager fileManager;
227  private TaggingManager taggingMgr;
228  private ScoringManager scoringManager;
229  private OsAccountRealmManager osAccountRealmManager;
230  private OsAccountManager osAccountManager;
231  private HostManager hostManager;
232  private PersonManager personManager;
233  private HostAddressManager hostAddressManager;
234 
235  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
236 
237  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
238 
239  public void registerForEvents(Object listener) {
240  eventBus.register(listener);
241  }
242 
243  public void unregisterForEvents(Object listener) {
244  eventBus.unregister(listener);
245  }
246 
247  void fireTSKEvent(Object event) {
248  eventBus.post(event);
249  }
250 
251  // Cache of frequently used content objects (e.g. data source, file system).
252  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
253 
254  private Examiner cachedCurrentExaminer = null;
255 
256  static {
257  Properties p = new Properties(System.getProperties());
258  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
259  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
260  System.setProperties(p);
261  }
262 
277  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
278  // Check if we can talk to the database.
279  if (info.getHost() == null || info.getHost().isEmpty()) {
280  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
281  } else if (info.getPort() == null || info.getPort().isEmpty()) {
282  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
283  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
284  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
285  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
286  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
287  }
288 
289  try {
290  Class.forName("org.postgresql.Driver"); //NON-NLS
291  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
292  if (conn != null) {
293  conn.close();
294  }
295  } catch (SQLException ex) {
296  String result;
297  String sqlState = ex.getSQLState().toLowerCase();
298  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
299  try {
300  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
301  // if we can reach the host, then it's probably port problem
302  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
303  } else {
304  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
305  }
306  } catch (IOException | MissingResourceException any) {
307  // it may be anything
308  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
309  }
310  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
311  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
312  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
313  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
314  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
315  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
316  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
317  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
318  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
319  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
320  } else {
321  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
322  }
323  throw new TskCoreException(result);
324  } catch (ClassNotFoundException ex) {
325  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
326  }
327  }
328 
340  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
341  Class.forName("org.sqlite.JDBC");
342  this.dbPath = dbPath;
343  this.dbType = dbType;
344  File dbFile = new File(dbPath);
345  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
346  this.databaseName = dbFile.getName();
347  this.connections = new SQLiteConnections(dbPath);
348  this.caseHandle = caseHandle;
349  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
350  init();
351  logSQLiteJDBCDriverInfo();
352  }
353 
371  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
372  this.dbPath = "";
373  this.databaseName = dbName;
374  this.dbType = dbType;
375  this.caseDirPath = caseDirPath;
376  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
377  this.caseHandle = caseHandle;
378  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
379  init();
380  }
381 
382  private void init() throws Exception {
383  typeIdToArtifactTypeMap = new ConcurrentHashMap<>();
384  typeIdToAttributeTypeMap = new ConcurrentHashMap<>();
385  typeNameToArtifactTypeMap = new ConcurrentHashMap<>();
386  typeNameToAttributeTypeMap = new ConcurrentHashMap<>();
387 
388  /*
389  * The database schema must be updated before loading blackboard
390  * artifact/attribute types
391  */
392  updateDatabaseSchema(null);
393  initBlackboardArtifactTypes();
394  initBlackboardAttributeTypes();
395  initNextArtifactId();
396 
397  try (CaseDbConnection connection = connections.getConnection()) {
398  initIngestModuleTypes(connection);
399  initIngestStatusTypes(connection);
400  initReviewStatuses(connection);
401  initEncodingTypes(connection);
402  populateHasChildrenMap(connection);
403  updateExaminers(connection);
404  initDBSchemaCreationVersion(connection);
405  }
406 
407  blackboard = new Blackboard(this);
408  fileManager = new FileManager(this);
409  communicationsMgr = new CommunicationsManager(this);
410  timelineMgr = new TimelineManager(this);
411  dbAccessManager = new CaseDbAccessManager(this);
412  taggingMgr = new TaggingManager(this);
413  scoringManager = new ScoringManager(this);
414  osAccountRealmManager = new OsAccountRealmManager(this);
415  osAccountManager = new OsAccountManager(this);
416  hostManager = new HostManager(this);
417  personManager = new PersonManager(this);
418  hostAddressManager = new HostAddressManager(this);
419  }
420 
426  static Set<String> getCoreTableNames() {
427  return CORE_TABLE_NAMES;
428  }
429 
435  static Set<String> getCoreIndexNames() {
436  return CORE_INDEX_NAMES;
437  }
438 
447  boolean getHasChildren(Content content) {
448  long objId = content.getId();
449  long mapIndex = objId / Integer.MAX_VALUE;
450  int mapValue = (int) (objId % Integer.MAX_VALUE);
451 
452  synchronized (hasChildrenBitSetMap) {
453  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
454  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
455  }
456  return false;
457  }
458  }
459 
465  private void setHasChildren(Long objId) {
466  long mapIndex = objId / Integer.MAX_VALUE;
467  int mapValue = (int) (objId % Integer.MAX_VALUE);
468 
469  synchronized (hasChildrenBitSetMap) {
470  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
471  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
472  } else {
473  SparseBitSet bitSet = new SparseBitSet();
474  bitSet.set(mapValue);
475  hasChildrenBitSetMap.put(mapIndex, bitSet);
476  }
477  }
478  }
479 
488  return communicationsMgr;
489  }
490 
497  return blackboard;
498  }
499 
506  return fileManager;
507  }
508 
517  return timelineMgr;
518  }
519 
520  /*
521  * Gets the case database access manager for this case.
522  *
523  * @return The per case CaseDbAccessManager object.
524  *
525  * @throws org.sleuthkit.datamodel.TskCoreException
526  */
528  return dbAccessManager;
529  }
530 
536  public synchronized TaggingManager getTaggingManager() {
537  return taggingMgr;
538  }
539 
548  return scoringManager;
549  }
550 
559  return osAccountRealmManager;
560  }
561 
570  return osAccountManager;
571  }
572 
581  return hostManager;
582  }
583 
592  return personManager;
593  }
594 
603  return hostAddressManager;
604  }
605 
612  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
614  try (CaseDbConnection connection = connections.getConnection();
615  Statement statement = connection.createStatement();) {
616  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
617  try {
618  statement.execute("INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name, category_type) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "' , " + type.getCategory().getID() + ")"); //NON-NLS
619  } catch (SQLException ex) {
620  try (ResultSet resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'")) { //NON-NLS
621  resultSet.next();
622  if (resultSet.getLong("count") == 0) {
623  throw ex;
624  }
625  }
626  }
627  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
628  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
629  }
630  if (dbType == DbType.POSTGRESQL) {
631  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
632  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
633  }
634  } finally {
636  }
637  }
638 
646  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
648  try (CaseDbConnection connection = connections.getConnection();
649  Statement statement = connection.createStatement();) {
650  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
651  try {
652  statement.execute("INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "', '" + type.getValueType().getType() + "')"); //NON-NLS
653  } catch (SQLException ex) {
654  try (ResultSet resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'")) { //NON-NLS
655  resultSet.next();
656  if (resultSet.getLong("count") == 0) {
657  throw ex;
658  }
659  }
660  }
661  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
662  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
663  }
664  if (this.dbType == DbType.POSTGRESQL) {
665  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
666  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
667  }
668  } finally {
670  }
671  }
672 
682  private void initNextArtifactId() throws SQLException, TskCoreException {
683  CaseDbConnection connection = null;
684  Statement statement = null;
685  ResultSet resultSet = null;
687  try {
688  connection = connections.getConnection();
689  statement = connection.createStatement();
690  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
691  resultSet.next();
692  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
693  if (this.nextArtifactId == 1) {
694  this.nextArtifactId = BASE_ARTIFACT_ID;
695  }
696  } finally {
697  closeResultSet(resultSet);
698  closeStatement(statement);
699  closeConnection(connection);
701  }
702  }
703 
711  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
712  Statement statement = null;
713  ResultSet resultSet = null;
715  try {
716  statement = connection.createStatement();
717  for (IngestModuleType type : IngestModuleType.values()) {
718  try {
719  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
720  } catch (SQLException ex) {
721  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
722  resultSet.next();
723  if (resultSet.getLong("count") == 0) {
724  throw ex;
725  }
726  resultSet.close();
727  resultSet = null;
728  }
729  }
730  } finally {
731  closeResultSet(resultSet);
732  closeStatement(statement);
734  }
735  }
736 
744  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
745  Statement statement = null;
746  ResultSet resultSet = null;
748  try {
749  statement = connection.createStatement();
750  for (IngestJobStatusType type : IngestJobStatusType.values()) {
751  try {
752  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
753  } catch (SQLException ex) {
754  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
755  resultSet.next();
756  if (resultSet.getLong("count") == 0) {
757  throw ex;
758  }
759  resultSet.close();
760  resultSet = null;
761  }
762  }
763  } finally {
764  closeResultSet(resultSet);
765  closeStatement(statement);
767  }
768  }
769 
776  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
777  Statement statement = null;
778  ResultSet resultSet = null;
780  try {
781  statement = connection.createStatement();
782  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
783  try {
784  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
785  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
786  } catch (SQLException ex) {
787  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
788  resultSet.next();
789  if (resultSet.getLong("count") == 0) {
790  throw ex;
791  }
792  resultSet.close();
793  resultSet = null;
794  }
795  }
796  } finally {
797  closeResultSet(resultSet);
798  closeStatement(statement);
800  }
801  }
802 
810  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
811  Statement statement = null;
812  ResultSet resultSet = null;
814  try {
815  statement = connection.createStatement();
816  for (TskData.EncodingType type : TskData.EncodingType.values()) {
817  try {
818  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
819  } catch (SQLException ex) {
820  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
821  resultSet.next();
822  if (resultSet.getLong("count") == 0) {
823  throw ex;
824  }
825  resultSet.close();
826  resultSet = null;
827  }
828  }
829  } finally {
830  closeResultSet(resultSet);
831  closeStatement(statement);
833  }
834  }
835 
844  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
845 
846  String loginName = System.getProperty("user.name");
847  if (loginName.isEmpty()) {
848  logger.log(Level.SEVERE, "Cannot determine logged in user name");
849  return;
850  }
851 
853  try {
854  PreparedStatement statement;
855  switch (getDatabaseType()) {
856  case POSTGRESQL:
857  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
858  break;
859  case SQLITE:
860  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
861  break;
862  default:
863  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
864  }
865  statement.clearParameters();
866  statement.setString(1, loginName);
867  connection.executeUpdate(statement);
868  } catch (SQLException ex) {
869  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
870  } finally {
872  }
873  }
874 
882  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
883  long timestamp = System.currentTimeMillis();
884 
885  Statement statement = null;
886  ResultSet resultSet = null;
888  try {
889  statement = connection.createStatement();
890  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
891 
892  synchronized (hasChildrenBitSetMap) {
893  while (resultSet.next()) {
894  setHasChildren(resultSet.getLong("par_obj_id"));
895  }
896  }
897  long delay = System.currentTimeMillis() - timestamp;
898  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
899  } catch (SQLException ex) {
900  throw new TskCoreException("Error populating parent node cache", ex);
901  } finally {
902  closeResultSet(resultSet);
903  closeStatement(statement);
905  }
906  }
907 
914  void addDataSourceToHasChildrenMap() throws TskCoreException {
915 
916  CaseDbConnection connection = connections.getConnection();
917  try {
918  populateHasChildrenMap(connection);
919  } finally {
920  closeConnection(connection);
921  }
922  }
923 
933  private void updateDatabaseSchema(String dbPath) throws Exception {
934  CaseDbConnection connection = null;
935  ResultSet resultSet = null;
936  Statement statement = null;
938  try {
939  connection = connections.getConnection();
940  connection.beginTransaction();
941 
942  boolean hasMinorVersion = false;
943  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
944  while (columns.next()) {
945  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
946  hasMinorVersion = true;
947  }
948  }
949 
950  // Get the schema version number of the case database from the tsk_db_info table.
951  int dbSchemaMajorVersion;
952  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
953 
954  statement = connection.createStatement();
955  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
956  + (hasMinorVersion ? ", schema_minor_ver" : "")
957  + " FROM tsk_db_info"); //NON-NLS
958  if (resultSet.next()) {
959  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
960  if (hasMinorVersion) {
961  //if there is a minor version column, use it, else default to zero.
962  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
963  }
964  } else {
965  throw new TskCoreException();
966  }
967  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
968 
969  resultSet.close();
970  resultSet = null;
971  statement.close();
972  statement = null;
973  //check schema compatibility
974  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
975  //we cannot open a db with a major schema version higher than the current one.
976  throw new TskUnsupportedSchemaVersionException(
977  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
978  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
979  //The schema version is compatible,possibly after upgrades.
980 
981  if (null != dbPath) {
982  // Make a backup copy of the database. Client code can get the path of the backup
983  // using the getBackupDatabasePath() method.
984  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
985  copyCaseDB(backupFilePath);
986  dbBackupPath = backupFilePath;
987  }
988 
989  // ***CALL SCHEMA UPDATE METHODS HERE***
990  // Each method should examine the schema version passed to it and either:
991  // a. do nothing and return the schema version unchanged, or
992  // b. upgrade the database and return the schema version that the db was upgraded to.
993  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
994  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
995  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
996  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
997  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
998  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
999  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
1000  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
1001  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
1002  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
1003  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
1004  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
1005  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
1006  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
1007  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
1008  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
1009 
1010  statement = connection.createStatement();
1011  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
1012  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
1013  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
1014  statement.close();
1015  statement = null;
1016  }
1017 
1018  connection.commitTransaction();
1019  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
1020  rollbackTransaction(connection);
1021  throw ex;
1022  } finally {
1023  closeResultSet(resultSet);
1024  closeStatement(statement);
1025  closeConnection(connection);
1027  }
1028  }
1029 
1037  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
1038 
1039  Statement statement = null;
1040  ResultSet resultSet = null;
1041  String createdSchemaMajorVersion = "0";
1042  String createdSchemaMinorVersion = "0";
1044  try {
1045  statement = connection.createStatement();
1046  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
1047  while (resultSet.next()) {
1048  String name = resultSet.getString("name");
1049  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
1050  createdSchemaMajorVersion = resultSet.getString("value");
1051  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
1052  createdSchemaMinorVersion = resultSet.getString("value");
1053  }
1054  }
1055 
1056  } finally {
1057  closeResultSet(resultSet);
1058  closeStatement(statement);
1060  }
1061 
1062  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
1063  }
1064 
1074  public void copyCaseDB(String newDBPath) throws IOException {
1075  if (dbPath.isEmpty()) {
1076  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1077  }
1078  InputStream in = null;
1079  OutputStream out = null;
1081  try {
1082  InputStream inFile = new FileInputStream(dbPath);
1083  in = new BufferedInputStream(inFile);
1084  OutputStream outFile = new FileOutputStream(newDBPath);
1085  out = new BufferedOutputStream(outFile);
1086  int bytesRead = in.read();
1087  while (bytesRead != -1) {
1088  out.write(bytesRead);
1089  bytesRead = in.read();
1090  }
1091  } finally {
1092  try {
1093  if (in != null) {
1094  in.close();
1095  }
1096  if (out != null) {
1097  out.flush();
1098  out.close();
1099  }
1100  } catch (IOException e) {
1101  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1102  }
1104  }
1105  }
1106 
1110  private void logSQLiteJDBCDriverInfo() {
1111  try {
1112  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1113  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1114  ? "native" : "pure-java")); //NON-NLS
1115  } catch (Exception ex) {
1116  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1117  }
1118  }
1119 
1133  @SuppressWarnings("deprecation")
1134  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1135  if (schemaVersion.getMajor() != 2) {
1136  return schemaVersion;
1137  }
1138  Statement statement = null;
1139  Statement statement2 = null;
1140  Statement updateStatement = null;
1141  ResultSet resultSet = null;
1143  try {
1144  statement = connection.createStatement();
1145  statement2 = connection.createStatement();
1146 
1147  // Add new tables for tags.
1148  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
1149  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
1150  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
1151 
1152  // Add a new table for reports.
1153  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
1154 
1155  // Add new columns to the image info table.
1156  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1157  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1158  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1159 
1160  // Add a new column to the file system info table.
1161  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1162 
1163  // Add a new column to the file table.
1164  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1165 
1166  // Add new columns and indexes to the attributes table and populate the
1167  // new column. Note that addition of the new column is a denormalization
1168  // to optimize attribute queries.
1169  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1170  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1171  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1172  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1173  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1174  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1175  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1176  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1177  + "FROM blackboard_attributes AS attrs " //NON-NLS
1178  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1179  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1180  updateStatement = connection.createStatement();
1181  while (resultSet.next()) {
1182  long artifactId = resultSet.getLong("artifact_id");
1183  int artifactTypeId = resultSet.getInt("artifact_type_id");
1184  updateStatement.executeUpdate(
1185  "UPDATE blackboard_attributes " //NON-NLS
1186  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1187  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1188  }
1189  resultSet.close();
1190 
1191  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1192  Map<String, Long> tagNames = new HashMap<>();
1193  long tagNameCounter = 1;
1194 
1195  // Convert file tags.
1196  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1197  resultSet = statement.executeQuery("SELECT * FROM \n"
1198  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1199  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1200  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1201  + "WHERE blackboard_artifacts.artifact_type_id = "
1202  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1203  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1204  + ") AS tagNames \n"
1205  + "INNER JOIN \n"
1206  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1207  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1208  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1209  + "ON tagNames.objId = fileData.objId2 \n"
1210  + "LEFT JOIN \n"
1211  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1212  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1213  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1214 
1215  while (resultSet.next()) {
1216  long objId = resultSet.getLong("objId");
1217  long fileSize = resultSet.getLong("fileSize");
1218  String tagName = resultSet.getString("name");
1219  String tagComment = resultSet.getString("comment");
1220  if (tagComment == null) {
1221  tagComment = "";
1222  }
1223 
1224  if (tagName != null && !tagName.isEmpty()) {
1225  // Get the index for the tag name, adding it to the database if needed.
1226  long tagNameIndex;
1227  if (tagNames.containsKey(tagName)) {
1228  tagNameIndex = tagNames.get(tagName);
1229  } else {
1230  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1231  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1232  tagNames.put(tagName, tagNameCounter);
1233  tagNameIndex = tagNameCounter;
1234  tagNameCounter++;
1235  }
1236 
1237  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1238  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1239  }
1240  }
1241  resultSet.close();
1242 
1243  // Convert artifact tags.
1244  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1245  resultSet = statement.executeQuery("SELECT * FROM \n"
1246  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1247  + "blackboard_attributes.value_text AS name\n"
1248  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1249  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1250  + "WHERE blackboard_artifacts.artifact_type_id = "
1251  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1252  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1253  + ") AS tagNames \n"
1254  + "INNER JOIN \n"
1255  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1256  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1257  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1258  + "LEFT JOIN \n"
1259  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1260  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1261  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1262 
1263  while (resultSet.next()) {
1264  long artifactId = resultSet.getLong("taggedArtifactId");
1265  String tagName = resultSet.getString("name");
1266  String tagComment = resultSet.getString("comment");
1267  if (tagComment == null) {
1268  tagComment = "";
1269  }
1270  if (tagName != null && !tagName.isEmpty()) {
1271  // Get the index for the tag name, adding it to the database if needed.
1272  long tagNameIndex;
1273  if (tagNames.containsKey(tagName)) {
1274  tagNameIndex = tagNames.get(tagName);
1275  } else {
1276  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1277  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1278  tagNames.put(tagName, tagNameCounter);
1279  tagNameIndex = tagNameCounter;
1280  tagNameCounter++;
1281  }
1282 
1283  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1284  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1285  }
1286  }
1287  resultSet.close();
1288 
1289  statement.execute(
1290  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1291  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1292  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1293  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1294  statement.execute(
1295  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1296  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1297  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1298 
1299  return new CaseDbSchemaVersionNumber(3, 0);
1300  } finally {
1301  closeStatement(updateStatement);
1302  closeResultSet(resultSet);
1303  closeStatement(statement);
1304  closeStatement(statement2);
1306  }
1307  }
1308 
1322  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1323  if (schemaVersion.getMajor() != 3) {
1324  return schemaVersion;
1325  }
1326 
1327  Statement statement = null;
1328  ResultSet resultSet = null;
1329  Statement queryStatement = null;
1330  ResultSet queryResultSet = null;
1331  Statement updateStatement = null;
1333  try {
1334  // Add mime_type column to tsk_files table. Populate with general
1335  // info artifact file signature data.
1336  statement = connection.createStatement();
1337  updateStatement = connection.createStatement();
1338  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1339  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1340  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1341  + "WHERE files.obj_id = arts.obj_id AND "
1342  + "arts.artifact_id = attrs.artifact_id AND "
1343  + "arts.artifact_type_id = 1 AND "
1344  + "attrs.attribute_type_id = 62");
1345  while (resultSet.next()) {
1346  updateStatement.executeUpdate(
1347  "UPDATE tsk_files " //NON-NLS
1348  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1349  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1350  }
1351  resultSet.close();
1352 
1353  // Add value_type column to blackboard_attribute_types table.
1354  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1355  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1356  while (resultSet.next()) {
1357  int attributeTypeId = resultSet.getInt("attribute_type_id");
1358  String attributeLabel = resultSet.getString("type_name");
1359  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
1360  updateStatement.executeUpdate(
1361  "UPDATE blackboard_attribute_types " //NON-NLS
1362  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1363  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1364  }
1365  }
1366  resultSet.close();
1367 
1368  // Add a data_sources_info table.
1369  queryStatement = connection.createStatement();
1370  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));");
1371  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1372  while (resultSet.next()) {
1373  long objectId = resultSet.getLong("obj_id");
1374  String timeZone = "";
1375  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1376  if (queryResultSet.next()) {
1377  timeZone = queryResultSet.getString("tzone");
1378  }
1379  queryResultSet.close();
1380  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1381  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1382  }
1383  resultSet.close();
1384 
1385  // Add data_source_obj_id column to the tsk_files table.
1386  //
1387  // NOTE: A new case database will have the following FK constraint:
1388  //
1389  // REFERENCES data_source_info (obj_id)
1390  //
1391  // The constraint is sacrificed here to avoid having to create and
1392  // populate a new tsk_files table.
1393  //
1394  // TODO: Do this right.
1395  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1396  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");
1397  while (resultSet.next()) {
1398  long fileId = resultSet.getLong("obj_id");
1399  long dataSourceId = getDataSourceObjectId(connection, fileId);
1400  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1401  }
1402  resultSet.close();
1403  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1404  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1405  if (this.dbType.equals(DbType.SQLITE)) {
1406  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
1407  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
1408  } else {
1409  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
1410  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
1411  }
1412 
1413  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
1414  initIngestModuleTypes(connection);
1415  initIngestStatusTypes(connection);
1416 
1417  return new CaseDbSchemaVersionNumber(4, 0);
1418 
1419  } finally {
1420  closeResultSet(queryResultSet);
1421  closeStatement(queryStatement);
1422  closeStatement(updateStatement);
1423  closeResultSet(resultSet);
1424  closeStatement(statement);
1426  }
1427  }
1428 
1442  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1443  if (schemaVersion.getMajor() != 4) {
1444  return schemaVersion;
1445  }
1446 
1447  Statement statement = null;
1449  try {
1450  // Add the review_statuses lookup table.
1451  statement = connection.createStatement();
1452  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1453 
1454  /*
1455  * Add review_status_id column to artifacts table.
1456  *
1457  * NOTE: For DBs created with schema 5 we define a foreign key
1458  * constraint on the review_status_column. We don't bother with this
1459  * for DBs updated to schema 5 because of limitations of the SQLite
1460  * ALTER TABLE command.
1461  */
1462  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1463 
1464  // Add the encoding table
1465  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1466  initEncodingTypes(connection);
1467 
1468  /*
1469  * This needs to be done due to a Autopsy/TSK out of synch problem.
1470  * Without this, it is possible to upgrade from version 4 to 5 and
1471  * then 5 to 6, but not from 4 to 6.
1472  */
1473  initReviewStatuses(connection);
1474 
1475  // Add encoding type column to tsk_files_path
1476  // This should really have the FOREIGN KEY constraint but there are problems
1477  // getting that to work, so we don't add it on this upgrade path.
1478  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1479 
1480  return new CaseDbSchemaVersionNumber(5, 0);
1481 
1482  } finally {
1483  closeStatement(statement);
1485  }
1486  }
1487 
1501  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1502  if (schemaVersion.getMajor() != 5) {
1503  return schemaVersion;
1504  }
1505 
1506  /*
1507  * This upgrade fixes a bug where some releases had artifact review
1508  * status support in the case database and others did not.
1509  */
1510  Statement statement = null;
1511  ResultSet resultSet = null;
1513  try {
1514  /*
1515  * Add the review_statuses lookup table, if missing.
1516  */
1517  statement = connection.createStatement();
1518  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)");
1519 
1520  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1521  resultSet.next();
1522  if (resultSet.getLong("count") == 0) {
1523  /*
1524  * Add review_status_id column to artifacts table.
1525  *
1526  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1527  * key constraint on the review_status_column. We don't bother
1528  * with this for DBs updated to schema 5 or 6 because of
1529  * limitations of the SQLite ALTER TABLE command.
1530  */
1531  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1532  }
1533 
1534  return new CaseDbSchemaVersionNumber(6, 0);
1535 
1536  } finally {
1537  closeResultSet(resultSet);
1538  closeStatement(statement);
1540  }
1541  }
1542 
1556  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1557  if (schemaVersion.getMajor() != 6) {
1558  return schemaVersion;
1559  }
1560 
1561  /*
1562  * This upgrade adds an indexed extension column to the tsk_files table.
1563  */
1564  Statement statement = null;
1565  Statement updstatement = null;
1566  ResultSet resultSet = null;
1568  try {
1569  statement = connection.createStatement();
1570  updstatement = connection.createStatement();
1571  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1572 
1573  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1574  while (resultSet.next()) {
1575  long objID = resultSet.getLong("obj_id");
1576  String name = resultSet.getString("name");
1577  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1578  + "WHERE obj_id = " + objID);
1579  }
1580 
1581  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1582 
1583  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1584  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1585 
1586  return new CaseDbSchemaVersionNumber(7, 0);
1587 
1588  } finally {
1589  closeResultSet(resultSet);
1590  closeStatement(statement);
1591  closeStatement(updstatement);
1593  }
1594  }
1595 
1609  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1610  if (schemaVersion.getMajor() != 7) {
1611  return schemaVersion;
1612  }
1613 
1614  if (schemaVersion.getMinor() != 0) {
1615  return schemaVersion;
1616  }
1617 
1618  /*
1619  * This upgrade adds a minor version number column.
1620  */
1621  Statement statement = null;
1622  ResultSet resultSet = null;
1624  try {
1625  statement = connection.createStatement();
1626 
1627  //add the schema minor version number column.
1628  if (schemaVersion.getMinor() == 0) {
1629  //add the schema minor version number column.
1630  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1631  }
1632  return new CaseDbSchemaVersionNumber(7, 1);
1633 
1634  } finally {
1635  closeResultSet(resultSet);
1636  closeStatement(statement);
1638  }
1639  }
1640 
1654  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1655  if (schemaVersion.getMajor() != 7) {
1656  return schemaVersion;
1657  }
1658 
1659  if (schemaVersion.getMinor() != 1) {
1660  return schemaVersion;
1661  }
1662 
1663  Statement statement = null;
1664  Statement updstatement = null;
1665  ResultSet resultSet = null;
1667  try {
1668  //add the data_source_obj_id column to blackboard_artifacts.
1669  statement = connection.createStatement();
1670  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1671 
1672  // populate data_source_obj_id for each artifact
1673  updstatement = connection.createStatement();
1674  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1675  while (resultSet.next()) {
1676  long artifact_id = resultSet.getLong("artifact_id");
1677  long obj_id = resultSet.getLong("obj_id");
1678  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1679  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1680  + "WHERE artifact_id = " + artifact_id);
1681  }
1682  closeResultSet(resultSet);
1683  closeStatement(statement);
1684  closeStatement(updstatement);
1685 
1686  /*
1687  * Add a knownStatus column to the tag_names table.
1688  */
1689  statement = connection.createStatement();
1690  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1691 
1692  // Create account_types, accounts, and account_relationships table
1693  if (this.dbType.equals(DbType.SQLITE)) {
1694  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1695  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))");
1696  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))");
1697  } else {
1698  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1699  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))");
1700  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))");
1701  }
1702 
1703  // Create indexes
1704  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1705  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1706  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1707  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1708  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1709  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1710  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1711 
1712  return new CaseDbSchemaVersionNumber(7, 2);
1713  } finally {
1714  closeResultSet(resultSet);
1715  closeStatement(statement);
1716  closeStatement(updstatement);
1718  }
1719  }
1720 
1734  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1735  if (schemaVersion.getMajor() != 7) {
1736  return schemaVersion;
1737  }
1738 
1739  if (schemaVersion.getMinor() != 2) {
1740  return schemaVersion;
1741  }
1742 
1743  Statement updateSchemaStatement = connection.createStatement();
1744  Statement getExistingReportsStatement = connection.createStatement();
1745  ResultSet resultSet = null;
1746  ResultSet existingReports = null;
1747 
1749  try {
1750  // Update the schema to turn report_id into an object id.
1751 
1752  // Unfortunately, SQLite doesn't support adding a constraint
1753  // to an existing table so we have to rename the old...
1754  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1755 
1756  // ...create the new...
1757  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))");
1758 
1759  // ...add the existing report records back...
1760  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1761  while (existingReports.next()) {
1762  String path = existingReports.getString(2);
1763  long crtime = existingReports.getInt(3);
1764  String sourceModule = existingReports.getString(4);
1765  String reportName = existingReports.getString(5);
1766 
1767  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1768  insertObjectStatement.clearParameters();
1769  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1770  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1771  connection.executeUpdate(insertObjectStatement);
1772  resultSet = insertObjectStatement.getGeneratedKeys();
1773  if (!resultSet.next()) {
1774  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1775  }
1776  long objectId = resultSet.getLong(1); //last_insert_rowid()
1777 
1778  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1779  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1780  insertReportStatement.clearParameters();
1781  insertReportStatement.setLong(1, objectId);
1782  insertReportStatement.setString(2, path);
1783  insertReportStatement.setLong(3, crtime);
1784  insertReportStatement.setString(4, sourceModule);
1785  insertReportStatement.setString(5, reportName);
1786  connection.executeUpdate(insertReportStatement);
1787  }
1788 
1789  // ...and drop the old table.
1790  updateSchemaStatement.execute("DROP TABLE old_reports");
1791 
1792  return new CaseDbSchemaVersionNumber(8, 0);
1793  } finally {
1794  closeResultSet(resultSet);
1795  closeResultSet(existingReports);
1796  closeStatement(updateSchemaStatement);
1797  closeStatement(getExistingReportsStatement);
1799  }
1800  }
1801 
1815  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1816  if (schemaVersion.getMajor() != 8) {
1817  return schemaVersion;
1818  }
1819 
1820  if (schemaVersion.getMinor() != 0) {
1821  return schemaVersion;
1822  }
1823 
1825 
1826  try (Statement statement = connection.createStatement();) {
1827  // create examiners table
1828  if (this.dbType.equals(DbType.SQLITE)) {
1829  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1830  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1831  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1832  } else {
1833  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1834  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1835  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1836  }
1837 
1838  return new CaseDbSchemaVersionNumber(8, 1);
1839  } finally {
1841  }
1842  }
1843 
1857  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1858  if (schemaVersion.getMajor() != 8) {
1859  return schemaVersion;
1860  }
1861 
1862  if (schemaVersion.getMinor() != 1) {
1863  return schemaVersion;
1864  }
1865 
1867 
1868  try (Statement statement = connection.createStatement();) {
1869  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1870  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1871 
1872  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1873 
1874  /*
1875  * Add new tsk_db_extended_info table with TSK version, creation
1876  * time schema and schema version numbers as the initial data. The
1877  * creation time schema version is set to 0, 0 to indicate that it
1878  * is not known.
1879  */
1880  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1881  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1882  result.next();
1883  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1884  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1885  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1886  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1887  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1888 
1889  String primaryKeyType;
1890  switch (getDatabaseType()) {
1891  case POSTGRESQL:
1892  primaryKeyType = "BIGSERIAL";
1893  break;
1894  case SQLITE:
1895  primaryKeyType = "INTEGER";
1896  break;
1897  default:
1898  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1899  }
1900 
1901  //create and initialize tsk_event_types tables
1902  statement.execute("CREATE TABLE tsk_event_types ("
1903  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1904  + " display_name TEXT UNIQUE NOT NULL, "
1905  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1906  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1907  + " values( 0, 'Event Types', null)");
1908  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1909  + " values(1, 'File System', 0)");
1910  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1911  + " values(2, 'Web Activity', 0)");
1912  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1913  + " values(3, 'Misc Types', 0)");
1914  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1915  + " values(4, 'Modified', 1)");
1916  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1917  + " values(5, 'Accessed', 1)");
1918  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1919  + " values(6, 'Created', 1)");
1920  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1921  + " values(7, 'Changed', 1)");
1922 
1923  //create tsk_events tables
1924  statement.execute("CREATE TABLE tsk_event_descriptions ("
1925  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1926  + " full_description TEXT NOT NULL, "
1927  + " med_description TEXT, "
1928  + " short_description TEXT,"
1929  + " data_source_obj_id BIGINT NOT NULL, "
1930  + " file_obj_id BIGINT NOT NULL, "
1931  + " artifact_id BIGINT, "
1932  + " hash_hit INTEGER NOT NULL, " //boolean
1933  + " tagged INTEGER NOT NULL, " //boolean
1934  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1935  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1936  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1937  );
1938 
1939  statement.execute("CREATE TABLE tsk_events ( "
1940  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1941  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1942  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1943  + " time INTEGER NOT NULL) "
1944  );
1945 
1946  //create tsk_events indices
1947  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1948  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1949  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1950  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1951  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1952  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1953  return new CaseDbSchemaVersionNumber(8, 2);
1954 
1955  } finally {
1957  }
1958  }
1959 
1973  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1974  if (schemaVersion.getMajor() != 8) {
1975  return schemaVersion;
1976  }
1977 
1978  if (schemaVersion.getMinor() != 2) {
1979  return schemaVersion;
1980  }
1981 
1983 
1984  ResultSet resultSet = null;
1985 
1986  try (Statement statement = connection.createStatement();) {
1987 
1988  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1989  // Unfortunately, SQLite doesn't support adding a constraint
1990  // to an existing table so we have to rename the old...
1991  String primaryKeyType;
1992  switch (getDatabaseType()) {
1993  case POSTGRESQL:
1994  primaryKeyType = "BIGSERIAL";
1995  break;
1996  case SQLITE:
1997  primaryKeyType = "INTEGER";
1998  break;
1999  default:
2000  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2001  }
2002 
2003  //create and initialize tsk_event_types tables which may or may not exist
2004  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
2005  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
2006  + " display_name TEXT UNIQUE NOT NULL, "
2007  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
2008 
2009  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
2010 
2011  // If there is something in resultSet then the table must have previously
2012  // existing therefore there is not need to populate
2013  if (!resultSet.next()) {
2014 
2015  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2016  + " values( 0, 'Event Types', null)");
2017  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2018  + " values(1, 'File System', 0)");
2019  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2020  + " values(2, 'Web Activity', 0)");
2021  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2022  + " values(3, 'Misc Types', 0)");
2023  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2024  + " values(4, 'Modified', 1)");
2025  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2026  + " values(5, 'Accessed', 1)");
2027  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2028  + " values(6, 'Created', 1)");
2029  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2030  + " values(7, 'Changed', 1)");
2031  }
2032 
2033  // Delete the old table that may have been created with the upgrade
2034  // from 8.1 to 8.2.
2035  statement.execute("DROP TABLE IF EXISTS tsk_events");
2036 
2037  // Delete the old table that may have been created with the upgrade
2038  // from 8.1 to 8.2
2039  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
2040 
2041  //create new tsk_event_description table
2042  statement.execute("CREATE TABLE tsk_event_descriptions ("
2043  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2044  + " full_description TEXT NOT NULL, "
2045  + " med_description TEXT, "
2046  + " short_description TEXT,"
2047  + " data_source_obj_id BIGINT NOT NULL, "
2048  + " file_obj_id BIGINT NOT NULL, "
2049  + " artifact_id BIGINT, "
2050  + " hash_hit INTEGER NOT NULL, " //boolean
2051  + " tagged INTEGER NOT NULL, " //boolean
2052  + " UNIQUE(full_description, file_obj_id, artifact_id), "
2053  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2054  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2055  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2056  );
2057 
2058  // create a new table
2059  statement.execute("CREATE TABLE tsk_events ( "
2060  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2061  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2062  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2063  + " time INTEGER NOT NULL, "
2064  + " UNIQUE (event_type_id, event_description_id, time))"
2065  );
2066 
2067  // Fix mistakenly set names in tsk_db_info_extended
2068  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2069  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2070 
2071  return new CaseDbSchemaVersionNumber(8, 3);
2072  } finally {
2073  closeResultSet(resultSet);
2075  }
2076  }
2077 
2099  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2100  if (schemaVersion.getMajor() != 8) {
2101  return schemaVersion;
2102  }
2103 
2104  if (schemaVersion.getMinor() != 3) {
2105  return schemaVersion;
2106  }
2107 
2108  Statement statement = connection.createStatement();
2109  ResultSet results = null;
2110 
2112  try {
2113  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2114  // the previous update code.
2115  if (null == getDatabaseType()) {
2116  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2117  }
2118 
2119  switch (getDatabaseType()) {
2120  case POSTGRESQL:
2121  // Check if the misnamed column is present
2122  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2123  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2124  if (results.next()) {
2125  // In PostgreSQL we can rename the column if it exists
2126  statement.execute("ALTER TABLE tsk_event_descriptions "
2127  + "RENAME COLUMN file_obj_id TO content_obj_id");
2128 
2129  // 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
2130  // Fix the schema, preserving any data if exists.
2131  statement.execute("CREATE TABLE temp_tsk_events ( "
2132  + " event_id BIGSERIAL PRIMARY KEY, "
2133  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2134  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2135  + " time BIGINT NOT NULL, "
2136  + " UNIQUE (event_type_id, event_description_id, time))"
2137  );
2138 
2139  // Copy the data
2140  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2141  + "event_description_id, time) SELECT * FROM tsk_events");
2142 
2143  // Drop the old table
2144  statement.execute("DROP TABLE tsk_events");
2145 
2146  // Rename the new table
2147  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2148 
2149  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2150  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2151  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2152  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2153  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2154  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2155  }
2156  break;
2157  case SQLITE:
2158  boolean hasMisnamedColumn = false;
2159  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2160  while (results.next()) {
2161  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2162  hasMisnamedColumn = true;
2163  break;
2164  }
2165  }
2166 
2167  if (hasMisnamedColumn) {
2168  // Since we can't rename the column we'll need to make new tables and copy the data
2169  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2170  + " event_description_id INTEGER PRIMARY KEY, "
2171  + " full_description TEXT NOT NULL, "
2172  + " med_description TEXT, "
2173  + " short_description TEXT,"
2174  + " data_source_obj_id BIGINT NOT NULL, "
2175  + " content_obj_id BIGINT NOT NULL, "
2176  + " artifact_id BIGINT, "
2177  + " hash_hit INTEGER NOT NULL, " //boolean
2178  + " tagged INTEGER NOT NULL, " //boolean
2179  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2180  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2181  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2182  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2183  );
2184 
2185  statement.execute("CREATE TABLE temp_tsk_events ( "
2186  + " event_id INTEGER PRIMARY KEY, "
2187  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2188  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2189  + " time INTEGER NOT NULL, "
2190  + " UNIQUE (event_type_id, event_description_id, time))"
2191  );
2192 
2193  // Copy the data
2194  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2195  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2196  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2197 
2198  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2199  + "event_description_id, time) SELECT * FROM tsk_events");
2200 
2201  // Drop the old tables
2202  statement.execute("DROP TABLE tsk_events");
2203  statement.execute("DROP TABLE tsk_event_descriptions");
2204 
2205  // Rename the new tables
2206  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2207  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2208 
2209  //create tsk_events indices
2210  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2211  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2212  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2213  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2214  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2215  }
2216  break;
2217  default:
2218  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2219  }
2220 
2221  // create pool info table
2222  if (this.dbType.equals(DbType.SQLITE)) {
2223  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)");
2224  } else {
2225  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)");
2226  }
2227 
2228  // Add new account types for newly supported messaging applications, if they dont exists already.
2229  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2230  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2231  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2232  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2233  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2234  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2235  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2236  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2237  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2238  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2239 
2240  return new CaseDbSchemaVersionNumber(8, 4);
2241  } finally {
2242  closeResultSet(results);
2243  closeStatement(statement);
2245  }
2246  }
2247 
2248  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2249  if (schemaVersion.getMajor() != 8) {
2250  return schemaVersion;
2251  }
2252 
2253  if (schemaVersion.getMinor() != 4) {
2254  return schemaVersion;
2255  }
2256 
2257  Statement statement = connection.createStatement();
2259  try {
2260  switch (getDatabaseType()) {
2261  case POSTGRESQL:
2262  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2263  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2264  break;
2265  case SQLITE:
2266  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2267  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2268  break;
2269  }
2270 
2271  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2272 
2273  /*
2274  * Update existing Project Vic tag names (from Image Gallery in
2275  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2276  * date and will not work with the Project VIC Report module. New
2277  * cases will get the new names from Image Gallery.
2278  */
2279  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2280  if (getDatabaseType() == DbType.POSTGRESQL) {
2281  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2282  } else {
2283  statement.execute(insertStmt);
2284  }
2285  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2286  if (resultSet != null && resultSet.next()) {
2287  int tagSetId = resultSet.getInt(1);
2288 
2289  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2290  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2291  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2292  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2293  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2294  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2295 
2296  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')";
2297  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')";
2298  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2299  statement.executeUpdate(deleteContentTag);
2300  statement.executeUpdate(deleteArtifactTag);
2301  statement.executeUpdate(deleteCat0);
2302 
2303  } else {
2304  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2305  }
2306  }
2307 
2308  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2309  // this column will have a foreign key constraint on the data_source_info table.
2310  // There does not seem to be a reasonable way to do this in an upgrade,
2311  // so upgraded cases will be missing the foreign key.
2312  switch (getDatabaseType()) {
2313  case POSTGRESQL:
2314  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2315  break;
2316  case SQLITE:
2317  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2318  break;
2319  }
2320  Statement updateStatement = connection.createStatement();
2321  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2322  while (resultSet.next()) {
2323  long fsId = resultSet.getLong("obj_id");
2324  long dataSourceId = getDataSourceObjectId(connection, fsId);
2325  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2326  }
2327  } finally {
2328  closeStatement(updateStatement);
2329  }
2330 
2331  return new CaseDbSchemaVersionNumber(8, 5);
2332 
2333  } finally {
2334  closeStatement(statement);
2336  }
2337  }
2338 
2339  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2340  if (schemaVersion.getMajor() != 8) {
2341  return schemaVersion;
2342  }
2343 
2344  if (schemaVersion.getMinor() != 5) {
2345  return schemaVersion;
2346  }
2347 
2348  Statement statement = connection.createStatement();
2350  try {
2351  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2352 
2353  return new CaseDbSchemaVersionNumber(8, 6);
2354 
2355  } finally {
2356  closeStatement(statement);
2358  }
2359  }
2360 
2361  @SuppressWarnings("deprecation")
2362  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2363  if (schemaVersion.getMajor() != 8) {
2364  return schemaVersion;
2365  }
2366 
2367  if (schemaVersion.getMinor() != 6) {
2368  return schemaVersion;
2369  }
2370 
2371  Statement statement = connection.createStatement();
2373  try {
2374  String dateDataType = "BIGINT";
2375  String bigIntDataType = "BIGINT";
2376  String blobDataType = "BYTEA";
2377  String primaryKeyType = "BIGSERIAL";
2378 
2379  if (this.dbType.equals(DbType.SQLITE)) {
2380  dateDataType = "INTEGER";
2381  bigIntDataType = "INTEGER";
2382  blobDataType = "BLOB";
2383  primaryKeyType = "INTEGER";
2384  }
2385  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2386  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2387  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2388  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2389 
2390  // Add category type and initialize the types. We use the list of artifact types that
2391  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2392  // case the built-in types change in a later release.
2393  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2394  String analysisTypeObjIdList
2395  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2396  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2397  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2398  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2399  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2400  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2401  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2402  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2403  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2404  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2405  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2406  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2407  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2408  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2409  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2410  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2411  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2412  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2413  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2414 
2415  // Create tsk file attributes table
2416  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2417  + "obj_id " + bigIntDataType + " NOT NULL, "
2418  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2419  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2420  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2421  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2422  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2423 
2424  // create analysis results tables
2425  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2426  + "conclusion TEXT, "
2427  + "significance INTEGER NOT NULL, "
2428  /* method_category was a column in a little distributed version of 9.0.
2429  * It was renamed to priority before public release. The 9.1 upgrade code
2430  * will add the priority column. This is commented out since it was never used. */
2431  // + "method_category INTEGER NOT NULL, "
2432  + "configuration TEXT, justification TEXT, "
2433  + "ignore_score INTEGER DEFAULT 0 " // boolean
2434  + ")");
2435 
2436  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2437  + "data_source_obj_id " + bigIntDataType + ", "
2438  + "significance INTEGER NOT NULL, "
2439  // See comment above on why this is commented out
2440  // + "method_category INTEGER NOT NULL, "
2441  + "UNIQUE (obj_id),"
2442  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2443  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2444  + ")");
2445 
2446  // Create person table.
2447  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2448  + "name TEXT NOT NULL, " // person name
2449  + "UNIQUE(name)) ");
2450 
2451  // Create host table.
2452  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2453  + "name TEXT NOT NULL, " // host name
2454  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2455  + "person_id INTEGER, "
2456  + "merged_into " + bigIntDataType + ", "
2457  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2458  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2459  + "UNIQUE(name)) ");
2460 
2461  // Create OS Account and related tables
2462  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2463  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2464  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2465  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2466  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2467  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2468  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2469  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2470  + "UNIQUE(realm_signature), "
2471  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2472  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2473 
2474  // Add host column and create a host for each existing data source.
2475  // We will create a host for each device id so that related data sources will
2476  // be associated with the same host.
2477  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2478  Statement updateStatement = connection.createStatement();
2479  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2480  Map<String, Long> hostMap = new HashMap<>();
2481  long hostIndex = 1;
2482  while (resultSet.next()) {
2483  long objId = resultSet.getLong("obj_id");
2484  String deviceId = resultSet.getString("device_id");
2485 
2486  if (!hostMap.containsKey(deviceId)) {
2487  String hostName = "Host " + hostIndex;
2488  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2489  hostMap.put(deviceId, hostIndex);
2490  hostIndex++;
2491  }
2492  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2493  }
2494  } finally {
2495  closeStatement(updateStatement);
2496  }
2497 
2498  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2499  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2500  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2501  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2502  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2503  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2504  + "status INTEGER, " // enabled/disabled/deleted
2505  + "type INTEGER, " // service/interactive
2506  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2507  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2508  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2509  + "UNIQUE(signature, realm_id), "
2510  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2511  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2512  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2513 
2514  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2515  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2516  + "host_id " + bigIntDataType + ", "
2517  + "source_obj_id " + bigIntDataType + ", "
2518  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2519  + "value_type INTEGER NOT NULL, "
2520  + "value_byte " + bigIntDataType + ", "
2521  + "value_text TEXT, "
2522  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2523  + "value_double NUMERIC(20, 10), "
2524  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2525  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2526  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2527  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2528 
2529  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2530  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2531  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2532  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2533  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2534  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2535  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2536 
2537  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2538  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2539  + "os_account_obj_id " + bigIntDataType + ", "
2540  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2541 
2542  // add owner_uid & os_account_obj_id columns to tsk_files
2543  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2544  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2545 
2546  // create host address tables
2547  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2548  + "address_type INTEGER NOT NULL, "
2549  + "address TEXT NOT NULL, "
2550  + "UNIQUE(address_type, address)) ");
2551 
2552  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2553  + "host_id " + bigIntDataType + " NOT NULL, "
2554  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2555  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2556  + "time " + bigIntDataType + ", " // time at which the mapping existed
2557  + "UNIQUE(host_id, addr_obj_id, time), "
2558  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2559  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2560  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2561 
2562  // stores associations between DNS name and IP address
2563  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2564  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2565  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2566  + "source_obj_id " + bigIntDataType + ", "
2567  + "time " + bigIntDataType + ", " // time at which the mapping existed
2568  + "UNIQUE(dns_address_id, ip_address_id, time), "
2569  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2570  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2571  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2572 
2573  // maps an address to an artifact using it
2574  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2575  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2576  + "obj_id " + bigIntDataType + " NOT NULL, "
2577  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2578  + "UNIQUE(addr_obj_id, obj_id), "
2579  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2580  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2581 
2582  return new CaseDbSchemaVersionNumber(9, 0);
2583 
2584  } finally {
2585  closeStatement(statement);
2587  }
2588  }
2589 
2590  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2591  if (schemaVersion.getMajor() != 9) {
2592  return schemaVersion;
2593  }
2594 
2595  if (schemaVersion.getMinor() != 0) {
2596  return schemaVersion;
2597  }
2598 
2599  Statement statement = connection.createStatement();
2601  try {
2602 
2603  // add an index on tsk_file_attributes table.
2604  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2605 
2606  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2607  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2608 
2609  return new CaseDbSchemaVersionNumber(9, 1);
2610  } finally {
2611  closeStatement(statement);
2613  }
2614  }
2615 
2627  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2628 
2629  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2630  switch (getDatabaseType()) {
2631  case POSTGRESQL:
2632  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2633  break;
2634  case SQLITE:
2635  insertSQL = "INSERT OR IGNORE " + insertSQL;
2636  break;
2637  default:
2638  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2639  }
2640  statement.execute(insertSQL); //NON-NLS
2641  }
2642 
2650  static String extractExtension(final String fileName) {
2651  String ext;
2652  int i = fileName.lastIndexOf(".");
2653  // > 0 because we assume it's not an extension if period is the first character
2654  if ((i > 0) && ((i + 1) < fileName.length())) {
2655  ext = fileName.substring(i + 1);
2656  } else {
2657  return "";
2658  }
2659  // we added this at one point to deal with files that had crazy names based on URLs
2660  // it's too hard though to clean those up and not mess up basic extensions though.
2661  // We need to add '-' to the below if we use it again
2662  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2663  // if (findNonAlphanumeric.length > 1) {
2664  // ext = findNonAlphanumeric[0];
2665  // }
2666  return ext.toLowerCase();
2667  }
2668 
2679  @Deprecated
2680  public int getSchemaVersion() {
2681  return getDBSchemaVersion().getMajor();
2682  }
2683 
2690  return CURRENT_DB_SCHEMA_VERSION;
2691  }
2692 
2700  return caseDBSchemaCreationVersion;
2701  }
2702 
2709  return this.dbType;
2710  }
2711 
2718  public String getBackupDatabasePath() {
2719  return dbBackupPath;
2720  }
2721 
2736  public CaseDbTransaction beginTransaction() throws TskCoreException {
2737  return new CaseDbTransaction(this);
2738  }
2739 
2745  public String getDatabaseName() {
2746  return databaseName;
2747  }
2748 
2755  public String getDbDirPath() {
2756  return caseDirPath;
2757  }
2758 
2765  if (dbType == DbType.SQLITE) {
2766  rwLock.writeLock().lock();
2767  }
2768  }
2769 
2776  if (dbType == DbType.SQLITE) {
2777  rwLock.writeLock().unlock();
2778  }
2779  }
2780 
2787  if (dbType == DbType.SQLITE) {
2788  rwLock.readLock().lock();
2789  }
2790  }
2791 
2798  if (dbType == DbType.SQLITE) {
2799  rwLock.readLock().unlock();
2800  }
2801  }
2802 
2812  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2813  try {
2814  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2815  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2817  //don't wrap in new TskCoreException
2818  throw ex;
2819  } catch (Exception ex) {
2820  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
2821  }
2822  }
2823 
2835  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
2836  try {
2837  /*
2838  * The flow of this method involves trying to open case and if
2839  * successful, return that case. If unsuccessful, an exception is
2840  * thrown. We catch any exceptions, and use tryConnect() to attempt
2841  * to obtain further information about the error. If tryConnect() is
2842  * unable to successfully connect, tryConnect() will throw a
2843  * TskCoreException with a message containing user-level error
2844  * reporting. If tryConnect() is able to connect, flow continues and
2845  * we rethrow the original exception obtained from trying to create
2846  * the case. In this way, we obtain more detailed information if we
2847  * are able, but do not lose any information if unable.
2848  */
2849  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2850  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
2851  } catch (PropertyVetoException exp) {
2852  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2853  throw new TskCoreException(exp.getMessage(), exp);
2855  //don't wrap in new TskCoreException
2856  throw ex;
2857  } catch (Exception exp) {
2858  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2859  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2860  }
2861  }
2862 
2872  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
2873  try {
2874  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
2875  factory.createCaseDatabase();
2876 
2877  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2878  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2879  } catch (Exception ex) {
2880  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
2881  }
2882  }
2883 
2899  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
2900  String databaseName = createCaseDataBaseName(caseName);
2901  try {
2914  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
2915  factory.createCaseDatabase();
2916 
2917  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2918  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
2919  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
2920  } catch (PropertyVetoException exp) {
2921  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2922  throw new TskCoreException(exp.getMessage(), exp);
2923  } catch (Exception exp) {
2924  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2925  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2926  }
2927  }
2928 
2938  private static String createCaseDataBaseName(String candidateDbName) {
2939  String dbName;
2940  if (!candidateDbName.isEmpty()) {
2941  /*
2942  * Replace all non-ASCII characters.
2943  */
2944  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
2945 
2946  /*
2947  * Replace all control characters.
2948  */
2949  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
2950 
2951  /*
2952  * Replace /, \, :, ?, space, ' ".
2953  */
2954  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
2955 
2956  /*
2957  * Make it all lowercase.
2958  */
2959  dbName = dbName.toLowerCase();
2960 
2961  /*
2962  * Must start with letter or underscore. If not, prepend an
2963  * underscore.
2964  */
2965  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
2966  dbName = "_" + dbName;
2967  }
2968 
2969  /*
2970  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
2971  * uniqueness.
2972  */
2973  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
2974  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
2975  }
2976 
2977  } else {
2978  /*
2979  * Must start with letter or underscore.
2980  */
2981  dbName = "_";
2982  }
2983  /*
2984  * Add the time stmap.
2985  */
2986  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
2987  Date date = new Date();
2988  dbName = dbName + "_" + dateFormat.format(date);
2989 
2990  return dbName;
2991  }
2992 
3000  public Examiner getCurrentExaminer() throws TskCoreException {
3001 
3002  // return cached value if there's one
3003  if (cachedCurrentExaminer != null) {
3004  return cachedCurrentExaminer;
3005  }
3006  String loginName = System.getProperty("user.name");
3007  if (loginName == null || loginName.isEmpty()) {
3008  throw new TskCoreException("Failed to determine logged in user name.");
3009  }
3010 
3011  ResultSet resultSet = null;
3012  CaseDbConnection connection = null;
3014  try {
3015  connection = connections.getConnection();
3016  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3017  statement.clearParameters();
3018  statement.setString(1, loginName);
3019  resultSet = connection.executeQuery(statement);
3020  if (resultSet.next()) {
3021  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3022  return cachedCurrentExaminer;
3023  } else {
3024  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3025  }
3026 
3027  } catch (SQLException ex) {
3028  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3029  } finally {
3030  closeResultSet(resultSet);
3031  closeConnection(connection);
3033  }
3034 
3035  }
3036 
3046  Examiner getExaminerById(long id) throws TskCoreException {
3047 
3048  CaseDbConnection connection = null;
3049  ResultSet resultSet = null;
3051  try {
3052  connection = connections.getConnection();
3053  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3054  statement.clearParameters();
3055  statement.setLong(1, id);
3056  resultSet = connection.executeQuery(statement);
3057  if (resultSet.next()) {
3058  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3059  } else {
3060  throw new TskCoreException("Error getting examaminer for id = " + id);
3061  }
3062  } catch (SQLException ex) {
3063  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3064  } finally {
3065  closeResultSet(resultSet);
3066  closeConnection(connection);
3068  }
3069  }
3070 
3088  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3089  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
3090  }
3091 
3100  public List<Content> getRootObjects() throws TskCoreException {
3101  CaseDbConnection connection = null;
3102  Statement s = null;
3103  ResultSet rs = null;
3105  try {
3106  connection = connections.getConnection();
3107  s = connection.createStatement();
3108  rs = connection.executeQuery(s, "SELECT obj_id, type FROM tsk_objects " //NON-NLS
3109  + "WHERE par_obj_id IS NULL"); //NON-NLS
3110  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3111  while (rs.next()) {
3112  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3113  }
3114 
3115  List<Content> rootObjs = new ArrayList<Content>();
3116  for (ObjectInfo i : infos) {
3117  if (null != i.type) {
3118  switch (i.type) {
3119  case IMG:
3120  rootObjs.add(getImageById(i.id));
3121  break;
3122  case ABSTRACTFILE:
3123  // Check if virtual dir for local files.
3124  AbstractFile af = getAbstractFileById(i.id);
3125  if (af instanceof VirtualDirectory) {
3126  rootObjs.add(af);
3127  } else {
3128  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3129  }
3130  break;
3131  case REPORT:
3132  break;
3133  case OS_ACCOUNT:
3134  break;
3135  case HOST_ADDRESS:
3136  break;
3137  case UNSUPPORTED:
3138  break;
3139  default:
3140  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3141  }
3142  }
3143  }
3144  return rootObjs;
3145  } catch (SQLException ex) {
3146  throw new TskCoreException("Error getting root objects", ex);
3147  } finally {
3148  closeResultSet(rs);
3149  closeStatement(s);
3150  closeConnection(connection);
3152  }
3153  }
3154 
3166  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3167 
3168  // check cached map first
3169  synchronized (deviceIdToDatasourceObjIdMap) {
3170  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3171  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3172  }
3173 
3174  CaseDbConnection connection = null;
3175  Statement s = null;
3176  ResultSet rs = null;
3178  try {
3179  connection = connections.getConnection();
3180  s = connection.createStatement();
3181  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3182  List<Long> dataSourceObjIds = new ArrayList<Long>();
3183  while (rs.next()) {
3184  dataSourceObjIds.add(rs.getLong("obj_id"));
3185 
3186  // Add to map of deviceID to data_source_obj_id.
3187  long ds_obj_id = rs.getLong("obj_id");
3188  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3189  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3190  } else {
3191  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3192  }
3193  }
3194  return dataSourceObjIds;
3195  } catch (SQLException ex) {
3196  throw new TskCoreException("Error getting data sources", ex);
3197  } finally {
3198  closeResultSet(rs);
3199  closeStatement(s);
3200  closeConnection(connection);
3202  }
3203  }
3204  }
3205 
3222  public List<DataSource> getDataSources() throws TskCoreException {
3223  CaseDbConnection connection = null;
3224  Statement statement = null;
3225  ResultSet resultSet = null;
3226  Statement statement2 = null;
3227  ResultSet resultSet2 = null;
3229  try {
3230  connection = connections.getConnection();
3231  statement = connection.createStatement();
3232  statement2 = connection.createStatement();
3233  resultSet = connection.executeQuery(statement,
3234  "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 "
3235  + "FROM data_source_info AS ds "
3236  + "LEFT JOIN tsk_image_info AS img "
3237  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3238 
3239  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3240  Map<Long, List<String>> imagePathsMap = getImagePaths();
3241 
3242  while (resultSet.next()) {
3243  DataSource dataSource;
3244  Long objectId = resultSet.getLong("obj_id");
3245  String deviceId = resultSet.getString("device_id");
3246  String timezone = resultSet.getString("time_zone");
3247  String type = resultSet.getString("type");
3248 
3249  if (type == null) {
3250  /*
3251  * No data found in 'tsk_image_info', so we build a
3252  * LocalFilesDataSource.
3253  */
3254 
3255  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3256  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3257  resultSet2.close();
3258 
3262  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3263  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3264  String parentPath = "/"; //NON-NLS
3265  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath);
3266  } else {
3267  /*
3268  * Data found in 'tsk_image_info', so we build an Image.
3269  */
3270  Long ssize = resultSet.getLong("ssize");
3271  Long size = resultSet.getLong("size");
3272  String md5 = resultSet.getString("md5");
3273  String sha1 = resultSet.getString("sha1");
3274  String sha256 = resultSet.getString("sha256");
3275  String name = resultSet.getString("display_name");
3276 
3277  List<String> imagePaths = imagePathsMap.get(objectId);
3278  if (name == null) {
3279  if (imagePaths.size() > 0) {
3280  String path = imagePaths.get(0);
3281  name = (new java.io.File(path)).getName();
3282  } else {
3283  name = "";
3284  }
3285  }
3286 
3287  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3288  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3289  }
3290 
3291  dataSourceList.add(dataSource);
3292  }
3293 
3294  return dataSourceList;
3295 
3296  } catch (SQLException ex) {
3297  throw new TskCoreException("Error getting data sources", ex);
3298  } finally {
3299  closeResultSet(resultSet);
3300  closeStatement(statement);
3301  closeResultSet(resultSet2);
3302  closeStatement(statement2);
3303  closeConnection(connection);
3305  }
3306  }
3307 
3327  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3328  DataSource dataSource = null;
3329  CaseDbConnection connection = null;
3330  Statement statement = null;
3331  ResultSet resultSet = null;
3332  Statement statement2 = null;
3333  ResultSet resultSet2 = null;
3335  try {
3336  connection = connections.getConnection();
3337  statement = connection.createStatement();
3338  statement2 = connection.createStatement();
3339  resultSet = connection.executeQuery(statement,
3340  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3341  + "FROM data_source_info AS ds "
3342  + "LEFT JOIN tsk_image_info AS img "
3343  + "ON ds.obj_id = img.obj_id "
3344  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3345  if (resultSet.next()) {
3346  String deviceId = resultSet.getString("device_id");
3347  String timezone = resultSet.getString("time_zone");
3348  String type = resultSet.getString("type");
3349 
3350  if (type == null) {
3351  /*
3352  * No data found in 'tsk_image_info', so we build an
3353  * LocalFilesDataSource.
3354  */
3355 
3356  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3357  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3358 
3362  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3363  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3364  String parentPath = "/"; //NON-NLS
3365  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath);
3366  } else {
3367  /*
3368  * Data found in 'tsk_image_info', so we build an Image.
3369  */
3370  Long ssize = resultSet.getLong("ssize");
3371  Long size = resultSet.getLong("size");
3372  String md5 = resultSet.getString("md5");
3373  String sha1 = resultSet.getString("sha1");
3374  String sha256 = resultSet.getString("sha256");
3375  String name = resultSet.getString("display_name");
3376 
3377  List<String> imagePaths = getImagePathsById(objectId, connection);
3378  if (name == null) {
3379  if (imagePaths.size() > 0) {
3380  String path = imagePaths.get(0);
3381  name = (new java.io.File(path)).getName();
3382  } else {
3383  name = "";
3384  }
3385  }
3386 
3387  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3388  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3389  }
3390  } else {
3391  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3392  }
3393  } catch (SQLException ex) {
3394  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3395  } finally {
3396  closeResultSet(resultSet);
3397  closeStatement(statement);
3398  closeResultSet(resultSet2);
3399  closeStatement(statement2);
3400  closeConnection(connection);
3402  }
3403 
3404  return dataSource;
3405  }
3406 
3417  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3418  return getArtifactsHelper("blackboard_artifacts.artifact_type_id = " + artifactTypeID);
3419  }
3420 
3431  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3432  CaseDbConnection connection = null;
3433  ResultSet rs = null;
3435  try {
3436  connection = connections.getConnection();
3437 
3438  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3439  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3440  statement.clearParameters();
3441  statement.setLong(1, objId);
3442  rs = connection.executeQuery(statement);
3443  long count = 0;
3444  if (rs.next()) {
3445  count = rs.getLong("count");
3446  }
3447  return count;
3448  } catch (SQLException ex) {
3449  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3450  } finally {
3451  closeResultSet(rs);
3452  closeConnection(connection);
3454  }
3455  }
3456 
3467  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3468  CaseDbConnection connection = null;
3469  ResultSet rs = null;
3471  try {
3472  connection = connections.getConnection();
3473 
3474  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3475  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3476  statement.clearParameters();
3477  statement.setInt(1, artifactTypeID);
3478  rs = connection.executeQuery(statement);
3479  long count = 0;
3480  if (rs.next()) {
3481  count = rs.getLong("count");
3482  }
3483  return count;
3484  } catch (SQLException ex) {
3485  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3486  } finally {
3487  closeResultSet(rs);
3488  closeConnection(connection);
3490  }
3491  }
3492 
3504  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3505  CaseDbConnection connection = null;
3506  ResultSet rs = null;
3508  try {
3509  connection = connections.getConnection();
3510 
3511  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3512  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3513  statement.clearParameters();
3514  statement.setInt(2, artifactTypeID);
3515  statement.setLong(1, dataSourceID);
3516  rs = connection.executeQuery(statement);
3517  long count = 0;
3518  if (rs.next()) {
3519  count = rs.getLong("count");
3520  }
3521  return count;
3522  } catch (SQLException ex) {
3523  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3524  } finally {
3525  closeResultSet(rs);
3526  closeConnection(connection);
3528  }
3529  }
3530 
3545  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3546  CaseDbConnection connection = null;
3547  Statement s = null;
3548  ResultSet rs = null;
3550  try {
3551  connection = connections.getConnection();
3552  s = connection.createStatement();
3553  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3554  + "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, "
3555  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3556  + " arts.review_status_id AS review_status_id " //NON-NLS
3557  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3558  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3559  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3560  + " AND attrs.value_text = '" + value + "'"
3561  + " AND types.artifact_type_id=arts.artifact_type_id"
3562  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()); //NON-NLS
3563  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3564  while (rs.next()) {
3565  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3566  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3567  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3568  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3569  }
3570  return artifacts;
3571  } catch (SQLException ex) {
3572  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3573  } finally {
3574  closeResultSet(rs);
3575  closeStatement(s);
3576  closeConnection(connection);
3578  }
3579  }
3580 
3598  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3599  String valSubStr = "%" + subString; //NON-NLS
3600  if (startsWith == false) {
3601  valSubStr += "%"; //NON-NLS
3602  }
3603  CaseDbConnection connection = null;
3604  Statement s = null;
3605  ResultSet rs = null;
3607  try {
3608  connection = connections.getConnection();
3609  s = connection.createStatement();
3610  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3611  + " 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
3612  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3613  + " arts.review_status_id AS review_status_id " //NON-NLS
3614  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3615  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3616  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3617  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3618  + " AND types.artifact_type_id=arts.artifact_type_id "
3619  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3620  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3621  while (rs.next()) {
3622  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3623  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3624  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3625  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3626  }
3627  return artifacts;
3628  } catch (SQLException ex) {
3629  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3630  } finally {
3631  closeResultSet(rs);
3632  closeStatement(s);
3633  closeConnection(connection);
3635  }
3636  }
3637 
3652  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3653  CaseDbConnection connection = null;
3654  Statement s = null;
3655  ResultSet rs = null;
3657  try {
3658  connection = connections.getConnection();
3659  s = connection.createStatement();
3660  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3661  + " 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, "
3662  + " types.type_name AS type_name, types.display_name AS display_name, "
3663  + " arts.review_status_id AS review_status_id "//NON-NLS
3664  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3665  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3666  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3667  + " AND attrs.value_int32 = " + value //NON-NLS
3668  + " AND types.artifact_type_id=arts.artifact_type_id "
3669  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3670  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3671  while (rs.next()) {
3672  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3673  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3674  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3675  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3676  }
3677  return artifacts;
3678  } catch (SQLException ex) {
3679  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3680  } finally {
3681  closeResultSet(rs);
3682  closeStatement(s);
3683  closeConnection(connection);
3685  }
3686  }
3687 
3702  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3703  CaseDbConnection connection = null;
3704  Statement s = null;
3705  ResultSet rs = null;
3707  try {
3708  connection = connections.getConnection();
3709  s = connection.createStatement();
3710  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3711  + " 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, "
3712  + " types.type_name AS type_name, types.display_name AS display_name, "
3713  + " arts.review_status_id AS review_status_id "//NON-NLS
3714  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3715  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3716  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3717  + " AND attrs.value_int64 = " + value //NON-NLS
3718  + " AND types.artifact_type_id=arts.artifact_type_id "
3719  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3720  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3721  while (rs.next()) {
3722  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3723  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3724  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3725  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3726  }
3727  return artifacts;
3728  } catch (SQLException ex) {
3729  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3730  } finally {
3731  closeResultSet(rs);
3732  closeStatement(s);
3733  closeConnection(connection);
3735  }
3736  }
3737 
3752  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3753  CaseDbConnection connection = null;
3754  Statement s = null;
3755  ResultSet rs = null;
3757  try {
3758  connection = connections.getConnection();
3759  s = connection.createStatement();
3760  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3761  + " 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, "
3762  + " types.type_name AS type_name, types.display_name AS display_name, "
3763  + " arts.review_status_id AS review_status_id "//NON-NLS
3764  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3765  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3766  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3767  + " AND attrs.value_double = " + value //NON-NLS
3768  + " AND types.artifact_type_id=arts.artifact_type_id "
3769  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3770  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3771  while (rs.next()) {
3772  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3773  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3774  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3775  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3776  }
3777  return artifacts;
3778  } catch (SQLException ex) {
3779  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3780  } finally {
3781  closeResultSet(rs);
3782  closeStatement(s);
3783  closeConnection(connection);
3785  }
3786  }
3787 
3802  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3803  CaseDbConnection connection = null;
3804  Statement s = null;
3805  ResultSet rs = null;
3807  try {
3808  connection = connections.getConnection();
3809  s = connection.createStatement();
3810  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3811  + " 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, "
3812  + " types.type_name AS type_name, types.display_name AS display_name, "
3813  + " arts.review_status_id AS review_status_id "//NON-NLS
3814  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3815  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3816  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3817  + " AND attrs.value_byte = " + value //NON-NLS
3818  + " AND types.artifact_type_id=arts.artifact_type_id "
3819  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
3820  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
3821  while (rs.next()) {
3822  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
3823  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
3824  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
3825  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
3826  }
3827  return artifacts;
3828  } catch (SQLException ex) {
3829  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3830  } finally {
3831  closeResultSet(rs);
3832  closeStatement(s);
3833  closeConnection(connection);
3835  }
3836  }
3837 
3845  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3846  CaseDbConnection connection = null;
3847  Statement s = null;
3848  ResultSet rs = null;
3850  try {
3851  connection = connections.getConnection();
3852  s = connection.createStatement();
3853  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
3854  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
3855  while (rs.next()) {
3856  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3857  rs.getString("type_name"), rs.getString("display_name"),
3858  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
3859  }
3860  return artifactTypes;
3861  } catch (SQLException ex) {
3862  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
3863  } finally {
3864  closeResultSet(rs);
3865  closeStatement(s);
3866  closeConnection(connection);
3868  }
3869  }
3870 
3879  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
3880  String typeIdList = "";
3881  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
3882  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
3883  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
3884  typeIdList += ", ";
3885  }
3886  }
3887  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
3888  + "WHERE artifact_type_id IN (" + typeIdList + ")";
3889  CaseDbConnection connection = null;
3890  Statement s = null;
3891  ResultSet rs = null;
3893  try {
3894  connection = connections.getConnection();
3895  s = connection.createStatement();
3896  rs = connection.executeQuery(s, query);
3897  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
3898  while (rs.next()) {
3899  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
3900  }
3901  return usedArts;
3902  } catch (SQLException ex) {
3903  throw new TskCoreException("Error getting artifact types in use", ex);
3904  } finally {
3905  closeResultSet(rs);
3906  closeStatement(s);
3907  closeConnection(connection);
3909  }
3910  }
3911 
3922  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
3923  CaseDbConnection connection = null;
3924  Statement s = null;
3925  ResultSet rs = null;
3927  try {
3928  connection = connections.getConnection();
3929  s = connection.createStatement();
3930  rs = connection.executeQuery(s,
3931  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
3932  + "types.type_name AS type_name, "
3933  + "types.display_name AS display_name, "
3934  + "types.category_type AS category_type "
3935  + "FROM blackboard_artifact_types AS types "
3936  + "INNER JOIN blackboard_artifacts AS arts "
3937  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
3938  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
3939  while (rs.next()) {
3940  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3941  rs.getString("type_name"), rs.getString("display_name"),
3942  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
3943  }
3944  return uniqueArtifactTypes;
3945  } catch (SQLException ex) {
3946  throw new TskCoreException("Error getting attribute types", ex);
3947  } finally {
3948  closeResultSet(rs);
3949  closeStatement(s);
3950  closeConnection(connection);
3952  }
3953  }
3954 
3962  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
3963  CaseDbConnection connection = null;
3964  Statement s = null;
3965  ResultSet rs = null;
3967  try {
3968  connection = connections.getConnection();
3969  s = connection.createStatement();
3970  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
3971  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
3972  while (rs.next()) {
3973  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
3974  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
3975  }
3976  return attribute_types;
3977  } catch (SQLException ex) {
3978  throw new TskCoreException("Error getting attribute types", ex);
3979  } finally {
3980  closeResultSet(rs);
3981  closeStatement(s);
3982  closeConnection(connection);
3984  }
3985  }
3986 
3998  public int getBlackboardAttributeTypesCount() throws TskCoreException {
3999  CaseDbConnection connection = null;
4000  Statement s = null;
4001  ResultSet rs = null;
4003  try {
4004  connection = connections.getConnection();
4005  s = connection.createStatement();
4006  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4007  int count = 0;
4008  if (rs.next()) {
4009  count = rs.getInt("count");
4010  }
4011  return count;
4012  } catch (SQLException ex) {
4013  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4014  } finally {
4015  closeResultSet(rs);
4016  closeStatement(s);
4017  closeConnection(connection);
4019  }
4020  }
4021 
4034  ArrayList<BlackboardArtifact> getArtifactsHelper(String whereClause) throws TskCoreException {
4035  CaseDbConnection connection = null;
4036  Statement statement = null;
4037  ResultSet rs = null;
4039  try {
4040  connection = connections.getConnection();
4041  statement = connection.createStatement();
4042  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
4043  + "blackboard_artifacts.obj_id AS obj_id, "
4044  + "blackboard_artifacts.artifact_obj_id AS artifact_obj_id, "
4045  + "blackboard_artifacts.data_source_obj_id AS data_source_obj_id, "
4046  + "blackboard_artifact_types.artifact_type_id AS artifact_type_id, "
4047  + "blackboard_artifact_types.type_name AS type_name, "
4048  + "blackboard_artifact_types.display_name AS display_name, "
4049  + "blackboard_artifacts.review_status_id AS review_status_id "
4050  + "FROM blackboard_artifacts, blackboard_artifact_types "
4051  + "WHERE blackboard_artifacts.artifact_type_id = blackboard_artifact_types.artifact_type_id "
4052  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
4053  + " AND " + whereClause;
4054  rs = connection.executeQuery(statement, query);
4055  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
4056  while (rs.next()) {
4057  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
4058  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4059  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4060  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
4061  }
4062  return artifacts;
4063  } catch (SQLException ex) {
4064  throw new TskCoreException("Error getting or creating a blackboard artifact", ex);
4065  } finally {
4066  closeResultSet(rs);
4067  closeStatement(statement);
4068  closeConnection(connection);
4070  }
4071  }
4072 
4085  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4086  CaseDbConnection connection = null;
4087  ResultSet rs = null;
4089  try {
4090  connection = connections.getConnection();
4091 
4092  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4093  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4094  statement.clearParameters();
4095  statement.setLong(1, obj_id);
4096  statement.setInt(2, artifactTypeID);
4097  rs = connection.executeQuery(statement);
4098  long count = 0;
4099  if (rs.next()) {
4100  count = rs.getLong("count");
4101  }
4102  return count;
4103  } catch (SQLException ex) {
4104  throw new TskCoreException("Error getting blackboard artifact count", ex);
4105  } finally {
4106  closeResultSet(rs);
4107  closeConnection(connection);
4109  }
4110  }
4111 
4124  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4125  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
4126  }
4127 
4140  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4141  return getArtifactsHelper("blackboard_artifacts.obj_id = " + obj_id + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
4142  }
4143 
4156  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4157  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4158  }
4159 
4172  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4173  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4174  if (artifactTypeID == -1) {
4175  return 0;
4176  }
4177  return getArtifactsCountHelper(artifactTypeID, obj_id);
4178  }
4179 
4192  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4193  return getArtifactsCountHelper(artifactTypeID, obj_id);
4194  }
4195 
4208  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4209  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4210  }
4211 
4223  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4224  return getArtifactsHelper("blackboard_artifact_types.type_name = '" + artifactTypeName + "';");
4225  }
4226 
4238  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4239  return getArtifactsHelper("blackboard_artifact_types.artifact_type_id = " + artifactType.getTypeID() + ";");
4240  }
4241 
4255  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4256  CaseDbConnection connection = null;
4257  Statement s = null;
4258  ResultSet rs = null;
4260  try {
4261  connection = connections.getConnection();
4262  s = connection.createStatement();
4263  rs = connection.executeQuery(s, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4264  + "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, "
4265  + "types.type_name AS type_name, types.display_name AS display_name,"
4266  + "arts.review_status_id AS review_status_id "//NON-NLS
4267  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
4268  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4269  + "AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
4270  + " AND arts.artifact_type_id = " + artifactType.getTypeID() //NON-NLS
4271  + " AND attrs.value_text = '" + value + "'" //NON-NLS
4272  + " AND types.artifact_type_id=arts.artifact_type_id"
4273  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());
4274  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
4275  while (rs.next()) {
4276  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
4277  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4278  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4279  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
4280  }
4281  return artifacts;
4282  } catch (SQLException ex) {
4283  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4284  } finally {
4285  closeResultSet(rs);
4286  closeStatement(s);
4287  closeConnection(connection);
4289  }
4290  }
4291 
4303  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4304  CaseDbConnection connection = null;
4305  Statement s = null;
4306  ResultSet rs = null;
4308  try {
4309  connection = connections.getConnection();
4310  s = connection.createStatement();
4311  rs = connection.executeQuery(s, "SELECT arts.artifact_id AS artifact_id, "
4312  + "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, "
4313  + "types.type_name AS type_name, types.display_name AS display_name,"
4314  + "arts.review_status_id AS review_status_id "//NON-NLS
4315  + "FROM blackboard_artifacts AS arts, blackboard_artifact_types AS types "
4316  + "WHERE arts.artifact_id = " + artifactID
4317  + " AND arts.artifact_type_id = types.artifact_type_id");
4318  if (rs.next()) {
4319  return new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
4320  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4321  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4322  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
4323  } else {
4324  /*
4325  * I think this should actually return null (or Optional) when
4326  * there is no artifact with the given id, but it looks like
4327  * existing code is not expecting that. -jm
4328  */
4329  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4330  }
4331  } catch (SQLException ex) {
4332  throw new TskCoreException("Error getting a blackboard artifact. " + ex.getMessage(), ex);
4333  } finally {
4334  closeResultSet(rs);
4335  closeConnection(connection);
4337  }
4338  }
4339 
4348  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4350  try (CaseDbConnection connection = connections.getConnection();) {
4351  addBlackBoardAttribute(attr, artifactTypeId, connection);
4352  } catch (SQLException ex) {
4353  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4354  } finally {
4356  }
4357  }
4358 
4368  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4369  CaseDbConnection connection = null;
4371  try {
4372  connection = connections.getConnection();
4373  connection.beginTransaction();
4374  for (final BlackboardAttribute attr : attributes) {
4375  addBlackBoardAttribute(attr, artifactTypeId, connection);
4376  }
4377  connection.commitTransaction();
4378  } catch (SQLException ex) {
4379  rollbackTransaction(connection);
4380  throw new TskCoreException("Error adding blackboard attributes", ex);
4381  } finally {
4382  closeConnection(connection);
4384  }
4385  }
4386 
4387  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4388  PreparedStatement statement;
4389  switch (attr.getAttributeType().getValueType()) {
4390  case STRING:
4391  case JSON:
4392  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4393  statement.clearParameters();
4394  statement.setString(7, attr.getValueString());
4395  break;
4396  case BYTE:
4397  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4398  statement.clearParameters();
4399  statement.setBytes(7, attr.getValueBytes());
4400  break;
4401  case INTEGER:
4402  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4403  statement.clearParameters();
4404  statement.setInt(7, attr.getValueInt());
4405  break;
4406  case LONG:
4407  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4408  statement.clearParameters();
4409  statement.setLong(7, attr.getValueLong());
4410  break;
4411  case DOUBLE:
4412  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4413  statement.clearParameters();
4414  statement.setDouble(7, attr.getValueDouble());
4415  break;
4416  case DATETIME:
4417  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4418  statement.clearParameters();
4419  statement.setLong(7, attr.getValueLong());
4420  break;
4421  default:
4422  throw new TskCoreException("Unrecognized artifact attribute value type");
4423  }
4424  statement.setLong(1, attr.getArtifactID());
4425  statement.setInt(2, artifactTypeId);
4426  statement.setString(3, attr.getSourcesCSV());
4427  statement.setString(4, "");
4428  statement.setInt(5, attr.getAttributeType().getTypeID());
4429  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4430  connection.executeUpdate(statement);
4431  }
4432 
4433  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4434  PreparedStatement statement;
4435  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4436  statement.clearParameters();
4437 
4438  statement.setLong(1, attr.getAttributeParentId());
4439  statement.setInt(2, attr.getAttributeType().getTypeID());
4440  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4441 
4442  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4443  statement.setBytes(4, attr.getValueBytes());
4444  } else {
4445  statement.setBytes(4, null);
4446  }
4447 
4448  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4449  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4450  statement.setString(5, attr.getValueString());
4451  } else {
4452  statement.setString(5, null);
4453  }
4454  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4455  statement.setInt(6, attr.getValueInt());
4456  } else {
4457  statement.setNull(6, java.sql.Types.INTEGER);
4458  }
4459 
4460  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4461  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4462  statement.setLong(7, attr.getValueLong());
4463  } else {
4464  statement.setNull(7, java.sql.Types.BIGINT);
4465  }
4466 
4467  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4468  statement.setDouble(8, attr.getValueDouble());
4469  } else {
4470  statement.setNull(8, java.sql.Types.DOUBLE);
4471  }
4472 
4473  connection.executeUpdate(statement);
4474  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4475  if (!resultSet.next()) {
4476  throw new TskCoreException(String.format("Failed to insert file attribute "
4477  + "with id=%d. The expected key was not generated", attr.getId()));
4478  }
4479 
4480  attr.setId(resultSet.getLong(1));
4481  }
4482  }
4483 
4494  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
4495  /*
4496  * WARNING: This is a temporary implementation that is not safe and
4497  * denormalizes the case datbase.
4498  *
4499  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
4500  * the sources of artifact attributes.
4501  */
4502  if (null == source || source.isEmpty()) {
4503  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
4504  }
4505  CaseDbConnection connection = null;
4507  Statement queryStmt = null;
4508  Statement updateStmt = null;
4509  ResultSet result = null;
4510  String newSources = "";
4511  try {
4512  connection = connections.getConnection();
4513  connection.beginTransaction();
4514  String valueClause = "";
4515  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
4516  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4517  switch (valueType) {
4518  case STRING:
4519  case JSON:
4520  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
4521  break;
4522  case INTEGER:
4523  valueClause = " value_int32 = " + attr.getValueInt();
4524  break;
4525  case LONG:
4526  case DATETIME:
4527  valueClause = " value_int64 = " + attr.getValueLong();
4528  break;
4529  case DOUBLE:
4530  valueClause = " value_double = " + attr.getValueDouble();
4531  break;
4532  default:
4533  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4534  }
4535  String query = "SELECT source FROM blackboard_attributes WHERE"
4536  + " artifact_id = " + attr.getArtifactID()
4537  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4538  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4539  + " AND " + valueClause + ";";
4540  queryStmt = connection.createStatement();
4541  updateStmt = connection.createStatement();
4542  result = connection.executeQuery(queryStmt, query);
4543  } else {
4544  /*
4545  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4546  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4547  * = ?
4548  */
4549  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4550  statement.clearParameters();
4551  statement.setLong(1, attr.getArtifactID());
4552  statement.setLong(2, attr.getAttributeType().getTypeID());
4553  statement.setBytes(3, attr.getValueBytes());
4554  result = connection.executeQuery(statement);
4555  }
4556  while (result.next()) {
4557  String oldSources = result.getString("source");
4558  if (null != oldSources && !oldSources.isEmpty()) {
4559  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4560  if (!uniqueSources.contains(source)) {
4561  newSources = oldSources + "," + source;
4562  } else {
4563  newSources = oldSources;
4564  }
4565  } else {
4566  newSources = source;
4567  }
4568  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4569  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4570  + " artifact_id = " + attr.getArtifactID()
4571  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4572  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4573  + " AND " + valueClause + ";";
4574  connection.executeUpdate(updateStmt, update);
4575  } else {
4576  /*
4577  * UPDATE blackboard_attributes SET source = ? WHERE
4578  * artifact_id = ? AND attribute_type_id = ? AND value_type
4579  * = 4 AND value_byte = ?
4580  */
4581  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4582  statement.clearParameters();
4583  statement.setString(1, newSources);
4584  statement.setLong(2, attr.getArtifactID());
4585  statement.setLong(3, attr.getAttributeType().getTypeID());
4586  statement.setBytes(4, attr.getValueBytes());
4587  connection.executeUpdate(statement);
4588  }
4589  }
4590  connection.commitTransaction();
4591  return newSources;
4592  } catch (SQLException ex) {
4593  rollbackTransaction(connection);
4594  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4595  } finally {
4596  closeResultSet(result);
4597  closeStatement(updateStmt);
4598  closeStatement(queryStmt);
4599  closeConnection(connection);
4601  }
4602  }
4603 
4618  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4619  CaseDbConnection connection = null;
4621  Statement s = null;
4622  ResultSet rs = null;
4623  try {
4624  connection = connections.getConnection();
4625  connection.beginTransaction();
4626  s = connection.createStatement();
4627  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
4628  if (!rs.next()) {
4629  rs.close();
4630  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
4631  int maxID = 0;
4632  if (rs.next()) {
4633  maxID = rs.getInt("highest_id");
4634  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4635  maxID = MIN_USER_DEFINED_TYPE_ID;
4636  } else {
4637  maxID++;
4638  }
4639  }
4640  connection.executeUpdate(s, "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name, value_type) VALUES ('" + maxID + "', '" + attrTypeString + "', '" + displayName + "', '" + valueType.getType() + "')"); //NON-NLS
4641  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
4642  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4643  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4644  connection.commitTransaction();
4645  return type;
4646  } else {
4647  throw new TskDataException("The attribute type that was added was already within the system.");
4648  }
4649 
4650  } catch (SQLException ex) {
4651  rollbackTransaction(connection);
4652  throw new TskCoreException("Error adding attribute type", ex);
4653  } finally {
4654  closeResultSet(rs);
4655  closeStatement(s);
4656  closeConnection(connection);
4658  }
4659  }
4660 
4671  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4672  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
4673  return this.typeNameToAttributeTypeMap.get(attrTypeName);
4674  }
4675  CaseDbConnection connection = null;
4676  Statement s = null;
4677  ResultSet rs = null;
4679  try {
4680  connection = connections.getConnection();
4681  s = connection.createStatement();
4682  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
4683  BlackboardAttribute.Type type = null;
4684  if (rs.next()) {
4685  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4686  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4687  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4688  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
4689  }
4690  return type;
4691  } catch (SQLException ex) {
4692  throw new TskCoreException("Error getting attribute type id", ex);
4693  } finally {
4694  closeResultSet(rs);
4695  closeStatement(s);
4696  closeConnection(connection);
4698  }
4699  }
4700 
4711  BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
4712  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
4713  return this.typeIdToAttributeTypeMap.get(typeID);
4714  }
4715  CaseDbConnection connection = null;
4716  Statement s = null;
4717  ResultSet rs = null;
4719  try {
4720  connection = connections.getConnection();
4721  s = connection.createStatement();
4722  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE attribute_type_id = " + typeID + ""); //NON-NLS
4723  BlackboardAttribute.Type type = null;
4724  if (rs.next()) {
4725  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4726  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4727  this.typeIdToAttributeTypeMap.put(typeID, type);
4728  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4729  }
4730  return type;
4731  } catch (SQLException ex) {
4732  throw new TskCoreException("Error getting attribute type id", ex);
4733  } finally {
4734  closeResultSet(rs);
4735  closeStatement(s);
4736  closeConnection(connection);
4738  }
4739  }
4740 
4751  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4752  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
4753  return this.typeNameToArtifactTypeMap.get(artTypeName);
4754  }
4755  CaseDbConnection connection = null;
4756  Statement s = null;
4757  ResultSet rs = null;
4759  try {
4760  connection = connections.getConnection();
4761  s = connection.createStatement();
4762  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
4763  BlackboardArtifact.Type type = null;
4764  if (rs.next()) {
4765  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4766  rs.getString("type_name"), rs.getString("display_name"),
4767  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
4768  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4769  this.typeNameToArtifactTypeMap.put(artTypeName, type);
4770  }
4771  return type;
4772  } catch (SQLException ex) {
4773  throw new TskCoreException("Error getting artifact type from the database", ex);
4774  } finally {
4775  closeResultSet(rs);
4776  closeStatement(s);
4777  closeConnection(connection);
4779  }
4780  }
4781 
4793  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
4794  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
4795  return typeIdToArtifactTypeMap.get(artTypeId);
4796  }
4797  CaseDbConnection connection = null;
4798  Statement s = null;
4799  ResultSet rs = null;
4801  try {
4802  connection = connections.getConnection();
4803  s = connection.createStatement();
4804  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types WHERE artifact_type_id = " + artTypeId + ""); //NON-NLS
4805  BlackboardArtifact.Type type = null;
4806  if (rs.next()) {
4807  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4808  rs.getString("type_name"), rs.getString("display_name"),
4809  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
4810  this.typeIdToArtifactTypeMap.put(artTypeId, type);
4811  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4812  return type;
4813  } else {
4814  throw new TskCoreException("No artifact type found matching id: " + artTypeId);
4815  }
4816  } catch (SQLException ex) {
4817  throw new TskCoreException("Error getting artifact type from the database", ex);
4818  } finally {
4819  closeResultSet(rs);
4820  closeStatement(s);
4821  closeConnection(connection);
4823  }
4824  }
4825 
4841  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4842 
4843  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
4844  }
4845 
4861  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
4862  CaseDbConnection connection = null;
4864  Statement s = null;
4865  ResultSet rs = null;
4866  try {
4867  connection = connections.getConnection();
4868  connection.beginTransaction();
4869  s = connection.createStatement();
4870  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
4871  if (!rs.next()) {
4872  rs.close();
4873  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
4874  int maxID = 0;
4875  if (rs.next()) {
4876  maxID = rs.getInt("highest_id");
4877  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4878  maxID = MIN_USER_DEFINED_TYPE_ID;
4879  } else {
4880  maxID++;
4881  }
4882  }
4883  connection.executeUpdate(s, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name, category_type) VALUES ('" + maxID + "', '" + artifactTypeName + "', '" + displayName + "', " + category.getID() + " )"); //NON-NLS
4884  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName, category);
4885  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4886  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4887  connection.commitTransaction();
4888  return type;
4889  } else {
4890  throw new TskDataException("The attribute type that was added was already within the system.");
4891  }
4892  } catch (SQLException ex) {
4893  rollbackTransaction(connection);
4894  throw new TskCoreException("Error adding artifact type", ex);
4895  } finally {
4896  closeResultSet(rs);
4897  closeStatement(s);
4898  closeConnection(connection);
4900  }
4901  }
4902 
4903  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4904  CaseDbConnection connection = null;
4905  Statement statement = null;
4906  ResultSet rs = null;
4908  try {
4909  connection = connections.getConnection();
4910  statement = connection.createStatement();
4911  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
4912  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
4913  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4914  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4915  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
4916  + "types.type_name AS type_name, types.display_name AS display_name "
4917  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
4918  + " AND attrs.attribute_type_id = types.attribute_type_id");
4919  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
4920  while (rs.next()) {
4921  int attributeTypeId = rs.getInt("attribute_type_id");
4922  String attributeTypeName = rs.getString("type_name");
4923  BlackboardAttribute.Type attributeType;
4924  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
4925  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
4926  } else {
4927  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
4928  rs.getString("display_name"),
4930  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
4931  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
4932  }
4933 
4934  final BlackboardAttribute attr = new BlackboardAttribute(
4935  rs.getLong("artifact_id"),
4936  attributeType,
4937  rs.getString("source"),
4938  rs.getString("context"),
4939  rs.getInt("value_int32"),
4940  rs.getLong("value_int64"),
4941  rs.getDouble("value_double"),
4942  rs.getString("value_text"),
4943  rs.getBytes("value_byte"), this
4944  );
4945  attr.setParentDataSourceID(artifact.getDataSourceObjectID());
4946  attributes.add(attr);
4947  }
4948  return attributes;
4949  } catch (SQLException ex) {
4950  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
4951  } finally {
4952  closeResultSet(rs);
4953  closeStatement(statement);
4954  closeConnection(connection);
4956  }
4957  }
4958 
4968  ArrayList<Attribute> getFileAttributes(final AbstractFile file) throws TskCoreException {
4969  CaseDbConnection connection = null;
4970  Statement statement = null;
4971  ResultSet rs = null;
4973  try {
4974  connection = connections.getConnection();
4975  statement = connection.createStatement();
4976  rs = connection.executeQuery(statement, "SELECT attrs.id as id, attrs.obj_id AS obj_id, "
4977  + "attrs.attribute_type_id AS attribute_type_id, "
4978  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4979  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4980  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
4981  + "types.type_name AS type_name, types.display_name AS display_name "
4982  + "FROM tsk_file_attributes AS attrs "
4983  + " INNER JOIN blackboard_attribute_types AS types "
4984  + " ON attrs.attribute_type_id = types.attribute_type_id "
4985  + " WHERE attrs.obj_id = " + file.getId());
4986 
4987  ArrayList<Attribute> attributes = new ArrayList<Attribute>();
4988  while (rs.next()) {
4989  int attributeTypeId = rs.getInt("attribute_type_id");
4990  String attributeTypeName = rs.getString("type_name");
4991  BlackboardAttribute.Type attributeType;
4992  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
4993  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
4994  } else {
4995  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
4996  rs.getString("display_name"),
4997  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getInt("value_type")));
4998  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
4999  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
5000  }
5001 
5002  final Attribute attr = new Attribute(
5003  rs.getLong("id"),
5004  rs.getLong("obj_id"),
5005  attributeType,
5006  rs.getInt("value_int32"),
5007  rs.getLong("value_int64"),
5008  rs.getDouble("value_double"),
5009  rs.getString("value_text"),
5010  rs.getBytes("value_byte"), this
5011  );
5012  attributes.add(attr);
5013  }
5014  return attributes;
5015  } catch (SQLException ex) {
5016  throw new TskCoreException("Error getting attributes for file, file id = " + file.getId(), ex);
5017  } finally {
5018  closeResultSet(rs);
5019  closeStatement(statement);
5020  closeConnection(connection);
5022  }
5023  }
5024 
5037  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
5038  CaseDbConnection connection = null;
5039  Statement s = null;
5040  ResultSet rs = null;
5042  try {
5043  connection = connections.getConnection();
5044  s = connection.createStatement();
5045  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
5046  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
5047  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
5048  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
5049  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
5050  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
5051  + "FROM blackboard_attributes " + whereClause); //NON-NLS
5052  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
5053  while (rs.next()) {
5055  // attribute type is cached, so this does not necessarily call to the db
5056  type = this.getAttributeType(rs.getInt("attribute_type_id"));
5058  rs.getLong("artifact_id"),
5059  type,
5060  rs.getString("source"),
5061  rs.getString("context"),
5062  rs.getInt("value_int32"),
5063  rs.getLong("value_int64"),
5064  rs.getDouble("value_double"),
5065  rs.getString("value_text"),
5066  rs.getBytes("value_byte"), this
5067  );
5068  matches.add(attr);
5069  }
5070  return matches;
5071  } catch (SQLException ex) {
5072  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5073  } finally {
5074  closeResultSet(rs);
5075  closeStatement(s);
5076  closeConnection(connection);
5078  }
5079  }
5080 
5092  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
5093  CaseDbConnection connection = null;
5094  Statement s = null;
5095  ResultSet rs = null;
5097  try {
5098  connection = connections.getConnection();
5099  s = connection.createStatement();
5100  rs = connection.executeQuery(s, "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
5101  + "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, "
5102  + "blackboard_artifacts.review_status_id AS review_status_id "
5103  + "FROM blackboard_artifacts " + whereClause); //NON-NLS
5104  ArrayList<BlackboardArtifact> matches = new ArrayList<BlackboardArtifact>();
5105  while (rs.next()) {
5106  BlackboardArtifact.Type type;
5107  // artifact type is cached, so this does not necessarily call to the db
5108  type = this.getArtifactType(rs.getInt("artifact_type_id"));
5109  BlackboardArtifact artifact = new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"),
5110  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
5111  type.getTypeID(), type.getTypeName(), type.getDisplayName(),
5112  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")));
5113  matches.add(artifact);
5114  }
5115  return matches;
5116  } catch (SQLException ex) {
5117  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5118  } finally {
5119  closeResultSet(rs);
5120  closeStatement(s);
5121  closeConnection(connection);
5123  }
5124  }
5125 
5140  @Deprecated
5141  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
5142  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
5143  if (type == null) {
5144  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
5145  }
5146 
5147  Category category = type.getCategory();
5148  if (category == null) {
5149  throw new TskCoreException(String.format("No category for %s (id: %d)",
5150  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
5151  type.getTypeID()));
5152  }
5153 
5154  Content content = getContentById(obj_id);
5155  if (content == null) {
5156  throw new TskCoreException("No content found for object id: " + obj_id);
5157  }
5158 
5159  switch (category) {
5160  case ANALYSIS_RESULT:
5161  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
5162  .getAnalysisResult();
5163  case DATA_ARTIFACT:
5164  return content.newDataArtifact(type, Collections.emptyList());
5165  default:
5166  throw new TskCoreException("Unknown category type: " + category.getName());
5167  }
5168  }
5169 
5182  @Deprecated
5183  @SuppressWarnings("deprecation")
5184  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
5185  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
5186  }
5187 
5203  @Deprecated
5204  @SuppressWarnings("deprecation")
5205  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5206  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
5207  try (CaseDbConnection connection = connections.getConnection()) {
5208  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5209  }
5210  }
5211 
5212  @Deprecated
5213  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5214  try (CaseDbConnection connection = connections.getConnection()) {
5215  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5216  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5217  }
5218  }
5219 
5220  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5221 
5222  PreparedStatement statement;
5223  if (dbType == DbType.POSTGRESQL) {
5224  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5225  statement.clearParameters();
5226  statement.setLong(1, obj_id);
5227  statement.setLong(2, artifact_obj_id);
5228  statement.setLong(3, data_source_obj_id);
5229  statement.setInt(4, artifact_type_id);
5230  } else {
5231  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5232  statement.clearParameters();
5233  this.nextArtifactId++;
5234  statement.setLong(1, this.nextArtifactId);
5235  statement.setLong(2, obj_id);
5236  statement.setLong(3, artifact_obj_id);
5237  statement.setLong(4, data_source_obj_id);
5238  statement.setInt(5, artifact_type_id);
5239  }
5240 
5241  return statement;
5242  }
5243 
5244  @Deprecated
5245  BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5247  try {
5248  long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5249  PreparedStatement statement = createInsertArtifactStatement(artifact_type_id, obj_id, artifact_obj_id, data_source_obj_id, connection);
5250 
5251  connection.executeUpdate(statement);
5252  try (ResultSet resultSet = statement.getGeneratedKeys()) {
5253  resultSet.next();
5254  return new BlackboardArtifact(this, resultSet.getLong(1), //last_insert_rowid()
5255  obj_id, artifact_obj_id, data_source_obj_id, artifact_type_id, artifactTypeName, artifactDisplayName, BlackboardArtifact.ReviewStatus.UNDECIDED, true);
5256  }
5257  } catch (SQLException ex) {
5258  throw new TskCoreException("Error creating a blackboard artifact", ex);
5259  } finally {
5261  }
5262  }
5263 
5282  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5283 
5284  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5285  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5286  }
5287 
5288  long artifactID;
5290  try {
5291  // add a row in tsk_objects
5292  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5293 
5294  // add a row in blackboard_artifacts table
5295  PreparedStatement insertArtifactstatement;
5296  ResultSet resultSet = null;
5297  try {
5298  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5299  connection.executeUpdate(insertArtifactstatement);
5300  resultSet = insertArtifactstatement.getGeneratedKeys();
5301  resultSet.next();
5302  artifactID = resultSet.getLong(1); //last_insert_rowid()
5303 
5304  // add a row in tsk_analysis_results if any data for it is set
5305  if (score.getSignificance() != Score.Significance.UNKNOWN
5306  || !StringUtils.isBlank(conclusion)
5307  || !StringUtils.isBlank(configuration)
5308  || !StringUtils.isBlank(justification)) {
5309 
5310  PreparedStatement analysisResultsStatement;
5311 
5312  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5313  analysisResultsStatement.clearParameters();
5314 
5315  analysisResultsStatement.setLong(1, artifactObjId);
5316  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5317  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5318  analysisResultsStatement.setInt(4, score.getPriority().getId());
5319  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5320  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5321 
5322  connection.executeUpdate(analysisResultsStatement);
5323  }
5324 
5325  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5326  artifactType.getTypeName(), artifactType.getDisplayName(),
5327  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5328  score, (conclusion != null) ? conclusion : "",
5329  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5330 
5331  } finally {
5332  closeResultSet(resultSet);
5333  }
5334 
5335  } catch (SQLException ex) {
5336  throw new TskCoreException("Error creating a analysis result", ex);
5337  } finally {
5339  }
5340  }
5341 
5354  boolean getContentHasChildren(Content content) throws TskCoreException {
5355  CaseDbConnection connection = null;
5356  ResultSet rs = null;
5358  try {
5359  connection = connections.getConnection();
5360 
5361  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5362  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5363  statement.clearParameters();
5364  statement.setLong(1, content.getId());
5365  rs = connection.executeQuery(statement);
5366  boolean hasChildren = false;
5367  if (rs.next()) {
5368  hasChildren = rs.getInt("count") > 0;
5369  }
5370  return hasChildren;
5371  } catch (SQLException e) {
5372  throw new TskCoreException("Error checking for children of parent " + content, e);
5373  } finally {
5374  closeResultSet(rs);
5375  closeConnection(connection);
5377  }
5378  }
5379 
5392  int getContentChildrenCount(Content content) throws TskCoreException {
5393 
5394  if (!this.getHasChildren(content)) {
5395  return 0;
5396  }
5397 
5398  CaseDbConnection connection = null;
5399  ResultSet rs = null;
5401  try {
5402  connection = connections.getConnection();
5403 
5404  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5405  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5406  statement.clearParameters();
5407  statement.setLong(1, content.getId());
5408  rs = connection.executeQuery(statement);
5409  int countChildren = -1;
5410  if (rs.next()) {
5411  countChildren = rs.getInt("count");
5412  }
5413  return countChildren;
5414  } catch (SQLException e) {
5415  throw new TskCoreException("Error checking for children of parent " + content, e);
5416  } finally {
5417  closeResultSet(rs);
5418  closeConnection(connection);
5420  }
5421  }
5422 
5434  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5435  CaseDbConnection connection = null;
5436  ResultSet rs = null;
5438  try {
5439  connection = connections.getConnection();
5440 
5441  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5442  statement.clearParameters();
5443  long parentId = parent.getId();
5444  statement.setLong(1, parentId);
5445  statement.setShort(2, type.getFileType());
5446  rs = connection.executeQuery(statement);
5447  return fileChildren(rs, connection, parentId);
5448  } catch (SQLException ex) {
5449  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5450  } finally {
5451  closeResultSet(rs);
5452  closeConnection(connection);
5454  }
5455  }
5456 
5466  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5467  CaseDbConnection connection = null;
5468  ResultSet rs = null;
5470  try {
5471  connection = connections.getConnection();
5472 
5473  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5474  statement.clearParameters();
5475  long parentId = parent.getId();
5476  statement.setLong(1, parentId);
5477  rs = connection.executeQuery(statement);
5478  return fileChildren(rs, connection, parentId);
5479  } catch (SQLException ex) {
5480  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5481  } finally {
5482  closeResultSet(rs);
5483  closeConnection(connection);
5485  }
5486  }
5487 
5499  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5500  CaseDbConnection connection = null;
5501  ResultSet rs = null;
5503  try {
5504  connection = connections.getConnection();
5505 
5506  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5507  statement.clearParameters();
5508  statement.setLong(1, parent.getId());
5509  statement.setShort(2, type.getFileType());
5510  rs = connection.executeQuery(statement);
5511  List<Long> children = new ArrayList<Long>();
5512  while (rs.next()) {
5513  children.add(rs.getLong("obj_id"));
5514  }
5515  return children;
5516  } catch (SQLException ex) {
5517  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5518  } finally {
5519  closeResultSet(rs);
5520  closeConnection(connection);
5522  }
5523  }
5524 
5534  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5535  CaseDbConnection connection = null;
5536  ResultSet rs = null;
5538  try {
5539  connection = connections.getConnection();
5540 
5541  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5542  statement.clearParameters();
5543  statement.setLong(1, parent.getId());
5544  rs = connection.executeQuery(statement);
5545  List<Long> children = new ArrayList<Long>();
5546  while (rs.next()) {
5547  children.add(rs.getLong("obj_id"));
5548  }
5549  return children;
5550  } catch (SQLException ex) {
5551  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5552  } finally {
5553  closeResultSet(rs);
5554  closeConnection(connection);
5556  }
5557  }
5558 
5569  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5570  CaseDbConnection connection = null;
5571  ResultSet rs = null;
5573  try {
5574  connection = connections.getConnection();
5575 
5576  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5577  statement.clearParameters();
5578  statement.setLong(1, parent.getId());
5579  rs = connection.executeQuery(statement);
5580  List<Long> children = new ArrayList<Long>();
5581  while (rs.next()) {
5582  children.add(rs.getLong("obj_id"));
5583  }
5584  return children;
5585  } catch (SQLException ex) {
5586  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5587  } finally {
5588  closeResultSet(rs);
5589  closeConnection(connection);
5591  }
5592  }
5593 
5603  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5604 
5605  long parentId = parent.getId();
5606  ArrayList<BlackboardArtifact> artsArray = getArtifactsHelper("blackboard_artifacts.obj_id = " + parentId + ";");
5607 
5608  List<Content> lc = new ArrayList<Content>();
5609  lc.addAll(artsArray);
5610  return lc;
5611  }
5612 
5621  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5622  CaseDbConnection connection = null;
5623  Statement s = null;
5624  ResultSet rs = null;
5626  try {
5627  connection = connections.getConnection();
5628  s = connection.createStatement();
5629  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5630  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5631  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5632  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5633  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5634  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5635  while (rs.next()) {
5636  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5637  }
5638  return infos;
5639  } catch (SQLException ex) {
5640  throw new TskCoreException("Error getting Children Info for Content", ex);
5641  } finally {
5642  closeResultSet(rs);
5643  closeStatement(s);
5644  closeConnection(connection);
5646  }
5647  }
5648 
5659  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5660  return getParentInfo(c.getId());
5661  }
5662 
5673  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5675  CaseDbConnection connection = null;
5676  Statement s = null;
5677  ResultSet rs = null;
5678  try {
5679  connection = connections.getConnection();
5680  s = connection.createStatement();
5681  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5682  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5683  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5684  + "WHERE child.obj_id = " + contentId); //NON-NLS
5685  if (rs.next()) {
5686  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5687  } else {
5688  return null;
5689  }
5690  } catch (SQLException ex) {
5691  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5692  } finally {
5693  closeResultSet(rs);
5694  closeStatement(s);
5695  closeConnection(connection);
5697  }
5698  }
5699 
5710  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5711  if (fsc.isRoot()) {
5712  // Given FsContent is a root object and can't have parent directory
5713  return null;
5714  } else {
5715  ObjectInfo parentInfo = getParentInfo(fsc);
5716  if (parentInfo == null) {
5717  return null;
5718  }
5719  Directory parent = null;
5720  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
5721  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
5722  } else {
5723  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
5724  }
5725  return parent;
5726  }
5727  }
5728 
5740  public Content getContentById(long id) throws TskCoreException {
5741  // First check to see if this exists in our frequently used content cache.
5742  Content content = frequentlyUsedContentMap.get(id);
5743  if (null != content) {
5744  return content;
5745  }
5746 
5747  long parentId;
5748  TskData.ObjectType type;
5749 
5750  CaseDbConnection connection = null;
5751  Statement s = null;
5752  ResultSet rs = null;
5754  try {
5755  connection = connections.getConnection();
5756  s = connection.createStatement();
5757  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
5758  if (!rs.next()) {
5759  return null;
5760  }
5761  parentId = rs.getLong("par_obj_id"); //NON-NLS
5762  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
5763  } catch (SQLException ex) {
5764  throw new TskCoreException("Error getting Content by ID.", ex);
5765  } finally {
5766  closeResultSet(rs);
5767  closeStatement(s);
5768  closeConnection(connection);
5770  }
5771 
5772  // Construct the object
5773  switch (type) {
5774  case IMG:
5775  content = getImageById(id);
5776  frequentlyUsedContentMap.put(id, content);
5777  break;
5778  case VS:
5779  content = getVolumeSystemById(id, parentId);
5780  break;
5781  case VOL:
5782  content = getVolumeById(id, parentId);
5783  frequentlyUsedContentMap.put(id, content);
5784  break;
5785  case POOL:
5786  content = getPoolById(id, parentId);
5787  break;
5788  case FS:
5789  content = getFileSystemById(id, parentId);
5790  frequentlyUsedContentMap.put(id, content);
5791  break;
5792  case ABSTRACTFILE:
5793  content = getAbstractFileById(id);
5794 
5795  // Add virtual and root directories to frequently used map.
5796  // Calling isRoot() on local directories goes up the entire directory structure
5797  // and they can only be the root of portable cases, so skip trying to add
5798  // them to the cache.
5799  if (((AbstractFile) content).isVirtual()
5800  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5801  frequentlyUsedContentMap.put(id, content);
5802  }
5803  break;
5804  case ARTIFACT:
5805  content = getArtifactById(id);
5806  break;
5807  case REPORT:
5808  content = getReportById(id);
5809  break;
5810  case OS_ACCOUNT:
5811  content = this.osAccountManager.getOsAccountByObjectId(id);
5812  break;
5813  case HOST_ADDRESS:
5814  content = hostAddressManager.getHostAddress(id);
5815  break;
5816  default:
5817  content = new UnsupportedContent(this, id);
5818  }
5819 
5820  return content;
5821  }
5822 
5830  String getFilePath(long id) {
5831 
5832  String filePath = null;
5833  CaseDbConnection connection = null;
5834  ResultSet rs = null;
5836  try {
5837  connection = connections.getConnection();
5838 
5839  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5840  statement.clearParameters();
5841  statement.setLong(1, id);
5842  rs = connection.executeQuery(statement);
5843  if (rs.next()) {
5844  filePath = rs.getString("path");
5845  }
5846  } catch (SQLException | TskCoreException ex) {
5847  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5848  } finally {
5849  closeResultSet(rs);
5850  closeConnection(connection);
5852  }
5853  return filePath;
5854  }
5855 
5863  TskData.EncodingType getEncodingType(long id) {
5864 
5865  TskData.EncodingType type = TskData.EncodingType.NONE;
5866  CaseDbConnection connection = null;
5867  ResultSet rs = null;
5869  try {
5870  connection = connections.getConnection();
5871  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5872  statement.clearParameters();
5873  statement.setLong(1, id);
5874  rs = connection.executeQuery(statement);
5875  if (rs.next()) {
5876  type = TskData.EncodingType.valueOf(rs.getInt(1));
5877  }
5878  } catch (SQLException | TskCoreException ex) {
5879  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5880  } finally {
5881  closeResultSet(rs);
5882  closeConnection(connection);
5884  }
5885  return type;
5886  }
5887 
5896  String getFileParentPath(long objectId, CaseDbConnection connection) {
5897  String parentPath = null;
5899  ResultSet rs = null;
5900  try {
5901  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5902  statement.clearParameters();
5903  statement.setLong(1, objectId);
5904  rs = connection.executeQuery(statement);
5905  if (rs.next()) {
5906  parentPath = rs.getString("parent_path");
5907  }
5908  } catch (SQLException ex) {
5909  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5910  } finally {
5911  closeResultSet(rs);
5913  }
5914  return parentPath;
5915  }
5916 
5925  String getFileName(long objectId, CaseDbConnection connection) {
5926  String fileName = null;
5928  ResultSet rs = null;
5929  try {
5930  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
5931  statement.clearParameters();
5932  statement.setLong(1, objectId);
5933  rs = connection.executeQuery(statement);
5934  if (rs.next()) {
5935  fileName = rs.getString("name");
5936  }
5937  } catch (SQLException ex) {
5938  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
5939  } finally {
5940  closeResultSet(rs);
5942  }
5943  return fileName;
5944  }
5945 
5956  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
5957 
5958  DerivedFile.DerivedMethod method = null;
5959  CaseDbConnection connection = null;
5960  ResultSet rs1 = null;
5961  ResultSet rs2 = null;
5963  try {
5964  connection = connections.getConnection();
5965 
5966  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
5967  statement.clearParameters();
5968  statement.setLong(1, id);
5969  rs1 = connection.executeQuery(statement);
5970  if (rs1.next()) {
5971  int method_id = rs1.getInt("derived_id");
5972  String rederive = rs1.getString("rederive");
5973  method = new DerivedFile.DerivedMethod(method_id, rederive);
5974  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
5975  statement.clearParameters();
5976  statement.setInt(1, method_id);
5977  rs2 = connection.executeQuery(statement);
5978  if (rs2.next()) {
5979  method.setToolName(rs2.getString("tool_name"));
5980  method.setToolVersion(rs2.getString("tool_version"));
5981  method.setOther(rs2.getString("other"));
5982  }
5983  }
5984  } catch (SQLException e) {
5985  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
5986  } finally {
5987  closeResultSet(rs2);
5988  closeResultSet(rs1);
5989  closeConnection(connection);
5991  }
5992  return method;
5993  }
5994 
6005  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
6006  CaseDbConnection connection = connections.getConnection();
6007  try {
6008  return getAbstractFileById(id, connection);
6009  } finally {
6010  closeConnection(connection);
6011  }
6012  }
6013 
6026  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
6028  ResultSet rs = null;
6029  try {
6030  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
6031  statement.clearParameters();
6032  statement.setLong(1, objectId);
6033  rs = connection.executeQuery(statement);
6034  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
6035  if (files.size() > 0) {
6036  return files.get(0);
6037  } else {
6038  return null;
6039  }
6040  } catch (SQLException ex) {
6041  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
6042  } finally {
6043  closeResultSet(rs);
6045  }
6046  }
6047 
6059  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
6060 
6061  CaseDbConnection connection = null;
6062  ResultSet rs = null;
6064  try {
6065  connection = connections.getConnection();
6066 
6067  // get the artifact type.
6068  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
6069  statement.clearParameters();
6070  statement.setLong(1, id);
6071 
6072  rs = connection.executeQuery(statement);
6073  if (!rs.next()) {
6074  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
6075  }
6076 
6077  // based on the artifact type category, get the analysis result or the data artifact
6078  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
6079  switch (artifactType.getCategory()) {
6080  case ANALYSIS_RESULT:
6081  return blackboard.getAnalysisResultById(id);
6082  case DATA_ARTIFACT:
6083  return blackboard.getDataArtifactById(id);
6084  default:
6085  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
6086  }
6087 
6088  } catch (SQLException ex) {
6089  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
6090  } finally {
6091  closeResultSet(rs);
6092  closeConnection(connection);
6094  }
6095  }
6096 
6107  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
6108  CaseDbConnection connection = null;
6109  ResultSet rs = null;
6111  try {
6112  connection = connections.getConnection();
6113 
6114  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_BY_ARTIFACT_ID);
6115  statement.clearParameters();
6116  statement.setLong(1, id);
6117  rs = connection.executeQuery(statement);
6118  List<BlackboardArtifact> artifacts = resultSetToArtifacts(rs);
6119  if (artifacts.size() > 0) {
6120  return artifacts.get(0);
6121  } else {
6122  return null;
6123  }
6124  } catch (SQLException ex) {
6125  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
6126  } finally {
6127  closeResultSet(rs);
6128  closeConnection(connection);
6130  }
6131  }
6132 
6145  private long getFileSystemId(long fileId, CaseDbConnection connection) {
6147  ResultSet rs = null;
6148  long ret = -1;
6149  try {
6150  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
6151  statement.clearParameters();
6152  statement.setLong(1, fileId);
6153  rs = connection.executeQuery(statement);
6154  if (rs.next()) {
6155  ret = rs.getLong("fs_obj_id");
6156  if (ret == 0) {
6157  ret = -1;
6158  }
6159  }
6160  } catch (SQLException e) {
6161  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
6162  } finally {
6163  closeResultSet(rs);
6165  }
6166  return ret;
6167  }
6168 
6180  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6181  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
6182  CaseDbConnection connection = null;
6183  Statement statement = null;
6184  ResultSet resultSet = null;
6186  try {
6187  connection = connections.getConnection();
6188  statement = connection.createStatement();
6189  resultSet = connection.executeQuery(statement, query);
6190  resultSet.next();
6191  return (resultSet.getLong("count") > 0L);
6192  } catch (SQLException ex) {
6193  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6194  } finally {
6195  closeResultSet(resultSet);
6196  closeStatement(statement);
6197  closeConnection(connection);
6199  }
6200  }
6201 
6210  private static boolean containsLikeWildcard(String str) {
6211  if (str == null) {
6212  return false;
6213  } else {
6214  return str.contains("%") || str.contains("_");
6215  }
6216  }
6217 
6229  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6230  String ext = "";
6231  if (!containsLikeWildcard(fileName)) {
6232  ext = SleuthkitCase.extractExtension(fileName);
6233  }
6234 
6235  List<AbstractFile> files = new ArrayList<>();
6236  CaseDbConnection connection = null;
6237  ResultSet resultSet = null;
6239  try {
6240  connection = connections.getConnection();
6241 
6242  PreparedStatement statement;
6243  if (ext.isEmpty()) {
6244  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6245  statement.clearParameters();
6246  statement.setString(1, fileName.toLowerCase());
6247  statement.setLong(2, dataSource.getId());
6248  } else {
6249  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6250  statement.clearParameters();
6251  statement.setString(1, ext);
6252  statement.setString(2, fileName.toLowerCase());
6253  statement.setLong(3, dataSource.getId());
6254  }
6255 
6256  resultSet = connection.executeQuery(statement);
6257  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6258  } catch (SQLException e) {
6259  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6260  } finally {
6261  closeResultSet(resultSet);
6262  closeConnection(connection);
6264  }
6265  return files;
6266  }
6267 
6281  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6282  String ext = "";
6283  if (!containsLikeWildcard(fileName)) {
6284  ext = SleuthkitCase.extractExtension(fileName);
6285  }
6286 
6287  List<AbstractFile> files = new ArrayList<>();
6288  CaseDbConnection connection = null;
6289  ResultSet resultSet = null;
6291  try {
6292  connection = connections.getConnection();
6293  PreparedStatement statement;
6294  if (ext.isEmpty()) {
6295  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6296  statement.clearParameters();
6297  statement.setString(1, fileName.toLowerCase());
6298  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6299  statement.setLong(3, dataSource.getId());
6300  } else {
6301  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6302  statement.clearParameters();
6303  statement.setString(1, ext);
6304  statement.setString(2, fileName.toLowerCase());
6305  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6306  statement.setLong(4, dataSource.getId());
6307  }
6308 
6309  resultSet = connection.executeQuery(statement);
6310  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6311  } catch (SQLException e) {
6312  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6313  } finally {
6314  closeResultSet(resultSet);
6315  closeConnection(connection);
6317  }
6318  return files;
6319  }
6320 
6332  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6333  CaseDbTransaction localTrans = beginTransaction();
6334  try {
6335  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6336  localTrans.commit();
6337  localTrans = null;
6338  return newVD;
6339  } finally {
6340  if (null != localTrans) {
6341  try {
6342  localTrans.rollback();
6343  } catch (TskCoreException ex2) {
6344  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6345  }
6346  }
6347  }
6348  }
6349 
6362  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6363  ResultSet resultSet = null;
6365  try {
6366  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6367  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6368  statement.clearParameters();
6369  if (parentId != 0) {
6370  statement.setLong(1, parentId);
6371  } else {
6372  statement.setNull(1, java.sql.Types.BIGINT);
6373  }
6374  statement.setInt(2, objectType);
6375  connection.executeUpdate(statement);
6376  resultSet = statement.getGeneratedKeys();
6377 
6378  if (resultSet.next()) {
6379  if (parentId != 0) {
6380  setHasChildren(parentId);
6381  }
6382  return resultSet.getLong(1); //last_insert_rowid()
6383  } else {
6384  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6385  }
6386  } finally {
6387  closeResultSet(resultSet);
6389  }
6390  }
6391 
6409  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6410  if (transaction == null) {
6411  throw new TskCoreException("Passed null CaseDbTransaction");
6412  }
6413 
6414  ResultSet resultSet = null;
6415  try {
6416  // Get the parent path.
6417  CaseDbConnection connection = transaction.getConnection();
6418 
6419  String parentPath;
6420  Content parent = this.getAbstractFileById(parentId, connection);
6421  if (parent instanceof AbstractFile) {
6422  if (isRootDirectory((AbstractFile) parent, transaction)) {
6423  parentPath = "/";
6424  } else {
6425  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6426  }
6427  } else {
6428  // The parent was either null or not an abstract file
6429  parentPath = "/";
6430  }
6431 
6432  // Insert a row for the virtual directory into the tsk_objects table.
6433  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6434 
6435  // Insert a row for the virtual directory into the tsk_files table.
6436  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6437  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension,owner_uid, os_account_obj_id)
6438  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?)
6439  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6440  statement.clearParameters();
6441  statement.setLong(1, newObjId);
6442 
6443  // If the parent is part of a file system, grab its file system ID
6444  if (0 != parentId) {
6445  long parentFs = this.getFileSystemId(parentId, connection);
6446  if (parentFs != -1) {
6447  statement.setLong(2, parentFs);
6448  } else {
6449  statement.setNull(2, java.sql.Types.BIGINT);
6450  }
6451  } else {
6452  statement.setNull(2, java.sql.Types.BIGINT);
6453  }
6454 
6455  // name
6456  statement.setString(3, directoryName);
6457 
6458  //type
6459  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6460  statement.setShort(5, (short) 1);
6461 
6462  //flags
6464  statement.setShort(6, dirType.getValue());
6466  statement.setShort(7, metaType.getValue());
6467 
6468  //allocated
6470  statement.setShort(8, dirFlag.getValue());
6471  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6472  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6473  statement.setShort(9, metaFlags);
6474 
6475  //size
6476  statement.setLong(10, 0);
6477 
6478  // nulls for params 11-14
6479  statement.setNull(11, java.sql.Types.BIGINT);
6480  statement.setNull(12, java.sql.Types.BIGINT);
6481  statement.setNull(13, java.sql.Types.BIGINT);
6482  statement.setNull(14, java.sql.Types.BIGINT);
6483 
6484  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6485  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6486  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6487  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6488 
6489  // parent path
6490  statement.setString(19, parentPath);
6491 
6492  // data source object id (same as object id if this is a data source)
6493  long dataSourceObjectId;
6494  if (0 == parentId) {
6495  dataSourceObjectId = newObjId;
6496  } else {
6497  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6498  }
6499  statement.setLong(20, dataSourceObjectId);
6500 
6501  //extension, since this is not really file we just set it to null
6502  statement.setString(21, null);
6503 
6504  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6505  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6506 
6507  connection.executeUpdate(statement);
6508 
6509  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6510  metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN,
6511  parentPath);
6512  } catch (SQLException e) {
6513  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6514  } finally {
6515  closeResultSet(resultSet);
6516  }
6517  }
6518 
6531  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6532  CaseDbTransaction localTrans = beginTransaction();
6533  try {
6534  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6535  localTrans.commit();
6536  return newLD;
6537  } catch (TskCoreException ex) {
6538  try {
6539  localTrans.rollback();
6540  } catch (TskCoreException ex2) {
6541  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6542  }
6543  throw ex;
6544  }
6545  }
6546 
6564  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6565  if (transaction == null) {
6566  throw new TskCoreException("Passed null CaseDbTransaction");
6567  }
6568 
6569  ResultSet resultSet = null;
6570  try {
6571  // Get the parent path.
6572  CaseDbConnection connection = transaction.getConnection();
6573  AbstractFile parent = getAbstractFileById(parentId, connection);
6574  String parentPath;
6575  if ((parent == null) || isRootDirectory(parent, transaction)) {
6576  parentPath = "/";
6577  } else {
6578  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6579  }
6580 
6581  // Insert a row for the local directory into the tsk_objects table.
6582  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6583 
6584  // Insert a row for the local directory into the tsk_files table.
6585  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6586  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6587  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6588  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6589  statement.clearParameters();
6590  statement.setLong(1, newObjId);
6591 
6592  // The parent of a local directory will never be a file system
6593  statement.setNull(2, java.sql.Types.BIGINT);
6594 
6595  // name
6596  statement.setString(3, directoryName);
6597 
6598  //type
6599  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6600  statement.setShort(5, (short) 1);
6601 
6602  //flags
6604  statement.setShort(6, dirType.getValue());
6606  statement.setShort(7, metaType.getValue());
6607 
6608  //allocated
6610  statement.setShort(8, dirFlag.getValue());
6611  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6612  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6613  statement.setShort(9, metaFlags);
6614 
6615  //size
6616  statement.setLong(10, 0);
6617 
6618  // nulls for params 11-14
6619  statement.setNull(11, java.sql.Types.BIGINT);
6620  statement.setNull(12, java.sql.Types.BIGINT);
6621  statement.setNull(13, java.sql.Types.BIGINT);
6622  statement.setNull(14, java.sql.Types.BIGINT);
6623 
6624  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6625  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6626  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6627  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6628 
6629  // parent path
6630  statement.setString(19, parentPath);
6631 
6632  // data source object id
6633  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6634  statement.setLong(20, dataSourceObjectId);
6635 
6636  //extension, since this is a directory we just set it to null
6637  statement.setString(21, null);
6638 
6639  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6640  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6641 
6642  connection.executeUpdate(statement);
6643 
6644  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6645  metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN,
6646  parentPath);
6647  } catch (SQLException e) {
6648  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6649  } finally {
6650  closeResultSet(resultSet);
6651  }
6652  }
6653 
6673  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6674  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6675  }
6676 
6697  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6698 
6699  Statement statement = null;
6700  try {
6701  CaseDbConnection connection = transaction.getConnection();
6702 
6703  // Insert a row for the root virtual directory of the data source
6704  // into the tsk_objects table.
6705  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6706 
6707  // If no host was supplied, make one
6708  if (host == null) {
6709  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
6710  }
6711 
6712  // Insert a row for the virtual directory of the data source into
6713  // the data_source_info table.
6714  statement = connection.createStatement();
6715  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
6716  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
6717 
6718  // Insert a row for the root virtual directory of the data source
6719  // into the tsk_files table. Note that its data source object id is
6720  // its own object id.
6721  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
6722  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
6723  // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6724  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
6725  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6726  preparedStatement.clearParameters();
6727  preparedStatement.setLong(1, newObjId);
6728  preparedStatement.setNull(2, java.sql.Types.BIGINT);
6729  preparedStatement.setString(3, rootDirectoryName);
6730  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6731  preparedStatement.setShort(5, (short) 1);
6733  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
6735  preparedStatement.setShort(7, metaType.getValue());
6737  preparedStatement.setShort(8, dirFlag.getValue());
6738  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6739  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6740  preparedStatement.setShort(9, metaFlags);
6741  preparedStatement.setLong(10, 0);
6742  preparedStatement.setNull(11, java.sql.Types.BIGINT);
6743  preparedStatement.setNull(12, java.sql.Types.BIGINT);
6744  preparedStatement.setNull(13, java.sql.Types.BIGINT);
6745  preparedStatement.setNull(14, java.sql.Types.BIGINT);
6746  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
6747  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6748  preparedStatement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6749  preparedStatement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6750  String parentPath = "/"; //NON-NLS
6751  preparedStatement.setString(19, parentPath);
6752  preparedStatement.setLong(20, newObjId);
6753  preparedStatement.setString(21, null); //extension, just set it to null
6754  preparedStatement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6755  preparedStatement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6756  connection.executeUpdate(preparedStatement);
6757 
6758  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, FileKnown.UNKNOWN, parentPath);
6759 
6760  } catch (SQLException ex) {
6761  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
6762  } finally {
6763  closeStatement(statement);
6764  }
6765  }
6766 
6786  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6787  String timezone, String md5, String sha1, String sha256,
6788  String deviceId,
6789  CaseDbTransaction transaction) throws TskCoreException {
6790  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
6791  }
6792 
6813  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6814  String timezone, String md5, String sha1, String sha256,
6815  String deviceId, Host host,
6816  CaseDbTransaction transaction) throws TskCoreException {
6817  Statement statement = null;
6818  try {
6819  // Insert a row for the Image into the tsk_objects table.
6820  CaseDbConnection connection = transaction.getConnection();
6821  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
6822 
6823  // Add a row to tsk_image_info
6824  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
6825  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
6826  preparedStatement.clearParameters();
6827  preparedStatement.setLong(1, newObjId);
6828  preparedStatement.setShort(2, (short) type.getValue());
6829  preparedStatement.setLong(3, sectorSize);
6830  preparedStatement.setString(4, timezone);
6831  //prevent negative size
6832  long savedSize = size < 0 ? 0 : size;
6833  preparedStatement.setLong(5, savedSize);
6834  preparedStatement.setString(6, md5);
6835  preparedStatement.setString(7, sha1);
6836  preparedStatement.setString(8, sha256);
6837  preparedStatement.setString(9, displayName);
6838  connection.executeUpdate(preparedStatement);
6839 
6840  // If there are paths, add them to tsk_image_names
6841  for (int i = 0; i < imagePaths.size(); i++) {
6842  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
6843  preparedStatement.clearParameters();
6844  preparedStatement.setLong(1, newObjId);
6845  preparedStatement.setString(2, imagePaths.get(i));
6846  preparedStatement.setLong(3, i);
6847  connection.executeUpdate(preparedStatement);
6848  }
6849 
6850  // Create the display name
6851  String name = displayName;
6852  if (name == null || name.isEmpty()) {
6853  if (imagePaths.size() > 0) {
6854  String path = imagePaths.get(0);
6855  name = (new java.io.File(path)).getName();
6856  } else {
6857  name = "";
6858  }
6859  }
6860 
6861  // Create a host if needed
6862  if (host == null) {
6863  if (name.isEmpty()) {
6864  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
6865  } else {
6866  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
6867  }
6868  }
6869 
6870  // Add a row to data_source_info
6871  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
6872  statement = connection.createStatement();
6873  preparedStatement.setLong(1, newObjId);
6874  preparedStatement.setString(2, deviceId);
6875  preparedStatement.setString(3, timezone);
6876  preparedStatement.setLong(4, new Date().getTime());
6877  preparedStatement.setLong(5, host.getHostId());
6878  connection.executeUpdate(preparedStatement);
6879 
6880  // Create the new Image object
6881  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
6882  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
6883  } catch (SQLException ex) {
6884  if (!imagePaths.isEmpty()) {
6885  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
6886  } else {
6887  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
6888  }
6889  } finally {
6890  closeStatement(statement);
6891  }
6892  }
6893 
6907  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
6908  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
6909  try {
6910  // Insert a row for the VolumeSystem into the tsk_objects table.
6911  CaseDbConnection connection = transaction.getConnection();
6912  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
6913 
6914  // Add a row to tsk_vs_info
6915  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
6916  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
6917  preparedStatement.clearParameters();
6918  preparedStatement.setLong(1, newObjId);
6919  preparedStatement.setShort(2, (short) type.getVsType());
6920  preparedStatement.setLong(3, imgOffset);
6921  preparedStatement.setLong(4, blockSize);
6922  connection.executeUpdate(preparedStatement);
6923 
6924  // Create the new VolumeSystem object
6925  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
6926  } catch (SQLException ex) {
6927  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
6928  parentObjId, imgOffset), ex);
6929  }
6930  }
6931 
6947  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
6948  long flags, CaseDbTransaction transaction) throws TskCoreException {
6949  try {
6950  // Insert a row for the Volume into the tsk_objects table.
6951  CaseDbConnection connection = transaction.getConnection();
6952  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
6953 
6954  // Add a row to tsk_vs_parts
6955  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
6956  PreparedStatement preparedStatement;
6957  if (this.dbType == DbType.POSTGRESQL) {
6958  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
6959  } else {
6960  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
6961  }
6962  preparedStatement.clearParameters();
6963  preparedStatement.setLong(1, newObjId);
6964  preparedStatement.setLong(2, addr);
6965  preparedStatement.setLong(3, start);
6966  preparedStatement.setLong(4, length);
6967  preparedStatement.setString(5, desc);
6968  preparedStatement.setShort(6, (short) flags);
6969  connection.executeUpdate(preparedStatement);
6970 
6971  // Create the new Volume object
6972  return new Volume(this, newObjId, addr, start, length, flags, desc);
6973  } catch (SQLException ex) {
6974  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
6975  }
6976  }
6977 
6989  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
6990  try {
6991  // Insert a row for the Pool into the tsk_objects table.
6992  CaseDbConnection connection = transaction.getConnection();
6993  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
6994 
6995  // Add a row to tsk_pool_info
6996  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
6997  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
6998  preparedStatement.clearParameters();
6999  preparedStatement.setLong(1, newObjId);
7000  preparedStatement.setShort(2, type.getValue());
7001  connection.executeUpdate(preparedStatement);
7002 
7003  // Create the new Pool object
7004  return new Pool(this, newObjId, type.getName(), type.getValue());
7005  } catch (SQLException ex) {
7006  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
7007  }
7008  }
7009 
7028  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
7029  long rootInum, long firstInum, long lastInum, String displayName,
7030  CaseDbTransaction transaction) throws TskCoreException {
7031  try {
7032  // Insert a row for the FileSystem into the tsk_objects table.
7033  CaseDbConnection connection = transaction.getConnection();
7034  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
7035 
7036  // Get the data source object ID
7037  long dataSourceId = getDataSourceObjectId(connection, newObjId);
7038 
7039  // Add a row to tsk_fs_info
7040  // 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)
7041  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
7042  preparedStatement.clearParameters();
7043  preparedStatement.setLong(1, newObjId);
7044  preparedStatement.setLong(2, dataSourceId);
7045  preparedStatement.setLong(3, imgOffset);
7046  preparedStatement.setInt(4, type.getValue());
7047  preparedStatement.setLong(5, blockSize);
7048  preparedStatement.setLong(6, blockCount);
7049  preparedStatement.setLong(7, rootInum);
7050  preparedStatement.setLong(8, firstInum);
7051  preparedStatement.setLong(9, lastInum);
7052  preparedStatement.setString(10, displayName);
7053  connection.executeUpdate(preparedStatement);
7054 
7055  // Create the new FileSystem object
7056  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
7057  firstInum, lastInum);
7058  } catch (SQLException ex) {
7059  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
7060  imgOffset, parentObjId), ex);
7061  }
7062  }
7063 
7089  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7090  String fileName,
7091  long metaAddr, int metaSeq,
7092  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7093  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7094  long ctime, long crtime, long atime, long mtime,
7095  boolean isFile, Content parent) throws TskCoreException {
7096 
7097  CaseDbTransaction transaction = beginTransaction();
7098  try {
7099 
7100  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
7101  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
7102  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
7103  OsAccount.NO_OWNER_ID, null,
7104  Collections.emptyList(), transaction);
7105 
7106  transaction.commit();
7107  transaction = null;
7108  return fileSystemFile;
7109  } finally {
7110  if (null != transaction) {
7111  try {
7112  transaction.rollback();
7113  } catch (TskCoreException ex2) {
7114  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7115  }
7116  }
7117  }
7118  }
7119 
7157  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7158  String fileName,
7159  long metaAddr, int metaSeq,
7160  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7161  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7162  long ctime, long crtime, long atime, long mtime,
7163  String md5Hash, String sha256Hash, String mimeType,
7164  boolean isFile, Content parent, String ownerUid,
7165  OsAccount osAccount, List<Attribute> fileAttributes,
7166  CaseDbTransaction transaction) throws TskCoreException {
7167 
7168  TimelineManager timelineManager = getTimelineManager();
7169 
7170  Statement queryStatement = null;
7171  String parentPath = "/";
7172  try {
7173  CaseDbConnection connection = transaction.getConnection();
7174 
7175  // Insert a row for the local/logical file into the tsk_objects table.
7176  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7177  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7178 
7179  if (parent instanceof AbstractFile) {
7180  AbstractFile parentFile = (AbstractFile) parent;
7181  if (isRootDirectory(parentFile, transaction)) {
7182  parentPath = "/";
7183  } else {
7184  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7185  }
7186  } else {
7187  parentPath = "/";
7188  }
7189 
7190  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7191  statement.clearParameters();
7192  statement.setLong(1, objectId); // obj_is
7193  statement.setLong(2, fsObjId); // fs_obj_id
7194  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7195  statement.setShort(4, (short) attrType.getValue()); // attr_type
7196  statement.setInt(5, attrId); // attr_id
7197  statement.setString(6, fileName); // name
7198  statement.setLong(7, metaAddr); // meta_addr
7199  statement.setInt(8, metaSeq); // meta_addr
7200  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7201  statement.setShort(10, (short) 1); // has_path
7203  statement.setShort(11, dirType.getValue()); // dir_type
7205  statement.setShort(12, metaType.getValue()); // meta_type
7206  statement.setShort(13, dirFlag.getValue()); // dir_flags
7207  statement.setShort(14, metaFlags); // meta_flags
7208  statement.setLong(15, size < 0 ? 0 : size);
7209  statement.setLong(16, ctime);
7210  statement.setLong(17, crtime);
7211  statement.setLong(18, atime);
7212  statement.setLong(19, mtime);
7213  statement.setString(20, md5Hash);
7214  statement.setString(21, sha256Hash);
7215  statement.setString(22, mimeType);
7216  statement.setString(23, parentPath);
7217  final String extension = extractExtension(fileName);
7218  statement.setString(24, extension);
7219  statement.setString(25, ownerUid);
7220  if (null != osAccount) {
7221  statement.setLong(26, osAccount.getId());
7222  } else {
7223  statement.setNull(26, java.sql.Types.BIGINT); // osAccountObjId
7224  }
7225 
7226  connection.executeUpdate(statement);
7227 
7228  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7229  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7230  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7231 
7232  timelineManager.addEventsForNewFile(derivedFile, connection);
7233 
7234  for (Attribute fileAttribute : fileAttributes) {
7235  fileAttribute.setAttributeParentId(objectId);
7236  fileAttribute.setCaseDatabase(this);
7237  addFileAttribute(fileAttribute, connection);
7238  }
7239 
7240  if (osAccount != null) {
7241  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.LAUNCHED, connection);
7242  }
7243 
7244  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7245  attrType, attrId, fileName, metaAddr, metaSeq,
7246  dirType, metaType, dirFlag, metaFlags,
7247  size, ctime, crtime, atime, mtime,
7248  (short) 0, 0, 0, md5Hash, sha256Hash, null, parentPath, mimeType,
7249  extension, ownerUid, osAccountId, fileAttributes);
7250 
7251  } catch (SQLException ex) {
7252  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);
7253  } finally {
7254  closeStatement(queryStatement);
7255  }
7256  }
7257 
7266  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7267  CaseDbConnection connection = null;
7268  Statement s = null;
7269  ResultSet rs = null;
7271  try {
7272  connection = connections.getConnection();
7273  s = connection.createStatement();
7274  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7275  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7276  + " AND obj_id = data_source_obj_id"
7277  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7278  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7279  while (rs.next()) {
7280  virtDirRootIds.add(virtualDirectory(rs, connection));
7281  }
7282  return virtDirRootIds;
7283  } catch (SQLException ex) {
7284  throw new TskCoreException("Error getting local files virtual folder id", ex);
7285  } finally {
7286  closeResultSet(rs);
7287  closeStatement(s);
7288  closeConnection(connection);
7290  }
7291  }
7292 
7305  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7306  assert (null != fileRanges);
7307  if (null == fileRanges) {
7308  throw new TskCoreException("TskFileRange object is null");
7309  }
7310 
7311  assert (null != parent);
7312  if (null == parent) {
7313  throw new TskCoreException("Conent is null");
7314  }
7315 
7316  CaseDbTransaction transaction = null;
7317  Statement statement = null;
7318  ResultSet resultSet = null;
7319 
7320  try {
7321  transaction = beginTransaction();
7322  CaseDbConnection connection = transaction.getConnection();
7323 
7324  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
7325  for (TskFileRange fileRange : fileRanges) {
7326  /*
7327  * Insert a row for the Tsk file range into the tsk_objects
7328  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7329  * ?)
7330  */
7331  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7332  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7333  /*
7334  * Insert a row for the Tsk file range into the tsk_files table:
7335  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7336  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7337  * ctime, crtime, atime, mtime, md5, known, mime_type,
7338  * parent_path, data_source_obj_id,extension, owner_uid,
7339  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7340  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
7341  */
7342  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7343  prepStmt.clearParameters();
7344  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7345  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7346  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]
7347  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7348  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7349  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7350  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7351  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7352  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7353  prepStmt.setLong(10, fileRange.getByteLen()); // size
7354  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7355  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7356  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7357  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7358  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7359  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7360  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7361  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
7362  prepStmt.setNull(19, java.sql.Types.VARCHAR); // parent path
7363  prepStmt.setLong(20, parent.getId()); // data_source_obj_id
7364 
7365  //extension, since this is not a FS file we just set it to null
7366  prepStmt.setString(21, null);
7367 
7368  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7369  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7370 
7371  connection.executeUpdate(prepStmt);
7372 
7373  /*
7374  * Insert a row in the tsk_layout_file table for each chunk of
7375  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7376  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7377  */
7378  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7379  prepStmt.clearParameters();
7380  prepStmt.setLong(1, fileRangeId); // obj_id
7381  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7382  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7383  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7384  connection.executeUpdate(prepStmt);
7385 
7386  /*
7387  * Create a layout file representation of the carved file.
7388  */
7389  fileRangeLayoutFiles.add(new LayoutFile(this,
7390  fileRangeId,
7391  parent.getId(),
7392  Long.toString(fileRange.getSequence()),
7397  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7398  fileRange.getByteLen(),
7399  0L, 0L, 0L, 0L,
7400  null, null,
7402  parent.getUniquePath(),
7403  null,
7404  OsAccount.NO_OWNER_ID,
7405  OsAccount.NO_ACCOUNT));
7406  }
7407 
7408  transaction.commit();
7409  transaction = null;
7410  return fileRangeLayoutFiles;
7411 
7412  } catch (SQLException ex) {
7413  throw new TskCoreException("Failed to add layout files to case database", ex);
7414  } finally {
7415  closeResultSet(resultSet);
7416  closeStatement(statement);
7417 
7418  if (null != transaction) {
7419  try {
7420  transaction.rollback();
7421  } catch (TskCoreException ex2) {
7422  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7423  }
7424  }
7425  }
7426  }
7427 
7439  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
7440  assert (null != carvingResult);
7441  if (null == carvingResult) {
7442  throw new TskCoreException("Carving is null");
7443  }
7444  assert (null != carvingResult.getParent());
7445  if (null == carvingResult.getParent()) {
7446  throw new TskCoreException("Carving result has null parent");
7447  }
7448  assert (null != carvingResult.getCarvedFiles());
7449  if (null == carvingResult.getCarvedFiles()) {
7450  throw new TskCoreException("Carving result has null carved files");
7451  }
7452  CaseDbTransaction transaction = null;
7453  Statement statement = null;
7454  ResultSet resultSet = null;
7455  try {
7456 
7457  /*
7458  * Carved files are "re-parented" as children of the $CarvedFiles
7459  * virtual directory of the root file system, volume, or image
7460  * ancestor of the carved files parent, but if no such ancestor is
7461  * found, then the parent specified in the carving result is used.
7462  */
7463  Content root = carvingResult.getParent();
7464  while (null != root) {
7465  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
7466  break;
7467  }
7468  root = root.getParent();
7469  }
7470  if (null == root) {
7471  root = carvingResult.getParent();
7472  }
7473 
7474  /*
7475  * Get or create the $CarvedFiles virtual directory for the root
7476  * ancestor.
7477  */
7478  VirtualDirectory carvedFilesDir;
7479  synchronized(carvedFileDirsLock) {
7480  carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
7481  if (null == carvedFilesDir) {
7482  List<Content> rootChildren;
7483  if (root instanceof FileSystem) {
7484  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
7485  } else {
7486  rootChildren = root.getChildren();
7487  }
7488  for (Content child : rootChildren) {
7489  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
7490  carvedFilesDir = (VirtualDirectory) child;
7491  break;
7492  }
7493  }
7494  if (null == carvedFilesDir) {
7495  long parId = root.getId();
7496  // $CarvedFiles should be a child of the root directory, not the file system
7497  if (root instanceof FileSystem) {
7498  Content rootDir = ((FileSystem) root).getRootDirectory();
7499  parId = rootDir.getId();
7500  }
7501  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
7502  }
7503  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDir);
7504  }
7505  }
7506 
7507  /*
7508  * Add the carved files to the database as children of the
7509  * $CarvedFile directory of the root ancestor.
7510  */
7511  transaction = beginTransaction();
7512  CaseDbConnection connection = transaction.getConnection();
7513  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
7514  List<LayoutFile> carvedFiles = new ArrayList<>();
7515  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
7516  /*
7517  * Insert a row for the carved file into the tsk_objects table:
7518  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7519  */
7520  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7521 
7522  /*
7523  * Insert a row for the carved file into the tsk_files table:
7524  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7525  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7526  * ctime, crtime, atime, mtime, md5, known, mime_type,
7527  * parent_path, data_source_obj_id,extenion, owner_uid,
7528  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7529  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7530  */
7531  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7532  prepStmt.clearParameters();
7533  prepStmt.setLong(1, carvedFileId); // obj_id
7534  if (root instanceof FileSystem) {
7535  prepStmt.setLong(2, root.getId()); // fs_obj_id
7536  } else {
7537  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7538  }
7539  prepStmt.setString(3, carvedFile.getName()); // name
7540  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
7541  prepStmt.setShort(5, (short) 1); // has_path
7542  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7543  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7544  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7545  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7546  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
7547  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7548  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7549  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7550  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7551  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7552  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7553  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7554  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
7555  prepStmt.setString(19, parentPath); // parent path
7556  prepStmt.setLong(20, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
7557  prepStmt.setString(21, extractExtension(carvedFile.getName())); //extension
7558 
7559  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7560  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7561 
7562  connection.executeUpdate(prepStmt);
7563 
7564  /*
7565  * Insert a row in the tsk_layout_file table for each chunk of
7566  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7567  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7568  */
7569  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7570  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
7571  prepStmt.clearParameters();
7572  prepStmt.setLong(1, carvedFileId); // obj_id
7573  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7574  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7575  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7576  connection.executeUpdate(prepStmt);
7577  }
7578 
7579  /*
7580  * Create a layout file representation of the carved file.
7581  */
7582  carvedFiles.add(new LayoutFile(this,
7583  carvedFileId,
7584  carvedFilesDir.getDataSourceObjectId(),
7585  carvedFile.getName(),
7590  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7591  carvedFile.getSizeInBytes(),
7592  0L, 0L, 0L, 0L,
7593  null, null,
7595  parentPath,
7596  null,
7597  OsAccount.NO_OWNER_ID,
7598  OsAccount.NO_ACCOUNT));
7599  }
7600 
7601  transaction.commit();
7602  transaction = null;
7603  return carvedFiles;
7604 
7605  } catch (SQLException ex) {
7606  throw new TskCoreException("Failed to add carved files to case database", ex);
7607  } finally {
7608  closeResultSet(resultSet);
7609  closeStatement(statement);
7610 
7611  if (null != transaction) {
7612  try {
7613  transaction.rollback();
7614  } catch (TskCoreException ex2) {
7615  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7616  }
7617  }
7618  }
7619  }
7620 
7651  public DerivedFile addDerivedFile(String fileName, String localPath,
7652  long size, long ctime, long crtime, long atime, long mtime,
7653  boolean isFile, Content parentObj,
7654  String rederiveDetails, String toolName, String toolVersion,
7655  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7656  CaseDbTransaction transaction = beginTransaction();
7657  try {
7658  DerivedFile df = addDerivedFile(fileName, localPath,
7659  size, ctime, crtime, atime, mtime,
7660  isFile, parentObj,
7661  rederiveDetails, toolName, toolVersion,
7662  otherDetails, encodingType, transaction);
7663  transaction.commit();
7664  return df;
7665  } catch (TskCoreException ex) {
7666  transaction.rollback();
7667  throw ex;
7668  }
7669  }
7670 
7671  public DerivedFile addDerivedFile(String fileName, String localPath,
7672  long size, long ctime, long crtime, long atime, long mtime,
7673  boolean isFile, Content parentObj,
7674  String rederiveDetails, String toolName, String toolVersion,
7675  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
7676  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7677  localPath = localPath.replaceAll("^[/\\\\]+", "");
7678 
7679  TimelineManager timelineManager = getTimelineManager();
7680 
7681  CaseDbConnection connection = transaction.getConnection();
7682  try {
7683  final long parentId = parentObj.getId();
7684  String parentPath = "";
7685  if (parentObj instanceof BlackboardArtifact) {
7686  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7687  } else if (parentObj instanceof AbstractFile) {
7688  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7689  }
7690 
7691  // Insert a row for the derived file into the tsk_objects table.
7692  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7693  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7694 
7695  // Insert a row for the virtual directory into the tsk_files table.
7696  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
7697  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
7698  // parent_path, data_source_obj_id, extension)
7699  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
7700  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7701  statement.clearParameters();
7702  statement.setLong(1, newObjId);
7703 
7704  // If the parentFile is part of a file system, use its file system object ID.
7705  long fsObjId = this.getFileSystemId(parentId, connection);
7706  if (fsObjId != -1) {
7707  statement.setLong(2, fsObjId);
7708  } else {
7709  statement.setNull(2, java.sql.Types.BIGINT);
7710  }
7711  statement.setString(3, fileName);
7712 
7713  //type, has_path
7714  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7715  statement.setShort(5, (short) 1);
7716 
7717  //flags
7719  statement.setShort(6, dirType.getValue());
7721  statement.setShort(7, metaType.getValue());
7722 
7723  //note: using alloc under assumption that derived files derive from alloc files
7725  statement.setShort(8, dirFlag.getValue());
7726  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7727  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7728  statement.setShort(9, metaFlags);
7729 
7730  //size
7731  //prevent negative size
7732  long savedSize = size < 0 ? 0 : size;
7733  statement.setLong(10, savedSize);
7734 
7735  //mactimes
7736  //long ctime, long crtime, long atime, long mtime,
7737  statement.setLong(11, ctime);
7738  statement.setLong(12, crtime);
7739  statement.setLong(13, atime);
7740  statement.setLong(14, mtime);
7741 
7742  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
7743  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7744  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7745  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
7746 
7747  //parent path
7748  statement.setString(19, parentPath);
7749 
7750  // root data source object id
7751  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
7752  statement.setLong(20, dataSourceObjId);
7753  final String extension = extractExtension(fileName);
7754  //extension
7755  statement.setString(21, extension);
7756 
7757  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7758  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7759 
7760  connection.executeUpdate(statement);
7761 
7762  //add localPath
7763  addFilePath(connection, newObjId, localPath, encodingType);
7764 
7765  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7766  savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
7767 
7768  timelineManager.addEventsForNewFile(derivedFile, connection);
7769 
7770  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
7771  return derivedFile;
7772  } catch (SQLException ex) {
7773  throw new TskCoreException("Failed to add derived file to case database", ex);
7774  }
7775  }
7776 
7807  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7808  long size, long ctime, long crtime, long atime, long mtime,
7809  boolean isFile, String mimeType,
7810  String rederiveDetails, String toolName, String toolVersion,
7811  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7812 
7813  CaseDbTransaction trans = null;
7814  try {
7815  Content parentObj = derivedFile.getParent();
7816 
7817  trans = beginTransaction();
7818  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
7819  size, ctime, crtime, atime, mtime,
7820  isFile, mimeType,
7821  rederiveDetails, toolName, toolVersion,
7822  otherDetails, encodingType, parentObj, trans);
7823  trans.commit();
7824  return updatedFile;
7825  } catch (TskCoreException ex) {
7826  if (trans != null) {
7827  trans.rollback();
7828  }
7829  throw ex;
7830  }
7831  }
7832 
7833  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7834  long size, long ctime, long crtime, long atime, long mtime,
7835  boolean isFile, String mimeType,
7836  String rederiveDetails, String toolName, String toolVersion,
7837  String otherDetails, TskData.EncodingType encodingType,
7838  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
7839 
7840  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7841  localPath = localPath.replaceAll("^[/\\\\]+", "");
7842 
7843  ResultSet rs = null;
7844  try {
7845  final long parentId = parentObj.getId();
7846  String parentPath = "";
7847  if (parentObj instanceof BlackboardArtifact) {
7848  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7849  } else if (parentObj instanceof AbstractFile) {
7850  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7851  }
7852  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
7853  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
7854  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
7855  statement.clearParameters();
7856 
7857  //type
7858  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7859 
7860  //flags
7862  statement.setShort(2, dirType.getValue());
7864  statement.setShort(3, metaType.getValue());
7865 
7866  //note: using alloc under assumption that derived files derive from alloc files
7868  statement.setShort(4, dirFlag.getValue());
7869  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7870  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7871  statement.setShort(5, metaFlags);
7872 
7873  //size
7874  //prevent negative size
7875  long savedSize = size < 0 ? 0 : size;
7876  statement.setLong(6, savedSize);
7877 
7878  //mactimes
7879  //long ctime, long crtime, long atime, long mtime,
7880  statement.setLong(7, ctime);
7881  statement.setLong(8, crtime);
7882  statement.setLong(9, atime);
7883  statement.setLong(10, mtime);
7884  statement.setString(11, mimeType);
7885  statement.setString(12, String.valueOf(derivedFile.getId()));
7886  trans.getConnection().executeUpdate(statement);
7887 
7888  //add localPath
7889  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
7890 
7891  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
7892  final String extension = extractExtension(derivedFile.getName());
7893  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
7894  savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
7895  } catch (SQLException ex) {
7896  throw new TskCoreException("Failed to add derived file to case database", ex);
7897  } finally {
7898  closeResultSet(rs);
7899  }
7900  }
7901 
7921  public LocalFile addLocalFile(String fileName, String localPath,
7922  long size, long ctime, long crtime, long atime, long mtime,
7923  boolean isFile, TskData.EncodingType encodingType,
7924  AbstractFile parent) throws TskCoreException {
7925 
7926  CaseDbTransaction localTrans = beginTransaction();
7927  try {
7928  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
7929  localTrans.commit();
7930  localTrans = null;
7931  return created;
7932  } finally {
7933  if (null != localTrans) {
7934  try {
7935  localTrans.rollback();
7936  } catch (TskCoreException ex2) {
7937  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7938  }
7939  }
7940  }
7941  }
7942 
7967  public LocalFile addLocalFile(String fileName, String localPath,
7968  long size, long ctime, long crtime, long atime, long mtime,
7969  boolean isFile, TskData.EncodingType encodingType,
7970  Content parent, CaseDbTransaction transaction) throws TskCoreException {
7971 
7972  return addLocalFile(fileName, localPath,
7973  size, ctime, crtime, atime, mtime,
7974  null, null, null,
7975  isFile, encodingType,
7976  parent, transaction);
7977  }
8006  public LocalFile addLocalFile(String fileName, String localPath,
8007  long size, long ctime, long crtime, long atime, long mtime,
8008  String md5, String sha256, FileKnown known, String mimeType,
8009  boolean isFile, TskData.EncodingType encodingType,
8010  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8011 
8012  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8013  md5, sha256, known, mimeType, isFile, encodingType,
8014  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8015 
8016  }
8047  public LocalFile addLocalFile(String fileName, String localPath,
8048  long size, long ctime, long crtime, long atime, long mtime,
8049  String md5, String sha256, FileKnown known, String mimeType,
8050  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8051  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8052  CaseDbConnection connection = transaction.getConnection();
8053  Statement queryStatement = null;
8054  try {
8055 
8056  // Insert a row for the local/logical file into the tsk_objects table.
8057  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8058  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8059 
8060  // Insert a row for the local/logical file into the tsk_files table.
8061  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8062  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
8063  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8064  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
8065  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8066  statement.clearParameters();
8067  statement.setLong(1, objectId);
8068  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8069  statement.setString(3, fileName);
8070  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8071  statement.setShort(5, (short) 1);
8073  statement.setShort(6, dirType.getValue());
8075  statement.setShort(7, metaType.getValue());
8077  statement.setShort(8, dirFlag.getValue());
8078  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8079  statement.setShort(9, metaFlags);
8080  //prevent negative size
8081  long savedSize = size < 0 ? 0 : size;
8082  statement.setLong(10, savedSize);
8083  statement.setLong(11, ctime);
8084  statement.setLong(12, crtime);
8085  statement.setLong(13, atime);
8086  statement.setLong(14, mtime);
8087  statement.setString(15, md5);
8088  statement.setString(16, sha256);
8089  if (known != null) {
8090  statement.setByte(17, known.getFileKnownValue());
8091  } else {
8092  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue());
8093  }
8094  statement.setString(18, mimeType);
8095  String parentPath;
8096  long dataSourceObjId;
8097 
8098  if (parent instanceof AbstractFile) {
8099  AbstractFile parentFile = (AbstractFile) parent;
8100  if (isRootDirectory(parentFile, transaction)) {
8101  parentPath = "/";
8102  } else {
8103  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8104  }
8105  dataSourceObjId = parentFile.getDataSourceObjectId();
8106  } else {
8107  parentPath = "/";
8108  dataSourceObjId = getDataSourceObjectId(connection, parent);
8109  }
8110  statement.setString(19, parentPath);
8111  statement.setLong(20, dataSourceObjId);
8112  final String extension = extractExtension(fileName);
8113  statement.setString(21, extension);
8114 
8115  if (ownerAccount != null) {
8116  statement.setString(22, ownerAccount); // ownerUid
8117  } else {
8118  statement.setNull(22, java.sql.Types.VARCHAR);
8119  }
8120 
8121  if (osAccountId != null) {
8122  statement.setLong(23, osAccountId); // osAccountObjId
8123  } else {
8124  statement.setNull(23, java.sql.Types.BIGINT);
8125  }
8126 
8127  connection.executeUpdate(statement);
8128  addFilePath(connection, objectId, localPath, encodingType);
8129  LocalFile localFile = new LocalFile(this,
8130  objectId,
8131  fileName,
8133  dirType,
8134  metaType,
8135  dirFlag,
8136  metaFlags,
8137  savedSize,
8138  ctime, crtime, atime, mtime,
8139  mimeType, md5, sha256, known,
8140  parent.getId(), parentPath,
8141  dataSourceObjId,
8142  localPath,
8143  encodingType, extension,
8144  ownerAccount, osAccountId);
8145  getTimelineManager().addEventsForNewFile(localFile, connection);
8146  return localFile;
8147 
8148  } catch (SQLException ex) {
8149  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);
8150  } finally {
8151  closeStatement(queryStatement);
8152  }
8153  }
8154 
8160  private class RootDirectoryKey {
8161 
8162  private long dataSourceId;
8163  private Long fileSystemId;
8164 
8165  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8166  this.dataSourceId = dataSourceId;
8167  this.fileSystemId = fileSystemId;
8168  }
8169 
8170  @Override
8171  public int hashCode() {
8172  int hash = 7;
8173  hash = 41 * hash + Objects.hashCode(dataSourceId);
8174  hash = 41 * hash + Objects.hashCode(fileSystemId);
8175  return hash;
8176  }
8177 
8178  @Override
8179  public boolean equals(Object obj) {
8180  if (this == obj) {
8181  return true;
8182  }
8183  if (obj == null) {
8184  return false;
8185  }
8186  if (getClass() != obj.getClass()) {
8187  return false;
8188  }
8189 
8190  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8191  if (dataSourceId != otherKey.dataSourceId) {
8192  return false;
8193  }
8194 
8195  if (fileSystemId != null) {
8196  return fileSystemId.equals(otherKey.fileSystemId);
8197  }
8198  return (otherKey.fileSystemId == null);
8199  }
8200  }
8201 
8214  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8215 
8216  // First check if we know the root directory for this data source and optionally
8217  // file system. There is only one root, so if we know it we can simply compare
8218  // this file ID to the known root directory.
8219  Long fsObjId = null;
8220  if (file instanceof FsContent) {
8221  fsObjId = ((FsContent) file).getFileSystemId();
8222  }
8223  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8224  synchronized (rootDirectoryMapLock) {
8225  if (rootDirectoryMap.containsKey(key)) {
8226  return rootDirectoryMap.get(key).equals(file.getId());
8227  }
8228  }
8229 
8230  // Fallback cache. We store the result of each database lookup
8231  // so it won't be done multiple times in a row. In practice, this will
8232  // only be used if this method was never called on the root directory.
8233  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8234  if (isRoot != null) {
8235  return isRoot;
8236  }
8237 
8238  CaseDbConnection connection = transaction.getConnection();
8239  Statement statement = null;
8240  ResultSet resultSet = null;
8241 
8242  try {
8243  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8244  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8245  + "WHERE ChildRow.obj_id = %s;", file.getId());
8246 
8247  statement = connection.createStatement();
8248  resultSet = statement.executeQuery(query);
8249  if (resultSet.next()) {
8250  long parentId = resultSet.getLong("parent_object_id");
8251  if (parentId == 0) {
8252  return true;
8253  }
8254  int type = resultSet.getInt("parent_type");
8255  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8256  || type == TskData.ObjectType.VS.getObjectType()
8257  || type == TskData.ObjectType.VOL.getObjectType()
8258  || type == TskData.ObjectType.FS.getObjectType();
8259  if (result == true) {
8260  synchronized (rootDirectoryMapLock) {
8261  // This is a root directory so save it
8262  rootDirectoryMap.put(key, file.getId());
8263  }
8264  }
8265  isRootDirectoryCache.put(file.getId(), result);
8266  return result;
8267 
8268  } else {
8269  // This is a root directory so save it
8270  synchronized (rootDirectoryMapLock) {
8271  rootDirectoryMap.put(key, file.getId());
8272  }
8273  isRootDirectoryCache.put(file.getId(), true);
8274 
8275  return true; // The file has no parent
8276 
8277  }
8278  } catch (SQLException ex) {
8279  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
8280  } finally {
8281  closeResultSet(resultSet);
8282  closeStatement(statement);
8283  }
8284  }
8285 
8305  public LayoutFile addLayoutFile(String fileName,
8306  long size,
8307  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
8308  long ctime, long crtime, long atime, long mtime,
8309  List<TskFileRange> fileRanges,
8310  Content parent) throws TskCoreException {
8311 
8312  if (null == parent) {
8313  throw new TskCoreException("Parent can not be null");
8314  }
8315 
8316  String parentPath;
8317  if (parent instanceof AbstractFile) {
8318  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
8319  } else {
8320  parentPath = "/";
8321  }
8322 
8323  CaseDbTransaction transaction = null;
8324  Statement statement = null;
8325  ResultSet resultSet = null;
8326  try {
8327  transaction = beginTransaction();
8328  CaseDbConnection connection = transaction.getConnection();
8329 
8330  /*
8331  * Insert a row for the layout file into the tsk_objects table:
8332  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8333  */
8334  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8335 
8336  /*
8337  * Insert a row for the file into the tsk_files table: INSERT INTO
8338  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
8339  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
8340  * mtime, md5, known, mime_type, parent_path,
8341  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
8342  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8343  */
8344  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8345  prepStmt.clearParameters();
8346  prepStmt.setLong(1, newFileId); // obj_id
8347 
8348  // If the parent is part of a file system, grab its file system ID
8349  if (0 != parent.getId()) {
8350  long parentFs = this.getFileSystemId(parent.getId(), connection);
8351  if (parentFs != -1) {
8352  prepStmt.setLong(2, parentFs);
8353  } else {
8354  prepStmt.setNull(2, java.sql.Types.BIGINT);
8355  }
8356  } else {
8357  prepStmt.setNull(2, java.sql.Types.BIGINT);
8358  }
8359  prepStmt.setString(3, fileName); // name
8360  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
8361  prepStmt.setShort(5, (short) 0); // has_path
8362  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8363  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8364  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
8365  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
8366  //prevent negative size
8367  long savedSize = size < 0 ? 0 : size;
8368  prepStmt.setLong(10, savedSize); // size
8369  prepStmt.setLong(11, ctime); // ctime
8370  prepStmt.setLong(12, crtime); // crtime
8371  prepStmt.setLong(13, atime); // atime
8372  prepStmt.setLong(14, mtime); // mtime
8373  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8374  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8375  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8376  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
8377  prepStmt.setString(19, parentPath); // parent path
8378  prepStmt.setLong(20, parent.getDataSource().getId()); // data_source_obj_id
8379 
8380  prepStmt.setString(21, extractExtension(fileName)); //extension
8381 
8382  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
8383  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
8384 
8385  connection.executeUpdate(prepStmt);
8386 
8387  /*
8388  * Insert a row in the tsk_layout_file table for each chunk of the
8389  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
8390  * byte_len, sequence) VALUES (?, ?, ?, ?)
8391  */
8392  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8393  for (TskFileRange tskFileRange : fileRanges) {
8394  prepStmt.clearParameters();
8395  prepStmt.setLong(1, newFileId); // obj_id
8396  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8397  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8398  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8399  connection.executeUpdate(prepStmt);
8400  }
8401 
8402  /*
8403  * Create a layout file representation of the carved file.
8404  */
8405  LayoutFile layoutFile = new LayoutFile(this,
8406  newFileId,
8407  parent.getDataSource().getId(),
8408  fileName,
8412  dirFlag,
8413  metaFlag.getValue(),
8414  savedSize,
8415  ctime, crtime, atime, mtime,
8416  null, null,
8418  parentPath,
8419  null,
8420  OsAccount.NO_OWNER_ID,
8421  OsAccount.NO_ACCOUNT);
8422 
8423  transaction.commit();
8424  transaction = null;
8425  return layoutFile;
8426 
8427  } catch (SQLException ex) {
8428  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
8429  } finally {
8430  closeResultSet(resultSet);
8431  closeStatement(statement);
8432 
8433  if (null != transaction) {
8434  try {
8435  transaction.rollback();
8436  } catch (TskCoreException ex2) {
8437  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8438  }
8439  }
8440  }
8441  }
8442 
8452  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
8453  if (content == null) {
8454  throw new TskCoreException("Null Content parameter given");
8455  }
8456  if (content instanceof AbstractFile) {
8457  return ((AbstractFile)content).getDataSourceObjectId();
8458  } else {
8459  return getDataSourceObjectId(connection, content.getId());
8460  }
8461  }
8462 
8475  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
8477  Statement statement = null;
8478  ResultSet resultSet = null;
8479  try {
8480  statement = connection.createStatement();
8481  long dataSourceObjId;
8482  long ancestorId = objectId;
8483  do {
8484  dataSourceObjId = ancestorId;
8485  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
8486  resultSet = statement.executeQuery(query);
8487  if (resultSet.next()) {
8488  ancestorId = resultSet.getLong("par_obj_id");
8489  } else {
8490  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
8491  }
8492  resultSet.close();
8493  resultSet = null;
8494  } while (0 != ancestorId); // Not NULL
8495  return dataSourceObjId;
8496  } catch (SQLException ex) {
8497  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
8498  } finally {
8499  closeResultSet(resultSet);
8500  closeStatement(statement);
8502  }
8503  }
8504 
8516  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8517  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
8518  statement.clearParameters();
8519  statement.setLong(1, objId);
8520  statement.setString(2, path);
8521  statement.setInt(3, type.getType());
8522  connection.executeUpdate(statement);
8523  }
8524 
8536  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8537  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
8538  statement.clearParameters();
8539  statement.setString(1, path);
8540  statement.setInt(2, type.getType());
8541  statement.setLong(3, objId);
8542  connection.executeUpdate(statement);
8543  }
8544 
8558  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
8559  String ext = "";
8560  if (!containsLikeWildcard(fileName)) {
8561  ext = SleuthkitCase.extractExtension(fileName);
8562  }
8563 
8564  CaseDbConnection connection = null;
8565  ResultSet rs = null;
8566  long parentId = parentFile.getId();
8567 
8569  try {
8570  connection = connections.getConnection();
8571 
8572  PreparedStatement statement;
8573  if (ext.isEmpty()) {
8574  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
8575  statement.clearParameters();
8576  statement.setLong(1, parentId);
8577  statement.setString(2, fileName);
8578  } else {
8579  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
8580  statement.clearParameters();
8581  statement.setString(1, ext);
8582  statement.setLong(2, parentId);
8583  statement.setString(3, fileName);
8584  }
8585 
8586  rs = connection.executeQuery(statement);
8587  return resultSetToAbstractFiles(rs, connection);
8588  } catch (SQLException ex) {
8589  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
8590  } finally {
8591  closeResultSet(rs);
8592  closeConnection(connection);
8594  }
8595  }
8596 
8608  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
8609  CaseDbConnection connection = null;
8610  Statement s = null;
8611  ResultSet rs = null;
8613  try {
8614  connection = connections.getConnection();
8615  s = connection.createStatement();
8616  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8617  rs.next();
8618  return rs.getLong("count");
8619  } catch (SQLException e) {
8620  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
8621  } finally {
8622  closeResultSet(rs);
8623  closeStatement(s);
8624  closeConnection(connection);
8626  }
8627  }
8628 
8646  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
8647  CaseDbConnection connection = null;
8648  Statement s = null;
8649  ResultSet rs = null;
8651  try {
8652  connection = connections.getConnection();
8653  s = connection.createStatement();
8654  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8655  return resultSetToAbstractFiles(rs, connection);
8656  } catch (SQLException e) {
8657  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
8658  } finally {
8659  closeResultSet(rs);
8660  closeStatement(s);
8661  closeConnection(connection);
8663  }
8664  }
8665 
8684  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
8685  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";
8687  try (CaseDbConnection connection = connections.getConnection()) {
8688  String query = String.format(queryTemplate, parentId, sqlWhereClause);
8689  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
8690  return resultSetToAbstractFiles(rs, connection);
8691  } catch (SQLException ex) {
8692  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
8693  }
8694  } finally {
8696  }
8697  }
8698 
8711  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
8712  CaseDbConnection connection = null;
8713  Statement s = null;
8714  ResultSet rs = null;
8716  try {
8717  connection = connections.getConnection();
8718  s = connection.createStatement();
8719  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8720  List<Long> ret = new ArrayList<>();
8721  while (rs.next()) {
8722  ret.add(rs.getLong("obj_id"));
8723  }
8724  return ret;
8725  } catch (SQLException e) {
8726  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
8727  } finally {
8728  closeResultSet(rs);
8729  closeStatement(s);
8730  closeConnection(connection);
8732  }
8733  }
8734 
8746  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
8747 
8748  // get the non-unique path (strip of image and volume path segments, if
8749  // the exist.
8750  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
8751 
8752  // split the file name from the parent path
8753  int lastSlash = path.lastIndexOf('/'); //NON-NLS
8754 
8755  // if the last slash is at the end, strip it off
8756  if (lastSlash == path.length()) {
8757  path = path.substring(0, lastSlash - 1);
8758  lastSlash = path.lastIndexOf('/'); //NON-NLS
8759  }
8760 
8761  String parentPath = path.substring(0, lastSlash);
8762  String fileName = path.substring(lastSlash);
8763 
8764  return findFiles(dataSource, fileName, parentPath);
8765  }
8766 
8777  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
8778  CaseDbConnection connection = null;
8779  Statement s = null;
8780  ResultSet rs = null;
8782  try {
8783  connection = connections.getConnection();
8784  s = connection.createStatement();
8785  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
8786  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
8787  while (rs.next()) {
8788  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
8789  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
8790  ranges.add(range);
8791  }
8792  return ranges;
8793  } catch (SQLException ex) {
8794  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
8795  } finally {
8796  closeResultSet(rs);
8797  closeStatement(s);
8798  closeConnection(connection);
8800  }
8801  }
8802 
8813  public Image getImageById(long id) throws TskCoreException {
8814  CaseDbConnection connection = null;
8815  Statement s = null;
8816  ResultSet rs = null;
8818  try {
8819  connection = connections.getConnection();
8820  s = connection.createStatement();
8821  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 "
8822  + "FROM tsk_image_info "
8823  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
8824  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
8825  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
8826 
8827  List<String> imagePaths = new ArrayList<>();
8828  long type, ssize, size;
8829  String tzone, md5, sha1, sha256, name, device_id, imagePath;
8830 
8831  if (rs.next()) {
8832  imagePath = rs.getString("name");
8833  if (imagePath != null) {
8834  imagePaths.add(imagePath);
8835  }
8836  type = rs.getLong("type"); //NON-NLS
8837  ssize = rs.getLong("ssize"); //NON-NLS
8838  tzone = rs.getString("tzone"); //NON-NLS
8839  size = rs.getLong("size"); //NON-NLS
8840  md5 = rs.getString("md5"); //NON-NLS
8841  sha1 = rs.getString("sha1"); //NON-NLS
8842  sha256 = rs.getString("sha256"); //NON-NLS
8843  name = rs.getString("display_name");
8844  if (name == null) {
8845  if (imagePaths.size() > 0) {
8846  String path = imagePaths.get(0);
8847  name = (new java.io.File(path)).getName();
8848  } else {
8849  name = "";
8850  }
8851  }
8852  device_id = rs.getString("device_id");
8853  } else {
8854  throw new TskCoreException("No image found for id: " + id);
8855  }
8856 
8857  // image can have multiple paths, therefore there can be multiple rows in the result set
8858  while (rs.next()) {
8859  imagePath = rs.getString("name");
8860  if (imagePath != null) {
8861  imagePaths.add(imagePath);
8862  }
8863  }
8864 
8865  return new Image(this, id, type, device_id, ssize, name,
8866  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
8867  } catch (SQLException ex) {
8868  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
8869  } finally {
8870  closeResultSet(rs);
8871  closeStatement(s);
8872  closeConnection(connection);
8874  }
8875  }
8876 
8888  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
8889  CaseDbConnection connection = null;
8890  Statement s = null;
8891  ResultSet rs = null;
8893  try {
8894  connection = connections.getConnection();
8895  s = connection.createStatement();
8896  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
8897  + "where obj_id = " + id); //NON-NLS
8898  if (rs.next()) {
8899  long type = rs.getLong("vs_type"); //NON-NLS
8900  long imgOffset = rs.getLong("img_offset"); //NON-NLS
8901  long blockSize = rs.getLong("block_size"); //NON-NLS
8902  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
8903  vs.setParent(parent);
8904  return vs;
8905  } else {
8906  throw new TskCoreException("No volume system found for id:" + id);
8907  }
8908  } catch (SQLException ex) {
8909  throw new TskCoreException("Error getting Volume System by ID.", ex);
8910  } finally {
8911  closeResultSet(rs);
8912  closeStatement(s);
8913  closeConnection(connection);
8915  }
8916  }
8917 
8926  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
8927  VolumeSystem vs = getVolumeSystemById(id, null);
8928  vs.setParentId(parentId);
8929  return vs;
8930  }
8931 
8943  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
8944  return getFileSystemByIdHelper(id, parent);
8945  }
8946 
8955  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
8956  Volume vol = null;
8957  FileSystem fs = getFileSystemById(id, vol);
8958  fs.setParentId(parentId);
8959  return fs;
8960  }
8961 
8973  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
8974  return getFileSystemByIdHelper(id, parent);
8975  }
8976 
8988  Pool getPoolById(long id, Content parent) throws TskCoreException {
8989  return getPoolByIdHelper(id, parent);
8990  }
8991 
9000  Pool getPoolById(long id, long parentId) throws TskCoreException {
9001  Pool pool = getPoolById(id, null);
9002  pool.setParentId(parentId);
9003  return pool;
9004  }
9005 
9017  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9018 
9020  try (CaseDbConnection connection = connections.getConnection();
9021  Statement s = connection.createStatement();
9022  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9023  + "where obj_id = " + id);) { //NON-NLS
9024  if (rs.next()) {
9025  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9026  pool.setParent(parent);
9027 
9028  return pool;
9029  } else {
9030  throw new TskCoreException("No pool found for ID:" + id);
9031  }
9032  } catch (SQLException ex) {
9033  throw new TskCoreException("Error getting Pool by ID", ex);
9034  } finally {
9036  }
9037  }
9038 
9050  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9051  // see if we already have it
9052  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9053  // but it should be the same...
9054  synchronized (fileSystemIdMap) {
9055  if (fileSystemIdMap.containsKey(id)) {
9056  return fileSystemIdMap.get(id);
9057  }
9058  }
9059  CaseDbConnection connection = null;
9060  Statement s = null;
9061  ResultSet rs = null;
9063  try {
9064  connection = connections.getConnection();
9065  s = connection.createStatement();
9066  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9067  + "where obj_id = " + id); //NON-NLS
9068  if (rs.next()) {
9069  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9070  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9071  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9072  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9073  fs.setParent(parent);
9074  // save it for the next call
9075  synchronized (fileSystemIdMap) {
9076  fileSystemIdMap.put(id, fs);
9077  }
9078  return fs;
9079  } else {
9080  throw new TskCoreException("No file system found for id:" + id);
9081  }
9082  } catch (SQLException ex) {
9083  throw new TskCoreException("Error getting File System by ID", ex);
9084  } finally {
9085  closeResultSet(rs);
9086  closeStatement(s);
9087  closeConnection(connection);
9089  }
9090  }
9091 
9103  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9104  CaseDbConnection connection = null;
9105  Statement s = null;
9106  ResultSet rs = null;
9108  try {
9109  connection = connections.getConnection();
9110  s = connection.createStatement();
9111  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9112  + "where obj_id = " + id); //NON-NLS
9113  if (rs.next()) {
9121  String description;
9122  try {
9123  description = rs.getString("desc");
9124  } catch (Exception ex) {
9125  description = rs.getString("descr");
9126  }
9127  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9128  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9129  description);
9130  vol.setParent(parent);
9131  return vol;
9132  } else {
9133  throw new TskCoreException("No volume found for id:" + id);
9134  }
9135  } catch (SQLException ex) {
9136  throw new TskCoreException("Error getting Volume by ID", ex);
9137  } finally {
9138  closeResultSet(rs);
9139  closeStatement(s);
9140  closeConnection(connection);
9142  }
9143  }
9144 
9153  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9154  Volume vol = getVolumeById(id, null);
9155  vol.setParentId(parentId);
9156  return vol;
9157  }
9158 
9170  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9171  CaseDbConnection connection = null;
9172  Statement s = null;
9173  ResultSet rs = null;
9175  try {
9176  connection = connections.getConnection();
9177  s = connection.createStatement();
9178  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9179  + "WHERE obj_id = " + id);
9180  Directory temp = null; //NON-NLS
9181  if (rs.next()) {
9182  final short type = rs.getShort("type"); //NON-NLS
9183  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9184  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9185  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9186  temp = directory(rs, parentFs);
9187  }
9188  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9189  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9190  }
9191  } else {
9192  throw new TskCoreException("No Directory found for id:" + id);
9193  }
9194  return temp;
9195  } catch (SQLException ex) {
9196  throw new TskCoreException("Error getting Directory by ID", ex);
9197  } finally {
9198  closeResultSet(rs);
9199  closeStatement(s);
9200  closeConnection(connection);
9202  }
9203  }
9204 
9214  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9215  List<FileSystem> fileSystems = new ArrayList<>();
9216  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9217 
9218  CaseDbConnection connection = null;
9219  Statement s = null;
9220  ResultSet rs = null;
9222  try {
9223  connection = connections.getConnection();
9224  s = connection.createStatement();
9225  rs = connection.executeQuery(s, queryStr); //NON-NLS
9226  while (rs.next()) {
9227  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9228  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9229  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9230  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9231  fs.setParent(null);
9232  fileSystems.add(fs);
9233  }
9234  } catch (SQLException ex) {
9235  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9236  } finally {
9237  closeResultSet(rs);
9238  closeStatement(s);
9239  closeConnection(connection);
9241  }
9242  return fileSystems;
9243  }
9244 
9255  List<Content> getImageChildren(Image img) throws TskCoreException {
9256  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9257  List<Content> children = new ArrayList<Content>();
9258  for (ObjectInfo info : childInfos) {
9259  if (null != info.type) {
9260  switch (info.type) {
9261  case VS:
9262  children.add(getVolumeSystemById(info.id, img));
9263  break;
9264  case POOL:
9265  children.add(getPoolById(info.id, img));
9266  break;
9267  case FS:
9268  children.add(getFileSystemById(info.id, img));
9269  break;
9270  case ABSTRACTFILE:
9271  AbstractFile f = getAbstractFileById(info.id);
9272  if (f != null) {
9273  children.add(f);
9274  }
9275  break;
9276  case ARTIFACT:
9277  BlackboardArtifact art = getArtifactById(info.id);
9278  if (art != null) {
9279  children.add(art);
9280  }
9281  break;
9282  case REPORT:
9283  // Do nothing for now - see JIRA-3673
9284  break;
9285  default:
9286  throw new TskCoreException("Image has child of invalid type: " + info.type);
9287  }
9288  }
9289  }
9290  return children;
9291  }
9292 
9303  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
9304  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9305  List<Long> children = new ArrayList<Long>();
9306  for (ObjectInfo info : childInfos) {
9307  if (info.type == ObjectType.VS
9308  || info.type == ObjectType.POOL
9309  || info.type == ObjectType.FS
9310  || info.type == ObjectType.ABSTRACTFILE
9311  || info.type == ObjectType.ARTIFACT) {
9312  children.add(info.id);
9313  } else if (info.type == ObjectType.REPORT) {
9314  // Do nothing for now - see JIRA-3673
9315  } else {
9316  throw new TskCoreException("Image has child of invalid type: " + info.type);
9317  }
9318  }
9319  return children;
9320  }
9321 
9332  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
9333  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9334  List<Content> children = new ArrayList<Content>();
9335  for (ObjectInfo info : childInfos) {
9336  if (null != info.type) {
9337  switch (info.type) {
9338  case VS:
9339  children.add(getVolumeSystemById(info.id, pool));
9340  break;
9341  case ABSTRACTFILE:
9342  AbstractFile f = getAbstractFileById(info.id);
9343  if (f != null) {
9344  children.add(f);
9345  }
9346  break;
9347  case ARTIFACT:
9348  BlackboardArtifact art = getArtifactById(info.id);
9349  if (art != null) {
9350  children.add(art);
9351  }
9352  break;
9353  default:
9354  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9355  }
9356  }
9357  }
9358  return children;
9359  }
9360 
9371  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
9372  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9373  List<Long> children = new ArrayList<Long>();
9374  for (ObjectInfo info : childInfos) {
9375  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9376  children.add(info.id);
9377  } else {
9378  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9379  }
9380  }
9381  return children;
9382  }
9383 
9394  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
9395  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9396  List<Content> children = new ArrayList<Content>();
9397  for (ObjectInfo info : childInfos) {
9398  if (null != info.type) {
9399  switch (info.type) {
9400  case VOL:
9401  children.add(getVolumeById(info.id, vs));
9402  break;
9403  case ABSTRACTFILE:
9404  AbstractFile f = getAbstractFileById(info.id);
9405  if (f != null) {
9406  children.add(f);
9407  }
9408  break;
9409  case ARTIFACT:
9410  BlackboardArtifact art = getArtifactById(info.id);
9411  if (art != null) {
9412  children.add(art);
9413  }
9414  break;
9415  default:
9416  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9417  }
9418  }
9419  }
9420  return children;
9421  }
9422 
9433  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
9434  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9435  List<Long> children = new ArrayList<Long>();
9436  for (ObjectInfo info : childInfos) {
9437  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9438  children.add(info.id);
9439  } else {
9440  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9441  }
9442  }
9443  return children;
9444  }
9445 
9456  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
9457  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9458  List<Content> children = new ArrayList<Content>();
9459  for (ObjectInfo info : childInfos) {
9460  if (null != info.type) {
9461  switch (info.type) {
9462  case POOL:
9463  children.add(getPoolById(info.id, vol));
9464  break;
9465  case FS:
9466  children.add(getFileSystemById(info.id, vol));
9467  break;
9468  case ABSTRACTFILE:
9469  AbstractFile f = getAbstractFileById(info.id);
9470  if (f != null) {
9471  children.add(f);
9472  }
9473  break;
9474  case ARTIFACT:
9475  BlackboardArtifact art = getArtifactById(info.id);
9476  if (art != null) {
9477  children.add(art);
9478  }
9479  break;
9480  default:
9481  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9482  }
9483  }
9484  }
9485  return children;
9486  }
9487 
9498  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
9499  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9500  final List<Long> children = new ArrayList<Long>();
9501  for (ObjectInfo info : childInfos) {
9502  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9503  children.add(info.id);
9504  } else {
9505  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9506  }
9507  }
9508  return children;
9509  }
9510 
9524  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
9525  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
9526  }
9527 
9542  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
9543  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this);
9544  return getImageById(imageId);
9545  }
9546 
9556  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
9557  CaseDbConnection connection = null;
9558  Statement s1 = null;
9559  ResultSet rs1 = null;
9561  try {
9562  connection = connections.getConnection();
9563  s1 = connection.createStatement();
9564  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
9565  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
9566  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
9567  while (rs1.next()) {
9568  long obj_id = rs1.getLong("obj_id"); //NON-NLS
9569  String name = rs1.getString("name"); //NON-NLS
9570  List<String> imagePaths = imgPaths.get(obj_id);
9571  if (imagePaths == null) {
9572  List<String> paths = new ArrayList<String>();
9573  if (name != null) {
9574  paths.add(name);
9575  }
9576  imgPaths.put(obj_id, paths);
9577  } else {
9578  if (name != null) {
9579  imagePaths.add(name);
9580  }
9581  }
9582  }
9583  return imgPaths;
9584  } catch (SQLException ex) {
9585  throw new TskCoreException("Error getting image paths.", ex);
9586  } finally {
9587  closeResultSet(rs1);
9588  closeStatement(s1);
9589  closeConnection(connection);
9591  }
9592  }
9593 
9605  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
9606  List<String> imagePaths = new ArrayList<>();
9608  Statement statement = null;
9609  ResultSet resultSet = null;
9610  try {
9611  statement = connection.createStatement();
9612  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
9613  while (resultSet.next()) {
9614  imagePaths.add(resultSet.getString("name"));
9615  }
9616  } catch (SQLException ex) {
9617  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
9618  } finally {
9619  closeResultSet(resultSet);
9620  closeStatement(statement);
9622  }
9623 
9624  return imagePaths;
9625  }
9626 
9633  public List<Image> getImages() throws TskCoreException {
9634  CaseDbConnection connection = null;
9635  Statement s = null;
9636  ResultSet rs = null;
9638  try {
9639  connection = connections.getConnection();
9640  s = connection.createStatement();
9641  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
9642  Collection<Long> imageIDs = new ArrayList<Long>();
9643  while (rs.next()) {
9644  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
9645  }
9646  List<Image> images = new ArrayList<Image>();
9647  for (long id : imageIDs) {
9648  images.add(getImageById(id));
9649  }
9650  return images;
9651  } catch (SQLException ex) {
9652  throw new TskCoreException("Error retrieving images.", ex);
9653  } finally {
9654  closeResultSet(rs);
9655  closeStatement(s);
9656  closeConnection(connection);
9658  }
9659  }
9660 
9671  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
9672  CaseDbConnection connection = null;
9674  PreparedStatement statement;
9675  try {
9676  connection = connections.getConnection();
9677  connection.beginTransaction();
9678  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
9679  statement.clearParameters();
9680  statement.setLong(1, obj_id);
9681  connection.executeUpdate(statement);
9682  for (int i = 0; i < paths.size(); i++) {
9683  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
9684  statement.clearParameters();
9685  statement.setLong(1, obj_id);
9686  statement.setString(2, paths.get(i));
9687  statement.setLong(3, i);
9688  connection.executeUpdate(statement);
9689  }
9690  connection.commitTransaction();
9691  } catch (SQLException ex) {
9692  rollbackTransaction(connection);
9693  throw new TskCoreException("Error updating image paths.", ex);
9694  } finally {
9695  closeConnection(connection);
9697  }
9698  }
9699 
9711  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
9712  CaseDbConnection connection = null;
9713  Statement statement;
9715  try {
9716  connection = connections.getConnection();
9717  statement = connection.createStatement();
9718  connection.beginTransaction();
9719  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
9720  // all associated rows from tsk_object and its children. For large data sources this may take some time.
9721  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
9722  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
9723  // associated rows from accounts table and its children.
9724  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
9725  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
9726  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
9727  statement.execute(accountSql);
9728  connection.commitTransaction();
9729  } catch (SQLException ex) {
9730  rollbackTransaction(connection);
9731  throw new TskCoreException("Error deleting data source.", ex);
9732  } finally {
9733  closeConnection(connection);
9735  }
9736  }
9737 
9763  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
9764  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
9765  try {
9766  while (rs.next()) {
9767  final short type = rs.getShort("type"); //NON-NLS
9768  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
9769  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
9770  FsContent result;
9771  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
9772  result = directory(rs, null);
9773  } else {
9774  result = file(rs, null);
9775  }
9776  results.add(result);
9777  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
9778  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
9779  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
9780  results.add(virtDir);
9781  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
9782  final LocalDirectory localDir = localDirectory(rs);
9783  results.add(localDir);
9784  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
9785  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
9786  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
9787  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
9788  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
9789  String parentPath = rs.getString("parent_path"); //NON-NLS
9790  if (parentPath == null) {
9791  parentPath = "/"; //NON-NLS
9792  }
9793 
9794  Long osAccountObjId = rs.getLong("os_account_obj_id");
9795  if (rs.wasNull()) {
9796  osAccountObjId = null;
9797  }
9798 
9799  LayoutFile lf = new LayoutFile(this,
9800  rs.getLong("obj_id"), //NON-NLS
9801  rs.getLong("data_source_obj_id"),
9802  rs.getString("name"), //NON-NLS
9803  atype,
9804  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9805  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
9806  rs.getLong("size"), //NON-NLS
9807  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
9808  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath,
9809  rs.getString("mime_type"),
9810  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
9811  results.add(lf);
9812  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
9813  final DerivedFile df;
9814  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
9815  results.add(df);
9816  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
9817  final LocalFile lf;
9818  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
9819  results.add(lf);
9820  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
9821  final SlackFile sf = slackFile(rs, null);
9822  results.add(sf);
9823  }
9824  } //end for each resultSet
9825  } catch (SQLException e) {
9826  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
9827  }
9828 
9829  return results;
9830  }
9831 
9832  // This following methods generate AbstractFile objects from a ResultSet
9844  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
9845  Long osAccountObjId = rs.getLong("os_account_obj_id");
9846  if (rs.wasNull()) {
9847  osAccountObjId = null;
9848  }
9849 
9850  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
9851  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
9852  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
9853  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
9854  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9855  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9856  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
9857  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
9858  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
9859  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
9860  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
9861  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"), osAccountObjId, Collections.emptyList()); //NON-NLS
9862  f.setFileSystem(fs);
9863  return f;
9864  }
9865 
9877  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
9878  Long osAccountObjId = rs.getLong("os_account_obj_id");
9879  if (rs.wasNull()) {
9880  osAccountObjId = null;
9881  }
9882 
9883  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
9884  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
9885  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
9886  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9887  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9888  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
9889  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
9890  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
9891  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
9892  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
9893  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
9894  dir.setFileSystem(fs);
9895  return dir;
9896  }
9897 
9908  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
9909  String parentPath = rs.getString("parent_path"); //NON-NLS
9910  if (parentPath == null) {
9911  parentPath = "";
9912  }
9913 
9914  long objId = rs.getLong("obj_id");
9915  long dsObjId = rs.getLong("data_source_obj_id");
9916  if (objId == dsObjId) { // virtual directory is a data source
9917 
9918  String deviceId = "";
9919  String timeZone = "";
9920  Statement s = null;
9921  ResultSet rsDataSourceInfo = null;
9922 
9924  try {
9925  s = connection.createStatement();
9926  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
9927  if (rsDataSourceInfo.next()) {
9928  deviceId = rsDataSourceInfo.getString("device_id");
9929  timeZone = rsDataSourceInfo.getString("time_zone");
9930  }
9931  } catch (SQLException ex) {
9932  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
9933  } finally {
9934  closeResultSet(rsDataSourceInfo);
9935  closeStatement(s);
9937  }
9938 
9939  return new LocalFilesDataSource(this,
9940  objId, dsObjId,
9941  deviceId,
9942  rs.getString("name"),
9943  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9944  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9945  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
9946  rs.getShort("meta_flags"),
9947  timeZone,
9948  rs.getString("md5"),
9949  rs.getString("sha256"),
9950  FileKnown.valueOf(rs.getByte("known")),
9951  parentPath);
9952  } else {
9953  final VirtualDirectory vd = new VirtualDirectory(this,
9954  objId, dsObjId,
9955  rs.getString("name"), //NON-NLS
9956  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9957  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9958  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
9959  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS
9960  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
9961  return vd;
9962  }
9963  }
9964 
9974  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
9975  String parentPath = rs.getString("parent_path"); //NON-NLS
9976  if (parentPath == null) {
9977  parentPath = "";
9978  }
9979  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
9980  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
9981  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9982  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9983  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
9984  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS
9985  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
9986  return ld;
9987  }
9988 
10002  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10003  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10004  long objId = rs.getLong("obj_id"); //NON-NLS
10005  String localPath = null;
10006  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10007  if (hasLocalPath) {
10008  ResultSet rsFilePath = null;
10010  try {
10011  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10012  statement.clearParameters();
10013  statement.setLong(1, objId);
10014  rsFilePath = connection.executeQuery(statement);
10015  if (rsFilePath.next()) {
10016  localPath = rsFilePath.getString("path");
10017  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10018  }
10019  } catch (SQLException ex) {
10020  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10021  } finally {
10022  closeResultSet(rsFilePath);
10024  }
10025  }
10026  String parentPath = rs.getString("parent_path"); //NON-NLS
10027  if (parentPath == null) {
10028  parentPath = "";
10029  }
10030 
10031  Long osAccountObjId = rs.getLong("os_account_obj_id");
10032  if (rs.wasNull()) {
10033  osAccountObjId = null;
10034  }
10035 
10036  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10037  rs.getString("name"), //NON-NLS
10038  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10039  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10040  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10041  rs.getLong("size"), //NON-NLS
10042  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10043  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10044  parentPath, localPath, parentId, rs.getString("mime_type"),
10045  encodingType, rs.getString("extension"),
10046  rs.getString("owner_uid"), osAccountObjId);
10047  return df;
10048  }
10049 
10063  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10064  long objId = rs.getLong("obj_id"); //NON-NLS
10065  String localPath = null;
10066  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10067  if (rs.getBoolean("has_path")) {
10068  ResultSet rsFilePath = null;
10070  try {
10071  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10072  statement.clearParameters();
10073  statement.setLong(1, objId);
10074  rsFilePath = connection.executeQuery(statement);
10075  if (rsFilePath.next()) {
10076  localPath = rsFilePath.getString("path");
10077  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10078  }
10079  } catch (SQLException ex) {
10080  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10081  } finally {
10082  closeResultSet(rsFilePath);
10084  }
10085  }
10086  String parentPath = rs.getString("parent_path"); //NON-NLS
10087  if (null == parentPath) {
10088  parentPath = "";
10089  }
10090  Long osAccountObjId = rs.getLong("os_account_obj_id");
10091  if (rs.wasNull()) {
10092  osAccountObjId = null;
10093  }
10094 
10095  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10096  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10097  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10098  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10099  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10100  rs.getLong("size"), //NON-NLS
10101  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10102  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10103  parentId, parentPath, rs.getLong("data_source_obj_id"),
10104  localPath, encodingType, rs.getString("extension"),
10105  rs.getString("owner_uid"), osAccountObjId);
10106  return file;
10107  }
10108 
10120  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10121  Long osAccountObjId = rs.getLong("os_account_obj_id");
10122  if (rs.wasNull()) {
10123  osAccountObjId = null;
10124  }
10125  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10126  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10127  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10128  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10129  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10130  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10131  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10132  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10133  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10134  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10135  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10136  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10137  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10138  f.setFileSystem(fs);
10139  return f;
10140  }
10141 
10153  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10154  List<Content> children = new ArrayList<Content>();
10155 
10156  while (rs.next()) {
10157  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10158 
10159  if (null != type) {
10160  switch (type) {
10161  case FS:
10162  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10163  FsContent result;
10164  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10165  result = directory(rs, null);
10166  } else {
10167  result = file(rs, null);
10168  }
10169  children.add(result);
10170  } else {
10171  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10172  children.add(virtDir);
10173  }
10174  break;
10175  case VIRTUAL_DIR:
10176  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10177  children.add(virtDir);
10178  break;
10179  case LOCAL_DIR:
10180  LocalDirectory localDir = localDirectory(rs);
10181  children.add(localDir);
10182  break;
10183  case UNALLOC_BLOCKS:
10184  case UNUSED_BLOCKS:
10185  case CARVED:
10186  case LAYOUT_FILE: {
10187  String parentPath = rs.getString("parent_path");
10188  if (parentPath == null) {
10189  parentPath = "";
10190  }
10191  Long osAccountObjId = rs.getLong("os_account_obj_id");
10192  if (rs.wasNull()) {
10193  osAccountObjId = null;
10194  }
10195  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
10196  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
10197  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
10198  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
10199  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
10200  rs.getLong("size"),
10201  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
10202  rs.getString("md5"), rs.getString("sha256"),
10203  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
10204  rs.getString("owner_uid"), osAccountObjId);
10205  children.add(lf);
10206  break;
10207  }
10208  case DERIVED:
10209  final DerivedFile df = derivedFile(rs, connection, parentId);
10210  children.add(df);
10211  break;
10212  case LOCAL: {
10213  final LocalFile lf = localFile(rs, connection, parentId);
10214  children.add(lf);
10215  break;
10216  }
10217  case SLACK: {
10218  final SlackFile sf = slackFile(rs, null);
10219  children.add(sf);
10220  break;
10221  }
10222  default:
10223  break;
10224  }
10225  }
10226  }
10227  return children;
10228  }
10229 
10245  private List<BlackboardArtifact> resultSetToArtifacts(ResultSet rs) throws SQLException, TskCoreException {
10246  ArrayList<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>();
10247  try {
10248  while (rs.next()) {
10249  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
10250  if (artifactType != null) {
10251  artifacts.add(new BlackboardArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"), rs.getLong("artifact_obj_id"), rs.getLong("data_source_obj_id"),
10252  rs.getInt("artifact_type_id"), artifactType.getTypeName(), artifactType.getDisplayName(),
10253  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id"))));
10254  } else {
10255  throw new TskCoreException("Error looking up artifact type ID " + rs.getInt("artifact_type_id") + " from artifact " + rs.getLong("artifact_id"));
10256  }
10257  } //end for each resultSet
10258  } catch (SQLException e) {
10259  logger.log(Level.SEVERE, "Error getting artifacts from result set", e); //NON-NLS
10260  }
10261 
10262  return artifacts;
10263  }
10264 
10286  public CaseDbQuery executeQuery(String query) throws TskCoreException {
10287  return new CaseDbQuery(query);
10288  }
10289 
10311  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
10312  return new CaseDbQuery(query, true);
10313  }
10314 
10322  CaseDbConnection getConnection() throws TskCoreException {
10323  return connections.getConnection();
10324  }
10325 
10333  String getCaseHandleIdentifier() {
10334  return caseHandleIdentifier;
10335  }
10336 
10337  @Override
10338  protected void finalize() throws Throwable {
10339  try {
10340  close();
10341  } finally {
10342  super.finalize();
10343  }
10344  }
10345 
10349  public synchronized void close() {
10351 
10352  try {
10353  connections.close();
10354  } catch (TskCoreException ex) {
10355  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
10356  }
10357 
10358  fileSystemIdMap.clear();
10359 
10360  try {
10361  if (this.caseHandle != null) {
10362  this.caseHandle.free();
10363  this.caseHandle = null;
10364  }
10365  } catch (TskCoreException ex) {
10366  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
10367  } finally {
10369  }
10370  }
10371 
10384  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
10385  long id = file.getId();
10386  FileKnown currentKnown = file.getKnown();
10387  if (currentKnown.compareTo(fileKnown) > 0) {
10388  return false;
10389  }
10391  try (CaseDbConnection connection = connections.getConnection();
10392  Statement statement = connection.createStatement();) {
10393  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
10394  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
10395  + "WHERE obj_id=" + id); //NON-NLS
10396 
10397  file.setKnown(fileKnown);
10398  } catch (SQLException ex) {
10399  throw new TskCoreException("Error setting Known status.", ex);
10400  } finally {
10402  }
10403  return true;
10404  }
10405 
10414  void setFileName(String name, long objId) throws TskCoreException {
10416  try (CaseDbConnection connection = connections.getConnection();) {
10417  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
10418  preparedStatement.clearParameters();
10419  preparedStatement.setString(1, name);
10420  preparedStatement.setLong(2, objId);
10421  connection.executeUpdate(preparedStatement);
10422  } catch (SQLException ex) {
10423  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10424  } finally {
10426  }
10427  }
10428 
10437  void setImageName(String name, long objId) throws TskCoreException {
10439  try (CaseDbConnection connection = connections.getConnection();) {
10440  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
10441  preparedStatement.clearParameters();
10442  preparedStatement.setString(1, name);
10443  preparedStatement.setLong(2, objId);
10444  connection.executeUpdate(preparedStatement);
10445  } catch (SQLException ex) {
10446  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10447  } finally {
10449  }
10450  }
10451 
10466  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
10467 
10469  try (CaseDbConnection connection = connections.getConnection();) {
10470  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
10471  preparedStatement.clearParameters();
10472  preparedStatement.setLong(1, totalSize);
10473  preparedStatement.setLong(2, sectorSize);
10474  preparedStatement.setLong(3, image.getId());
10475  connection.executeUpdate(preparedStatement);
10476  } catch (SQLException ex) {
10477  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);
10478  } finally {
10480  }
10481  }
10482 
10492  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
10494  try (CaseDbConnection connection = connections.getConnection();
10495  Statement statement = connection.createStatement()) {
10496  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
10497  file.setMIMEType(mimeType);
10498  } catch (SQLException ex) {
10499  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
10500  } finally {
10502  }
10503  }
10504 
10515  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
10516 
10517  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
10518  short metaFlag = file.getMetaFlagsAsInt();
10519  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
10520  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
10521  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
10522 
10523  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
10524  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
10525 
10527  try (CaseDbConnection connection = connections.getConnection();
10528  Statement statement = connection.createStatement();) {
10529  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
10530 
10531  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
10532  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
10533 
10534  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
10535 
10536  } catch (SQLException ex) {
10537  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
10538  } finally {
10540  }
10541  }
10542 
10552  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
10553  if (md5Hash == null) {
10554  return;
10555  }
10556  long id = file.getId();
10558  try (CaseDbConnection connection = connections.getConnection();) {
10559  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
10560  statement.clearParameters();
10561  statement.setString(1, md5Hash.toLowerCase());
10562  statement.setLong(2, id);
10563  connection.executeUpdate(statement);
10564  file.setMd5Hash(md5Hash.toLowerCase());
10565  } catch (SQLException ex) {
10566  throw new TskCoreException("Error setting MD5 hash", ex);
10567  } finally {
10569  }
10570  }
10571 
10581  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
10582  if (md5Hash == null) {
10583  return;
10584  }
10585  long id = img.getId();
10587  try (CaseDbConnection connection = connections.getConnection();) {
10588  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
10589  statement.clearParameters();
10590  statement.setString(1, md5Hash.toLowerCase());
10591  statement.setLong(2, id);
10592  connection.executeUpdate(statement);
10593  } catch (SQLException ex) {
10594  throw new TskCoreException("Error setting MD5 hash", ex);
10595  } finally {
10597  }
10598  }
10599 
10610  String getMd5ImageHash(Image img) throws TskCoreException {
10611  long id = img.getId();
10612  CaseDbConnection connection = null;
10613  ResultSet rs = null;
10614  String hash = "";
10616  try {
10617  connection = connections.getConnection();
10618 
10619  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
10620  statement.clearParameters();
10621  statement.setLong(1, id);
10622  rs = connection.executeQuery(statement);
10623  if (rs.next()) {
10624  hash = rs.getString("md5");
10625  }
10626  return hash;
10627  } catch (SQLException ex) {
10628  throw new TskCoreException("Error getting MD5 hash", ex);
10629  } finally {
10630  closeResultSet(rs);
10631  closeConnection(connection);
10633  }
10634  }
10635 
10645  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
10646  if (sha1Hash == null) {
10647  return;
10648  }
10649  long id = img.getId();
10651  try (CaseDbConnection connection = connections.getConnection();) {
10652  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
10653  statement.clearParameters();
10654  statement.setString(1, sha1Hash.toLowerCase());
10655  statement.setLong(2, id);
10656  connection.executeUpdate(statement);
10657  } catch (SQLException ex) {
10658  throw new TskCoreException("Error setting SHA1 hash", ex);
10659  } finally {
10661  }
10662  }
10663 
10674  String getSha1ImageHash(Image img) throws TskCoreException {
10675  long id = img.getId();
10676  CaseDbConnection connection = null;
10677  ResultSet rs = null;
10678  String hash = "";
10680  try {
10681  connection = connections.getConnection();
10682 
10683  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
10684  statement.clearParameters();
10685  statement.setLong(1, id);
10686  rs = connection.executeQuery(statement);
10687  if (rs.next()) {
10688  hash = rs.getString("sha1");
10689  }
10690  return hash;
10691  } catch (SQLException ex) {
10692  throw new TskCoreException("Error getting SHA1 hash", ex);
10693  } finally {
10694  closeResultSet(rs);
10695  closeConnection(connection);
10697  }
10698  }
10699 
10709  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
10710  if (sha256Hash == null) {
10711  return;
10712  }
10713  long id = img.getId();
10715  try (CaseDbConnection connection = connections.getConnection();) {
10716  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
10717  statement.clearParameters();
10718  statement.setString(1, sha256Hash.toLowerCase());
10719  statement.setLong(2, id);
10720  connection.executeUpdate(statement);
10721  } catch (SQLException ex) {
10722  throw new TskCoreException("Error setting SHA256 hash", ex);
10723  } finally {
10725  }
10726  }
10727 
10738  String getSha256ImageHash(Image img) throws TskCoreException {
10739  long id = img.getId();
10740  CaseDbConnection connection = null;
10741  ResultSet rs = null;
10742  String hash = "";
10744  try {
10745  connection = connections.getConnection();
10746 
10747  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
10748  statement.clearParameters();
10749  statement.setLong(1, id);
10750  rs = connection.executeQuery(statement);
10751  if (rs.next()) {
10752  hash = rs.getString("sha256");
10753  }
10754  return hash;
10755  } catch (SQLException ex) {
10756  throw new TskCoreException("Error setting SHA256 hash", ex);
10757  } finally {
10758  closeResultSet(rs);
10759  closeConnection(connection);
10761  }
10762  }
10763 
10772  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
10773 
10774  long id = datasource.getId();
10776  try (CaseDbConnection connection = connections.getConnection();) {
10777  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
10778  statement.clearParameters();
10779  statement.setString(1, details);
10780  statement.setLong(2, id);
10781  connection.executeUpdate(statement);
10782  } catch (SQLException ex) {
10783  throw new TskCoreException("Error setting acquisition details", ex);
10784  } finally {
10786  }
10787  }
10788 
10800  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
10801 
10802  long id = datasource.getId();
10804  try (CaseDbConnection connection = connections.getConnection();) {
10805  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
10806  statement.clearParameters();
10807  statement.setString(1, settings);
10808  statement.setString(2, name);
10809  statement.setString(3, version);
10810  statement.setLong(4, id);
10811  connection.executeUpdate(statement);
10812  } catch (SQLException ex) {
10813  throw new TskCoreException("Error setting acquisition details", ex);
10814  } finally {
10816  }
10817  }
10818 
10828  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
10829  try {
10830  CaseDbConnection connection = trans.getConnection();
10831  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
10832  statement.clearParameters();
10833  statement.setString(1, details);
10834  statement.setLong(2, dataSourceId);
10835  connection.executeUpdate(statement);
10836  } catch (SQLException ex) {
10837  throw new TskCoreException("Error setting acquisition details", ex);
10838  }
10839  }
10840 
10850  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
10851  long id = datasource.getId();
10852  CaseDbConnection connection = null;
10853  ResultSet rs = null;
10854  String hash = "";
10856  try {
10857  connection = connections.getConnection();
10858 
10859  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
10860  statement.clearParameters();
10861  statement.setLong(1, id);
10862  rs = connection.executeQuery(statement);
10863  if (rs.next()) {
10864  hash = rs.getString("acquisition_details");
10865  }
10866  return hash;
10867  } catch (SQLException ex) {
10868  throw new TskCoreException("Error setting acquisition details", ex);
10869  } finally {
10870  closeResultSet(rs);
10871  closeConnection(connection);
10873  }
10874  }
10875 
10886  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
10887  long id = datasource.getId();
10888  CaseDbConnection connection = null;
10889  ResultSet rs = null;
10890  String returnValue = "";
10892  try {
10893  connection = connections.getConnection();
10894 
10895  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
10896  statement.clearParameters();
10897  statement.setLong(1, id);
10898  rs = connection.executeQuery(statement);
10899  if (rs.next()) {
10900  returnValue = rs.getString(columnName);
10901  }
10902  return returnValue;
10903  } catch (SQLException ex) {
10904  throw new TskCoreException("Error setting acquisition details", ex);
10905  } finally {
10906  closeResultSet(rs);
10907  closeConnection(connection);
10909  }
10910  }
10911 
10922  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
10923  long id = datasource.getId();
10924  CaseDbConnection connection = null;
10925  ResultSet rs = null;
10926  Long returnValue = null;
10928  try {
10929  connection = connections.getConnection();
10930 
10931  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
10932  statement.clearParameters();
10933  statement.setLong(1, id);
10934  rs = connection.executeQuery(statement);
10935  if (rs.next()) {
10936  returnValue = rs.getLong(columnName);
10937  }
10938  return returnValue;
10939  } catch (SQLException ex) {
10940  throw new TskCoreException("Error setting acquisition details", ex);
10941  } finally {
10942  closeResultSet(rs);
10943  closeConnection(connection);
10945  }
10946  }
10947 
10958  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
10959  if (newStatus == null) {
10960  return;
10961  }
10963  try (CaseDbConnection connection = connections.getConnection();
10964  Statement statement = connection.createStatement();) {
10965  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
10966  + " SET review_status_id=" + newStatus.getID()
10967  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
10968  } catch (SQLException ex) {
10969  throw new TskCoreException("Error setting review status", ex);
10970  } finally {
10972  }
10973  }
10974 
10985  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
10986  CaseDbConnection connection = null;
10987  Statement s = null;
10988  ResultSet rs = null;
10990  try {
10991  connection = connections.getConnection();
10992  s = connection.createStatement();
10993  Short contentShort = contentType.getValue();
10994  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
10995  int count = 0;
10996  if (rs.next()) {
10997  count = rs.getInt("count");
10998  }
10999  return count;
11000  } catch (SQLException ex) {
11001  throw new TskCoreException("Error getting number of objects.", ex);
11002  } finally {
11003  closeResultSet(rs);
11004  closeStatement(s);
11005  closeConnection(connection);
11007  }
11008  }
11009 
11018  public static String escapeSingleQuotes(String text) {
11019  String escapedText = null;
11020  if (text != null) {
11021  escapedText = text.replaceAll("'", "''");
11022  }
11023  return escapedText;
11024  }
11025 
11033  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11034  if (md5Hash == null) {
11035  return Collections.<AbstractFile>emptyList();
11036  }
11037 
11038  CaseDbConnection connection = null;
11039  Statement s = null;
11040  ResultSet rs = null;
11042  try {
11043  connection = connections.getConnection();
11044  s = connection.createStatement();
11045  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11046  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11047  + "AND size > 0"); //NON-NLS
11048  return resultSetToAbstractFiles(rs, connection);
11049  } catch (SQLException | TskCoreException ex) {
11050  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11051  } finally {
11052  closeResultSet(rs);
11053  closeStatement(s);
11054  closeConnection(connection);
11056  }
11057  return Collections.<AbstractFile>emptyList();
11058  }
11059 
11066  public boolean allFilesMd5Hashed() {
11067  boolean allFilesAreHashed = false;
11068 
11069  CaseDbConnection connection = null;
11070  Statement s = null;
11071  ResultSet rs = null;
11073  try {
11074  connection = connections.getConnection();
11075  s = connection.createStatement();
11076  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11077  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11078  + "AND md5 IS NULL " //NON-NLS
11079  + "AND size > '0'"); //NON-NLS
11080  if (rs.next() && rs.getInt("count") == 0) {
11081  allFilesAreHashed = true;
11082  }
11083  } catch (SQLException | TskCoreException ex) {
11084  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11085  } finally {
11086  closeResultSet(rs);
11087  closeStatement(s);
11088  closeConnection(connection);
11090  }
11091  return allFilesAreHashed;
11092  }
11093 
11099  public int countFilesMd5Hashed() {
11100  int count = 0;
11101 
11103  CaseDbConnection connection = null;
11104  Statement s = null;
11105  ResultSet rs = null;
11106  try {
11107  connection = connections.getConnection();
11108  s = connection.createStatement();
11109  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11110  + "WHERE md5 IS NOT NULL " //NON-NLS
11111  + "AND size > '0'"); //NON-NLS
11112  if (rs.next()) {
11113  count = rs.getInt("count");
11114  }
11115  } catch (SQLException | TskCoreException ex) {
11116  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11117  } finally {
11118  closeResultSet(rs);
11119  closeStatement(s);
11120  closeConnection(connection);
11122  }
11123  return count;
11124 
11125  }
11126 
11135  public List<TagName> getAllTagNames() throws TskCoreException {
11136  CaseDbConnection connection = null;
11137  ResultSet resultSet = null;
11139  try {
11140  connection = connections.getConnection();
11141 
11142  // SELECT * FROM tag_names
11143  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11144  resultSet = connection.executeQuery(statement);
11145  ArrayList<TagName> tagNames = new ArrayList<>();
11146  while (resultSet.next()) {
11147  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11148  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11149  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11150  }
11151  return tagNames;
11152  } catch (SQLException ex) {
11153  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11154  } finally {
11155  closeResultSet(resultSet);
11156  closeConnection(connection);
11158  }
11159  }
11160 
11171  public List<TagName> getTagNamesInUse() throws TskCoreException {
11172  CaseDbConnection connection = null;
11173  ResultSet resultSet = null;
11175  try {
11176  connection = connections.getConnection();
11177 
11178  // 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)
11179  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
11180  resultSet = connection.executeQuery(statement);
11181  ArrayList<TagName> tagNames = new ArrayList<>();
11182  while (resultSet.next()) {
11183  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11184  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11185  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11186  }
11187  return tagNames;
11188  } catch (SQLException ex) {
11189  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11190  } finally {
11191  closeResultSet(resultSet);
11192  closeConnection(connection);
11194  }
11195  }
11196 
11209  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
11210 
11211  ArrayList<TagName> tagNames = new ArrayList<>();
11212  // SELECT * FROM tag_names WHERE tag_name_id IN
11213  // ( 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 = ? "
11214  // UNION
11215  // 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 = ? )
11216  // )
11217  CaseDbConnection connection = null;
11218  ResultSet resultSet = null;
11220  try {
11221  connection = connections.getConnection();
11222 
11223  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
11224  statement.setLong(1, dsObjId);
11225  statement.setLong(2, dsObjId);
11226  resultSet = connection.executeQuery(statement); //NON-NLS
11227  while (resultSet.next()) {
11228  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11229  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11230  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11231  }
11232  return tagNames;
11233  } catch (SQLException ex) {
11234  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
11235  } finally {
11236  closeResultSet(resultSet);
11237  closeConnection(connection);
11239  }
11240  }
11241 
11255  @Deprecated
11256  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
11257  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
11258  }
11259 
11274  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
11276  try (CaseDbConnection connection = connections.getConnection();) {
11277  PreparedStatement statement;
11278  // INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?
11279  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OR_UPDATE_TAG_NAME, Statement.RETURN_GENERATED_KEYS);
11280  statement.clearParameters();
11281  statement.setString(5, description);
11282  statement.setString(6, color.getName());
11283  statement.setByte(7, knownStatus.getFileKnownValue());
11284  statement.setString(1, displayName);
11285  statement.setString(2, description);
11286  statement.setString(3, color.getName());
11287  statement.setByte(4, knownStatus.getFileKnownValue());
11288  connection.executeUpdate(statement);
11289 
11290  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAME_BY_NAME);
11291  statement.clearParameters();
11292  statement.setString(1, displayName);
11293  try (ResultSet resultSet = connection.executeQuery(statement)) {
11294  resultSet.next();
11295  return new TagName(resultSet.getLong("tag_name_id"), displayName, description, color, knownStatus, resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11296  }
11297  } catch (SQLException ex) {
11298  throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex);
11299  } finally {
11301  }
11302  }
11303 
11318  @Deprecated
11319  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
11320  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
11321  }
11322 
11323  /*
11324  * Deletes a row from the content_tags table in the case database. @param
11325  * tag A ContentTag data transfer object (DTO) for the row to delete.
11326  * @throws TskCoreException
11327  */
11328  public void deleteContentTag(ContentTag tag) throws TskCoreException {
11330  try {
11331  // DELETE FROM content_tags WHERE tag_id = ?
11332  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
11333  statement.clearParameters();
11334  statement.setLong(1, tag.getId());
11335  trans.getConnection().executeUpdate(statement);
11336 
11337  // update the aggregate score for the content
11338  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
11339  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11340  ? tag.getContent().getDataSource().getId()
11341  : null;
11342 
11343  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
11344 
11345  trans.commit();
11346  trans = null;
11347  } catch (SQLException ex) {
11348  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
11349  } finally {
11350  if (trans != null) {
11351  trans.rollback();
11352  }
11353  }
11354  }
11355 
11364  public List<ContentTag> getAllContentTags() throws TskCoreException {
11365  CaseDbConnection connection = null;
11366  ResultSet resultSet = null;
11368  try {
11369  connection = connections.getConnection();
11370 
11371  // 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
11372  // FROM content_tags
11373  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11374  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11375  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
11376  resultSet = connection.executeQuery(statement);
11377  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11378  while (resultSet.next()) {
11379  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11380  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11381  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11382  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
11383  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
11384  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
11385  }
11386  return tags;
11387  } catch (SQLException ex) {
11388  throw new TskCoreException("Error selecting rows from content_tags table", ex);
11389  } finally {
11390  closeResultSet(resultSet);
11391  closeConnection(connection);
11393  }
11394  }
11395 
11406  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
11407  if (tagName.getId() == Tag.ID_NOT_SET) {
11408  throw new TskCoreException("TagName object is invalid, id not set");
11409  }
11410  CaseDbConnection connection = null;
11411  ResultSet resultSet = null;
11413  try {
11414  connection = connections.getConnection();
11415 
11416  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
11417  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
11418  statement.clearParameters();
11419  statement.setLong(1, tagName.getId());
11420  resultSet = connection.executeQuery(statement);
11421  if (resultSet.next()) {
11422  return resultSet.getLong("count");
11423  } else {
11424  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11425  }
11426  } catch (SQLException ex) {
11427  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11428  } finally {
11429  closeResultSet(resultSet);
11430  closeConnection(connection);
11432  }
11433  }
11434 
11450  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11451 
11452  if (tagName.getId() == Tag.ID_NOT_SET) {
11453  throw new TskCoreException("TagName object is invalid, id not set");
11454  }
11455 
11456  CaseDbConnection connection = null;
11457  ResultSet resultSet = null;
11459  try {
11460  connection = connections.getConnection();
11461 
11462  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11463  // + " AND content_tags.tag_name_id = ? "
11464  // + " AND tsk_files.data_source_obj_id = ? "
11465  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11466  statement.clearParameters();
11467  statement.setLong(1, tagName.getId());
11468  statement.setLong(2, dsObjId);
11469 
11470  resultSet = connection.executeQuery(statement);
11471  if (resultSet.next()) {
11472  return resultSet.getLong("count");
11473  } else {
11474  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11475  }
11476  } catch (SQLException ex) {
11477  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11478  } finally {
11479  closeResultSet(resultSet);
11480  closeConnection(connection);
11482  }
11483  }
11484 
11495  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
11496 
11497  CaseDbConnection connection = null;
11498  ResultSet resultSet = null;
11499  ContentTag tag = null;
11501  try {
11502  connection = connections.getConnection();
11503 
11504  // 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
11505  // FROM content_tags
11506  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11507  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11508  // WHERE tag_id = ?
11509  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
11510  statement.clearParameters();
11511  statement.setLong(1, contentTagID);
11512  resultSet = connection.executeQuery(statement);
11513 
11514  while (resultSet.next()) {
11515  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11516  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11517  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11518  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
11519  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
11520  }
11521  resultSet.close();
11522 
11523  } catch (SQLException ex) {
11524  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
11525  } finally {
11526  closeResultSet(resultSet);
11527  closeConnection(connection);
11529  }
11530  return tag;
11531  }
11532 
11544  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
11545  if (tagName.getId() == Tag.ID_NOT_SET) {
11546  throw new TskCoreException("TagName object is invalid, id not set");
11547  }
11548  CaseDbConnection connection = null;
11549  ResultSet resultSet = null;
11551  try {
11552  connection = connections.getConnection();
11553 
11554  // 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
11555  // FROM content_tags
11556  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11557  // WHERE tag_name_id = ?
11558  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
11559  statement.clearParameters();
11560  statement.setLong(1, tagName.getId());
11561  resultSet = connection.executeQuery(statement);
11562  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11563  while (resultSet.next()) {
11564  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11565  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11566  tags.add(tag);
11567  }
11568  resultSet.close();
11569  return tags;
11570  } catch (SQLException ex) {
11571  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
11572  } finally {
11573  closeResultSet(resultSet);
11574  closeConnection(connection);
11576  }
11577  }
11578 
11591  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11592 
11593  CaseDbConnection connection = null;
11594  ResultSet resultSet = null;
11596  try {
11597  connection = connections.getConnection();
11598 
11599  // 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
11600  // FROM content_tags as content_tags, tsk_files as tsk_files
11601  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11602  // WHERE content_tags.obj_id = tsk_files.obj_id
11603  // AND content_tags.tag_name_id = ?
11604  // AND tsk_files.data_source_obj_id = ?
11605  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11606  statement.clearParameters();
11607  statement.setLong(1, tagName.getId());
11608  statement.setLong(2, dsObjId);
11609  resultSet = connection.executeQuery(statement);
11610  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11611  while (resultSet.next()) {
11612  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11613  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11614  tags.add(tag);
11615  }
11616  resultSet.close();
11617  return tags;
11618  } catch (SQLException ex) {
11619  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
11620  } finally {
11621  closeResultSet(resultSet);
11622  closeConnection(connection);
11624  }
11625  }
11626 
11638  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
11639  CaseDbConnection connection = null;
11640  ResultSet resultSet = null;
11642  try {
11643  connection = connections.getConnection();
11644 
11645  // 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
11646  // FROM content_tags
11647  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11648  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11649  // WHERE content_tags.obj_id = ?
11650  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
11651  statement.clearParameters();
11652  statement.setLong(1, content.getId());
11653  resultSet = connection.executeQuery(statement);
11654  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11655  while (resultSet.next()) {
11656  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11657  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11658  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11659  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
11660  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11661  tags.add(tag);
11662  }
11663  return tags;
11664  } catch (SQLException ex) {
11665  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
11666  } finally {
11667  closeResultSet(resultSet);
11668  closeConnection(connection);
11670  }
11671  }
11672 
11687  @Deprecated
11688  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
11689  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
11690  }
11691 
11692  /*
11693  * Deletes a row from the blackboard_artifact_tags table in the case
11694  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
11695  * representing the row to delete. @throws TskCoreException
11696  */
11697  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
11699  try {
11700  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
11701  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
11702  statement.clearParameters();
11703  statement.setLong(1, tag.getId());
11704  trans.getConnection().executeUpdate(statement);
11705 
11706  // update the aggregate score for the artifact
11707  Long artifactObjId = tag.getArtifact().getId();
11708  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11709  ? tag.getContent().getDataSource().getId()
11710  : null;
11711 
11712  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
11713 
11714  trans.commit();
11715  trans = null;
11716  } catch (SQLException ex) {
11717  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
11718  } finally {
11719  if (trans != null) {
11720  trans.rollback();
11721  }
11722  }
11723  }
11724 
11734  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
11735  CaseDbConnection connection = null;
11736  ResultSet resultSet = null;
11738  try {
11739  connection = connections.getConnection();
11740 
11741  // 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
11742  // FROM blackboard_artifact_tags
11743  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
11744  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11745  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
11746  resultSet = connection.executeQuery(statement);
11747  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
11748  while (resultSet.next()) {
11749  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11750  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11751  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11752  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11753  Content content = getContentById(artifact.getObjectID());
11754  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11755  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11756  tags.add(tag);
11757  }
11758  return tags;
11759  } catch (SQLException ex) {
11760  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
11761  } finally {
11762  closeResultSet(resultSet);
11763  closeConnection(connection);
11765  }
11766  }
11767 
11778  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
11779  if (tagName.getId() == Tag.ID_NOT_SET) {
11780  throw new TskCoreException("TagName object is invalid, id not set");
11781  }
11782  CaseDbConnection connection = null;
11783  ResultSet resultSet = null;
11785  try {
11786  connection = connections.getConnection();
11787 
11788  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
11789  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
11790  statement.clearParameters();
11791  statement.setLong(1, tagName.getId());
11792  resultSet = connection.executeQuery(statement);
11793  if (resultSet.next()) {
11794  return resultSet.getLong("count");
11795  } else {
11796  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11797  }
11798  } catch (SQLException ex) {
11799  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11800  } finally {
11801  closeResultSet(resultSet);
11802  closeConnection(connection);
11804  }
11805  }
11806 
11821  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11822 
11823  if (tagName.getId() == Tag.ID_NOT_SET) {
11824  throw new TskCoreException("TagName object is invalid, id not set");
11825  }
11826 
11827  CaseDbConnection connection = null;
11828  ResultSet resultSet = null;
11830  try {
11831  connection = connections.getConnection();
11832 
11833  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
11834  // + " AND artifact_tags.tag_name_id = ?"
11835  // + " AND arts.data_source_obj_id = ? "
11836  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
11837  statement.clearParameters();
11838  statement.setLong(1, tagName.getId());
11839  statement.setLong(2, dsObjId);
11840  resultSet = connection.executeQuery(statement);
11841  if (resultSet.next()) {
11842  return resultSet.getLong("count");
11843  } else {
11844  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11845  }
11846  } catch (SQLException ex) {
11847  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11848  } finally {
11849  closeResultSet(resultSet);
11850  closeConnection(connection);
11852  }
11853  }
11854 
11866  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
11867  if (tagName.getId() == Tag.ID_NOT_SET) {
11868  throw new TskCoreException("TagName object is invalid, id not set");
11869  }
11870  CaseDbConnection connection = null;
11871  ResultSet resultSet = null;
11873  try {
11874  connection = connections.getConnection();
11875 
11876  // 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
11877  // FROM blackboard_artifact_tags
11878  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11879  // WHERE tag_name_id = ?
11880  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
11881  statement.clearParameters();
11882  statement.setLong(1, tagName.getId());
11883  resultSet = connection.executeQuery(statement);
11884  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
11885  while (resultSet.next()) {
11886  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11887  Content content = getContentById(artifact.getObjectID());
11888  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11889  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11890  tags.add(tag);
11891  }
11892  return tags;
11893  } catch (SQLException ex) {
11894  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
11895  } finally {
11896  closeResultSet(resultSet);
11897  closeConnection(connection);
11899  }
11900  }
11901 
11916  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11917 
11918  if (tagName.getId() == Tag.ID_NOT_SET) {
11919  throw new TskCoreException("TagName object is invalid, id not set");
11920  }
11921 
11922  CaseDbConnection connection = null;
11923  ResultSet resultSet = null;
11925  try {
11926  connection = connections.getConnection();
11927 
11928  // 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
11929  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
11930  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
11931  // WHERE artifact_tags.artifact_id = arts.artifact_id
11932  // AND artifact_tags.tag_name_id = ?
11933  // AND arts.data_source_obj_id = ?
11934  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11935  statement.clearParameters();
11936  statement.setLong(1, tagName.getId());
11937  statement.setLong(2, dsObjId);
11938  resultSet = connection.executeQuery(statement);
11939  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
11940  while (resultSet.next()) {
11941  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11942  Content content = getContentById(artifact.getObjectID());
11943  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11944  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11945  tags.add(tag);
11946  }
11947  return tags;
11948  } catch (SQLException ex) {
11949  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11950  } finally {
11951  closeResultSet(resultSet);
11952  closeConnection(connection);
11954  }
11955 
11956  }
11957 
11969  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
11970 
11971  CaseDbConnection connection = null;
11972  ResultSet resultSet = null;
11973  BlackboardArtifactTag tag = null;
11975  try {
11976  connection = connections.getConnection();
11977 
11978  //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
11979  // FROM blackboard_artifact_tags
11980  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
11981  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11982  // WHERE blackboard_artifact_tags.tag_id = ?
11983  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
11984  statement.clearParameters();
11985  statement.setLong(1, artifactTagID);
11986  resultSet = connection.executeQuery(statement);
11987 
11988  while (resultSet.next()) {
11989  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11990  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11991  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11992  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11993  Content content = getContentById(artifact.getObjectID());
11994  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11995  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
11996  }
11997  resultSet.close();
11998 
11999  } catch (SQLException ex) {
12000  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12001  } finally {
12002  closeResultSet(resultSet);
12003  closeConnection(connection);
12005  }
12006  return tag;
12007  }
12008 
12021  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12022  CaseDbConnection connection = null;
12023  ResultSet resultSet = null;
12025  try {
12026  connection = connections.getConnection();
12027 
12028  // 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
12029  // FROM blackboard_artifact_tags
12030  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12031  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12032  // WHERE blackboard_artifact_tags.artifact_id = ?
12033  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12034  statement.clearParameters();
12035  statement.setLong(1, artifact.getArtifactID());
12036  resultSet = connection.executeQuery(statement);
12037  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12038  while (resultSet.next()) {
12039  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12040  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12041  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12042  Content content = getContentById(artifact.getObjectID());
12043  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12044  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12045  tags.add(tag);
12046  }
12047  return tags;
12048  } catch (SQLException ex) {
12049  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12050  } finally {
12051  closeResultSet(resultSet);
12052  closeConnection(connection);
12054  }
12055  }
12056 
12065  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12067  try (CaseDbConnection connection = connections.getConnection();) {
12068  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12069  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12070  statement.clearParameters();
12071  statement.setString(1, newPath);
12072  statement.setLong(2, objectId);
12073  connection.executeUpdate(statement);
12074  } catch (SQLException ex) {
12075  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12076  } finally {
12078  }
12079  }
12080 
12094  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12095  return addReport(localPath, sourceModuleName, reportName, null);
12096  }
12097 
12113  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12114  // Make sure the local path of the report is in the database directory
12115  // or one of its subdirectories.
12116  String relativePath = ""; //NON-NLS
12117  long createTime = 0;
12118  String localPathLower = localPath.toLowerCase();
12119 
12120  if (localPathLower.startsWith("http")) {
12121  relativePath = localPathLower;
12122  createTime = System.currentTimeMillis() / 1000;
12123  } else {
12124  /*
12125  * Note: The following call to .relativize() may be dangerous in
12126  * case-sensitive operating systems and should be looked at. For
12127  * now, we are simply relativizing the paths as all lower case, then
12128  * using the length of the result to pull out the appropriate number
12129  * of characters from the localPath String.
12130  */
12131  try {
12132  String casePathLower = getDbDirPath().toLowerCase();
12133  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12134  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12135  } catch (IllegalArgumentException ex) {
12136  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12137  throw new TskCoreException(errorMessage, ex);
12138  }
12139  try {
12140  // get its file time
12141  java.io.File tempFile = new java.io.File(localPath);
12142  // Convert to UNIX epoch (seconds, not milliseconds).
12143  createTime = tempFile.lastModified() / 1000;
12144  } catch (Exception ex) {
12145  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12146  }
12147  }
12148 
12149  // Write the report data to the database.
12151  try (CaseDbConnection connection = connections.getConnection();) {
12152  // Insert a row for the report into the tsk_objects table.
12153  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12154  long parentObjId = 0;
12155  if (parent != null) {
12156  parentObjId = parent.getId();
12157  }
12158  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
12159 
12160  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
12161  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
12162  statement.clearParameters();
12163  statement.setLong(1, objectId);
12164  statement.setString(2, relativePath);
12165  statement.setLong(3, createTime);
12166  statement.setString(4, sourceModuleName);
12167  statement.setString(5, reportName);
12168  connection.executeUpdate(statement);
12169  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
12170  } catch (SQLException ex) {
12171  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
12172  } finally {
12174  }
12175  }
12176 
12185  public List<Report> getAllReports() throws TskCoreException {
12186  CaseDbConnection connection = null;
12187  ResultSet resultSet = null;
12188  ResultSet parentResultSet = null;
12189  PreparedStatement statement = null;
12190  Statement parentStatement = null;
12192  try {
12193  connection = connections.getConnection();
12194 
12195  // SELECT * FROM reports
12196  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
12197  parentStatement = connection.createStatement();
12198  resultSet = connection.executeQuery(statement);
12199  ArrayList<Report> reports = new ArrayList<Report>();
12200  while (resultSet.next()) {
12201  String localpath = resultSet.getString("path");
12202  if (localpath.toLowerCase().startsWith("http") == false) {
12203  // make path absolute
12204  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
12205  }
12206 
12207  // get the report parent
12208  Content parent = null;
12209  long reportId = resultSet.getLong("obj_id"); // NON-NLS
12210  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
12211  parentResultSet = parentStatement.executeQuery(parentQuery);
12212  if (parentResultSet.next()) {
12213  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12214  parent = this.getContentById(parentId);
12215  }
12216  parentResultSet.close();
12217 
12218  reports.add(new Report(this,
12219  reportId,
12220  localpath,
12221  resultSet.getLong("crtime"), //NON-NLS
12222  resultSet.getString("src_module_name"), //NON-NLS
12223  resultSet.getString("report_name"),
12224  parent)); //NON-NLS
12225  }
12226  return reports;
12227  } catch (SQLException ex) {
12228  throw new TskCoreException("Error querying reports table", ex);
12229  } finally {
12230  closeResultSet(resultSet);
12231  closeResultSet(parentResultSet);
12232  closeStatement(statement);
12233  closeStatement(parentStatement);
12234 
12235  closeConnection(connection);
12237  }
12238  }
12239 
12249  public Report getReportById(long id) throws TskCoreException {
12250  CaseDbConnection connection = null;
12251  PreparedStatement statement = null;
12252  Statement parentStatement = null;
12253  ResultSet resultSet = null;
12254  ResultSet parentResultSet = null;
12255  Report report = null;
12257  try {
12258  connection = connections.getConnection();
12259 
12260  // SELECT * FROM reports WHERE obj_id = ?
12261  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
12262  parentStatement = connection.createStatement();
12263  statement.clearParameters();
12264  statement.setLong(1, id);
12265  resultSet = connection.executeQuery(statement);
12266 
12267  if (resultSet.next()) {
12268  // get the report parent
12269  Content parent = null;
12270  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
12271  parentResultSet = parentStatement.executeQuery(parentQuery);
12272  if (parentResultSet.next()) {
12273  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12274  parent = this.getContentById(parentId);
12275  }
12276 
12277  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
12278  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
12279  resultSet.getLong("crtime"), //NON-NLS
12280  resultSet.getString("src_module_name"), //NON-NLS
12281  resultSet.getString("report_name"),
12282  parent); //NON-NLS
12283  } else {
12284  throw new TskCoreException("No report found for id: " + id);
12285  }
12286  } catch (SQLException ex) {
12287  throw new TskCoreException("Error querying reports table for id: " + id, ex);
12288  } finally {
12289  closeResultSet(resultSet);
12290  closeResultSet(parentResultSet);
12291  closeStatement(statement);
12292  closeStatement(parentStatement);
12293  closeConnection(connection);
12295  }
12296 
12297  return report;
12298  }
12299 
12307  public void deleteReport(Report report) throws TskCoreException {
12309  try (CaseDbConnection connection = connections.getConnection();) {
12310  // DELETE FROM reports WHERE reports.obj_id = ?
12311  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
12312  statement.setLong(1, report.getId());
12313  connection.executeUpdate(statement);
12314  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
12315  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
12316  statement.setLong(1, report.getId());
12317  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
12318  connection.executeUpdate(statement);
12319  } catch (SQLException ex) {
12320  throw new TskCoreException("Error querying reports table", ex);
12321  } finally {
12323  }
12324  }
12325 
12326  static void closeResultSet(ResultSet resultSet) {
12327  if (resultSet != null) {
12328  try {
12329  resultSet.close();
12330  } catch (SQLException ex) {
12331  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
12332  }
12333  }
12334  }
12335 
12336  static void closeStatement(Statement statement) {
12337  if (statement != null) {
12338  try {
12339  statement.close();
12340  } catch (SQLException ex) {
12341  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
12342 
12343  }
12344  }
12345  }
12346 
12347  static void closeConnection(CaseDbConnection connection) {
12348  if (connection != null) {
12349  connection.close();
12350  }
12351  }
12352 
12353  private static void rollbackTransaction(CaseDbConnection connection) {
12354  if (connection != null) {
12355  connection.rollbackTransaction();
12356  }
12357  }
12358 
12367  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
12369  try (CaseDbConnection connection = connections.getConnection();) {
12370  Statement statement = connection.createStatement();
12371  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
12372  } catch (SQLException ex) {
12373  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
12374  } finally {
12376  }
12377  }
12378 
12379  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
12381  try (CaseDbConnection connection = connections.getConnection();
12382  Statement statement = connection.createStatement();) {
12383  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
12384  } catch (SQLException ex) {
12385  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
12386  } finally {
12388  }
12389  }
12390 
12407  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
12408  CaseDbConnection connection = null;
12410  ResultSet resultSet = null;
12411  Statement statement;
12412  try {
12413  connection = connections.getConnection();
12414  connection.beginTransaction();
12415  statement = connection.createStatement();
12416  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
12417  insertStatement.setLong(1, dataSource.getId());
12418  insertStatement.setString(2, hostName);
12419  insertStatement.setLong(3, jobStart.getTime());
12420  insertStatement.setLong(4, jobEnd.getTime());
12421  insertStatement.setInt(5, status.ordinal());
12422  insertStatement.setString(6, settingsDir);
12423  connection.executeUpdate(insertStatement);
12424  resultSet = insertStatement.getGeneratedKeys();
12425  resultSet.next();
12426  long id = resultSet.getLong(1); //last_insert_rowid()
12427  for (int i = 0; i < ingestModules.size(); i++) {
12428  IngestModuleInfo ingestModule = ingestModules.get(i);
12429  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
12430  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
12431  }
12432  resultSet.close();
12433  resultSet = null;
12434  connection.commitTransaction();
12435  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
12436  } catch (SQLException ex) {
12437  rollbackTransaction(connection);
12438  throw new TskCoreException("Error adding the ingest job.", ex);
12439  } finally {
12440  closeResultSet(resultSet);
12441  closeConnection(connection);
12443  }
12444  }
12445 
12459  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
12460  CaseDbConnection connection = null;
12461  ResultSet resultSet = null;
12462  Statement statement = null;
12463  String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version;
12465  try {
12466  connection = connections.getConnection();
12467  statement = connection.createStatement();
12468  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12469  if (!resultSet.next()) {
12470  resultSet.close();
12471  resultSet = null;
12472  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
12473  insertStatement.setString(1, displayName);
12474  insertStatement.setString(2, uniqueName);
12475  insertStatement.setInt(3, type.ordinal());
12476  insertStatement.setString(4, version);
12477  connection.executeUpdate(insertStatement);
12478  resultSet = statement.getGeneratedKeys();
12479  resultSet.next();
12480  long id = resultSet.getLong(1); //last_insert_rowid()
12481  resultSet.close();
12482  resultSet = null;
12483  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
12484  } else {
12485  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12486  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12487  }
12488  } catch (SQLException ex) {
12489  try {
12490  closeStatement(statement);
12491  if (connection != null) {
12492  statement = connection.createStatement();
12493  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12494  if (resultSet.next()) {
12495  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12496  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12497  }
12498  }
12499  throw new TskCoreException("Couldn't add new module to database.", ex);
12500  } catch (SQLException ex1) {
12501  throw new TskCoreException("Couldn't add new module to database.", ex1);
12502  }
12503  } finally {
12504  closeResultSet(resultSet);
12505  closeStatement(statement);
12506  closeConnection(connection);
12508  }
12509  }
12510 
12518  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
12519  CaseDbConnection connection = null;
12520  ResultSet resultSet = null;
12521  Statement statement = null;
12522  List<IngestJobInfo> ingestJobs = new ArrayList<>();
12524  try {
12525  connection = connections.getConnection();
12526  statement = connection.createStatement();
12527  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
12528  while (resultSet.next()) {
12529  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
12530  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
12531  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
12532  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
12533  }
12534  return ingestJobs;
12535  } catch (SQLException ex) {
12536  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
12537  } finally {
12538  closeResultSet(resultSet);
12539  closeStatement(statement);
12540  closeConnection(connection);
12542  }
12543  }
12544 
12555  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
12556  ResultSet resultSet = null;
12557  Statement statement = null;
12558  List<IngestModuleInfo> ingestModules = new ArrayList<>();
12560  try {
12561  statement = connection.createStatement();
12562  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
12563  + "ingest_job_modules.pipeline_position AS pipeline_position, "
12564  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
12565  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
12566  + "FROM ingest_job_modules, ingest_modules "
12567  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
12568  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
12569  + "ORDER BY (ingest_job_modules.pipeline_position);");
12570  while (resultSet.next()) {
12571  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12572  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
12573  }
12574  return ingestModules;
12575  } finally {
12576  closeResultSet(resultSet);
12577  closeStatement(statement);
12579 
12580  }
12581  }
12582 
12592  String getInsertOrIgnoreSQL(String sql) {
12593  switch (getDatabaseType()) {
12594  case POSTGRESQL:
12595  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
12596  case SQLITE:
12597  return " INSERT OR IGNORE " + sql; //NON-NLS
12598  default:
12599  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
12600  }
12601  }
12602 
12606  static class ObjectInfo {
12607 
12608  private long id;
12609  private TskData.ObjectType type;
12610 
12611  ObjectInfo(long id, ObjectType type) {
12612  this.id = id;
12613  this.type = type;
12614  }
12615 
12616  long getId() {
12617  return id;
12618  }
12619 
12620  TskData.ObjectType getType() {
12621  return type;
12622  }
12623  }
12624 
12625  private interface DbCommand {
12626 
12627  void execute() throws SQLException;
12628  }
12629 
12630  private enum PREPARED_STATEMENT {
12631 
12632  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
12633  + "WHERE artifact_type_id = ?"), //NON-NLS
12634  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
12635  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
12636  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
12637  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
12638  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
12639  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12640  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12641  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
12642  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
12643  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
12644  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12645  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12646  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
12647  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12648  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12649  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12650  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12651  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
12652  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12653  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12654  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12655  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12656  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12657  + "WHERE tsk_files.extension = ? AND "
12658  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
12659  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12660  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12661  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12662  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12663  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12664  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
12665  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12666  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12667  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12668  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
12669  + "AND tsk_files.type = ? )"), //NON-NLS
12670  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
12671  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12672  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12673  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
12674  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
12675  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12676  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
12677  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12678  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
12679  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12680  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
12681  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12682  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
12683  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12684  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
12685  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12686  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
12687  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12688  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
12689  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12690  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
12691  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
12692  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
12693  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
12694  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
12695  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
12696  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12697  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12698  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
12699  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
12700  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12701  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12702  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12703  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
12704  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
12705  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
12706  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
12707  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
12708  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
12709  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
12710  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12711  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12712  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
12713  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
12714  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
12715  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
12716  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, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id ) " //NON-NLS
12717  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
12718  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, mime_type, parent_path, extension, owner_uid, os_account_obj_id )"
12719  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
12720  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
12721  + "WHERE obj_id = ?"), //NON-NLS
12722  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
12723  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12724  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
12725  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
12726  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
12727  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
12728  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
12729  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
12730  + "WHERE tag_name_id IN " //NON-NLS
12731  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
12732  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
12733  + "WHERE tag_name_id IN "
12734  + "( SELECT content_tags.tag_name_id as tag_name_id "
12735  + "FROM content_tags as content_tags, tsk_files as tsk_files"
12736  + " WHERE content_tags.obj_id = tsk_files.obj_id"
12737  + " AND tsk_files.data_source_obj_id = ?"
12738  + " UNION "
12739  + "SELECT artifact_tags.tag_name_id as tag_name_id "
12740  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
12741  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
12742  + " AND arts.data_source_obj_id = ?"
12743  + " )"),
12744  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
12745  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12746  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
12747  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
12748  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
12749  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
12750  + " AND content_tags.tag_name_id = ? "
12751  + " AND tsk_files.data_source_obj_id = ? "
12752  ),
12753  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 "
12754  + "FROM content_tags "
12755  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12756  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12757  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 "
12758  + "FROM content_tags "
12759  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12760  + "WHERE tag_name_id = ?"), //NON-NLS
12761  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 "
12762  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
12763  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
12764  + " AND content_tags.obj_id = tsk_files.obj_id"
12765  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
12766  + " AND content_tags.tag_name_id = ?"
12767  + " AND tsk_files.data_source_obj_id = ? "),
12768  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 "
12769  + "FROM content_tags "
12770  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12771  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12772  + "WHERE tag_id = ?"), //NON-NLS
12773  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 "
12774  + "FROM content_tags "
12775  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12776  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12777  + "WHERE content_tags.obj_id = ?"), //NON-NLS
12778  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
12779  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12780  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
12781  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 "
12782  + "FROM blackboard_artifact_tags "
12783  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12784  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12785  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
12786  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"
12787  + " AND artifact_tags.tag_name_id = ?"
12788  + " AND arts.data_source_obj_id = ? "),
12789  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 "
12790  + "FROM blackboard_artifact_tags "
12791  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12792  + "WHERE tag_name_id = ?"), //NON-NLS
12793  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 "
12794  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
12795  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
12796  + " AND artifact_tags.artifact_id = arts.artifact_id"
12797  + " AND artifact_tags.tag_name_id = ? "
12798  + " AND arts.data_source_obj_id = ? "),
12799  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 "
12800  + "FROM blackboard_artifact_tags "
12801  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12802  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12803  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
12804  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 "
12805  + "FROM blackboard_artifact_tags "
12806  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12807  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12808  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
12809  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
12810  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
12811  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
12812  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
12813  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
12814  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12815  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
12816  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
12817  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
12818  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
12819  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
12820  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
12821  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
12822  + "WHERE (tsk_objects.par_obj_id = ?)"),
12823  INSERT_OR_UPDATE_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?) ON CONFLICT (display_name) DO UPDATE SET description = ?, color = ?, knownStatus = ?"),
12824  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
12825  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
12826  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
12827  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
12828  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
12829  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
12830  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
12831  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
12832  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
12833  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
12834  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
12835  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"),
12836  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
12837  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
12838  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
12839  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
12840  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)"
12841  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
12842  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?"),
12843  SELECT_TAG_NAME_BY_NAME("SELECT * FROM tag_names where display_name = ?");
12844 
12845  private final String sql;
12846 
12847  private PREPARED_STATEMENT(String sql) {
12848  this.sql = sql;
12849  }
12850 
12851  String getSQL() {
12852  return sql;
12853  }
12854  }
12855 
12861  abstract private class ConnectionPool {
12862 
12863  private PooledDataSource pooledDataSource;
12864 
12865  public ConnectionPool() {
12866  pooledDataSource = null;
12867  }
12868 
12869  CaseDbConnection getConnection() throws TskCoreException {
12870  if (pooledDataSource == null) {
12871  throw new TskCoreException("Error getting case database connection - case is closed");
12872  }
12873  try {
12874  return getPooledConnection();
12875  } catch (SQLException exp) {
12876  throw new TskCoreException(exp.getMessage());
12877  }
12878  }
12879 
12880  void close() throws TskCoreException {
12881  if (pooledDataSource != null) {
12882  try {
12883  pooledDataSource.close();
12884  } catch (SQLException exp) {
12885  throw new TskCoreException(exp.getMessage());
12886  } finally {
12887  pooledDataSource = null;
12888  }
12889  }
12890  }
12891 
12892  abstract CaseDbConnection getPooledConnection() throws SQLException;
12893 
12894  public PooledDataSource getPooledDataSource() {
12895  return pooledDataSource;
12896  }
12897 
12898  public void setPooledDataSource(PooledDataSource pooledDataSource) {
12899  this.pooledDataSource = pooledDataSource;
12900  }
12901  }
12902 
12907  private final class SQLiteConnections extends ConnectionPool {
12908 
12909  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
12910 
12911  SQLiteConnections(String dbPath) throws SQLException {
12912  configurationOverrides.put("acquireIncrement", "2");
12913  configurationOverrides.put("initialPoolSize", "5");
12914  configurationOverrides.put("minPoolSize", "5");
12915  /*
12916  * NOTE: max pool size and max statements are related. If you
12917  * increase max pool size, then also increase statements.
12918  */
12919  configurationOverrides.put("maxPoolSize", "20");
12920  configurationOverrides.put("maxStatements", "200");
12921  configurationOverrides.put("maxStatementsPerConnection", "20");
12922 
12923  SQLiteConfig config = new SQLiteConfig();
12924  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
12925  config.setReadUncommited(true);
12926  config.enforceForeignKeys(true); // Enforce foreign key constraints.
12927  SQLiteDataSource unpooled = new SQLiteDataSource(config);
12928  unpooled.setUrl("jdbc:sqlite:" + dbPath);
12929  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
12930  }
12931 
12932  @Override
12933  public CaseDbConnection getPooledConnection() throws SQLException {
12934  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
12935  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
12936  // Temporarily filter out Image Gallery threads
12937  if (!Thread.currentThread().getName().contains("ImageGallery")) {
12938  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());
12939  }
12940  }
12941  return new SQLiteConnection(getPooledDataSource().getConnection());
12942  }
12943  }
12944 
12949  private final class PostgreSQLConnections extends ConnectionPool {
12950 
12951  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
12952  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
12953  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
12954  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
12955  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
12956  comboPooledDataSource.setUser(userName);
12957  comboPooledDataSource.setPassword(password);
12958  comboPooledDataSource.setAcquireIncrement(2);
12959  comboPooledDataSource.setInitialPoolSize(5);
12960  comboPooledDataSource.setMinPoolSize(5);
12961  /*
12962  * NOTE: max pool size and max statements are related. If you
12963  * increase max pool size, then also increase statements.
12964  */
12965  comboPooledDataSource.setMaxPoolSize(20);
12966  comboPooledDataSource.setMaxStatements(200);
12967  comboPooledDataSource.setMaxStatementsPerConnection(20);
12968  setPooledDataSource(comboPooledDataSource);
12969  }
12970 
12971  @Override
12972  public CaseDbConnection getPooledConnection() throws SQLException {
12973  return new PostgreSQLConnection(getPooledDataSource().getConnection());
12974  }
12975  }
12976 
12980  abstract class CaseDbConnection implements AutoCloseable {
12981 
12982  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
12983  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
12984 
12985  private class CreateStatement implements DbCommand {
12986 
12987  private final Connection connection;
12988  private Statement statement = null;
12989 
12990  CreateStatement(Connection connection) {
12991  this.connection = connection;
12992  }
12993 
12994  Statement getStatement() {
12995  return statement;
12996  }
12997 
12998  @Override
12999  public void execute() throws SQLException {
13000  statement = connection.createStatement();
13001  }
13002  }
13003 
13004  private class SetAutoCommit implements DbCommand {
13005 
13006  private final Connection connection;
13007  private final boolean mode;
13008 
13009  SetAutoCommit(Connection connection, boolean mode) {
13010  this.connection = connection;
13011  this.mode = mode;
13012  }
13013 
13014  @Override
13015  public void execute() throws SQLException {
13016  connection.setAutoCommit(mode);
13017  }
13018  }
13019 
13020  private class Commit implements DbCommand {
13021 
13022  private final Connection connection;
13023 
13024  Commit(Connection connection) {
13025  this.connection = connection;
13026  }
13027 
13028  @Override
13029  public void execute() throws SQLException {
13030  connection.commit();
13031  }
13032  }
13033 
13042  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13043 
13044  private final Connection connection;
13045 
13046  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13047  this.connection = connection;
13048  }
13049 
13050  @Override
13051  public void execute() throws SQLException {
13052  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13053  preparedStatement.execute();
13054 
13055  }
13056  }
13057 
13058  private class ExecuteQuery implements DbCommand {
13059 
13060  private final Statement statement;
13061  private final String query;
13062  private ResultSet resultSet;
13063 
13064  ExecuteQuery(Statement statement, String query) {
13065  this.statement = statement;
13066  this.query = query;
13067  }
13068 
13069  ResultSet getResultSet() {
13070  return resultSet;
13071  }
13072 
13073  @Override
13074  public void execute() throws SQLException {
13075  resultSet = statement.executeQuery(query);
13076  }
13077  }
13078 
13079  private class ExecutePreparedStatementQuery implements DbCommand {
13080 
13081  private final PreparedStatement preparedStatement;
13082  private ResultSet resultSet;
13083 
13084  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13085  this.preparedStatement = preparedStatement;
13086  }
13087 
13088  ResultSet getResultSet() {
13089  return resultSet;
13090  }
13091 
13092  @Override
13093  public void execute() throws SQLException {
13094  resultSet = preparedStatement.executeQuery();
13095  }
13096  }
13097 
13098  private class ExecutePreparedStatementUpdate implements DbCommand {
13099 
13100  private final PreparedStatement preparedStatement;
13101 
13102  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
13103  this.preparedStatement = preparedStatement;
13104  }
13105 
13106  @Override
13107  public void execute() throws SQLException {
13108  preparedStatement.executeUpdate();
13109  }
13110  }
13111 
13112  private class ExecuteStatementUpdate implements DbCommand {
13113 
13114  private final Statement statement;
13115  private final String updateCommand;
13116 
13117  ExecuteStatementUpdate(Statement statement, String updateCommand) {
13118  this.statement = statement;
13119  this.updateCommand = updateCommand;
13120  }
13121 
13122  @Override
13123  public void execute() throws SQLException {
13124  statement.executeUpdate(updateCommand);
13125  }
13126  }
13127 
13128  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
13129 
13130  private final Statement statement;
13131  private final int generateKeys;
13132  private final String updateCommand;
13133 
13134  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
13135  this.statement = statement;
13136  this.generateKeys = generateKeys;
13137  this.updateCommand = updateCommand;
13138  }
13139 
13140  @Override
13141  public void execute() throws SQLException {
13142  statement.executeUpdate(updateCommand, generateKeys);
13143  }
13144  }
13145 
13146  private class PrepareStatement implements DbCommand {
13147 
13148  private final Connection connection;
13149  private final String input;
13150  private PreparedStatement preparedStatement = null;
13151 
13152  PrepareStatement(Connection connection, String input) {
13153  this.connection = connection;
13154  this.input = input;
13155  }
13156 
13157  PreparedStatement getPreparedStatement() {
13158  return preparedStatement;
13159  }
13160 
13161  @Override
13162  public void execute() throws SQLException {
13163  preparedStatement = connection.prepareStatement(input);
13164  }
13165  }
13166 
13167  private class PrepareStatementGenerateKeys implements DbCommand {
13168 
13169  private final Connection connection;
13170  private final String input;
13171  private final int generateKeys;
13172  private PreparedStatement preparedStatement = null;
13173 
13174  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
13175  this.connection = connection;
13176  this.input = input;
13177  this.generateKeys = generateKeysInput;
13178  }
13179 
13180  PreparedStatement getPreparedStatement() {
13181  return preparedStatement;
13182  }
13183 
13184  @Override
13185  public void execute() throws SQLException {
13186  preparedStatement = connection.prepareStatement(input, generateKeys);
13187  }
13188  }
13189 
13190  abstract void executeCommand(DbCommand command) throws SQLException;
13191 
13192  private final Connection connection;
13193  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
13194  private final Map<String, PreparedStatement> adHocPreparedStatements;
13195 
13196  CaseDbConnection(Connection connection) {
13197  this.connection = connection;
13198  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
13199  adHocPreparedStatements = new HashMap<>();
13200  }
13201 
13202  boolean isOpen() {
13203  return this.connection != null;
13204  }
13205 
13206  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
13207  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
13208  }
13209 
13210  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
13211  // Lazy statement preparation.
13212  PreparedStatement statement;
13213  if (this.preparedStatements.containsKey(statementKey)) {
13214  statement = this.preparedStatements.get(statementKey);
13215  } else {
13216  statement = prepareStatement(statementKey.getSQL(), generateKeys);
13217  this.preparedStatements.put(statementKey, statement);
13218  }
13219  return statement;
13220  }
13221 
13233  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
13234  PreparedStatement statement;
13235  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
13236  if (adHocPreparedStatements.containsKey(statementKey)) {
13237  statement = this.adHocPreparedStatements.get(statementKey);
13238  } else {
13239  statement = prepareStatement(sqlStatement, generateKeys);
13240  this.adHocPreparedStatements.put(statementKey, statement);
13241  }
13242  return statement;
13243  }
13244 
13245  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13246  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
13247  executeCommand(prepareStatement);
13248  return prepareStatement.getPreparedStatement();
13249  }
13250 
13251  Statement createStatement() throws SQLException {
13252  CreateStatement createStatement = new CreateStatement(this.connection);
13253  executeCommand(createStatement);
13254  return createStatement.getStatement();
13255  }
13256 
13257  void beginTransaction() throws SQLException {
13258  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
13259  executeCommand(setAutoCommit);
13260  }
13261 
13262  void commitTransaction() throws SQLException {
13263  Commit commit = new Commit(connection);
13264  executeCommand(commit);
13265  // You must turn auto commit back on when done with the transaction.
13266  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
13267  executeCommand(setAutoCommit);
13268  }
13269 
13275  void rollbackTransaction() {
13276  try {
13277  connection.rollback();
13278  } catch (SQLException e) {
13279  logger.log(Level.SEVERE, "Error rolling back transaction", e);
13280  }
13281  try {
13282  connection.setAutoCommit(true);
13283  } catch (SQLException e) {
13284  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
13285  }
13286  }
13287 
13295  void rollbackTransactionWithThrow() throws SQLException {
13296  try {
13297  connection.rollback();
13298  } finally {
13299  connection.setAutoCommit(true);
13300  }
13301  }
13302 
13311  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
13312  switch (getDatabaseType()) {
13313  case POSTGRESQL:
13314  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
13315  executeCommand(tableWriteLock);
13316  break;
13317  case SQLITE:
13318  // We do nothing here because we assume the entire SQLite DB is already locked from
13319  // when the analysis results were added/deleted in the same transaction.
13320  break;
13321  default:
13322  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
13323  }
13324  }
13325 
13326  ResultSet executeQuery(Statement statement, String query) throws SQLException {
13327  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
13328  executeCommand(queryCommand);
13329  return queryCommand.getResultSet();
13330  }
13331 
13341  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
13342  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
13343  executeCommand(executePreparedStatementQuery);
13344  return executePreparedStatementQuery.getResultSet();
13345  }
13346 
13347  void executeUpdate(Statement statement, String update) throws SQLException {
13348  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
13349  }
13350 
13351  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13352  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
13353  executeCommand(executeStatementUpdate);
13354  }
13355 
13356  void executeUpdate(PreparedStatement statement) throws SQLException {
13357  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
13358  executeCommand(executePreparedStatementUpdate);
13359  }
13360 
13364  @Override
13365  public void close() {
13366  try {
13367  for (PreparedStatement stmt : preparedStatements.values()) {
13368  closeStatement(stmt);
13369  }
13370  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
13371  closeStatement(stmt);
13372  }
13373  connection.close();
13374  } catch (SQLException ex) {
13375  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
13376  }
13377  }
13378 
13379  Connection getConnection() {
13380  return this.connection;
13381  }
13382  }
13383 
13387  private final class SQLiteConnection extends CaseDbConnection {
13388 
13389  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
13390  private static final int SQLITE_BUSY_ERROR = 5;
13391 
13392  SQLiteConnection(Connection conn) {
13393  super(conn);
13394  }
13395 
13396  @Override
13397  void executeCommand(DbCommand command) throws SQLException {
13398  int retryCounter = 0;
13399  while (true) {
13400  try {
13401  command.execute(); // Perform the operation
13402  break;
13403  } catch (SQLException ex) {
13404  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
13405  try {
13406 
13407  // We do not notify of error here, as this is not an
13408  // error condition. It is likely a temporary busy or
13409  // locked issue and we will retry.
13410  retryCounter++;
13411  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13412  } catch (InterruptedException exp) {
13413  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13414  }
13415  } else {
13416  throw ex;
13417  }
13418  }
13419  }
13420  }
13421  }
13422 
13426  private final class PostgreSQLConnection extends CaseDbConnection {
13427 
13428  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
13429  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
13430  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
13431  private static final int MAX_RETRIES = 3;
13432 
13433  PostgreSQLConnection(Connection conn) {
13434  super(conn);
13435  }
13436 
13437  @Override
13438  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13439  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
13440  executeCommand(executeStatementUpdateGenerateKeys);
13441  }
13442 
13443  @Override
13444  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13445  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
13446  executeCommand(prepareStatementGenerateKeys);
13447  return prepareStatementGenerateKeys.getPreparedStatement();
13448  }
13449 
13450  @Override
13451  void executeCommand(DbCommand command) throws SQLException {
13452  SQLException lastException = null;
13453  for (int retries = 0; retries < MAX_RETRIES; retries++) {
13454  try {
13455  command.execute();
13456  lastException = null; // reset since we had a successful execution
13457  break;
13458  } catch (SQLException ex) {
13459  lastException = ex;
13460  String sqlState = ex.getSQLState();
13461  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
13462  try {
13463  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13464  } catch (InterruptedException exp) {
13465  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13466  }
13467  } else {
13468  throw ex;
13469  }
13470  }
13471  }
13472 
13473  // rethrow the exception if we bailed because of too many retries
13474  if (lastException != null) {
13475  throw lastException;
13476  }
13477  }
13478  }
13479 
13494  public static final class CaseDbTransaction {
13495 
13496  private final CaseDbConnection connection;
13497  private SleuthkitCase sleuthkitCase;
13498 
13499  // A collection of object score changes that ocuured as part of this transaction.
13500  // When the transaction is committed, events are fired to notify any listeners.
13501  // Score changes are stored as a map keyed by objId to prevent duplicates.
13502  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
13503  private List<Host> hostsAdded = new ArrayList<>();
13504  private List<OsAccount> accountsChanged = new ArrayList<>();
13505  private List<OsAccount> accountsAdded = new ArrayList<>();
13506  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
13507  private List<Long> deletedResultObjectIds = new ArrayList<>();
13508 
13509  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
13510  private static final Object threadsWithOpenTransactionLock = new Object();
13511 
13512  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
13513  this.sleuthkitCase = sleuthkitCase;
13514 
13515  sleuthkitCase.acquireSingleUserCaseWriteLock();
13516  this.connection = sleuthkitCase.getConnection();
13517  try {
13518  synchronized (threadsWithOpenTransactionLock) {
13519  this.connection.beginTransaction();
13520  threadsWithOpenTransaction.add(Thread.currentThread().getId());
13521  }
13522  } catch (SQLException ex) {
13523  sleuthkitCase.releaseSingleUserCaseWriteLock();
13524  throw new TskCoreException("Failed to create transaction on case database", ex);
13525  }
13526 
13527  }
13528 
13536  CaseDbConnection getConnection() {
13537  return this.connection;
13538  }
13539 
13545  void registerScoreChange(ScoreChange scoreChange) {
13546  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
13547  }
13548 
13554  void registerAddedHost(Host host) {
13555  if (host != null) {
13556  this.hostsAdded.add(host);
13557  }
13558  }
13559 
13565  void registerChangedOsAccount(OsAccount account) {
13566  if (account != null) {
13567  accountsChanged.add(account);
13568  }
13569  }
13570 
13576  void registerDeletedOsAccount(long osAccountObjId) {
13577  deletedOsAccountObjectIds.add(osAccountObjId);
13578  }
13579 
13585  void registerAddedOsAccount(OsAccount account) {
13586  if (account != null) {
13587  accountsAdded.add(account);
13588  }
13589  }
13590 
13597  void registerDeletedAnalysisResult(long analysisResultObjId) {
13598  this.deletedResultObjectIds.add(analysisResultObjId);
13599  }
13600 
13609  private static boolean hasOpenTransaction(long threadId) {
13610  synchronized (threadsWithOpenTransactionLock) {
13611  return threadsWithOpenTransaction.contains(threadId);
13612  }
13613  }
13614 
13621  public void commit() throws TskCoreException {
13622  try {
13623  this.connection.commitTransaction();
13624  } catch (SQLException ex) {
13625  throw new TskCoreException("Failed to commit transaction on case database", ex);
13626  } finally {
13627  close();
13628 
13629  if (!scoreChangeMap.isEmpty()) {
13630  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
13631  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
13632  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
13633  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
13634  }
13635  }
13636  if (!hostsAdded.isEmpty()) {
13637  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
13638  }
13639  if (!accountsAdded.isEmpty()) {
13640  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
13641  }
13642  if (!accountsChanged.isEmpty()) {
13643  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
13644  }
13645  if (!deletedOsAccountObjectIds.isEmpty()) {
13646  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
13647  }
13648  if (!deletedResultObjectIds.isEmpty()) {
13649  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
13650  }
13651  }
13652  }
13653 
13660  public void rollback() throws TskCoreException {
13661  try {
13662  this.connection.rollbackTransactionWithThrow();
13663  } catch (SQLException ex) {
13664  throw new TskCoreException("Case database transaction rollback failed", ex);
13665  } finally {
13666  close();
13667  }
13668  }
13669 
13674  void close() {
13675  this.connection.close();
13676  sleuthkitCase.releaseSingleUserCaseWriteLock();
13677  synchronized (threadsWithOpenTransactionLock) {
13678  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
13679  }
13680  }
13681  }
13682 
13692  public final class CaseDbQuery implements AutoCloseable {
13693 
13694  private ResultSet resultSet;
13695  private CaseDbConnection connection;
13696 
13697  private CaseDbQuery(String query) throws TskCoreException {
13698  this(query, false);
13699  }
13700 
13701  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
13702  if (!allowWriteQuery) {
13703  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
13704  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
13705  }
13706  }
13707 
13709  try {
13710  connection = connections.getConnection();
13711  resultSet = connection.executeQuery(connection.createStatement(), query);
13712  } catch (SQLException ex) {
13714  throw new TskCoreException("Error executing query: ", ex);
13715  } catch (TskCoreException ex) {
13717  throw ex;
13718  }
13719  }
13720 
13726  public ResultSet getResultSet() {
13727  return resultSet;
13728  }
13729 
13730  @Override
13731  public void close() throws TskCoreException {
13732  try {
13733  if (resultSet != null) {
13734  final Statement statement = resultSet.getStatement();
13735  if (statement != null) {
13736  statement.close();
13737  }
13738  resultSet.close();
13739  }
13740  closeConnection(connection);
13741  } catch (SQLException ex) {
13742  throw new TskCoreException("Error closing query: ", ex);
13743  } finally {
13745  }
13746  }
13747  }
13748 
13756  @Deprecated
13757  public void addErrorObserver(ErrorObserver observer) {
13758  sleuthkitCaseErrorObservers.add(observer);
13759  }
13760 
13768  @Deprecated
13769  public void removeErrorObserver(ErrorObserver observer) {
13770  int i = sleuthkitCaseErrorObservers.indexOf(observer);
13771  if (i >= 0) {
13772  sleuthkitCaseErrorObservers.remove(i);
13773  }
13774  }
13775 
13784  @Deprecated
13785  public void submitError(String context, String errorMessage) {
13786  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
13787  if (observer != null) {
13788  try {
13789  observer.receiveError(context, errorMessage);
13790  } catch (Exception ex) {
13791  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
13792 
13793  }
13794  }
13795  }
13796  }
13797 
13803  @Deprecated
13804  public interface ErrorObserver {
13805 
13812  public enum Context {
13813 
13817  IMAGE_READ_ERROR("Image File Read Error"),
13821  DATABASE_READ_ERROR("Database Read Error");
13822 
13823  private final String contextString;
13824 
13825  private Context(String context) {
13826  this.contextString = context;
13827  }
13828 
13829  public String getContextString() {
13830  return contextString;
13831  }
13832  };
13833 
13834  void receiveError(String context, String errorMessage);
13835  }
13836 
13847  @Deprecated
13848  long getDataSourceObjectId(long objectId) {
13849  try {
13850  CaseDbConnection connection = connections.getConnection();
13851  try {
13852  return getDataSourceObjectId(connection, objectId);
13853  } finally {
13854  closeConnection(connection);
13855  }
13856  } catch (TskCoreException ex) {
13857  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
13858  return 0;
13859  }
13860  }
13861 
13871  @Deprecated
13872  public long getLastObjectId() throws TskCoreException {
13873  CaseDbConnection connection = null;
13874  ResultSet rs = null;
13876  try {
13877  connection = connections.getConnection();
13878 
13879  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
13880  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
13881  rs = connection.executeQuery(statement);
13882  long id = -1;
13883  if (rs.next()) {
13884  id = rs.getLong("max_obj_id");
13885  }
13886  return id;
13887  } catch (SQLException e) {
13888  throw new TskCoreException("Error getting last object id", e);
13889  } finally {
13890  closeResultSet(rs);
13891  closeConnection(connection);
13893  }
13894  }
13895 
13909  @Deprecated
13910  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
13911  CaseDbConnection connection = null;
13912  Statement s = null;
13913  ResultSet rs = null;
13915  try {
13916  connection = connections.getConnection();
13917  s = connection.createStatement();
13918  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
13919  List<FsContent> results = new ArrayList<FsContent>();
13920  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
13921  for (AbstractFile f : temp) {
13922  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
13923  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
13924  results.add((FsContent) f);
13925  }
13926  }
13927  return results;
13928  } catch (SQLException e) {
13929  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
13930  } finally {
13931  closeResultSet(rs);
13932  closeStatement(s);
13933  closeConnection(connection);
13935  }
13936  }
13937 
13949  @Deprecated
13950  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
13951  CaseDbConnection connection = null;
13952  Statement s = null;
13953  ResultSet rs = null;
13955  try {
13956  connection = connections.getConnection();
13957  s = connection.createStatement();
13958  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
13959  int typeId = -1;
13960  if (rs.next()) {
13961  typeId = rs.getInt("artifact_type_id");
13962  }
13963  return typeId;
13964  } catch (SQLException ex) {
13965  throw new TskCoreException("Error getting artifact type id", ex);
13966  } finally {
13967  closeResultSet(rs);
13968  closeStatement(s);
13969  closeConnection(connection);
13971  }
13972  }
13973 
13983  @Deprecated
13984  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
13985  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
13986  }
13987 
14001  @Deprecated
14002  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14003  try {
14004  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14005  } catch (TskDataException ex) {
14006  throw new TskCoreException("Failed to add artifact type.", ex);
14007  }
14008  }
14009 
14023  @Deprecated
14024  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14025  try {
14026  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14027  } catch (TskDataException ex) {
14028  throw new TskCoreException("Couldn't add new attribute type");
14029  }
14030  }
14031 
14042  @Deprecated
14043  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14044  CaseDbConnection connection = null;
14045  Statement s = null;
14046  ResultSet rs = null;
14048  try {
14049  connection = connections.getConnection();
14050  s = connection.createStatement();
14051  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
14052  int typeId = -1;
14053  if (rs.next()) {
14054  typeId = rs.getInt("attribute_type_id");
14055  }
14056  return typeId;
14057  } catch (SQLException ex) {
14058  throw new TskCoreException("Error getting attribute type id", ex);
14059  } finally {
14060  closeResultSet(rs);
14061  closeStatement(s);
14062  closeConnection(connection);
14064  }
14065  }
14066 
14079  @Deprecated
14080  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
14081  CaseDbConnection connection = null;
14082  Statement s = null;
14083  ResultSet rs = null;
14085  try {
14086  connection = connections.getConnection();
14087  s = connection.createStatement();
14088  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14089  if (rs.next()) {
14090  return rs.getString("type_name");
14091  } else {
14092  throw new TskCoreException("No type with that id");
14093  }
14094  } catch (SQLException ex) {
14095  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14096  } finally {
14097  closeResultSet(rs);
14098  closeStatement(s);
14099  closeConnection(connection);
14101  }
14102  }
14103 
14116  @Deprecated
14117  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
14118  CaseDbConnection connection = null;
14119  Statement s = null;
14120  ResultSet rs = null;
14122  try {
14123  connection = connections.getConnection();
14124  s = connection.createStatement();
14125  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14126  if (rs.next()) {
14127  return rs.getString("display_name");
14128  } else {
14129  throw new TskCoreException("No type with that id");
14130  }
14131  } catch (SQLException ex) {
14132  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14133  } finally {
14134  closeResultSet(rs);
14135  closeStatement(s);
14136  closeConnection(connection);
14138  }
14139  }
14140 
14150  @Deprecated
14151  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
14152  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
14153  }
14154 
14170  @Deprecated
14171  public ResultSet runQuery(String query) throws SQLException {
14172  CaseDbConnection connection = null;
14174  try {
14175  connection = connections.getConnection();
14176  return connection.executeQuery(connection.createStatement(), query);
14177  } catch (TskCoreException ex) {
14178  throw new SQLException("Error getting connection for ad hoc query", ex);
14179  } finally {
14180  //TODO unlock should be done in closeRunQuery()
14181  //but currently not all code calls closeRunQuery - need to fix this
14182  closeConnection(connection);
14184  }
14185  }
14186 
14196  @Deprecated
14197  public void closeRunQuery(ResultSet resultSet) throws SQLException {
14198  final Statement statement = resultSet.getStatement();
14199  resultSet.close();
14200  if (statement != null) {
14201  statement.close();
14202  }
14203  }
14204 
14221  @Deprecated
14222  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
14223  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
14224  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
14225  files.add(carvedFile);
14226  CarvingResult carvingResult;
14227  Content parent = getContentById(containerId);
14228  if (parent instanceof FileSystem
14229  || parent instanceof Volume
14230  || parent instanceof Image) {
14231  carvingResult = new CarvingResult(parent, files);
14232  } else {
14233  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
14234  }
14235  return addCarvedFiles(carvingResult).get(0);
14236  }
14237 
14251  @Deprecated
14252  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
14253  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
14254  for (CarvedFileContainer container : filesToAdd) {
14255  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
14256  carvedFiles.add(carvedFile);
14257  }
14258  CarvingResult carvingResult;
14259  Content parent = getContentById(filesToAdd.get(0).getId());
14260  if (parent instanceof FileSystem
14261  || parent instanceof Volume
14262  || parent instanceof Image) {
14263  carvingResult = new CarvingResult(parent, carvedFiles);
14264  } else {
14265  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
14266  }
14267  return addCarvedFiles(carvingResult);
14268  }
14269 
14299  @Deprecated
14300  public DerivedFile addDerivedFile(String fileName, String localPath,
14301  long size, long ctime, long crtime, long atime, long mtime,
14302  boolean isFile, AbstractFile parentFile,
14303  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
14304  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14305  isFile, parentFile, rederiveDetails, toolName, toolVersion,
14306  otherDetails, TskData.EncodingType.NONE);
14307  }
14308 
14338  @Deprecated
14339  public LocalFile addLocalFile(String fileName, String localPath,
14340  long size, long ctime, long crtime, long atime, long mtime,
14341  String md5, FileKnown known, String mimeType,
14342  boolean isFile, TskData.EncodingType encodingType,
14343  Content parent, CaseDbTransaction transaction) throws TskCoreException {
14344 
14345  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14346  md5, null, known, mimeType, isFile, encodingType,
14347  parent, transaction);
14348  }
14349 
14374  @Deprecated
14375  public LocalFile addLocalFile(String fileName, String localPath,
14376  long size, long ctime, long crtime, long atime, long mtime,
14377  boolean isFile,
14378  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
14379  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
14380  TskData.EncodingType.NONE, parent, transaction);
14381  }
14382 
14402  @Deprecated
14403  public LocalFile addLocalFile(String fileName, String localPath,
14404  long size, long ctime, long crtime, long atime, long mtime,
14405  boolean isFile,
14406  AbstractFile parent) throws TskCoreException {
14407  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14408  isFile, TskData.EncodingType.NONE, parent);
14409  }
14410 
14427  @Deprecated
14428  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
14429  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
14430  }
14431 
14442  @Deprecated
14443  public Collection<FileSystem> getFileSystems(Image image) {
14444  try {
14445  return getImageFileSystems(image);
14446  } catch (TskCoreException ex) {
14447  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
14448  return new ArrayList<>();
14449  }
14450  }
14451 
14469  @Deprecated
14470  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
14471  return findFilesInFolder(fileName, parentFile);
14472  }
14473 
14481  @Deprecated
14482  public void acquireExclusiveLock() {
14484  }
14485 
14493  @Deprecated
14494  public void releaseExclusiveLock() {
14496  }
14497 
14505  @Deprecated
14506  public void acquireSharedLock() {
14508  }
14509 
14517  @Deprecated
14518  public void releaseSharedLock() {
14520  }
14521 };
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)
FS
File that can be found in file system tree.
Definition: TskData.java:678
static FileKnown valueOf(byte known)
Definition: TskData.java:803
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)
Type(int typeID, String typeName, String displayName, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType)
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:501
CaseDbSchemaVersionNumber getDBSchemaCreationVersion()
void newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
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)
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
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)
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:687
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:681
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:679
BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
long countFilesWhere(String sqlWhereClause)
long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id)
FS
File System - see tsk_fs_info for more details.
Definition: TskData.java:631
Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction)
boolean isFileFromSource(Content dataSource, long fileId)
ArrayList< BlackboardArtifact > getMatchingArtifacts(String whereClause)
VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact.ARTIFACT_TYPE > getBlackboardArtifactTypesInUse()
int getAttrTypeID(String attrTypeName)
Report addReport(String localPath, String sourceModuleName, String reportName, Content parent)
List< Content > getChildren()
USED
Metadata structure has been allocated at least once.
Definition: TskData.java:208
void unregisterForEvents(Object listener)
LOCAL_DIR
Local directory that was added (not from a disk image)
Definition: TskData.java:686
final List< LayoutFile > addCarvedFiles(CarvingResult carvingResult)
VOL
Volume - see tsk_vs_parts for more details.
Definition: TskData.java:630
void closeRunQuery(ResultSet resultSet)
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
int addAttrType(String attrTypeString, String displayName)
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag)
long getContentTagsCountByTagName(TagName tagName, long dsObjId)
List< ContentTag > getContentTagsByTagName(TagName tagName)
BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id)
static String escapeSingleQuotes(String text)
String getAttrTypeDisplayName(int attrTypeID)
List< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
List< AbstractFile > findFiles(Content dataSource, String fileName)
List< AbstractFile > findFilesInFolder(String fileName, AbstractFile parentFile)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone)
static HTML_COLOR getColorByName(String colorName)
Definition: TagName.java:76
REPORT
Artifact - see blackboard_artifacts for more details.
Definition: TskData.java:634
List< AbstractFile > findFilesByMd5(String md5Hash)
long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID)
BlackboardArtifact.Type getArtifactType(String artTypeName)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:680
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()
UNALLOC_BLOCKS
Set of blocks not allocated by file system. Parent should be image, volume, or file system...
Definition: TskData.java:682
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
ArrayList< BlackboardAttribute > getMatchingAttributes(String whereClause)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
long getBlackboardArtifactsTypeCount(int artifactTypeID)
List< ContentTag > getContentTagsByTagName(TagName tagName, long dsObjId)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
static ObjectType valueOf(short objectType)
Definition: TskData.java:662
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:784
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:684
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:632
ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
DataSource getDataSource(long objectId)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith)
Iterable< BlackboardArtifact.Type > getArtifactTypes()
List< BlackboardAttribute.Type > getAttributeTypes()
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction)
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:629
IMG
Disk Image - see tsk_image_info for more details.
Definition: TskData.java:628
UNALLOC
Name is in an unallocated state.
Definition: TskData.java:157
Collection< FileSystem > getFileSystems(Image image)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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