Sleuth Kit Java Bindings (JNI)  4.11.0
Java bindings for using The Sleuth Kit
SleuthkitCase.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
21 import com.google.common.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;
92 import org.sqlite.SQLiteConfig;
93 import org.sqlite.SQLiteDataSource;
94 import org.sqlite.SQLiteJDBCLoader;
95 
100 public class SleuthkitCase {
101 
102  private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
103 
108  static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
109  = new CaseDbSchemaVersionNumber(9, 1);
110 
111  private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value
112  private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName());
113  private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
114  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
115  private static final String SQL_ERROR_CONNECTION_GROUP = "08";
116  private static final String SQL_ERROR_AUTHENTICATION_GROUP = "28";
117  private static final String SQL_ERROR_PRIVILEGE_GROUP = "42";
118  private static final String SQL_ERROR_RESOURCE_GROUP = "53";
119  private static final String SQL_ERROR_LIMIT_GROUP = "54";
120  private static final String SQL_ERROR_INTERNAL_GROUP = "xx";
121  private static final int MIN_USER_DEFINED_TYPE_ID = 10000;
122 
123  private static final Set<String> CORE_TABLE_NAMES = ImmutableSet.of(
124  "tsk_events",
125  "tsk_event_descriptions",
126  "tsk_event_types",
127  "tsk_db_info",
128  "tsk_objects",
129  "tsk_image_info",
130  "tsk_image_names",
131  "tsk_vs_info",
132  "tsk_vs_parts",
133  "tsk_fs_info",
134  "tsk_file_layout",
135  "tsk_files",
136  "tsk_files_path",
137  "tsk_files_derived",
138  "tsk_files_derived_method",
139  "tag_names",
140  "content_tags",
141  "blackboard_artifact_tags",
142  "blackboard_artifacts",
143  "blackboard_attributes",
144  "blackboard_artifact_types",
145  "blackboard_attribute_types",
146  "data_source_info",
147  "file_encoding_types",
148  "ingest_module_types",
149  "ingest_job_status_types",
150  "ingest_modules",
151  "ingest_jobs",
152  "ingest_job_modules",
153  "account_types",
154  "accounts",
155  "account_relationships",
156  "review_statuses",
157  "reports,");
158 
159  private static final Set<String> CORE_INDEX_NAMES = ImmutableSet.of(
160  "parObjId",
161  "layout_objID",
162  "artifact_objID",
163  "artifact_artifact_objID",
164  "artifact_typeID",
165  "attrsArtifactID",
166  "mime_type",
167  "file_extension",
168  "relationships_account1",
169  "relationships_account2",
170  "relationships_relationship_source_obj_id",
171  "relationships_date_time",
172  "relationships_relationship_type",
173  "relationships_data_source_obj_id",
174  "events_time",
175  "events_type",
176  "events_data_source_obj_id",
177  "events_file_obj_id",
178  "events_artifact_id");
179 
180  private static final String TSK_VERSION_KEY = "TSK_VER";
181  private static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_MAJOR_VERSION";
182  private static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
183  private static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
184  private static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
185 
186  private final ConnectionPool connections;
187  private final Object carvedFileDirsLock = new Object();
188  private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<>();
189  private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<>(); // Cache for file system files.
190  private final List<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<>();
191  private final String databaseName;
192  private final String dbPath;
193  private final DbType dbType;
194  private final String caseDirPath;
195  private SleuthkitJNI.CaseDbHandle caseHandle;
196  private final String caseHandleIdentifier; // Used to identify this case in the JNI cache.
197  private String dbBackupPath;
198  private Map<Integer, BlackboardArtifact.Type> typeIdToArtifactTypeMap;
199  private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
200  private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
201  private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
202  private CaseDbSchemaVersionNumber caseDBSchemaCreationVersion;
203 
204  // Objects for caching the result of isRootDirectory(). Lock is for visibility only.
205  private final Object rootDirectoryMapLock = new Object();
206  private final Map<RootDirectoryKey, Long> rootDirectoryMap = new HashMap<>();
207  private final Cache<Long, Boolean> isRootDirectoryCache
208  = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
209 
210  /*
211  * First parameter is used to specify the SparseBitSet to use, as object IDs
212  * can be larger than the max size of a SparseBitSet
213  */
214  private final Map<Long, SparseBitSet> hasChildrenBitSetMap = new HashMap<>();
215 
216  private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
217  // This read/write lock is used to implement a layer of locking on top of
218  // the locking protocol provided by the underlying SQLite database. The Java
219  // locking protocol improves performance for reasons that are not currently
220  // understood. Note that the lock is contructed to use a fairness policy.
221  private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
222 
223  private CommunicationsManager communicationsMgr;
224  private TimelineManager timelineMgr;
225  private Blackboard blackboard;
226  private CaseDbAccessManager dbAccessManager;
227  private FileManager fileManager;
228  private TaggingManager taggingMgr;
229  private ScoringManager scoringManager;
230  private OsAccountRealmManager osAccountRealmManager;
231  private OsAccountManager osAccountManager;
232  private HostManager hostManager;
233  private PersonManager personManager;
234  private HostAddressManager hostAddressManager;
235 
236  private final Map<String, Set<Long>> deviceIdToDatasourceObjIdMap = new HashMap<>();
237 
238  private final EventBus eventBus = new EventBus("SleuthkitCase-EventBus");
239 
240  public void registerForEvents(Object listener) {
241  eventBus.register(listener);
242  }
243 
244  public void unregisterForEvents(Object listener) {
245  eventBus.unregister(listener);
246  }
247 
248  void fireTSKEvent(Object event) {
249  eventBus.post(event);
250  }
251 
252  // Cache of frequently used content objects (e.g. data source, file system).
253  private final Map<Long, Content> frequentlyUsedContentMap = new HashMap<>();
254 
255  private Examiner cachedCurrentExaminer = null;
256 
257  static {
258  Properties p = new Properties(System.getProperties());
259  p.put("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
260  p.put("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "SEVERE");
261  System.setProperties(p);
262  }
263 
278  public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException {
279  // Check if we can talk to the database.
280  if (info.getHost() == null || info.getHost().isEmpty()) {
281  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingHostname")); //NON-NLS
282  } else if (info.getPort() == null || info.getPort().isEmpty()) {
283  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPort")); //NON-NLS
284  } else if (info.getUserName() == null || info.getUserName().isEmpty()) {
285  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingUsername")); //NON-NLS
286  } else if (info.getPassword() == null || info.getPassword().isEmpty()) {
287  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.MissingPassword")); //NON-NLS
288  }
289 
290  try {
291  Class.forName("org.postgresql.Driver"); //NON-NLS
292  Connection conn = DriverManager.getConnection("jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres", info.getUserName(), info.getPassword()); //NON-NLS
293  if (conn != null) {
294  conn.close();
295  }
296  } catch (SQLException ex) {
297  String result;
298  String sqlState = ex.getSQLState().toLowerCase();
299  if (sqlState.startsWith(SQL_ERROR_CONNECTION_GROUP)) {
300  try {
301  if (InetAddress.getByName(info.getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
302  // if we can reach the host, then it's probably port problem
303  result = bundle.getString("DatabaseConnectionCheck.Port"); //NON-NLS
304  } else {
305  result = bundle.getString("DatabaseConnectionCheck.HostnameOrPort"); //NON-NLS
306  }
307  } catch (IOException | MissingResourceException any) {
308  // it may be anything
309  result = bundle.getString("DatabaseConnectionCheck.Everything"); //NON-NLS
310  }
311  } else if (sqlState.startsWith(SQL_ERROR_AUTHENTICATION_GROUP)) {
312  result = bundle.getString("DatabaseConnectionCheck.Authentication"); //NON-NLS
313  } else if (sqlState.startsWith(SQL_ERROR_PRIVILEGE_GROUP)) {
314  result = bundle.getString("DatabaseConnectionCheck.Access"); //NON-NLS
315  } else if (sqlState.startsWith(SQL_ERROR_RESOURCE_GROUP)) {
316  result = bundle.getString("DatabaseConnectionCheck.ServerDiskSpace"); //NON-NLS
317  } else if (sqlState.startsWith(SQL_ERROR_LIMIT_GROUP)) {
318  result = bundle.getString("DatabaseConnectionCheck.ServerRestart"); //NON-NLS
319  } else if (sqlState.startsWith(SQL_ERROR_INTERNAL_GROUP)) {
320  result = bundle.getString("DatabaseConnectionCheck.InternalServerIssue"); //NON-NLS
321  } else {
322  result = bundle.getString("DatabaseConnectionCheck.Connection"); //NON-NLS
323  }
324  throw new TskCoreException(result);
325  } catch (ClassNotFoundException ex) {
326  throw new TskCoreException(bundle.getString("DatabaseConnectionCheck.Installation")); //NON-NLS
327  }
328  }
329 
341  private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType) throws Exception {
342  Class.forName("org.sqlite.JDBC");
343  this.dbPath = dbPath;
344  this.dbType = dbType;
345  File dbFile = new File(dbPath);
346  this.caseDirPath = dbFile.getParentFile().getAbsolutePath();
347  this.databaseName = dbFile.getName();
348  this.connections = new SQLiteConnections(dbPath);
349  this.caseHandle = caseHandle;
350  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
351  init();
352  logSQLiteJDBCDriverInfo();
353  }
354 
372  private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType) throws Exception {
373  this.dbPath = "";
374  this.databaseName = dbName;
375  this.dbType = dbType;
376  this.caseDirPath = caseDirPath;
377  this.connections = new PostgreSQLConnections(host, port, dbName, userName, password);
378  this.caseHandle = caseHandle;
379  this.caseHandleIdentifier = caseHandle.getCaseDbIdentifier();
380  init();
381  }
382 
383  private void init() throws Exception {
384  typeIdToArtifactTypeMap = new ConcurrentHashMap<>();
385  typeIdToAttributeTypeMap = new ConcurrentHashMap<>();
386  typeNameToArtifactTypeMap = new ConcurrentHashMap<>();
387  typeNameToAttributeTypeMap = new ConcurrentHashMap<>();
388 
389  /*
390  * The database schema must be updated before loading blackboard
391  * artifact/attribute types
392  */
393  updateDatabaseSchema(null);
394  initBlackboardArtifactTypes();
395  initBlackboardAttributeTypes();
396  initNextArtifactId();
397 
398  try (CaseDbConnection connection = connections.getConnection()) {
399  initIngestModuleTypes(connection);
400  initIngestStatusTypes(connection);
401  initReviewStatuses(connection);
402  initEncodingTypes(connection);
403  populateHasChildrenMap(connection);
404  updateExaminers(connection);
405  initDBSchemaCreationVersion(connection);
406  }
407 
408  blackboard = new Blackboard(this);
409  fileManager = new FileManager(this);
410  communicationsMgr = new CommunicationsManager(this);
411  timelineMgr = new TimelineManager(this);
412  dbAccessManager = new CaseDbAccessManager(this);
413  taggingMgr = new TaggingManager(this);
414  scoringManager = new ScoringManager(this);
415  osAccountRealmManager = new OsAccountRealmManager(this);
416  osAccountManager = new OsAccountManager(this);
417  hostManager = new HostManager(this);
418  personManager = new PersonManager(this);
419  hostAddressManager = new HostAddressManager(this);
420  }
421 
427  static Set<String> getCoreTableNames() {
428  return CORE_TABLE_NAMES;
429  }
430 
436  static Set<String> getCoreIndexNames() {
437  return CORE_INDEX_NAMES;
438  }
439 
448  boolean getHasChildren(Content content) {
449  long objId = content.getId();
450  long mapIndex = objId / Integer.MAX_VALUE;
451  int mapValue = (int) (objId % Integer.MAX_VALUE);
452 
453  synchronized (hasChildrenBitSetMap) {
454  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
455  return hasChildrenBitSetMap.get(mapIndex).get(mapValue);
456  }
457  return false;
458  }
459  }
460 
466  private void setHasChildren(Long objId) {
467  long mapIndex = objId / Integer.MAX_VALUE;
468  int mapValue = (int) (objId % Integer.MAX_VALUE);
469 
470  synchronized (hasChildrenBitSetMap) {
471  if (hasChildrenBitSetMap.containsKey(mapIndex)) {
472  hasChildrenBitSetMap.get(mapIndex).set(mapValue);
473  } else {
474  SparseBitSet bitSet = new SparseBitSet();
475  bitSet.set(mapValue);
476  hasChildrenBitSetMap.put(mapIndex, bitSet);
477  }
478  }
479  }
480 
489  return communicationsMgr;
490  }
491 
498  return blackboard;
499  }
500 
507  return fileManager;
508  }
509 
518  return timelineMgr;
519  }
520 
521  /*
522  * Gets the case database access manager for this case.
523  *
524  * @return The per case CaseDbAccessManager object.
525  *
526  * @throws org.sleuthkit.datamodel.TskCoreException
527  */
529  return dbAccessManager;
530  }
531 
537  public synchronized TaggingManager getTaggingManager() {
538  return taggingMgr;
539  }
540 
549  return scoringManager;
550  }
551 
560  return osAccountRealmManager;
561  }
562 
571  return osAccountManager;
572  }
573 
582  return hostManager;
583  }
584 
593  return personManager;
594  }
595 
604  return hostAddressManager;
605  }
606 
613  private void initBlackboardArtifactTypes() throws SQLException, TskCoreException {
615  try (CaseDbConnection connection = connections.getConnection();
616  Statement statement = connection.createStatement();) {
617  for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) {
618  try {
619  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
620  } catch (SQLException ex) {
621  try (ResultSet resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'")) { //NON-NLS
622  resultSet.next();
623  if (resultSet.getLong("count") == 0) {
624  throw ex;
625  }
626  }
627  }
628  this.typeIdToArtifactTypeMap.put(type.getTypeID(), new BlackboardArtifact.Type(type));
629  this.typeNameToArtifactTypeMap.put(type.getLabel(), new BlackboardArtifact.Type(type));
630  }
631  if (dbType == DbType.POSTGRESQL) {
632  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ARTIFACT_TYPE.values())).getTypeID() + 1;
633  statement.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
634  }
635  } finally {
637  }
638  }
639 
647  private void initBlackboardAttributeTypes() throws SQLException, TskCoreException {
649  try (CaseDbConnection connection = connections.getConnection();
650  Statement statement = connection.createStatement();) {
651  for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) {
652  try {
653  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
654  } catch (SQLException ex) {
655  try (ResultSet resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'")) { //NON-NLS
656  resultSet.next();
657  if (resultSet.getLong("count") == 0) {
658  throw ex;
659  }
660  }
661  }
662  this.typeIdToAttributeTypeMap.put(type.getTypeID(), new BlackboardAttribute.Type(type));
663  this.typeNameToAttributeTypeMap.put(type.getLabel(), new BlackboardAttribute.Type(type));
664  }
665  if (this.dbType == DbType.POSTGRESQL) {
666  int newPrimaryKeyIndex = Collections.max(Arrays.asList(ATTRIBUTE_TYPE.values())).getTypeID() + 1;
667  statement.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + newPrimaryKeyIndex); //NON-NLS
668  }
669  } finally {
671  }
672  }
673 
683  private void initNextArtifactId() throws SQLException, TskCoreException {
684  CaseDbConnection connection = null;
685  Statement statement = null;
686  ResultSet resultSet = null;
688  try {
689  connection = connections.getConnection();
690  statement = connection.createStatement();
691  resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) AS max_artifact_id FROM blackboard_artifacts"); //NON-NLS
692  resultSet.next();
693  this.nextArtifactId = resultSet.getLong("max_artifact_id") + 1;
694  if (this.nextArtifactId == 1) {
695  this.nextArtifactId = BASE_ARTIFACT_ID;
696  }
697  } finally {
698  closeResultSet(resultSet);
699  closeStatement(statement);
700  closeConnection(connection);
702  }
703  }
704 
712  private void initIngestModuleTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
713  Statement statement = null;
714  ResultSet resultSet = null;
716  try {
717  statement = connection.createStatement();
718  for (IngestModuleType type : IngestModuleType.values()) {
719  try {
720  statement.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
721  } catch (SQLException ex) {
722  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_module_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
723  resultSet.next();
724  if (resultSet.getLong("count") == 0) {
725  throw ex;
726  }
727  resultSet.close();
728  resultSet = null;
729  }
730  }
731  } finally {
732  closeResultSet(resultSet);
733  closeStatement(statement);
735  }
736  }
737 
745  private void initIngestStatusTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
746  Statement statement = null;
747  ResultSet resultSet = null;
749  try {
750  statement = connection.createStatement();
751  for (IngestJobStatusType type : IngestJobStatusType.values()) {
752  try {
753  statement.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); //NON-NLS
754  } catch (SQLException ex) {
755  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM ingest_job_status_types WHERE type_id = " + type.ordinal() + ";"); //NON-NLS
756  resultSet.next();
757  if (resultSet.getLong("count") == 0) {
758  throw ex;
759  }
760  resultSet.close();
761  resultSet = null;
762  }
763  }
764  } finally {
765  closeResultSet(resultSet);
766  closeStatement(statement);
768  }
769  }
770 
777  private void initReviewStatuses(CaseDbConnection connection) throws SQLException, TskCoreException {
778  Statement statement = null;
779  ResultSet resultSet = null;
781  try {
782  statement = connection.createStatement();
783  for (BlackboardArtifact.ReviewStatus status : BlackboardArtifact.ReviewStatus.values()) {
784  try {
785  statement.execute("INSERT INTO review_statuses (review_status_id, review_status_name, display_name) " //NON-NLS
786  + "VALUES (" + status.getID() + ",'" + status.getName() + "','" + status.getDisplayName() + "')"); //NON-NLS
787  } catch (SQLException ex) {
788  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM review_statuses WHERE review_status_id = " + status.getID()); //NON-NLS
789  resultSet.next();
790  if (resultSet.getLong("count") == 0) {
791  throw ex;
792  }
793  resultSet.close();
794  resultSet = null;
795  }
796  }
797  } finally {
798  closeResultSet(resultSet);
799  closeStatement(statement);
801  }
802  }
803 
811  private void initEncodingTypes(CaseDbConnection connection) throws SQLException, TskCoreException {
812  Statement statement = null;
813  ResultSet resultSet = null;
815  try {
816  statement = connection.createStatement();
817  for (TskData.EncodingType type : TskData.EncodingType.values()) {
818  try {
819  statement.execute("INSERT INTO file_encoding_types (encoding_type, name) VALUES (" + type.getType() + " , '" + type.name() + "')"); //NON-NLS
820  } catch (SQLException ex) {
821  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM file_encoding_types WHERE encoding_type = " + type.getType()); //NON-NLS
822  resultSet.next();
823  if (resultSet.getLong("count") == 0) {
824  throw ex;
825  }
826  resultSet.close();
827  resultSet = null;
828  }
829  }
830  } finally {
831  closeResultSet(resultSet);
832  closeStatement(statement);
834  }
835  }
836 
845  private void updateExaminers(CaseDbConnection connection) throws SQLException, TskCoreException {
846 
847  String loginName = System.getProperty("user.name");
848  if (loginName.isEmpty()) {
849  logger.log(Level.SEVERE, "Cannot determine logged in user name");
850  return;
851  }
852 
854  try {
855  PreparedStatement statement;
856  switch (getDatabaseType()) {
857  case POSTGRESQL:
858  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_POSTGRESQL);
859  break;
860  case SQLITE:
861  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_EXAMINER_SQLITE);
862  break;
863  default:
864  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
865  }
866  statement.clearParameters();
867  statement.setString(1, loginName);
868  connection.executeUpdate(statement);
869  } catch (SQLException ex) {
870  throw new TskCoreException("Error inserting row in tsk_examiners. login name: " + loginName, ex);
871  } finally {
873  }
874  }
875 
883  private void populateHasChildrenMap(CaseDbConnection connection) throws TskCoreException {
884  long timestamp = System.currentTimeMillis();
885 
886  Statement statement = null;
887  ResultSet resultSet = null;
889  try {
890  statement = connection.createStatement();
891  resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
892 
893  synchronized (hasChildrenBitSetMap) {
894  while (resultSet.next()) {
895  setHasChildren(resultSet.getLong("par_obj_id"));
896  }
897  }
898  long delay = System.currentTimeMillis() - timestamp;
899  logger.log(Level.INFO, "Time to initialize parent node cache: {0} ms", delay); //NON-NLS
900  } catch (SQLException ex) {
901  throw new TskCoreException("Error populating parent node cache", ex);
902  } finally {
903  closeResultSet(resultSet);
904  closeStatement(statement);
906  }
907  }
908 
915  void addDataSourceToHasChildrenMap() throws TskCoreException {
916 
917  CaseDbConnection connection = connections.getConnection();
918  try {
919  populateHasChildrenMap(connection);
920  } finally {
921  closeConnection(connection);
922  }
923  }
924 
934  private void updateDatabaseSchema(String dbPath) throws Exception {
935  CaseDbConnection connection = null;
936  ResultSet resultSet = null;
937  Statement statement = null;
939  try {
940  connection = connections.getConnection();
941  connection.beginTransaction();
942 
943  boolean hasMinorVersion = false;
944  ResultSet columns = connection.getConnection().getMetaData().getColumns(null, null, "tsk_db_info", "schema%");
945  while (columns.next()) {
946  if (columns.getString("COLUMN_NAME").equals("schema_minor_ver")) {
947  hasMinorVersion = true;
948  }
949  }
950 
951  // Get the schema version number of the case database from the tsk_db_info table.
952  int dbSchemaMajorVersion;
953  int dbSchemaMinorVersion = 0; //schemas before 7 have no minor version , default it to zero.
954 
955  statement = connection.createStatement();
956  resultSet = connection.executeQuery(statement, "SELECT schema_ver"
957  + (hasMinorVersion ? ", schema_minor_ver" : "")
958  + " FROM tsk_db_info"); //NON-NLS
959  if (resultSet.next()) {
960  dbSchemaMajorVersion = resultSet.getInt("schema_ver"); //NON-NLS
961  if (hasMinorVersion) {
962  //if there is a minor version column, use it, else default to zero.
963  dbSchemaMinorVersion = resultSet.getInt("schema_minor_ver"); //NON-NLS
964  }
965  } else {
966  throw new TskCoreException();
967  }
968  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(dbSchemaMajorVersion, dbSchemaMinorVersion);
969 
970  resultSet.close();
971  resultSet = null;
972  statement.close();
973  statement = null;
974  //check schema compatibility
975  if (false == CURRENT_DB_SCHEMA_VERSION.isCompatible(dbSchemaVersion)) {
976  //we cannot open a db with a major schema version higher than the current one.
977  throw new TskUnsupportedSchemaVersionException(
978  "Unsupported DB schema version " + dbSchemaVersion + ", the highest supported schema version is " + CURRENT_DB_SCHEMA_VERSION.getMajor() + ".X");
979  } else if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) < 0) {
980  //The schema version is compatible,possibly after upgrades.
981 
982  if (null != dbPath) {
983  // Make a backup copy of the database. Client code can get the path of the backup
984  // using the getBackupDatabasePath() method.
985  String backupFilePath = dbPath + ".schemaVer" + dbSchemaVersion.toString() + ".backup"; //NON-NLS
986  copyCaseDB(backupFilePath);
987  dbBackupPath = backupFilePath;
988  }
989 
990  // ***CALL SCHEMA UPDATE METHODS HERE***
991  // Each method should examine the schema version passed to it and either:
992  // a. do nothing and return the schema version unchanged, or
993  // b. upgrade the database and return the schema version that the db was upgraded to.
994  dbSchemaVersion = updateFromSchema2toSchema3(dbSchemaVersion, connection);
995  dbSchemaVersion = updateFromSchema3toSchema4(dbSchemaVersion, connection);
996  dbSchemaVersion = updateFromSchema4toSchema5(dbSchemaVersion, connection);
997  dbSchemaVersion = updateFromSchema5toSchema6(dbSchemaVersion, connection);
998  dbSchemaVersion = updateFromSchema6toSchema7(dbSchemaVersion, connection);
999  dbSchemaVersion = updateFromSchema7toSchema7dot1(dbSchemaVersion, connection);
1000  dbSchemaVersion = updateFromSchema7dot1toSchema7dot2(dbSchemaVersion, connection);
1001  dbSchemaVersion = updateFromSchema7dot2toSchema8dot0(dbSchemaVersion, connection);
1002  dbSchemaVersion = updateFromSchema8dot0toSchema8dot1(dbSchemaVersion, connection);
1003  dbSchemaVersion = updateFromSchema8dot1toSchema8dot2(dbSchemaVersion, connection);
1004  dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection);
1005  dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection);
1006  dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection);
1007  dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection);
1008  dbSchemaVersion = updateFromSchema8dot6toSchema9dot0(dbSchemaVersion, connection);
1009  dbSchemaVersion = updateFromSchema9dot0toSchema9dot1(dbSchemaVersion, connection);
1010 
1011  statement = connection.createStatement();
1012  connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS
1013  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS
1014  connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMinor() + " WHERE name = '" + SCHEMA_MINOR_VERSION_KEY + "'"); //NON-NLS
1015  statement.close();
1016  statement = null;
1017  }
1018 
1019  connection.commitTransaction();
1020  } catch (Exception ex) { // Cannot do exception multi-catch in Java 6, so use catch-all.
1021  rollbackTransaction(connection);
1022  throw ex;
1023  } finally {
1024  closeResultSet(resultSet);
1025  closeStatement(statement);
1026  closeConnection(connection);
1028  }
1029  }
1030 
1038  private void initDBSchemaCreationVersion(CaseDbConnection connection) throws SQLException {
1039 
1040  Statement statement = null;
1041  ResultSet resultSet = null;
1042  String createdSchemaMajorVersion = "0";
1043  String createdSchemaMinorVersion = "0";
1045  try {
1046  statement = connection.createStatement();
1047  resultSet = connection.executeQuery(statement, "SELECT name, value FROM tsk_db_info_extended");
1048  while (resultSet.next()) {
1049  String name = resultSet.getString("name");
1050  if (name.equals(CREATION_SCHEMA_MAJOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MAJOR_VERSION")) {
1051  createdSchemaMajorVersion = resultSet.getString("value");
1052  } else if (name.equals(CREATION_SCHEMA_MINOR_VERSION_KEY) || name.equals("CREATED_SCHEMA_MINOR_VERSION")) {
1053  createdSchemaMinorVersion = resultSet.getString("value");
1054  }
1055  }
1056 
1057  } finally {
1058  closeResultSet(resultSet);
1059  closeStatement(statement);
1061  }
1062 
1063  caseDBSchemaCreationVersion = new CaseDbSchemaVersionNumber(Integer.parseInt(createdSchemaMajorVersion), Integer.parseInt(createdSchemaMinorVersion));
1064  }
1065 
1075  public void copyCaseDB(String newDBPath) throws IOException {
1076  if (dbPath.isEmpty()) {
1077  throw new IOException("Copying case database files is not supported for this type of case database"); //NON-NLS
1078  }
1079  InputStream in = null;
1080  OutputStream out = null;
1082  try {
1083  InputStream inFile = new FileInputStream(dbPath);
1084  in = new BufferedInputStream(inFile);
1085  OutputStream outFile = new FileOutputStream(newDBPath);
1086  out = new BufferedOutputStream(outFile);
1087  int bytesRead = in.read();
1088  while (bytesRead != -1) {
1089  out.write(bytesRead);
1090  bytesRead = in.read();
1091  }
1092  } finally {
1093  try {
1094  if (in != null) {
1095  in.close();
1096  }
1097  if (out != null) {
1098  out.flush();
1099  out.close();
1100  }
1101  } catch (IOException e) {
1102  logger.log(Level.WARNING, "Could not close streams after db copy", e); //NON-NLS
1103  }
1105  }
1106  }
1107 
1111  private void logSQLiteJDBCDriverInfo() {
1112  try {
1113  SleuthkitCase.logger.info(String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
1114  SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
1115  ? "native" : "pure-java")); //NON-NLS
1116  } catch (Exception ex) {
1117  SleuthkitCase.logger.log(Level.SEVERE, "Error querying case database mode", ex);
1118  }
1119  }
1120 
1134  @SuppressWarnings("deprecation")
1135  private CaseDbSchemaVersionNumber updateFromSchema2toSchema3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1136  if (schemaVersion.getMajor() != 2) {
1137  return schemaVersion;
1138  }
1139  Statement statement = null;
1140  Statement statement2 = null;
1141  Statement updateStatement = null;
1142  ResultSet resultSet = null;
1144  try {
1145  statement = connection.createStatement();
1146  statement2 = connection.createStatement();
1147 
1148  // Add new tables for tags.
1149  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
1150  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
1151  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
1152 
1153  // Add a new table for reports.
1154  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
1155 
1156  // Add new columns to the image info table.
1157  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN size INTEGER;"); //NON-NLS
1158  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN md5 TEXT;"); //NON-NLS
1159  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN display_name TEXT;"); //NON-NLS
1160 
1161  // Add a new column to the file system info table.
1162  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN display_name TEXT;"); //NON-NLS
1163 
1164  // Add a new column to the file table.
1165  statement.execute("ALTER TABLE tsk_files ADD COLUMN meta_seq INTEGER;"); //NON-NLS
1166 
1167  // Add new columns and indexes to the attributes table and populate the
1168  // new column. Note that addition of the new column is a denormalization
1169  // to optimize attribute queries.
1170  statement.execute("ALTER TABLE blackboard_attributes ADD COLUMN artifact_type_id INTEGER NULL NOT NULL DEFAULT -1;"); //NON-NLS
1171  statement.execute("CREATE INDEX attribute_artifactTypeId ON blackboard_attributes(artifact_type_id);"); //NON-NLS
1172  statement.execute("CREATE INDEX attribute_valueText ON blackboard_attributes(value_text);"); //NON-NLS
1173  statement.execute("CREATE INDEX attribute_valueInt32 ON blackboard_attributes(value_int32);"); //NON-NLS
1174  statement.execute("CREATE INDEX attribute_valueInt64 ON blackboard_attributes(value_int64);"); //NON-NLS
1175  statement.execute("CREATE INDEX attribute_valueDouble ON blackboard_attributes(value_double);"); //NON-NLS
1176  resultSet = statement.executeQuery("SELECT attrs.artifact_id AS artifact_id, " //NON-NLS
1177  + "arts.artifact_type_id AS artifact_type_id " //NON-NLS
1178  + "FROM blackboard_attributes AS attrs " //NON-NLS
1179  + "INNER JOIN blackboard_artifacts AS arts " //NON-NLS
1180  + "WHERE attrs.artifact_id = arts.artifact_id;"); //NON-NLS
1181  updateStatement = connection.createStatement();
1182  while (resultSet.next()) {
1183  long artifactId = resultSet.getLong("artifact_id");
1184  int artifactTypeId = resultSet.getInt("artifact_type_id");
1185  updateStatement.executeUpdate(
1186  "UPDATE blackboard_attributes " //NON-NLS
1187  + "SET artifact_type_id = " + artifactTypeId //NON-NLS
1188  + " WHERE blackboard_attributes.artifact_id = " + artifactId + ";"); //NON-NLS
1189  }
1190  resultSet.close();
1191 
1192  // Convert existing tag artifact and attribute rows to rows in the new tags tables.
1193  Map<String, Long> tagNames = new HashMap<>();
1194  long tagNameCounter = 1;
1195 
1196  // Convert file tags.
1197  // We need data from the TSK_TAG_NAME and TSK_COMMENT attributes, and need the file size from the tsk_files table.
1198  resultSet = statement.executeQuery("SELECT * FROM \n"
1199  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, blackboard_attributes.value_text AS name\n"
1200  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1201  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1202  + "WHERE blackboard_artifacts.artifact_type_id = "
1203  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1204  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1205  + ") AS tagNames \n"
1206  + "INNER JOIN \n"
1207  + "(SELECT tsk_files.obj_id as objId2, tsk_files.size AS fileSize \n"
1208  + "FROM blackboard_artifacts INNER JOIN tsk_files \n"
1209  + "ON blackboard_artifacts.obj_id = tsk_files.obj_id) AS fileData \n"
1210  + "ON tagNames.objId = fileData.objId2 \n"
1211  + "LEFT JOIN \n"
1212  + "(SELECT value_text AS comment, artifact_id AS tagArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1213  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1214  + "ON tagNames.artifactId = tagComments.tagArtifactId");
1215 
1216  while (resultSet.next()) {
1217  long objId = resultSet.getLong("objId");
1218  long fileSize = resultSet.getLong("fileSize");
1219  String tagName = resultSet.getString("name");
1220  String tagComment = resultSet.getString("comment");
1221  if (tagComment == null) {
1222  tagComment = "";
1223  }
1224 
1225  if (tagName != null && !tagName.isEmpty()) {
1226  // Get the index for the tag name, adding it to the database if needed.
1227  long tagNameIndex;
1228  if (tagNames.containsKey(tagName)) {
1229  tagNameIndex = tagNames.get(tagName);
1230  } else {
1231  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1232  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1233  tagNames.put(tagName, tagNameCounter);
1234  tagNameIndex = tagNameCounter;
1235  tagNameCounter++;
1236  }
1237 
1238  statement2.execute("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) "
1239  + "VALUES(" + objId + ", " + tagNameIndex + ", \"" + tagComment + "\", 0, " + fileSize + ")");
1240  }
1241  }
1242  resultSet.close();
1243 
1244  // Convert artifact tags.
1245  // We need data from the TSK_TAG_NAME, TSK_TAGGED_ARTIFACT, and TSK_COMMENT attributes.
1246  resultSet = statement.executeQuery("SELECT * FROM \n"
1247  + "(SELECT blackboard_artifacts.obj_id AS objId, blackboard_attributes.artifact_id AS artifactId, "
1248  + "blackboard_attributes.value_text AS name\n"
1249  + "FROM blackboard_artifacts INNER JOIN blackboard_attributes \n"
1250  + "ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id \n"
1251  + "WHERE blackboard_artifacts.artifact_type_id = "
1252  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()
1253  + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
1254  + ") AS tagNames \n"
1255  + "INNER JOIN \n"
1256  + "(SELECT value_int64 AS taggedArtifactId, artifact_id AS associatedArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1257  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID() + ") AS tagArtifacts \n"
1258  + "ON tagNames.artifactId = tagArtifacts.associatedArtifactId \n"
1259  + "LEFT JOIN \n"
1260  + "(SELECT value_text AS comment, artifact_id AS commentArtifactId FROM blackboard_attributes WHERE attribute_type_id = "
1261  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID() + ") AS tagComments \n"
1262  + "ON tagNames.artifactId = tagComments.commentArtifactId");
1263 
1264  while (resultSet.next()) {
1265  long artifactId = resultSet.getLong("taggedArtifactId");
1266  String tagName = resultSet.getString("name");
1267  String tagComment = resultSet.getString("comment");
1268  if (tagComment == null) {
1269  tagComment = "";
1270  }
1271  if (tagName != null && !tagName.isEmpty()) {
1272  // Get the index for the tag name, adding it to the database if needed.
1273  long tagNameIndex;
1274  if (tagNames.containsKey(tagName)) {
1275  tagNameIndex = tagNames.get(tagName);
1276  } else {
1277  statement2.execute("INSERT INTO tag_names (display_name, description, color) "
1278  + "VALUES(\"" + tagName + "\", \"\", \"None\")");
1279  tagNames.put(tagName, tagNameCounter);
1280  tagNameIndex = tagNameCounter;
1281  tagNameCounter++;
1282  }
1283 
1284  statement2.execute("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment) "
1285  + "VALUES(" + artifactId + ", " + tagNameIndex + ", \"" + tagComment + "\")");
1286  }
1287  }
1288  resultSet.close();
1289 
1290  statement.execute(
1291  "DELETE FROM blackboard_attributes WHERE artifact_id IN " //NON-NLS
1292  + "(SELECT artifact_id FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1293  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1294  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ");"); //NON-NLS
1295  statement.execute(
1296  "DELETE FROM blackboard_artifacts WHERE artifact_type_id = " //NON-NLS
1297  + ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
1298  + " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ";"); //NON-NLS
1299 
1300  return new CaseDbSchemaVersionNumber(3, 0);
1301  } finally {
1302  closeStatement(updateStatement);
1303  closeResultSet(resultSet);
1304  closeStatement(statement);
1305  closeStatement(statement2);
1307  }
1308  }
1309 
1323  private CaseDbSchemaVersionNumber updateFromSchema3toSchema4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1324  if (schemaVersion.getMajor() != 3) {
1325  return schemaVersion;
1326  }
1327 
1328  Statement statement = null;
1329  ResultSet resultSet = null;
1330  Statement queryStatement = null;
1331  ResultSet queryResultSet = null;
1332  Statement updateStatement = null;
1334  try {
1335  // Add mime_type column to tsk_files table. Populate with general
1336  // info artifact file signature data.
1337  statement = connection.createStatement();
1338  updateStatement = connection.createStatement();
1339  statement.execute("ALTER TABLE tsk_files ADD COLUMN mime_type TEXT;");
1340  resultSet = statement.executeQuery("SELECT files.obj_id AS obj_id, attrs.value_text AS value_text "
1341  + "FROM tsk_files AS files, blackboard_attributes AS attrs, blackboard_artifacts AS arts "
1342  + "WHERE files.obj_id = arts.obj_id AND "
1343  + "arts.artifact_id = attrs.artifact_id AND "
1344  + "arts.artifact_type_id = 1 AND "
1345  + "attrs.attribute_type_id = 62");
1346  while (resultSet.next()) {
1347  updateStatement.executeUpdate(
1348  "UPDATE tsk_files " //NON-NLS
1349  + "SET mime_type = '" + resultSet.getString("value_text") + "' " //NON-NLS
1350  + "WHERE tsk_files.obj_id = " + resultSet.getInt("obj_id") + ";"); //NON-NLS
1351  }
1352  resultSet.close();
1353 
1354  // Add value_type column to blackboard_attribute_types table.
1355  statement.execute("ALTER TABLE blackboard_attribute_types ADD COLUMN value_type INTEGER NOT NULL DEFAULT -1;");
1356  resultSet = statement.executeQuery("SELECT * FROM blackboard_attribute_types AS types"); //NON-NLS
1357  while (resultSet.next()) {
1358  int attributeTypeId = resultSet.getInt("attribute_type_id");
1359  String attributeLabel = resultSet.getString("type_name");
1360  if (attributeTypeId < MIN_USER_DEFINED_TYPE_ID) {
1361  updateStatement.executeUpdate(
1362  "UPDATE blackboard_attribute_types " //NON-NLS
1363  + "SET value_type = " + ATTRIBUTE_TYPE.fromLabel(attributeLabel).getValueType().getType() + " " //NON-NLS
1364  + "WHERE blackboard_attribute_types.attribute_type_id = " + attributeTypeId + ";"); //NON-NLS
1365  }
1366  }
1367  resultSet.close();
1368 
1369  // Add a data_sources_info table.
1370  queryStatement = connection.createStatement();
1371  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));");
1372  resultSet = statement.executeQuery("SELECT * FROM tsk_objects WHERE par_obj_id IS NULL");
1373  while (resultSet.next()) {
1374  long objectId = resultSet.getLong("obj_id");
1375  String timeZone = "";
1376  queryResultSet = queryStatement.executeQuery("SELECT tzone FROM tsk_image_info WHERE obj_id = " + objectId);
1377  if (queryResultSet.next()) {
1378  timeZone = queryResultSet.getString("tzone");
1379  }
1380  queryResultSet.close();
1381  updateStatement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) "
1382  + "VALUES(" + objectId + ", '" + UUID.randomUUID().toString() + "' , '" + timeZone + "');");
1383  }
1384  resultSet.close();
1385 
1386  // Add data_source_obj_id column to the tsk_files table.
1387  //
1388  // NOTE: A new case database will have the following FK constraint:
1389  //
1390  // REFERENCES data_source_info (obj_id)
1391  //
1392  // The constraint is sacrificed here to avoid having to create and
1393  // populate a new tsk_files table.
1394  //
1395  // TODO: Do this right.
1396  statement.execute("ALTER TABLE tsk_files ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
1397  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");
1398  while (resultSet.next()) {
1399  long fileId = resultSet.getLong("obj_id");
1400  long dataSourceId = getDataSourceObjectId(connection, fileId);
1401  updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";");
1402  }
1403  resultSet.close();
1404  statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1405  statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS
1406  if (this.dbType.equals(DbType.SQLITE)) {
1407  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
1408  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
1409  } else {
1410  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
1411  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
1412  }
1413 
1414  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
1415  initIngestModuleTypes(connection);
1416  initIngestStatusTypes(connection);
1417 
1418  return new CaseDbSchemaVersionNumber(4, 0);
1419 
1420  } finally {
1421  closeResultSet(queryResultSet);
1422  closeStatement(queryStatement);
1423  closeStatement(updateStatement);
1424  closeResultSet(resultSet);
1425  closeStatement(statement);
1427  }
1428  }
1429 
1443  private CaseDbSchemaVersionNumber updateFromSchema4toSchema5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1444  if (schemaVersion.getMajor() != 4) {
1445  return schemaVersion;
1446  }
1447 
1448  Statement statement = null;
1450  try {
1451  // Add the review_statuses lookup table.
1452  statement = connection.createStatement();
1453  statement.execute("CREATE TABLE review_statuses (review_status_id INTEGER PRIMARY KEY, review_status_name TEXT NOT NULL, display_name TEXT NOT NULL)");
1454 
1455  /*
1456  * Add review_status_id column to artifacts table.
1457  *
1458  * NOTE: For DBs created with schema 5 we define a foreign key
1459  * constraint on the review_status_column. We don't bother with this
1460  * for DBs updated to schema 5 because of limitations of the SQLite
1461  * ALTER TABLE command.
1462  */
1463  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1464 
1465  // Add the encoding table
1466  statement.execute("CREATE TABLE file_encoding_types (encoding_type INTEGER PRIMARY KEY, name TEXT NOT NULL);");
1467  initEncodingTypes(connection);
1468 
1469  /*
1470  * This needs to be done due to a Autopsy/TSK out of synch problem.
1471  * Without this, it is possible to upgrade from version 4 to 5 and
1472  * then 5 to 6, but not from 4 to 6.
1473  */
1474  initReviewStatuses(connection);
1475 
1476  // Add encoding type column to tsk_files_path
1477  // This should really have the FOREIGN KEY constraint but there are problems
1478  // getting that to work, so we don't add it on this upgrade path.
1479  statement.execute("ALTER TABLE tsk_files_path ADD COLUMN encoding_type INTEGER NOT NULL DEFAULT 0;");
1480 
1481  return new CaseDbSchemaVersionNumber(5, 0);
1482 
1483  } finally {
1484  closeStatement(statement);
1486  }
1487  }
1488 
1502  private CaseDbSchemaVersionNumber updateFromSchema5toSchema6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1503  if (schemaVersion.getMajor() != 5) {
1504  return schemaVersion;
1505  }
1506 
1507  /*
1508  * This upgrade fixes a bug where some releases had artifact review
1509  * status support in the case database and others did not.
1510  */
1511  Statement statement = null;
1512  ResultSet resultSet = null;
1514  try {
1515  /*
1516  * Add the review_statuses lookup table, if missing.
1517  */
1518  statement = connection.createStatement();
1519  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)");
1520 
1521  resultSet = connection.executeQuery(statement, "SELECT COUNT(*) AS count FROM review_statuses"); //NON-NLS
1522  resultSet.next();
1523  if (resultSet.getLong("count") == 0) {
1524  /*
1525  * Add review_status_id column to artifacts table.
1526  *
1527  * NOTE: For DBs created with schema 5 or 6 we define a foreign
1528  * key constraint on the review_status_column. We don't bother
1529  * with this for DBs updated to schema 5 or 6 because of
1530  * limitations of the SQLite ALTER TABLE command.
1531  */
1532  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN review_status_id INTEGER NOT NULL DEFAULT " + BlackboardArtifact.ReviewStatus.UNDECIDED.getID());
1533  }
1534 
1535  return new CaseDbSchemaVersionNumber(6, 0);
1536 
1537  } finally {
1538  closeResultSet(resultSet);
1539  closeStatement(statement);
1541  }
1542  }
1543 
1557  private CaseDbSchemaVersionNumber updateFromSchema6toSchema7(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1558  if (schemaVersion.getMajor() != 6) {
1559  return schemaVersion;
1560  }
1561 
1562  /*
1563  * This upgrade adds an indexed extension column to the tsk_files table.
1564  */
1565  Statement statement = null;
1566  Statement updstatement = null;
1567  ResultSet resultSet = null;
1569  try {
1570  statement = connection.createStatement();
1571  updstatement = connection.createStatement();
1572  statement.execute("ALTER TABLE tsk_files ADD COLUMN extension TEXT");
1573 
1574  resultSet = connection.executeQuery(statement, "SELECT obj_id,name FROM tsk_files"); //NON-NLS
1575  while (resultSet.next()) {
1576  long objID = resultSet.getLong("obj_id");
1577  String name = resultSet.getString("name");
1578  updstatement.executeUpdate("UPDATE tsk_files SET extension = '" + escapeSingleQuotes(extractExtension(name)) + "' "
1579  + "WHERE obj_id = " + objID);
1580  }
1581 
1582  statement.execute("CREATE INDEX file_extension ON tsk_files ( extension )");
1583 
1584  // Add artifact_obj_id column to blackboard_artifacts table, data conversion for old versions isn't necesarry.
1585  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN artifact_obj_id INTEGER NOT NULL DEFAULT -1");
1586 
1587  return new CaseDbSchemaVersionNumber(7, 0);
1588 
1589  } finally {
1590  closeResultSet(resultSet);
1591  closeStatement(statement);
1592  closeStatement(updstatement);
1594  }
1595  }
1596 
1610  private CaseDbSchemaVersionNumber updateFromSchema7toSchema7dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1611  if (schemaVersion.getMajor() != 7) {
1612  return schemaVersion;
1613  }
1614 
1615  if (schemaVersion.getMinor() != 0) {
1616  return schemaVersion;
1617  }
1618 
1619  /*
1620  * This upgrade adds a minor version number column.
1621  */
1622  Statement statement = null;
1623  ResultSet resultSet = null;
1625  try {
1626  statement = connection.createStatement();
1627 
1628  //add the schema minor version number column.
1629  if (schemaVersion.getMinor() == 0) {
1630  //add the schema minor version number column.
1631  statement.execute("ALTER TABLE tsk_db_info ADD COLUMN schema_minor_ver INTEGER DEFAULT 1");
1632  }
1633  return new CaseDbSchemaVersionNumber(7, 1);
1634 
1635  } finally {
1636  closeResultSet(resultSet);
1637  closeStatement(statement);
1639  }
1640  }
1641 
1655  private CaseDbSchemaVersionNumber updateFromSchema7dot1toSchema7dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1656  if (schemaVersion.getMajor() != 7) {
1657  return schemaVersion;
1658  }
1659 
1660  if (schemaVersion.getMinor() != 1) {
1661  return schemaVersion;
1662  }
1663 
1664  Statement statement = null;
1665  Statement updstatement = null;
1666  ResultSet resultSet = null;
1668  try {
1669  //add the data_source_obj_id column to blackboard_artifacts.
1670  statement = connection.createStatement();
1671  statement.execute("ALTER TABLE blackboard_artifacts ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1");
1672 
1673  // populate data_source_obj_id for each artifact
1674  updstatement = connection.createStatement();
1675  resultSet = connection.executeQuery(statement, "SELECT artifact_id, obj_id FROM blackboard_artifacts"); //NON-NLS
1676  while (resultSet.next()) {
1677  long artifact_id = resultSet.getLong("artifact_id");
1678  long obj_id = resultSet.getLong("obj_id");
1679  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
1680  updstatement.executeUpdate("UPDATE blackboard_artifacts SET data_source_obj_id = " + data_source_obj_id + " "
1681  + "WHERE artifact_id = " + artifact_id);
1682  }
1683  closeResultSet(resultSet);
1684  closeStatement(statement);
1685  closeStatement(updstatement);
1686 
1687  /*
1688  * Add a knownStatus column to the tag_names table.
1689  */
1690  statement = connection.createStatement();
1691  statement.execute("ALTER TABLE tag_names ADD COLUMN knownStatus INTEGER NOT NULL DEFAULT " + TskData.FileKnown.UNKNOWN.getFileKnownValue());
1692 
1693  // Create account_types, accounts, and account_relationships table
1694  if (this.dbType.equals(DbType.SQLITE)) {
1695  statement.execute("CREATE TABLE account_types (account_type_id INTEGER PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1696  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))");
1697  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))");
1698  } else {
1699  statement.execute("CREATE TABLE account_types (account_type_id BIGSERIAL PRIMARY KEY, type_name TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL)");
1700  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))");
1701  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))");
1702  }
1703 
1704  // Create indexes
1705  statement.execute("CREATE INDEX artifact_artifact_objID ON blackboard_artifacts(artifact_obj_id)");
1706  statement.execute("CREATE INDEX relationships_account1 ON account_relationships(account1_id)");
1707  statement.execute("CREATE INDEX relationships_account2 ON account_relationships(account2_id)");
1708  statement.execute("CREATE INDEX relationships_relationship_source_obj_id ON account_relationships(relationship_source_obj_id)");
1709  statement.execute("CREATE INDEX relationships_date_time ON account_relationships(date_time)");
1710  statement.execute("CREATE INDEX relationships_relationship_type ON account_relationships(relationship_type)");
1711  statement.execute("CREATE INDEX relationships_data_source_obj_id ON account_relationships(data_source_obj_id)");
1712 
1713  return new CaseDbSchemaVersionNumber(7, 2);
1714  } finally {
1715  closeResultSet(resultSet);
1716  closeStatement(statement);
1717  closeStatement(updstatement);
1719  }
1720  }
1721 
1735  private CaseDbSchemaVersionNumber updateFromSchema7dot2toSchema8dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1736  if (schemaVersion.getMajor() != 7) {
1737  return schemaVersion;
1738  }
1739 
1740  if (schemaVersion.getMinor() != 2) {
1741  return schemaVersion;
1742  }
1743 
1744  Statement updateSchemaStatement = connection.createStatement();
1745  Statement getExistingReportsStatement = connection.createStatement();
1746  ResultSet resultSet = null;
1747  ResultSet existingReports = null;
1748 
1750  try {
1751  // Update the schema to turn report_id into an object id.
1752 
1753  // Unfortunately, SQLite doesn't support adding a constraint
1754  // to an existing table so we have to rename the old...
1755  updateSchemaStatement.execute("ALTER TABLE reports RENAME TO old_reports");
1756 
1757  // ...create the new...
1758  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))");
1759 
1760  // ...add the existing report records back...
1761  existingReports = getExistingReportsStatement.executeQuery("SELECT * FROM old_reports");
1762  while (existingReports.next()) {
1763  String path = existingReports.getString(2);
1764  long crtime = existingReports.getInt(3);
1765  String sourceModule = existingReports.getString(4);
1766  String reportName = existingReports.getString(5);
1767 
1768  PreparedStatement insertObjectStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
1769  insertObjectStatement.clearParameters();
1770  insertObjectStatement.setNull(1, java.sql.Types.BIGINT);
1771  insertObjectStatement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
1772  connection.executeUpdate(insertObjectStatement);
1773  resultSet = insertObjectStatement.getGeneratedKeys();
1774  if (!resultSet.next()) {
1775  throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, path));
1776  }
1777  long objectId = resultSet.getLong(1); //last_insert_rowid()
1778 
1779  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
1780  PreparedStatement insertReportStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
1781  insertReportStatement.clearParameters();
1782  insertReportStatement.setLong(1, objectId);
1783  insertReportStatement.setString(2, path);
1784  insertReportStatement.setLong(3, crtime);
1785  insertReportStatement.setString(4, sourceModule);
1786  insertReportStatement.setString(5, reportName);
1787  connection.executeUpdate(insertReportStatement);
1788  }
1789 
1790  // ...and drop the old table.
1791  updateSchemaStatement.execute("DROP TABLE old_reports");
1792 
1793  return new CaseDbSchemaVersionNumber(8, 0);
1794  } finally {
1795  closeResultSet(resultSet);
1796  closeResultSet(existingReports);
1797  closeStatement(updateSchemaStatement);
1798  closeStatement(getExistingReportsStatement);
1800  }
1801  }
1802 
1816  private CaseDbSchemaVersionNumber updateFromSchema8dot0toSchema8dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1817  if (schemaVersion.getMajor() != 8) {
1818  return schemaVersion;
1819  }
1820 
1821  if (schemaVersion.getMinor() != 0) {
1822  return schemaVersion;
1823  }
1824 
1826 
1827  try (Statement statement = connection.createStatement();) {
1828  // create examiners table
1829  if (this.dbType.equals(DbType.SQLITE)) {
1830  statement.execute("CREATE TABLE tsk_examiners (examiner_id INTEGER PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name) )");
1831  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1832  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id INTEGER REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1833  } else {
1834  statement.execute("CREATE TABLE tsk_examiners (examiner_id BIGSERIAL PRIMARY KEY, login_name TEXT NOT NULL, display_name TEXT, UNIQUE(login_name))");
1835  statement.execute("ALTER TABLE content_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1836  statement.execute("ALTER TABLE blackboard_artifact_tags ADD COLUMN examiner_id BIGINT REFERENCES tsk_examiners(examiner_id) DEFAULT NULL");
1837  }
1838 
1839  return new CaseDbSchemaVersionNumber(8, 1);
1840  } finally {
1842  }
1843  }
1844 
1858  private CaseDbSchemaVersionNumber updateFromSchema8dot1toSchema8dot2(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1859  if (schemaVersion.getMajor() != 8) {
1860  return schemaVersion;
1861  }
1862 
1863  if (schemaVersion.getMinor() != 1) {
1864  return schemaVersion;
1865  }
1866 
1868 
1869  try (Statement statement = connection.createStatement();) {
1870  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha1 TEXT DEFAULT NULL");
1871  statement.execute("ALTER TABLE tsk_image_info ADD COLUMN sha256 TEXT DEFAULT NULL");
1872 
1873  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_details TEXT");
1874 
1875  /*
1876  * Add new tsk_db_extended_info table with TSK version, creation
1877  * time schema and schema version numbers as the initial data. The
1878  * creation time schema version is set to 0, 0 to indicate that it
1879  * is not known.
1880  */
1881  statement.execute("CREATE TABLE tsk_db_info_extended (name TEXT PRIMARY KEY, value TEXT NOT NULL)");
1882  ResultSet result = statement.executeQuery("SELECT tsk_ver FROM tsk_db_info");
1883  result.next();
1884  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + TSK_VERSION_KEY + "', '" + result.getLong("tsk_ver") + "')");
1885  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MAJOR_VERSION_KEY + "', '8')");
1886  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + SCHEMA_MINOR_VERSION_KEY + "', '2')");
1887  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '0')");
1888  statement.execute("INSERT INTO tsk_db_info_extended (name, value) VALUES ('" + CREATION_SCHEMA_MINOR_VERSION_KEY + "', '0')");
1889 
1890  String primaryKeyType;
1891  switch (getDatabaseType()) {
1892  case POSTGRESQL:
1893  primaryKeyType = "BIGSERIAL";
1894  break;
1895  case SQLITE:
1896  primaryKeyType = "INTEGER";
1897  break;
1898  default:
1899  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
1900  }
1901 
1902  //create and initialize tsk_event_types tables
1903  statement.execute("CREATE TABLE tsk_event_types ("
1904  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
1905  + " display_name TEXT UNIQUE NOT NULL, "
1906  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
1907  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1908  + " values( 0, 'Event Types', null)");
1909  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1910  + " values(1, 'File System', 0)");
1911  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1912  + " values(2, 'Web Activity', 0)");
1913  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1914  + " values(3, 'Misc Types', 0)");
1915  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1916  + " values(4, 'Modified', 1)");
1917  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1918  + " values(5, 'Accessed', 1)");
1919  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1920  + " values(6, 'Created', 1)");
1921  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
1922  + " values(7, 'Changed', 1)");
1923 
1924  //create tsk_events tables
1925  statement.execute("CREATE TABLE tsk_event_descriptions ("
1926  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
1927  + " full_description TEXT NOT NULL, "
1928  + " med_description TEXT, "
1929  + " short_description TEXT,"
1930  + " data_source_obj_id BIGINT NOT NULL, "
1931  + " file_obj_id BIGINT NOT NULL, "
1932  + " artifact_id BIGINT, "
1933  + " hash_hit INTEGER NOT NULL, " //boolean
1934  + " tagged INTEGER NOT NULL, " //boolean
1935  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
1936  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
1937  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
1938  );
1939 
1940  statement.execute("CREATE TABLE tsk_events ( "
1941  + " event_id " + primaryKeyType + " PRIMARY KEY, "
1942  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
1943  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
1944  + " time INTEGER NOT NULL) "
1945  );
1946 
1947  //create tsk_events indices
1948  statement.execute("CREATE INDEX events_time ON tsk_events(time)");
1949  statement.execute("CREATE INDEX events_type ON tsk_events(event_type_id)");
1950  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
1951  statement.execute("CREATE INDEX events_file_obj_id ON tsk_event_descriptions(file_obj_id) ");
1952  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
1953  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
1954  return new CaseDbSchemaVersionNumber(8, 2);
1955 
1956  } finally {
1958  }
1959  }
1960 
1974  private CaseDbSchemaVersionNumber updateFromSchema8dot2toSchema8dot3(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
1975  if (schemaVersion.getMajor() != 8) {
1976  return schemaVersion;
1977  }
1978 
1979  if (schemaVersion.getMinor() != 2) {
1980  return schemaVersion;
1981  }
1982 
1984 
1985  ResultSet resultSet = null;
1986 
1987  try (Statement statement = connection.createStatement();) {
1988 
1989  // Add the uniqueness constraint to the tsk_event and tsk_event_description tables.
1990  // Unfortunately, SQLite doesn't support adding a constraint
1991  // to an existing table so we have to rename the old...
1992  String primaryKeyType;
1993  switch (getDatabaseType()) {
1994  case POSTGRESQL:
1995  primaryKeyType = "BIGSERIAL";
1996  break;
1997  case SQLITE:
1998  primaryKeyType = "INTEGER";
1999  break;
2000  default:
2001  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2002  }
2003 
2004  //create and initialize tsk_event_types tables which may or may not exist
2005  statement.execute("CREATE TABLE IF NOT EXISTS tsk_event_types ("
2006  + " event_type_id " + primaryKeyType + " PRIMARY KEY, "
2007  + " display_name TEXT UNIQUE NOT NULL, "
2008  + " super_type_id INTEGER REFERENCES tsk_event_types(event_type_id) )");
2009 
2010  resultSet = statement.executeQuery("SELECT * from tsk_event_types");
2011 
2012  // If there is something in resultSet then the table must have previously
2013  // existing therefore there is not need to populate
2014  if (!resultSet.next()) {
2015 
2016  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2017  + " values( 0, 'Event Types', null)");
2018  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2019  + " values(1, 'File System', 0)");
2020  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2021  + " values(2, 'Web Activity', 0)");
2022  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2023  + " values(3, 'Misc Types', 0)");
2024  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2025  + " values(4, 'Modified', 1)");
2026  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2027  + " values(5, 'Accessed', 1)");
2028  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2029  + " values(6, 'Created', 1)");
2030  statement.execute("insert into tsk_event_types(event_type_id, display_name, super_type_id)"
2031  + " values(7, 'Changed', 1)");
2032  }
2033 
2034  // Delete the old table that may have been created with the upgrade
2035  // from 8.1 to 8.2.
2036  statement.execute("DROP TABLE IF EXISTS tsk_events");
2037 
2038  // Delete the old table that may have been created with the upgrade
2039  // from 8.1 to 8.2
2040  statement.execute("DROP TABLE IF EXISTS tsk_event_descriptions");
2041 
2042  //create new tsk_event_description table
2043  statement.execute("CREATE TABLE tsk_event_descriptions ("
2044  + " event_description_id " + primaryKeyType + " PRIMARY KEY, "
2045  + " full_description TEXT NOT NULL, "
2046  + " med_description TEXT, "
2047  + " short_description TEXT,"
2048  + " data_source_obj_id BIGINT NOT NULL, "
2049  + " file_obj_id BIGINT NOT NULL, "
2050  + " artifact_id BIGINT, "
2051  + " hash_hit INTEGER NOT NULL, " //boolean
2052  + " tagged INTEGER NOT NULL, " //boolean
2053  + " UNIQUE(full_description, file_obj_id, artifact_id), "
2054  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2055  + " FOREIGN KEY(file_obj_id) REFERENCES tsk_files(obj_id), "
2056  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2057  );
2058 
2059  // create a new table
2060  statement.execute("CREATE TABLE tsk_events ( "
2061  + " event_id " + primaryKeyType + " PRIMARY KEY, "
2062  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2063  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id) ,"
2064  + " time INTEGER NOT NULL, "
2065  + " UNIQUE (event_type_id, event_description_id, time))"
2066  );
2067 
2068  // Fix mistakenly set names in tsk_db_info_extended
2069  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MAJOR_VERSION' WHERE name = 'CREATED_SCHEMA_MAJOR_VERSION'");
2070  statement.execute("UPDATE tsk_db_info_extended SET name = 'CREATION_SCHEMA_MINOR_VERSION' WHERE name = 'CREATED_SCHEMA_MINOR_VERSION'");
2071 
2072  return new CaseDbSchemaVersionNumber(8, 3);
2073  } finally {
2074  closeResultSet(resultSet);
2076  }
2077  }
2078 
2100  private CaseDbSchemaVersionNumber updateFromSchema8dot3toSchema8dot4(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2101  if (schemaVersion.getMajor() != 8) {
2102  return schemaVersion;
2103  }
2104 
2105  if (schemaVersion.getMinor() != 3) {
2106  return schemaVersion;
2107  }
2108 
2109  Statement statement = connection.createStatement();
2110  ResultSet results = null;
2111 
2113  try {
2114  // This is a bug fix update for a misnamed column in tsk_event_descriptions in
2115  // the previous update code.
2116  if (null == getDatabaseType()) {
2117  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2118  }
2119 
2120  switch (getDatabaseType()) {
2121  case POSTGRESQL:
2122  // Check if the misnamed column is present
2123  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2124  + "WHERE table_name='tsk_event_descriptions' and column_name='file_obj_id'");
2125  if (results.next()) {
2126  // In PostgreSQL we can rename the column if it exists
2127  statement.execute("ALTER TABLE tsk_event_descriptions "
2128  + "RENAME COLUMN file_obj_id TO content_obj_id");
2129 
2130  // 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
2131  // Fix the schema, preserving any data if exists.
2132  statement.execute("CREATE TABLE temp_tsk_events ( "
2133  + " event_id BIGSERIAL PRIMARY KEY, "
2134  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2135  + " event_description_id BIGINT NOT NULL REFERENCES tsk_event_descriptions(event_description_id),"
2136  + " time BIGINT NOT NULL, "
2137  + " UNIQUE (event_type_id, event_description_id, time))"
2138  );
2139 
2140  // Copy the data
2141  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2142  + "event_description_id, time) SELECT * FROM tsk_events");
2143 
2144  // Drop the old table
2145  statement.execute("DROP TABLE tsk_events");
2146 
2147  // Rename the new table
2148  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2149 
2150  //create tsk_events indices that were skipped in the 8.2 to 8.3 update code
2151  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2152  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2153  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2154  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2155  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2156  }
2157  break;
2158  case SQLITE:
2159  boolean hasMisnamedColumn = false;
2160  results = statement.executeQuery("pragma table_info('tsk_event_descriptions')");
2161  while (results.next()) {
2162  if (results.getString("name") != null && results.getString("name").equals("file_obj_id")) {
2163  hasMisnamedColumn = true;
2164  break;
2165  }
2166  }
2167 
2168  if (hasMisnamedColumn) {
2169  // Since we can't rename the column we'll need to make new tables and copy the data
2170  statement.execute("CREATE TABLE temp_tsk_event_descriptions ("
2171  + " event_description_id INTEGER PRIMARY KEY, "
2172  + " full_description TEXT NOT NULL, "
2173  + " med_description TEXT, "
2174  + " short_description TEXT,"
2175  + " data_source_obj_id BIGINT NOT NULL, "
2176  + " content_obj_id BIGINT NOT NULL, "
2177  + " artifact_id BIGINT, "
2178  + " hash_hit INTEGER NOT NULL, " //boolean
2179  + " tagged INTEGER NOT NULL, " //boolean
2180  + " UNIQUE(full_description, content_obj_id, artifact_id), "
2181  + " FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id), "
2182  + " FOREIGN KEY(content_obj_id) REFERENCES tsk_files(obj_id), "
2183  + " FOREIGN KEY(artifact_id) REFERENCES blackboard_artifacts(artifact_id))"
2184  );
2185 
2186  statement.execute("CREATE TABLE temp_tsk_events ( "
2187  + " event_id INTEGER PRIMARY KEY, "
2188  + " event_type_id BIGINT NOT NULL REFERENCES tsk_event_types(event_type_id) ,"
2189  + " event_description_id BIGINT NOT NULL REFERENCES temp_tsk_event_descriptions(event_description_id),"
2190  + " time INTEGER NOT NULL, "
2191  + " UNIQUE (event_type_id, event_description_id, time))"
2192  );
2193 
2194  // Copy the data
2195  statement.execute("INSERT INTO temp_tsk_event_descriptions(event_description_id, full_description, "
2196  + "med_description, short_description, data_source_obj_id, content_obj_id, artifact_id, "
2197  + "hash_hit, tagged) SELECT * FROM tsk_event_descriptions");
2198 
2199  statement.execute("INSERT INTO temp_tsk_events(event_id, event_type_id, "
2200  + "event_description_id, time) SELECT * FROM tsk_events");
2201 
2202  // Drop the old tables
2203  statement.execute("DROP TABLE tsk_events");
2204  statement.execute("DROP TABLE tsk_event_descriptions");
2205 
2206  // Rename the new tables
2207  statement.execute("ALTER TABLE temp_tsk_event_descriptions RENAME TO tsk_event_descriptions");
2208  statement.execute("ALTER TABLE temp_tsk_events RENAME TO tsk_events");
2209 
2210  //create tsk_events indices
2211  statement.execute("CREATE INDEX events_data_source_obj_id ON tsk_event_descriptions(data_source_obj_id) ");
2212  statement.execute("CREATE INDEX events_content_obj_id ON tsk_event_descriptions(content_obj_id) ");
2213  statement.execute("CREATE INDEX events_artifact_id ON tsk_event_descriptions(artifact_id) ");
2214  statement.execute("CREATE INDEX events_sub_type_time ON tsk_events(event_type_id, time) ");
2215  statement.execute("CREATE INDEX events_time ON tsk_events(time) ");
2216  }
2217  break;
2218  default:
2219  throw new TskCoreException("Unsupported data base type: " + getDatabaseType().toString());
2220  }
2221 
2222  // create pool info table
2223  if (this.dbType.equals(DbType.SQLITE)) {
2224  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)");
2225  } else {
2226  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)");
2227  }
2228 
2229  // Add new account types for newly supported messaging applications, if they dont exists already.
2230  insertAccountTypeIfNotExists(statement, "IMO", "IMO");
2231  insertAccountTypeIfNotExists(statement, "LINE", "LINE");
2232  insertAccountTypeIfNotExists(statement, "SKYPE", "Skype");
2233  insertAccountTypeIfNotExists(statement, "TANGO", "Tango");
2234  insertAccountTypeIfNotExists(statement, "TEXTNOW", "TextNow");
2235  insertAccountTypeIfNotExists(statement, "THREEMA", "ThreeMa");
2236  insertAccountTypeIfNotExists(statement, "VIBER", "Viber");
2237  insertAccountTypeIfNotExists(statement, "XENDER", "Xender");
2238  insertAccountTypeIfNotExists(statement, "ZAPYA", "Zapya");
2239  insertAccountTypeIfNotExists(statement, "SHAREIT", "ShareIt");
2240 
2241  return new CaseDbSchemaVersionNumber(8, 4);
2242  } finally {
2243  closeResultSet(results);
2244  closeStatement(statement);
2246  }
2247  }
2248 
2249  private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2250  if (schemaVersion.getMajor() != 8) {
2251  return schemaVersion;
2252  }
2253 
2254  if (schemaVersion.getMinor() != 4) {
2255  return schemaVersion;
2256  }
2257 
2258  Statement statement = connection.createStatement();
2260  try {
2261  switch (getDatabaseType()) {
2262  case POSTGRESQL:
2263  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id BIGSERIAL PRIMARY KEY, name TEXT UNIQUE)");
2264  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id BIGINT REFERENCES tsk_tag_sets(tag_set_id)");
2265  break;
2266  case SQLITE:
2267  statement.execute("CREATE TABLE tsk_tag_sets (tag_set_id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
2268  statement.execute("ALTER TABLE tag_names ADD COLUMN tag_set_id INTEGER REFERENCES tsk_tag_sets(tag_set_id)");
2269  break;
2270  }
2271 
2272  statement.execute("ALTER TABLE tag_names ADD COLUMN rank INTEGER");
2273 
2274  /*
2275  * Update existing Project Vic tag names (from Image Gallery in
2276  * Autopsy) to be part of a Tag Set. NOTE: These names are out of
2277  * date and will not work with the Project VIC Report module. New
2278  * cases will get the new names from Image Gallery.
2279  */
2280  String insertStmt = "INSERT INTO tsk_tag_sets (name) VALUES ('Project VIC')";
2281  if (getDatabaseType() == DbType.POSTGRESQL) {
2282  statement.execute(insertStmt, Statement.RETURN_GENERATED_KEYS);
2283  } else {
2284  statement.execute(insertStmt);
2285  }
2286  try (ResultSet resultSet = statement.getGeneratedKeys()) {
2287  if (resultSet != null && resultSet.next()) {
2288  int tagSetId = resultSet.getInt(1);
2289 
2290  String updateQuery = "UPDATE tag_names SET tag_set_id = %d, color = '%s', rank = %d, display_name = '%s' WHERE display_name = '%s'";
2291  statement.executeUpdate(String.format(updateQuery, tagSetId, "Red", 1, "Child Exploitation (Illegal)", "CAT-1: Child Exploitation (Illegal)"));
2292  statement.executeUpdate(String.format(updateQuery, tagSetId, "Lime", 2, "Child Exploitation (Non-Illegal/Age Difficult)", "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"));
2293  statement.executeUpdate(String.format(updateQuery, tagSetId, "Yellow", 3, "CGI/Animation (Child Exploitive)", "CAT-3: CGI/Animation (Child Exploitive)"));
2294  statement.executeUpdate(String.format(updateQuery, tagSetId, "Purple", 4, "Exemplar/Comparison (Internal Use Only)", "CAT-4: Exemplar/Comparison (Internal Use Only)"));
2295  statement.executeUpdate(String.format(updateQuery, tagSetId, "Fuchsia", 5, "Non-pertinent", "CAT-5: Non-pertinent"));
2296 
2297  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')";
2298  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')";
2299  String deleteCat0 = "DELETE FROM tag_names WHERE display_name = 'CAT-0: Uncategorized'";
2300  statement.executeUpdate(deleteContentTag);
2301  statement.executeUpdate(deleteArtifactTag);
2302  statement.executeUpdate(deleteCat0);
2303 
2304  } else {
2305  throw new TskCoreException("Failed to retrieve the default tag_set_id from DB");
2306  }
2307  }
2308 
2309  // Add data_source_obj_id column to the tsk_files table. For newly created cases
2310  // this column will have a foreign key constraint on the data_source_info table.
2311  // There does not seem to be a reasonable way to do this in an upgrade,
2312  // so upgraded cases will be missing the foreign key.
2313  switch (getDatabaseType()) {
2314  case POSTGRESQL:
2315  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id BIGINT NOT NULL DEFAULT -1;");
2316  break;
2317  case SQLITE:
2318  statement.execute("ALTER TABLE tsk_fs_info ADD COLUMN data_source_obj_id INTEGER NOT NULL DEFAULT -1;");
2319  break;
2320  }
2321  Statement updateStatement = connection.createStatement();
2322  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id FROM tsk_fs_info")) {
2323  while (resultSet.next()) {
2324  long fsId = resultSet.getLong("obj_id");
2325  long dataSourceId = getDataSourceObjectId(connection, fsId);
2326  updateStatement.executeUpdate("UPDATE tsk_fs_info SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fsId + ";");
2327  }
2328  } finally {
2329  closeStatement(updateStatement);
2330  }
2331 
2332  return new CaseDbSchemaVersionNumber(8, 5);
2333 
2334  } finally {
2335  closeStatement(statement);
2337  }
2338  }
2339 
2340  private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2341  if (schemaVersion.getMajor() != 8) {
2342  return schemaVersion;
2343  }
2344 
2345  if (schemaVersion.getMinor() != 5) {
2346  return schemaVersion;
2347  }
2348 
2349  Statement statement = connection.createStatement();
2351  try {
2352  statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT");
2353 
2354  return new CaseDbSchemaVersionNumber(8, 6);
2355 
2356  } finally {
2357  closeStatement(statement);
2359  }
2360  }
2361 
2362  @SuppressWarnings("deprecation")
2363  private CaseDbSchemaVersionNumber updateFromSchema8dot6toSchema9dot0(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2364  if (schemaVersion.getMajor() != 8) {
2365  return schemaVersion;
2366  }
2367 
2368  if (schemaVersion.getMinor() != 6) {
2369  return schemaVersion;
2370  }
2371 
2372  Statement statement = connection.createStatement();
2374  try {
2375  String dateDataType = "BIGINT";
2376  String bigIntDataType = "BIGINT";
2377  String blobDataType = "BYTEA";
2378  String primaryKeyType = "BIGSERIAL";
2379 
2380  if (this.dbType.equals(DbType.SQLITE)) {
2381  dateDataType = "INTEGER";
2382  bigIntDataType = "INTEGER";
2383  blobDataType = "BLOB";
2384  primaryKeyType = "INTEGER";
2385  }
2386  statement.execute("ALTER TABLE data_source_info ADD COLUMN added_date_time " + dateDataType);
2387  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_settings TEXT");
2388  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_name TEXT");
2389  statement.execute("ALTER TABLE data_source_info ADD COLUMN acquisition_tool_version TEXT");
2390 
2391  // Add category type and initialize the types. We use the list of artifact types that
2392  // were categorized as analysis results as of the 8.7 update to ensure consistency in
2393  // case the built-in types change in a later release.
2394  statement.execute("ALTER TABLE blackboard_artifact_types ADD COLUMN category_type INTEGER DEFAULT 0");
2395  String analysisTypeObjIdList
2396  = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ", "
2397  + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ", "
2398  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + ", "
2399  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() + ", "
2400  + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() + ", "
2401  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + ", "
2402  + BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() + ", "
2403  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + ", "
2404  + BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID() + ", "
2405  + BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() + ", "
2406  + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + ", "
2407  + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID() + ", "
2408  + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + ", "
2409  + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ", "
2410  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID() + ", "
2411  + BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT.getTypeID() + ", "
2412  + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CATEGORIZATION.getTypeID();
2413  statement.execute("UPDATE blackboard_artifact_types SET category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID()
2414  + " WHERE artifact_type_id IN (" + analysisTypeObjIdList + ")");
2415 
2416  // Create tsk file attributes table
2417  statement.execute("CREATE TABLE tsk_file_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2418  + "obj_id " + bigIntDataType + " NOT NULL, "
2419  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2420  + "value_type INTEGER NOT NULL, value_byte " + blobDataType + ", "
2421  + "value_text TEXT, value_int32 INTEGER, value_int64 " + bigIntDataType + ", value_double NUMERIC(20, 10), "
2422  + "FOREIGN KEY(obj_id) REFERENCES tsk_files(obj_id) ON DELETE CASCADE, "
2423  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2424 
2425  // create analysis results tables
2426  statement.execute("CREATE TABLE tsk_analysis_results (artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2427  + "conclusion TEXT, "
2428  + "significance INTEGER NOT NULL, "
2429  /*
2430  * method_category was a column in a little distributed
2431  * version of 9.0. It was renamed to priority before public
2432  * release. The 9.1 upgrade code will add the priority
2433  * column. This is commented out since it was never used.
2434  */
2435  // + "method_category INTEGER NOT NULL, "
2436  + "configuration TEXT, justification TEXT, "
2437  + "ignore_score INTEGER DEFAULT 0 " // boolean
2438  + ")");
2439 
2440  statement.execute("CREATE TABLE tsk_aggregate_score( obj_id " + bigIntDataType + " PRIMARY KEY, "
2441  + "data_source_obj_id " + bigIntDataType + ", "
2442  + "significance INTEGER NOT NULL, "
2443  // See comment above on why this is commented out
2444  // + "method_category INTEGER NOT NULL, "
2445  + "UNIQUE (obj_id),"
2446  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2447  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2448  + ")");
2449 
2450  // Create person table.
2451  statement.execute("CREATE TABLE tsk_persons (id " + primaryKeyType + " PRIMARY KEY, "
2452  + "name TEXT NOT NULL, " // person name
2453  + "UNIQUE(name)) ");
2454 
2455  // Create host table.
2456  statement.execute("CREATE TABLE tsk_hosts (id " + primaryKeyType + " PRIMARY KEY, "
2457  + "name TEXT NOT NULL, " // host name
2458  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2459  + "person_id INTEGER, "
2460  + "merged_into " + bigIntDataType + ", "
2461  + "FOREIGN KEY(person_id) REFERENCES tsk_persons(id) ON DELETE SET NULL, "
2462  + "FOREIGN KEY(merged_into) REFERENCES tsk_hosts(id), "
2463  + "UNIQUE(name)) ");
2464 
2465  // Create OS Account and related tables
2466  statement.execute("CREATE TABLE tsk_os_account_realms (id " + primaryKeyType + " PRIMARY KEY, "
2467  + "realm_name TEXT DEFAULT NULL, " // realm name - for a domain realm, may be null
2468  + "realm_addr TEXT DEFAULT NULL, " // a sid/uid or some some other identifier, may be null
2469  + "realm_signature TEXT NOT NULL, " // Signature exists only to prevent duplicates. It is made up of realm address/name and scope host
2470  + "scope_host_id " + bigIntDataType + " DEFAULT NULL, " // if the realm scope is a single host
2471  + "scope_confidence INTEGER, " // indicates whether we know for sure the realm scope or if we are inferring it
2472  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2473  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2474  + "UNIQUE(realm_signature), "
2475  + "FOREIGN KEY(scope_host_id) REFERENCES tsk_hosts(id),"
2476  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_account_realms(id) )");
2477 
2478  // Add host column and create a host for each existing data source.
2479  // We will create a host for each device id so that related data sources will
2480  // be associated with the same host.
2481  statement.execute("ALTER TABLE data_source_info ADD COLUMN host_id INTEGER REFERENCES tsk_hosts(id)");
2482  Statement updateStatement = connection.createStatement();
2483  try (ResultSet resultSet = statement.executeQuery("SELECT obj_id, device_id FROM data_source_info")) {
2484  Map<String, Long> hostMap = new HashMap<>();
2485  long hostIndex = 1;
2486  while (resultSet.next()) {
2487  long objId = resultSet.getLong("obj_id");
2488  String deviceId = resultSet.getString("device_id");
2489 
2490  if (!hostMap.containsKey(deviceId)) {
2491  String hostName = "Host " + hostIndex;
2492  updateStatement.execute("INSERT INTO tsk_hosts (name, db_status) VALUES ('" + hostName + "', 0)");
2493  hostMap.put(deviceId, hostIndex);
2494  hostIndex++;
2495  }
2496  updateStatement.execute("UPDATE data_source_info SET host_id = " + hostMap.get(deviceId) + " WHERE obj_id = " + objId);
2497  }
2498  } finally {
2499  closeStatement(updateStatement);
2500  }
2501 
2502  statement.execute("CREATE TABLE tsk_os_accounts (os_account_obj_id " + bigIntDataType + " PRIMARY KEY, "
2503  + "login_name TEXT DEFAULT NULL, " // login name, if available, may be null
2504  + "full_name TEXT DEFAULT NULL, " // full name, if available, may be null
2505  + "realm_id " + bigIntDataType + " NOT NULL, " // realm for the account
2506  + "addr TEXT DEFAULT NULL, " // SID/UID, if available
2507  + "signature TEXT NOT NULL, " // This exists only to prevent duplicates. It is either the addr or the login_name whichever is not null.
2508  + "status INTEGER, " // enabled/disabled/deleted
2509  + "type INTEGER, " // service/interactive
2510  + "created_date " + bigIntDataType + " DEFAULT NULL, "
2511  + "db_status INTEGER DEFAULT 0, " // active/merged/deleted
2512  + "merged_into " + bigIntDataType + " DEFAULT NULL, "
2513  + "UNIQUE(signature, realm_id), "
2514  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2515  + "FOREIGN KEY(realm_id) REFERENCES tsk_os_account_realms(id),"
2516  + "FOREIGN KEY(merged_into) REFERENCES tsk_os_accounts(os_account_obj_id) )");
2517 
2518  statement.execute("CREATE TABLE tsk_os_account_attributes (id " + primaryKeyType + " PRIMARY KEY, "
2519  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2520  + "host_id " + bigIntDataType + ", "
2521  + "source_obj_id " + bigIntDataType + ", "
2522  + "attribute_type_id " + bigIntDataType + " NOT NULL, "
2523  + "value_type INTEGER NOT NULL, "
2524  + "value_byte " + bigIntDataType + ", "
2525  + "value_text TEXT, "
2526  + "value_int32 INTEGER, value_int64 " + bigIntDataType + ", "
2527  + "value_double NUMERIC(20, 10), "
2528  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2529  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), "
2530  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL, "
2531  + "FOREIGN KEY(attribute_type_id) REFERENCES blackboard_attribute_types(attribute_type_id))");
2532 
2533  statement.execute("CREATE TABLE tsk_os_account_instances (id " + primaryKeyType + " PRIMARY KEY, "
2534  + "os_account_obj_id " + bigIntDataType + " NOT NULL, "
2535  + "data_source_obj_id " + bigIntDataType + " NOT NULL, "
2536  + "instance_type INTEGER NOT NULL, " // PerformedActionOn/ReferencedOn
2537  + "UNIQUE(os_account_obj_id, data_source_obj_id), "
2538  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id), "
2539  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2540 
2541  statement.execute("CREATE TABLE tsk_data_artifacts ( "
2542  + "artifact_obj_id " + bigIntDataType + " PRIMARY KEY, "
2543  + "os_account_obj_id " + bigIntDataType + ", "
2544  + "FOREIGN KEY(os_account_obj_id) REFERENCES tsk_os_accounts(os_account_obj_id)) ");
2545 
2546  // add owner_uid & os_account_obj_id columns to tsk_files
2547  statement.execute("ALTER TABLE tsk_files ADD COLUMN owner_uid TEXT DEFAULT NULL");
2548  statement.execute("ALTER TABLE tsk_files ADD COLUMN os_account_obj_id " + bigIntDataType + " DEFAULT NULL REFERENCES tsk_os_accounts(os_account_obj_id) ");
2549 
2550  // create host address tables
2551  statement.execute("CREATE TABLE tsk_host_addresses (id " + primaryKeyType + " PRIMARY KEY, "
2552  + "address_type INTEGER NOT NULL, "
2553  + "address TEXT NOT NULL, "
2554  + "UNIQUE(address_type, address)) ");
2555 
2556  statement.execute("CREATE TABLE tsk_host_address_map (id " + primaryKeyType + " PRIMARY KEY, "
2557  + "host_id " + bigIntDataType + " NOT NULL, "
2558  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2559  + "source_obj_id " + bigIntDataType + ", " // object id of the source where this mapping was found.
2560  + "time " + bigIntDataType + ", " // time at which the mapping existed
2561  + "UNIQUE(host_id, addr_obj_id, time), "
2562  + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id) ON DELETE CASCADE, "
2563  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id), "
2564  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2565 
2566  // stores associations between DNS name and IP address
2567  statement.execute("CREATE TABLE tsk_host_address_dns_ip_map (id " + primaryKeyType + " PRIMARY KEY, "
2568  + "dns_address_id " + bigIntDataType + " NOT NULL, "
2569  + "ip_address_id " + bigIntDataType + " NOT NULL, "
2570  + "source_obj_id " + bigIntDataType + ", "
2571  + "time " + bigIntDataType + ", " // time at which the mapping existed
2572  + "UNIQUE(dns_address_id, ip_address_id, time), "
2573  + "FOREIGN KEY(dns_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2574  + "FOREIGN KEY(ip_address_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE,"
2575  + "FOREIGN KEY(source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE SET NULL )");
2576 
2577  // maps an address to an artifact using it
2578  statement.execute("CREATE TABLE tsk_host_address_usage (id " + primaryKeyType + " PRIMARY KEY, "
2579  + "addr_obj_id " + bigIntDataType + " NOT NULL, "
2580  + "obj_id " + bigIntDataType + " NOT NULL, "
2581  + "data_source_obj_id " + bigIntDataType + " NOT NULL, " // data source where the usage was found
2582  + "UNIQUE(addr_obj_id, obj_id), "
2583  + "FOREIGN KEY(addr_obj_id) REFERENCES tsk_host_addresses(id) ON DELETE CASCADE, "
2584  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE )");
2585 
2586  return new CaseDbSchemaVersionNumber(9, 0);
2587 
2588  } finally {
2589  closeStatement(statement);
2591  }
2592  }
2593 
2594  private CaseDbSchemaVersionNumber updateFromSchema9dot0toSchema9dot1(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException {
2595  if (schemaVersion.getMajor() != 9) {
2596  return schemaVersion;
2597  }
2598 
2599  if (schemaVersion.getMinor() != 0) {
2600  return schemaVersion;
2601  }
2602 
2603  Statement statement = connection.createStatement();
2604  ResultSet results = null;
2606  try {
2607  // The 9.0 schema contained method_category columns that were renamed to priority.
2608  switch (getDatabaseType()) {
2609  case POSTGRESQL:
2610  // Check if the misnamed column is present. We'll assume here that the column will exist
2611  // in both tables if present in one.
2612  results = statement.executeQuery("SELECT column_name FROM information_schema.columns "
2613  + "WHERE table_name='tsk_analysis_results' and column_name='method_category'");
2614  if (results.next()) {
2615  // In PostgreSQL we can delete the column
2616  statement.execute("ALTER TABLE tsk_analysis_results "
2617  + "DROP COLUMN method_category");
2618  statement.execute("ALTER TABLE tsk_aggregate_score "
2619  + "DROP COLUMN method_category");
2620  }
2621  break;
2622  case SQLITE:
2623  // Check if the misnamed column is present. We'll assume here that the column will exist
2624  // in both tables if present in one.
2625  boolean hasMisnamedColumn = false;
2626  results = statement.executeQuery("pragma table_info('tsk_analysis_results')");
2627  while (results.next()) {
2628  if (results.getString("name") != null && results.getString("name").equals("method_category")) {
2629  hasMisnamedColumn = true;
2630  break;
2631  }
2632  }
2633 
2634  if (hasMisnamedColumn) {
2635  // Since we can't rename the column we'll need to make a new table and copy the data.
2636  // We'll add the priority column later.
2637  statement.execute("CREATE TABLE temp_tsk_analysis_results (artifact_obj_id INTEGER PRIMARY KEY, "
2638  + "conclusion TEXT, "
2639  + "significance INTEGER NOT NULL, "
2640  + "configuration TEXT, justification TEXT, "
2641  + "ignore_score INTEGER DEFAULT 0 " // boolean
2642  + ")");
2643  statement.execute("CREATE TABLE temp_tsk_aggregate_score( obj_id INTEGER PRIMARY KEY, "
2644  + "data_source_obj_id INTEGER, "
2645  + "significance INTEGER NOT NULL, "
2646  + "UNIQUE (obj_id),"
2647  + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, "
2648  + "FOREIGN KEY(data_source_obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE "
2649  + ")");
2650 
2651  // Copy the data
2652  statement.execute("INSERT INTO temp_tsk_analysis_results(artifact_obj_id, "
2653  + "conclusion, justification, significance, configuration, ignore_score) "
2654  + "SELECT artifact_obj_id, conclusion, justification, significance, configuration, ignore_score FROM tsk_analysis_results");
2655  statement.execute("INSERT INTO temp_tsk_aggregate_score(obj_id, "
2656  + "data_source_obj_id, significance) "
2657  + "SELECT obj_id, data_source_obj_id, significance FROM tsk_aggregate_score");
2658 
2659  // Drop the old tables
2660  statement.execute("DROP TABLE tsk_analysis_results");
2661  statement.execute("DROP TABLE tsk_aggregate_score");
2662 
2663  // Rename the new tables
2664  statement.execute("ALTER TABLE temp_tsk_analysis_results RENAME TO tsk_analysis_results");
2665  statement.execute("ALTER TABLE temp_tsk_aggregate_score RENAME TO tsk_aggregate_score");
2666 
2667  }
2668  break;
2669  default:
2670  throw new TskCoreException("Unsupported database type: " + getDatabaseType().toString());
2671  }
2672 
2673  // add an index on tsk_file_attributes table.
2674  statement.execute("CREATE INDEX tsk_file_attributes_obj_id ON tsk_file_attributes(obj_id)");
2675 
2676  statement.execute("ALTER TABLE tsk_analysis_results ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2677  statement.execute("ALTER TABLE tsk_aggregate_score ADD COLUMN priority INTEGER NOT NULL DEFAULT " + Score.Priority.NORMAL.getId());
2678 
2679  statement.execute("UPDATE blackboard_artifact_types SET category_type = 1 WHERE artifact_type_id = 16");
2680 
2681  return new CaseDbSchemaVersionNumber(9, 1);
2682  } finally {
2683  closeResultSet(results);
2684  closeStatement(statement);
2686  }
2687  }
2688 
2700  private void insertAccountTypeIfNotExists(Statement statement, String type_name, String display_name) throws TskCoreException, SQLException {
2701 
2702  String insertSQL = String.format("INTO account_types(type_name, display_name) VALUES ('%s', '%s')", type_name, display_name);
2703  switch (getDatabaseType()) {
2704  case POSTGRESQL:
2705  insertSQL = "INSERT " + insertSQL + " ON CONFLICT DO NOTHING"; //NON-NLS
2706  break;
2707  case SQLITE:
2708  insertSQL = "INSERT OR IGNORE " + insertSQL;
2709  break;
2710  default:
2711  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
2712  }
2713  statement.execute(insertSQL); //NON-NLS
2714  }
2715 
2723  static String extractExtension(final String fileName) {
2724  String ext;
2725  int i = fileName.lastIndexOf(".");
2726  // > 0 because we assume it's not an extension if period is the first character
2727  if ((i > 0) && ((i + 1) < fileName.length())) {
2728  ext = fileName.substring(i + 1);
2729  } else {
2730  return "";
2731  }
2732  // we added this at one point to deal with files that had crazy names based on URLs
2733  // it's too hard though to clean those up and not mess up basic extensions though.
2734  // We need to add '-' to the below if we use it again
2735  // String[] findNonAlphanumeric = ext.split("[^a-zA-Z0-9_]");
2736  // if (findNonAlphanumeric.length > 1) {
2737  // ext = findNonAlphanumeric[0];
2738  // }
2739  return ext.toLowerCase();
2740  }
2741 
2752  @Deprecated
2753  public int getSchemaVersion() {
2754  return getDBSchemaVersion().getMajor();
2755  }
2756 
2763  return CURRENT_DB_SCHEMA_VERSION;
2764  }
2765 
2773  return caseDBSchemaCreationVersion;
2774  }
2775 
2782  return this.dbType;
2783  }
2784 
2791  public String getBackupDatabasePath() {
2792  return dbBackupPath;
2793  }
2794 
2809  public CaseDbTransaction beginTransaction() throws TskCoreException {
2810  return new CaseDbTransaction(this);
2811  }
2812 
2818  public String getDatabaseName() {
2819  return databaseName;
2820  }
2821 
2828  public String getDbDirPath() {
2829  return caseDirPath;
2830  }
2831 
2838  if (dbType == DbType.SQLITE) {
2839  rwLock.writeLock().lock();
2840  }
2841  }
2842 
2849  if (dbType == DbType.SQLITE) {
2850  rwLock.writeLock().unlock();
2851  }
2852  }
2853 
2860  if (dbType == DbType.SQLITE) {
2861  rwLock.readLock().lock();
2862  }
2863  }
2864 
2871  if (dbType == DbType.SQLITE) {
2872  rwLock.readLock().unlock();
2873  }
2874  }
2875 
2885  public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
2886  try {
2887  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2888  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2890  //don't wrap in new TskCoreException
2891  throw ex;
2892  } catch (Exception ex) {
2893  throw new TskCoreException("Failed to open case database at " + dbPath, ex);
2894  }
2895  }
2896 
2908  public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir) throws TskCoreException {
2909  try {
2910  /*
2911  * The flow of this method involves trying to open case and if
2912  * successful, return that case. If unsuccessful, an exception is
2913  * thrown. We catch any exceptions, and use tryConnect() to attempt
2914  * to obtain further information about the error. If tryConnect() is
2915  * unable to successfully connect, tryConnect() will throw a
2916  * TskCoreException with a message containing user-level error
2917  * reporting. If tryConnect() is able to connect, flow continues and
2918  * we rethrow the original exception obtained from trying to create
2919  * the case. In this way, we obtain more detailed information if we
2920  * are able, but do not lose any information if unable.
2921  */
2922  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2923  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDir, info.getDbType());
2924  } catch (PropertyVetoException exp) {
2925  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2926  throw new TskCoreException(exp.getMessage(), exp);
2928  //don't wrap in new TskCoreException
2929  throw ex;
2930  } catch (Exception exp) {
2931  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2932  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2933  }
2934  }
2935 
2945  public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
2946  try {
2947  CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
2948  factory.createCaseDatabase();
2949 
2950  SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
2951  return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE);
2952  } catch (Exception ex) {
2953  throw new TskCoreException("Failed to create case database at " + dbPath, ex);
2954  }
2955  }
2956 
2972  public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath) throws TskCoreException {
2973  String databaseName = createCaseDataBaseName(caseName);
2974  try {
2987  CaseDatabaseFactory factory = new CaseDatabaseFactory(databaseName, info);
2988  factory.createCaseDatabase();
2989 
2990  final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info);
2991  return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()),
2992  databaseName, info.getUserName(), info.getPassword(), caseHandle, caseDirPath, info.getDbType());
2993  } catch (PropertyVetoException exp) {
2994  // In this case, the JDBC driver doesn't support PostgreSQL. Use the generic message here.
2995  throw new TskCoreException(exp.getMessage(), exp);
2996  } catch (Exception exp) {
2997  tryConnect(info); // attempt to connect, throw with user-friendly message if unable
2998  throw new TskCoreException(exp.getMessage(), exp); // throw with generic message if tryConnect() was successful
2999  }
3000  }
3001 
3011  private static String createCaseDataBaseName(String candidateDbName) {
3012  String dbName;
3013  if (!candidateDbName.isEmpty()) {
3014  /*
3015  * Replace all non-ASCII characters.
3016  */
3017  dbName = candidateDbName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
3018 
3019  /*
3020  * Replace all control characters.
3021  */
3022  dbName = dbName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
3023 
3024  /*
3025  * Replace /, \, :, ?, space, ' ".
3026  */
3027  dbName = dbName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
3028 
3029  /*
3030  * Make it all lowercase.
3031  */
3032  dbName = dbName.toLowerCase();
3033 
3034  /*
3035  * Must start with letter or underscore. If not, prepend an
3036  * underscore.
3037  */
3038  if ((dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_'))) {
3039  dbName = "_" + dbName;
3040  }
3041 
3042  /*
3043  * Truncate to 63 - 16 = 47 chars to accomodate a timestamp for
3044  * uniqueness.
3045  */
3046  if (dbName.length() > MAX_DB_NAME_LEN_BEFORE_TIMESTAMP) {
3047  dbName = dbName.substring(0, MAX_DB_NAME_LEN_BEFORE_TIMESTAMP);
3048  }
3049 
3050  } else {
3051  /*
3052  * Must start with letter or underscore.
3053  */
3054  dbName = "_";
3055  }
3056  /*
3057  * Add the time stmap.
3058  */
3059  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
3060  Date date = new Date();
3061  dbName = dbName + "_" + dateFormat.format(date);
3062 
3063  return dbName;
3064  }
3065 
3073  public Examiner getCurrentExaminer() throws TskCoreException {
3074 
3075  // return cached value if there's one
3076  if (cachedCurrentExaminer != null) {
3077  return cachedCurrentExaminer;
3078  }
3079  String loginName = System.getProperty("user.name");
3080  if (loginName == null || loginName.isEmpty()) {
3081  throw new TskCoreException("Failed to determine logged in user name.");
3082  }
3083 
3084  ResultSet resultSet = null;
3085  CaseDbConnection connection = null;
3087  try {
3088  connection = connections.getConnection();
3089  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_LOGIN_NAME);
3090  statement.clearParameters();
3091  statement.setString(1, loginName);
3092  resultSet = connection.executeQuery(statement);
3093  if (resultSet.next()) {
3094  cachedCurrentExaminer = new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("display_name"));
3095  return cachedCurrentExaminer;
3096  } else {
3097  throw new TskCoreException("Error getting examaminer for name = " + loginName);
3098  }
3099 
3100  } catch (SQLException ex) {
3101  throw new TskCoreException("Error getting examaminer for name = " + loginName, ex);
3102  } finally {
3103  closeResultSet(resultSet);
3104  closeConnection(connection);
3106  }
3107 
3108  }
3109 
3119  Examiner getExaminerById(long id) throws TskCoreException {
3120 
3121  CaseDbConnection connection = null;
3122  ResultSet resultSet = null;
3124  try {
3125  connection = connections.getConnection();
3126  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_EXAMINER_BY_ID);
3127  statement.clearParameters();
3128  statement.setLong(1, id);
3129  resultSet = connection.executeQuery(statement);
3130  if (resultSet.next()) {
3131  return new Examiner(resultSet.getLong("examiner_id"), resultSet.getString("login_name"), resultSet.getString("full_name"));
3132  } else {
3133  throw new TskCoreException("Error getting examaminer for id = " + id);
3134  }
3135  } catch (SQLException ex) {
3136  throw new TskCoreException("Error getting examaminer for id = " + id, ex);
3137  } finally {
3138  closeResultSet(resultSet);
3139  closeConnection(connection);
3141  }
3142  }
3143 
3161  public AddImageProcess makeAddImageProcess(String timeZone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageCopyPath) {
3162  return this.caseHandle.initAddImageProcess(timeZone, addUnallocSpace, noFatFsOrphans, imageCopyPath, this);
3163  }
3164 
3173  public List<Content> getRootObjects() throws TskCoreException {
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, type FROM tsk_objects " //NON-NLS
3182  + "WHERE par_obj_id IS NULL"); //NON-NLS
3183  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
3184  while (rs.next()) {
3185  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
3186  }
3187 
3188  List<Content> rootObjs = new ArrayList<Content>();
3189  for (ObjectInfo i : infos) {
3190  if (null != i.type) {
3191  switch (i.type) {
3192  case IMG:
3193  rootObjs.add(getImageById(i.id));
3194  break;
3195  case ABSTRACTFILE:
3196  // Check if virtual dir for local files.
3197  AbstractFile af = getAbstractFileById(i.id);
3198  if (af instanceof VirtualDirectory) {
3199  rootObjs.add(af);
3200  } else {
3201  throw new TskCoreException("Parentless object has wrong type to be a root (ABSTRACTFILE, but not VIRTUAL_DIRECTORY: " + i.type);
3202  }
3203  break;
3204  case REPORT:
3205  break;
3206  case OS_ACCOUNT:
3207  break;
3208  case HOST_ADDRESS:
3209  break;
3210  case UNSUPPORTED:
3211  break;
3212  default:
3213  throw new TskCoreException("Parentless object has wrong type to be a root: " + i.type);
3214  }
3215  }
3216  }
3217  return rootObjs;
3218  } catch (SQLException ex) {
3219  throw new TskCoreException("Error getting root objects", ex);
3220  } finally {
3221  closeResultSet(rs);
3222  closeStatement(s);
3223  closeConnection(connection);
3225  }
3226  }
3227 
3239  List<Long> getDataSourceObjIds(String deviceId) throws TskCoreException {
3240 
3241  // check cached map first
3242  synchronized (deviceIdToDatasourceObjIdMap) {
3243  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3244  return new ArrayList<Long>(deviceIdToDatasourceObjIdMap.get(deviceId));
3245  }
3246 
3247  CaseDbConnection connection = null;
3248  Statement s = null;
3249  ResultSet rs = null;
3251  try {
3252  connection = connections.getConnection();
3253  s = connection.createStatement();
3254  rs = connection.executeQuery(s, "SELECT obj_id FROM data_source_info WHERE device_id = '" + deviceId + "'"); //NON-NLS
3255  List<Long> dataSourceObjIds = new ArrayList<Long>();
3256  while (rs.next()) {
3257  dataSourceObjIds.add(rs.getLong("obj_id"));
3258 
3259  // Add to map of deviceID to data_source_obj_id.
3260  long ds_obj_id = rs.getLong("obj_id");
3261  if (deviceIdToDatasourceObjIdMap.containsKey(deviceId)) {
3262  deviceIdToDatasourceObjIdMap.get(deviceId).add(ds_obj_id);
3263  } else {
3264  deviceIdToDatasourceObjIdMap.put(deviceId, new HashSet<Long>(Arrays.asList(ds_obj_id)));
3265  }
3266  }
3267  return dataSourceObjIds;
3268  } catch (SQLException ex) {
3269  throw new TskCoreException("Error getting data sources", ex);
3270  } finally {
3271  closeResultSet(rs);
3272  closeStatement(s);
3273  closeConnection(connection);
3275  }
3276  }
3277  }
3278 
3295  public List<DataSource> getDataSources() throws TskCoreException {
3296  CaseDbConnection connection = null;
3297  Statement statement = null;
3298  ResultSet resultSet = null;
3299  Statement statement2 = null;
3300  ResultSet resultSet2 = null;
3302  try {
3303  connection = connections.getConnection();
3304  statement = connection.createStatement();
3305  statement2 = connection.createStatement();
3306  resultSet = connection.executeQuery(statement,
3307  "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 "
3308  + "FROM data_source_info AS ds "
3309  + "LEFT JOIN tsk_image_info AS img "
3310  + "ON ds.obj_id = img.obj_id"); //NON-NLS
3311 
3312  List<DataSource> dataSourceList = new ArrayList<DataSource>();
3313  Map<Long, List<String>> imagePathsMap = getImagePaths();
3314 
3315  while (resultSet.next()) {
3316  DataSource dataSource;
3317  Long objectId = resultSet.getLong("obj_id");
3318  String deviceId = resultSet.getString("device_id");
3319  String timezone = resultSet.getString("time_zone");
3320  String type = resultSet.getString("type");
3321 
3322  if (type == null) {
3323  /*
3324  * No data found in 'tsk_image_info', so we build a
3325  * LocalFilesDataSource.
3326  */
3327 
3328  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3329  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3330  resultSet2.close();
3331 
3335  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3336  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3337  String parentPath = "/"; //NON-NLS
3338  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath);
3339  } else {
3340  /*
3341  * Data found in 'tsk_image_info', so we build an Image.
3342  */
3343  Long ssize = resultSet.getLong("ssize");
3344  Long size = resultSet.getLong("size");
3345  String md5 = resultSet.getString("md5");
3346  String sha1 = resultSet.getString("sha1");
3347  String sha256 = resultSet.getString("sha256");
3348  String name = resultSet.getString("display_name");
3349 
3350  List<String> imagePaths = imagePathsMap.get(objectId);
3351  if (name == null) {
3352  if (imagePaths.size() > 0) {
3353  String path = imagePaths.get(0);
3354  name = (new java.io.File(path)).getName();
3355  } else {
3356  name = "";
3357  }
3358  }
3359 
3360  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3361  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3362  }
3363 
3364  dataSourceList.add(dataSource);
3365  }
3366 
3367  return dataSourceList;
3368 
3369  } catch (SQLException ex) {
3370  throw new TskCoreException("Error getting data sources", ex);
3371  } finally {
3372  closeResultSet(resultSet);
3373  closeStatement(statement);
3374  closeResultSet(resultSet2);
3375  closeStatement(statement2);
3376  closeConnection(connection);
3378  }
3379  }
3380 
3400  public DataSource getDataSource(long objectId) throws TskDataException, TskCoreException {
3401  DataSource dataSource = null;
3402  CaseDbConnection connection = null;
3403  Statement statement = null;
3404  ResultSet resultSet = null;
3405  Statement statement2 = null;
3406  ResultSet resultSet2 = null;
3408  try {
3409  connection = connections.getConnection();
3410  statement = connection.createStatement();
3411  statement2 = connection.createStatement();
3412  resultSet = connection.executeQuery(statement,
3413  "SELECT ds.device_id, ds.time_zone, img.type, img.ssize, img.size, img.md5, img.sha1, img.sha256, img.display_name "
3414  + "FROM data_source_info AS ds "
3415  + "LEFT JOIN tsk_image_info AS img "
3416  + "ON ds.obj_id = img.obj_id "
3417  + "WHERE ds.obj_id = " + objectId); //NON-NLS
3418  if (resultSet.next()) {
3419  String deviceId = resultSet.getString("device_id");
3420  String timezone = resultSet.getString("time_zone");
3421  String type = resultSet.getString("type");
3422 
3423  if (type == null) {
3424  /*
3425  * No data found in 'tsk_image_info', so we build an
3426  * LocalFilesDataSource.
3427  */
3428 
3429  resultSet2 = connection.executeQuery(statement2, "SELECT name FROM tsk_files WHERE tsk_files.obj_id = " + objectId); //NON-NLS
3430  String dsName = (resultSet2.next()) ? resultSet2.getString("name") : "";
3431 
3435  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
3436  | TSK_FS_META_FLAG_ENUM.USED.getValue());
3437  String parentPath = "/"; //NON-NLS
3438  dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath);
3439  } else {
3440  /*
3441  * Data found in 'tsk_image_info', so we build an Image.
3442  */
3443  Long ssize = resultSet.getLong("ssize");
3444  Long size = resultSet.getLong("size");
3445  String md5 = resultSet.getString("md5");
3446  String sha1 = resultSet.getString("sha1");
3447  String sha256 = resultSet.getString("sha256");
3448  String name = resultSet.getString("display_name");
3449 
3450  List<String> imagePaths = getImagePathsById(objectId, connection);
3451  if (name == null) {
3452  if (imagePaths.size() > 0) {
3453  String path = imagePaths.get(0);
3454  name = (new java.io.File(path)).getName();
3455  } else {
3456  name = "";
3457  }
3458  }
3459 
3460  dataSource = new Image(this, objectId, Long.valueOf(type), deviceId, ssize, name,
3461  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, size);
3462  }
3463  } else {
3464  throw new TskDataException(String.format("There is no data source with obj_id = %d", objectId));
3465  }
3466  } catch (SQLException ex) {
3467  throw new TskCoreException(String.format("Error getting data source with obj_id = %d", objectId), ex);
3468  } finally {
3469  closeResultSet(resultSet);
3470  closeStatement(statement);
3471  closeResultSet(resultSet2);
3472  closeStatement(statement2);
3473  closeConnection(connection);
3475  }
3476 
3477  return dataSource;
3478  }
3479 
3492  @Deprecated
3493  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID) throws TskCoreException {
3494  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3495  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeID)));
3496  return artifacts;
3497  }
3498 
3509  public long getBlackboardArtifactsCount(long objId) throws TskCoreException {
3510  CaseDbConnection connection = null;
3511  ResultSet rs = null;
3513  try {
3514  connection = connections.getConnection();
3515 
3516  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ?
3517  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_FROM_SOURCE);
3518  statement.clearParameters();
3519  statement.setLong(1, objId);
3520  rs = connection.executeQuery(statement);
3521  long count = 0;
3522  if (rs.next()) {
3523  count = rs.getLong("count");
3524  }
3525  return count;
3526  } catch (SQLException ex) {
3527  throw new TskCoreException("Error getting number of blackboard artifacts by content", ex);
3528  } finally {
3529  closeResultSet(rs);
3530  closeConnection(connection);
3532  }
3533  }
3534 
3545  public long getBlackboardArtifactsTypeCount(int artifactTypeID) throws TskCoreException {
3546  CaseDbConnection connection = null;
3547  ResultSet rs = null;
3549  try {
3550  connection = connections.getConnection();
3551 
3552  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3553  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE);
3554  statement.clearParameters();
3555  statement.setInt(1, artifactTypeID);
3556  rs = connection.executeQuery(statement);
3557  long count = 0;
3558  if (rs.next()) {
3559  count = rs.getLong("count");
3560  }
3561  return count;
3562  } catch (SQLException ex) {
3563  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
3564  } finally {
3565  closeResultSet(rs);
3566  closeConnection(connection);
3568  }
3569  }
3570 
3582  public long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID) throws TskCoreException {
3583  CaseDbConnection connection = null;
3584  ResultSet rs = null;
3586  try {
3587  connection = connections.getConnection();
3588 
3589  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE artifact_type_id = ?
3590  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_OF_TYPE_BY_DATA_SOURCE);
3591  statement.clearParameters();
3592  statement.setInt(2, artifactTypeID);
3593  statement.setLong(1, dataSourceID);
3594  rs = connection.executeQuery(statement);
3595  long count = 0;
3596  if (rs.next()) {
3597  count = rs.getLong("count");
3598  }
3599  return count;
3600  } catch (SQLException ex) {
3601  throw new TskCoreException(String.format("Error getting number of blackboard artifacts by type (%d) and data source (%d)", artifactTypeID, dataSourceID), ex);
3602  } finally {
3603  closeResultSet(rs);
3604  closeConnection(connection);
3606  }
3607  }
3608 
3625  @Deprecated
3626  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
3628  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3629  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3630  + "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, "
3631  + "types.type_name AS type_name, types.display_name AS display_name, "//NON-NLS
3632  + " arts.review_status_id AS review_status_id " //NON-NLS
3633  + "FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3634  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3635  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3636  + " AND attrs.value_text = '" + value + "'"
3637  + " AND types.artifact_type_id=arts.artifact_type_id"
3638  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) { //NON-NLS
3639 
3640  List<Long> analysisArtifactObjIds = new ArrayList<>();
3641  List<Long> dataArtifactObjIds = new ArrayList<>();
3642  while (resultSet.next()) {
3643  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3644  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3645  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3646  } else {
3647  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3648  }
3649  }
3650 
3651  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3652  if (!analysisArtifactObjIds.isEmpty()) {
3653  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3654  }
3655 
3656  if (!dataArtifactObjIds.isEmpty()) {
3657  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3658  }
3659  return artifacts;
3660  } catch (SQLException ex) {
3661  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3662  } finally {
3664  }
3665  }
3666 
3685  @Deprecated
3686  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String subString, boolean startsWith) throws TskCoreException {
3687  String valSubStr = "%" + subString; //NON-NLS
3688  if (startsWith == false) {
3689  valSubStr += "%"; //NON-NLS
3690  }
3691 
3693  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3694  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3695  + " 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
3696  + " types.type_name AS type_name, types.display_name AS display_name, " //NON-NLS
3697  + " arts.review_status_id AS review_status_id " //NON-NLS
3698  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3699  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3700  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3701  + " AND LOWER(attrs.value_text) LIKE LOWER('" + valSubStr + "')"
3702  + " AND types.artifact_type_id=arts.artifact_type_id "
3703  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3704  List<Long> analysisArtifactObjIds = new ArrayList<>();
3705  List<Long> dataArtifactObjIds = new ArrayList<>();
3706  while (resultSet.next()) {
3707  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3708  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3709  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3710  } else {
3711  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3712  }
3713  }
3714 
3715  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3716  if (!analysisArtifactObjIds.isEmpty()) {
3717  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3718  }
3719 
3720  if (!dataArtifactObjIds.isEmpty()) {
3721  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3722  }
3723  return artifacts;
3724  } catch (SQLException ex) {
3725  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3726  } finally {
3728  }
3729  }
3730 
3746  @Deprecated
3747  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value) throws TskCoreException {
3749  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3750  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3751  + " 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, "
3752  + " types.type_name AS type_name, types.display_name AS display_name, "
3753  + " arts.review_status_id AS review_status_id "//NON-NLS
3754  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3755  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3756  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3757  + " AND attrs.value_int32 = " + value //NON-NLS
3758  + " AND types.artifact_type_id=arts.artifact_type_id "
3759  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3760  List<Long> analysisArtifactObjIds = new ArrayList<>();
3761  List<Long> dataArtifactObjIds = new ArrayList<>();
3762  while (resultSet.next()) {
3763  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3764  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3765  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3766  } else {
3767  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3768  }
3769  }
3770 
3771  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3772  if (!analysisArtifactObjIds.isEmpty()) {
3773  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3774  }
3775 
3776  if (!dataArtifactObjIds.isEmpty()) {
3777  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3778  }
3779  return artifacts;
3780  } catch (SQLException ex) {
3781  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3782  } finally {
3784  }
3785  }
3786 
3803  @Deprecated
3804  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value) throws TskCoreException {
3806  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3807  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3808  + " 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, "
3809  + " types.type_name AS type_name, types.display_name AS display_name, "
3810  + " arts.review_status_id AS review_status_id "//NON-NLS
3811  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3812  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3813  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3814  + " AND attrs.value_int64 = " + value //NON-NLS
3815  + " AND types.artifact_type_id=arts.artifact_type_id "
3816  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3817  List<Long> analysisArtifactObjIds = new ArrayList<>();
3818  List<Long> dataArtifactObjIds = new ArrayList<>();
3819  while (resultSet.next()) {
3820  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3821  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3822  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3823  } else {
3824  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3825  }
3826  }
3827 
3828  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3829  if (!analysisArtifactObjIds.isEmpty()) {
3830  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3831  }
3832 
3833  if (!dataArtifactObjIds.isEmpty()) {
3834  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3835  }
3836  return artifacts;
3837  } catch (SQLException ex) {
3838  throw new TskCoreException("Error getting blackboard artifacts by attribute. " + ex.getMessage(), ex);
3839  } finally {
3841  }
3842  }
3843 
3860  @Deprecated
3861  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, double value) throws TskCoreException {
3863  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3864  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3865  + " 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, "
3866  + " types.type_name AS type_name, types.display_name AS display_name, "
3867  + " arts.review_status_id AS review_status_id "//NON-NLS
3868  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3869  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3870  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3871  + " AND attrs.value_double = " + value //NON-NLS
3872  + " AND types.artifact_type_id=arts.artifact_type_id "
3873  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3874  List<Long> analysisArtifactObjIds = new ArrayList<>();
3875  List<Long> dataArtifactObjIds = new ArrayList<>();
3876  while (resultSet.next()) {
3877  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3878  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3879  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3880  } else {
3881  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3882  }
3883  }
3884 
3885  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3886  if (!analysisArtifactObjIds.isEmpty()) {
3887  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3888  }
3889 
3890  if (!dataArtifactObjIds.isEmpty()) {
3891  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3892  }
3893  return artifacts;
3894  } catch (SQLException ex) {
3895  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3896  } finally {
3898  }
3899  }
3900 
3917  @Deprecated
3918  public List<BlackboardArtifact> getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, byte value) throws TskCoreException {
3919 
3921  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement();
3922  ResultSet resultSet = connection.executeQuery(statement, "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
3923  + " 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, "
3924  + " types.type_name AS type_name, types.display_name AS display_name, "
3925  + " arts.review_status_id AS review_status_id "//NON-NLS
3926  + " FROM blackboard_artifacts AS arts, blackboard_attributes AS attrs, blackboard_artifact_types AS types " //NON-NLS
3927  + " WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
3928  + " AND attrs.attribute_type_id = " + attrType.getTypeID() //NON-NLS
3929  + " AND attrs.value_byte = " + value //NON-NLS
3930  + " AND types.artifact_type_id=arts.artifact_type_id "
3931  + " AND arts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID());) {
3932  List<Long> analysisArtifactObjIds = new ArrayList<>();
3933  List<Long> dataArtifactObjIds = new ArrayList<>();
3934  while (resultSet.next()) {
3935  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
3936  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
3937  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3938  } else {
3939  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
3940  }
3941  }
3942 
3943  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
3944  if (!analysisArtifactObjIds.isEmpty()) {
3945  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
3946  }
3947 
3948  if (!dataArtifactObjIds.isEmpty()) {
3949  artifacts.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
3950  }
3951  return artifacts;
3952  } catch (SQLException ex) {
3953  throw new TskCoreException("Error getting blackboard artifacts by attribute", ex);
3954  } finally {
3956  }
3957  }
3958 
3966  public Iterable<BlackboardArtifact.Type> getArtifactTypes() throws TskCoreException {
3967  CaseDbConnection connection = null;
3968  Statement s = null;
3969  ResultSet rs = null;
3971  try {
3972  connection = connections.getConnection();
3973  s = connection.createStatement();
3974  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types"); //NON-NLS
3975  ArrayList<BlackboardArtifact.Type> artifactTypes = new ArrayList<BlackboardArtifact.Type>();
3976  while (rs.next()) {
3977  artifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
3978  rs.getString("type_name"), rs.getString("display_name"),
3979  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
3980  }
3981  return artifactTypes;
3982  } catch (SQLException ex) {
3983  throw new TskCoreException("Error getting artifact types", ex); //NON-NLS
3984  } finally {
3985  closeResultSet(rs);
3986  closeStatement(s);
3987  closeConnection(connection);
3989  }
3990  }
3991 
4000  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypesInUse() throws TskCoreException {
4001  String typeIdList = "";
4002  for (int i = 0; i < BlackboardArtifact.ARTIFACT_TYPE.values().length; ++i) {
4003  typeIdList += BlackboardArtifact.ARTIFACT_TYPE.values()[i].getTypeID();
4004  if (i < BlackboardArtifact.ARTIFACT_TYPE.values().length - 1) {
4005  typeIdList += ", ";
4006  }
4007  }
4008  String query = "SELECT DISTINCT artifact_type_id FROM blackboard_artifacts "
4009  + "WHERE artifact_type_id IN (" + typeIdList + ")";
4010  CaseDbConnection connection = null;
4011  Statement s = null;
4012  ResultSet rs = null;
4014  try {
4015  connection = connections.getConnection();
4016  s = connection.createStatement();
4017  rs = connection.executeQuery(s, query);
4018  ArrayList<BlackboardArtifact.ARTIFACT_TYPE> usedArts = new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>();
4019  while (rs.next()) {
4020  usedArts.add(ARTIFACT_TYPE.fromID(rs.getInt("artifact_type_id")));
4021  }
4022  return usedArts;
4023  } catch (SQLException ex) {
4024  throw new TskCoreException("Error getting artifact types in use", ex);
4025  } finally {
4026  closeResultSet(rs);
4027  closeStatement(s);
4028  closeConnection(connection);
4030  }
4031  }
4032 
4043  public List<BlackboardArtifact.Type> getArtifactTypesInUse() throws TskCoreException {
4044  CaseDbConnection connection = null;
4045  Statement s = null;
4046  ResultSet rs = null;
4048  try {
4049  connection = connections.getConnection();
4050  s = connection.createStatement();
4051  rs = connection.executeQuery(s,
4052  "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
4053  + "types.type_name AS type_name, "
4054  + "types.display_name AS display_name, "
4055  + "types.category_type AS category_type "
4056  + "FROM blackboard_artifact_types AS types "
4057  + "INNER JOIN blackboard_artifacts AS arts "
4058  + "ON arts.artifact_type_id = types.artifact_type_id"); //NON-NLS
4059  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<BlackboardArtifact.Type>();
4060  while (rs.next()) {
4061  uniqueArtifactTypes.add(new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4062  rs.getString("type_name"), rs.getString("display_name"),
4063  BlackboardArtifact.Category.fromID(rs.getInt("category_type"))));
4064  }
4065  return uniqueArtifactTypes;
4066  } catch (SQLException ex) {
4067  throw new TskCoreException("Error getting attribute types", ex);
4068  } finally {
4069  closeResultSet(rs);
4070  closeStatement(s);
4071  closeConnection(connection);
4073  }
4074  }
4075 
4083  public List<BlackboardAttribute.Type> getAttributeTypes() throws TskCoreException {
4084  CaseDbConnection connection = null;
4085  Statement s = null;
4086  ResultSet rs = null;
4088  try {
4089  connection = connections.getConnection();
4090  s = connection.createStatement();
4091  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types"); //NON-NLS
4092  ArrayList<BlackboardAttribute.Type> attribute_types = new ArrayList<BlackboardAttribute.Type>();
4093  while (rs.next()) {
4094  attribute_types.add(new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4095  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type"))));
4096  }
4097  return attribute_types;
4098  } catch (SQLException ex) {
4099  throw new TskCoreException("Error getting attribute types", ex);
4100  } finally {
4101  closeResultSet(rs);
4102  closeStatement(s);
4103  closeConnection(connection);
4105  }
4106  }
4107 
4119  public int getBlackboardAttributeTypesCount() throws TskCoreException {
4120  CaseDbConnection connection = null;
4121  Statement s = null;
4122  ResultSet rs = null;
4124  try {
4125  connection = connections.getConnection();
4126  s = connection.createStatement();
4127  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM blackboard_attribute_types"); //NON-NLS
4128  int count = 0;
4129  if (rs.next()) {
4130  count = rs.getInt("count");
4131  }
4132  return count;
4133  } catch (SQLException ex) {
4134  throw new TskCoreException("Error getting number of blackboard artifacts by type", ex);
4135  } finally {
4136  closeResultSet(rs);
4137  closeStatement(s);
4138  closeConnection(connection);
4140  }
4141  }
4142 
4155  private long getArtifactsCountHelper(int artifactTypeID, long obj_id) throws TskCoreException {
4156  CaseDbConnection connection = null;
4157  ResultSet rs = null;
4159  try {
4160  connection = connections.getConnection();
4161 
4162  // SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND artifact_type_id = ?
4163  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_SOURCE_AND_TYPE);
4164  statement.clearParameters();
4165  statement.setLong(1, obj_id);
4166  statement.setInt(2, artifactTypeID);
4167  rs = connection.executeQuery(statement);
4168  long count = 0;
4169  if (rs.next()) {
4170  count = rs.getLong("count");
4171  }
4172  return count;
4173  } catch (SQLException ex) {
4174  throw new TskCoreException("Error getting blackboard artifact count", ex);
4175  } finally {
4176  closeResultSet(rs);
4177  closeConnection(connection);
4179  }
4180  }
4181 
4194  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName, long obj_id) throws TskCoreException {
4195  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4196  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeName), obj_id));
4197  return artifacts;
4198  }
4199 
4212  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(int artifactTypeID, long obj_id) throws TskCoreException {
4213  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4214  artifacts.addAll(blackboard.getArtifactsBySourceId(getArtifactType(artifactTypeID), obj_id));
4215  return artifacts;
4216  }
4217 
4230  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4231  return getBlackboardArtifacts(artifactType.getTypeID(), obj_id);
4232  }
4233 
4246  public long getBlackboardArtifactsCount(String artifactTypeName, long obj_id) throws TskCoreException {
4247  int artifactTypeID = this.getArtifactType(artifactTypeName).getTypeID();
4248  if (artifactTypeID == -1) {
4249  return 0;
4250  }
4251  return getArtifactsCountHelper(artifactTypeID, obj_id);
4252  }
4253 
4266  public long getBlackboardArtifactsCount(int artifactTypeID, long obj_id) throws TskCoreException {
4267  return getArtifactsCountHelper(artifactTypeID, obj_id);
4268  }
4269 
4282  public long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
4283  return getArtifactsCountHelper(artifactType.getTypeID(), obj_id);
4284  }
4285 
4297  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(String artifactTypeName) throws TskCoreException {
4298  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4299  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactTypeName)));
4300  return artifacts;
4301  }
4302 
4314  public ArrayList<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType) throws TskCoreException {
4315  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4316  artifacts.addAll(blackboard.getArtifactsByType(getArtifactType(artifactType.getTypeID())));
4317  return artifacts;
4318  }
4319 
4335  @Deprecated
4336  public List<BlackboardArtifact> getBlackboardArtifacts(ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) throws TskCoreException {
4337 
4338  String dataArtifactJoin = "tsk_data_artifacts ON tsk_data_artifacts.artifact_obj_id = arts.artifact_obj_id";
4339  String analysisResultJoin = "tsk_analysis_result ON tsk_analysis_result.artifact_obj_id = arts.artifact_obj_id";
4340  String dataArtifactColumns = ", tsk_data_artifacts.os_account_obj_id AS os_account_obj_id";
4341  String analysResultColumns = ", tsk_analysis_result.conclusion AS conclusion, tsk_analysis_result.significance AS significance, tsk_analysis_result.priority AS priority, tsk_analysis_result.conclusion AS conclusion, tsk_analysis_result.significance AS significance, tsk_analysis_result.priority AS priority,";
4342 
4343  String formatQuery = "SELECT DISTINCT arts.artifact_id AS artifact_id, " //NON-NLS
4344  + "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, "
4345  + "types.type_name AS type_name, types.display_name AS display_name,"
4346  + "arts.review_status_id AS review_status_id %s "//NON-NLS
4347  + "FROM blackboard_artifacts AS arts "
4348  + "JOIN blackboard_attributes AS attrs "
4349  + "JOIN blackboard_artifact_types AS types " //NON-NLS
4350  + "LEFT JOIN %s "
4351  + "WHERE arts.artifact_id = attrs.artifact_id " //NON-NLS
4352  + "AND attrs.attribute_type_id = %d "
4353  + " AND arts.artifact_type_id = %d "
4354  + " AND attrs.value_text = '%s' " //NON-NLS
4355  + " AND types.artifact_type_id=arts.artifact_type_id "
4356  + " AND arts.review_status_id != %d";
4357 
4358  String query = String.format(formatQuery,
4359  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysResultColumns : dataArtifactColumns),
4360  (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT ? analysisResultJoin : dataArtifactJoin),
4361  attrType.getTypeID(),
4362  artifactType.getTypeID(),
4363  value,
4365 
4367  try (CaseDbConnection connection = connections.getConnection(); Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
4368  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
4369  while (rs.next()) {
4370  if (artifactType.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
4371  Long osAccountObjId = rs.getLong("os_account_obj_id");
4372  if (rs.wasNull()) {
4373  osAccountObjId = null;
4374  }
4375 
4376  artifacts.add(new DataArtifact(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4377  rs.getLong("artifact_obj_id"),
4378  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4379  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4380  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")), osAccountObjId, false));
4381  } else {
4382  artifacts.add(new AnalysisResult(this, rs.getLong("artifact_id"), rs.getLong("obj_id"),
4383  rs.getLong("artifact_obj_id"),
4384  rs.getObject("data_source_obj_id") != null ? rs.getLong("data_source_obj_id") : null,
4385  rs.getInt("artifact_type_id"), rs.getString("type_name"), rs.getString("display_name"),
4386  BlackboardArtifact.ReviewStatus.withID(rs.getInt("review_status_id")),
4387  new Score(Score.Significance.fromID(rs.getInt("significance")), Score.Priority.fromID(rs.getInt("priority"))),
4388  rs.getString("conclusion"), rs.getString("configuration"), rs.getString("justification")));
4389  }
4390  }
4391  return artifacts;
4392  } catch (SQLException ex) {
4393  throw new TskCoreException("Error getting blackboard artifacts by artifact type and attribute. " + ex.getMessage(), ex);
4394  } finally {
4396  }
4397  }
4398 
4410  public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreException {
4411  List<DataArtifact> dataArtifacts = blackboard.getDataArtifactsWhere("artifacts.artifact_id = " + artifactID);
4412  if (!dataArtifacts.isEmpty()) {
4413  return dataArtifacts.get(0);
4414  }
4415 
4416  List<AnalysisResult> analysisResults = blackboard.getAnalysisResultsWhere("artifacts.artifact_id = " + artifactID);
4417  if (!analysisResults.isEmpty()) {
4418  return analysisResults.get(0);
4419  }
4420 
4421  throw new TskCoreException("No blackboard artifact with id " + artifactID);
4422  }
4423 
4432  public void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId) throws TskCoreException {
4434  try (CaseDbConnection connection = connections.getConnection();) {
4435  addBlackBoardAttribute(attr, artifactTypeId, connection);
4436  } catch (SQLException ex) {
4437  throw new TskCoreException("Error adding blackboard attribute " + attr.toString(), ex);
4438  } finally {
4440  }
4441  }
4442 
4452  public void addBlackboardAttributes(Collection<BlackboardAttribute> attributes, int artifactTypeId) throws TskCoreException {
4453  CaseDbConnection connection = null;
4455  try {
4456  connection = connections.getConnection();
4457  connection.beginTransaction();
4458  for (final BlackboardAttribute attr : attributes) {
4459  addBlackBoardAttribute(attr, artifactTypeId, connection);
4460  }
4461  connection.commitTransaction();
4462  } catch (SQLException ex) {
4463  rollbackTransaction(connection);
4464  throw new TskCoreException("Error adding blackboard attributes", ex);
4465  } finally {
4466  closeConnection(connection);
4468  }
4469  }
4470 
4471  void addBlackBoardAttribute(BlackboardAttribute attr, int artifactTypeId, CaseDbConnection connection) throws SQLException, TskCoreException {
4472  PreparedStatement statement;
4473  switch (attr.getAttributeType().getValueType()) {
4474  case STRING:
4475  case JSON:
4476  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_STRING_ATTRIBUTE);
4477  statement.clearParameters();
4478  statement.setString(7, attr.getValueString());
4479  break;
4480  case BYTE:
4481  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_BYTE_ATTRIBUTE);
4482  statement.clearParameters();
4483  statement.setBytes(7, attr.getValueBytes());
4484  break;
4485  case INTEGER:
4486  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INT_ATTRIBUTE);
4487  statement.clearParameters();
4488  statement.setInt(7, attr.getValueInt());
4489  break;
4490  case LONG:
4491  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4492  statement.clearParameters();
4493  statement.setLong(7, attr.getValueLong());
4494  break;
4495  case DOUBLE:
4496  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DOUBLE_ATTRIBUTE);
4497  statement.clearParameters();
4498  statement.setDouble(7, attr.getValueDouble());
4499  break;
4500  case DATETIME:
4501  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LONG_ATTRIBUTE);
4502  statement.clearParameters();
4503  statement.setLong(7, attr.getValueLong());
4504  break;
4505  default:
4506  throw new TskCoreException("Unrecognized artifact attribute value type");
4507  }
4508  statement.setLong(1, attr.getArtifactID());
4509  statement.setInt(2, artifactTypeId);
4510  statement.setString(3, attr.getSourcesCSV());
4511  statement.setString(4, "");
4512  statement.setInt(5, attr.getAttributeType().getTypeID());
4513  statement.setLong(6, attr.getAttributeType().getValueType().getType());
4514  connection.executeUpdate(statement);
4515  }
4516 
4517  void addFileAttribute(Attribute attr, CaseDbConnection connection) throws SQLException, TskCoreException {
4518  PreparedStatement statement;
4519  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_ATTRIBUTE, Statement.RETURN_GENERATED_KEYS);
4520  statement.clearParameters();
4521 
4522  statement.setLong(1, attr.getAttributeParentId());
4523  statement.setInt(2, attr.getAttributeType().getTypeID());
4524  statement.setLong(3, attr.getAttributeType().getValueType().getType());
4525 
4526  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
4527  statement.setBytes(4, attr.getValueBytes());
4528  } else {
4529  statement.setBytes(4, null);
4530  }
4531 
4532  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
4533  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
4534  statement.setString(5, attr.getValueString());
4535  } else {
4536  statement.setString(5, null);
4537  }
4538  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
4539  statement.setInt(6, attr.getValueInt());
4540  } else {
4541  statement.setNull(6, java.sql.Types.INTEGER);
4542  }
4543 
4544  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
4545  || attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
4546  statement.setLong(7, attr.getValueLong());
4547  } else {
4548  statement.setNull(7, java.sql.Types.BIGINT);
4549  }
4550 
4551  if (attr.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
4552  statement.setDouble(8, attr.getValueDouble());
4553  } else {
4554  statement.setNull(8, java.sql.Types.DOUBLE);
4555  }
4556 
4557  connection.executeUpdate(statement);
4558  try (ResultSet resultSet = statement.getGeneratedKeys()) {
4559  if (!resultSet.next()) {
4560  throw new TskCoreException(String.format("Failed to insert file attribute "
4561  + "with id=%d. The expected key was not generated", attr.getId()));
4562  }
4563 
4564  attr.setId(resultSet.getLong(1));
4565  }
4566  }
4567 
4578  String addSourceToArtifactAttribute(BlackboardAttribute attr, String source) throws TskCoreException {
4579  /*
4580  * WARNING: This is a temporary implementation that is not safe and
4581  * denormalizes the case datbase.
4582  *
4583  * TODO (JIRA-2294): Provide a safe and normalized solution to tracking
4584  * the sources of artifact attributes.
4585  */
4586  if (null == source || source.isEmpty()) {
4587  throw new TskCoreException("Attempt to add null or empty source module name to artifact attribute");
4588  }
4589  CaseDbConnection connection = null;
4591  Statement queryStmt = null;
4592  Statement updateStmt = null;
4593  ResultSet result = null;
4594  String newSources = "";
4595  try {
4596  connection = connections.getConnection();
4597  connection.beginTransaction();
4598  String valueClause = "";
4599  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType = attr.getAttributeType().getValueType();
4600  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4601  switch (valueType) {
4602  case STRING:
4603  case JSON:
4604  valueClause = " value_text = '" + escapeSingleQuotes(attr.getValueString()) + "'";
4605  break;
4606  case INTEGER:
4607  valueClause = " value_int32 = " + attr.getValueInt();
4608  break;
4609  case LONG:
4610  case DATETIME:
4611  valueClause = " value_int64 = " + attr.getValueLong();
4612  break;
4613  case DOUBLE:
4614  valueClause = " value_double = " + attr.getValueDouble();
4615  break;
4616  default:
4617  throw new TskCoreException(String.format("Unrecognized value type for attribute %s", attr.getDisplayString()));
4618  }
4619  String query = "SELECT source FROM blackboard_attributes WHERE"
4620  + " artifact_id = " + attr.getArtifactID()
4621  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4622  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4623  + " AND " + valueClause + ";";
4624  queryStmt = connection.createStatement();
4625  updateStmt = connection.createStatement();
4626  result = connection.executeQuery(queryStmt, query);
4627  } else {
4628  /*
4629  * SELECT source FROM blackboard_attributes WHERE artifact_id =
4630  * ? AND attribute_type_id = ? AND value_type = 4 AND value_byte
4631  * = ?
4632  */
4633  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ATTR_BY_VALUE_BYTE);
4634  statement.clearParameters();
4635  statement.setLong(1, attr.getArtifactID());
4636  statement.setLong(2, attr.getAttributeType().getTypeID());
4637  statement.setBytes(3, attr.getValueBytes());
4638  result = connection.executeQuery(statement);
4639  }
4640  while (result.next()) {
4641  String oldSources = result.getString("source");
4642  if (null != oldSources && !oldSources.isEmpty()) {
4643  Set<String> uniqueSources = new HashSet<String>(Arrays.asList(oldSources.split(",")));
4644  if (!uniqueSources.contains(source)) {
4645  newSources = oldSources + "," + source;
4646  } else {
4647  newSources = oldSources;
4648  }
4649  } else {
4650  newSources = source;
4651  }
4652  if (BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE != valueType) {
4653  String update = "UPDATE blackboard_attributes SET source = '" + newSources + "' WHERE"
4654  + " artifact_id = " + attr.getArtifactID()
4655  + " AND attribute_type_id = " + attr.getAttributeType().getTypeID()
4656  + " AND value_type = " + attr.getAttributeType().getValueType().getType()
4657  + " AND " + valueClause + ";";
4658  connection.executeUpdate(updateStmt, update);
4659  } else {
4660  /*
4661  * UPDATE blackboard_attributes SET source = ? WHERE
4662  * artifact_id = ? AND attribute_type_id = ? AND value_type
4663  * = 4 AND value_byte = ?
4664  */
4665  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ATTR_BY_VALUE_BYTE);
4666  statement.clearParameters();
4667  statement.setString(1, newSources);
4668  statement.setLong(2, attr.getArtifactID());
4669  statement.setLong(3, attr.getAttributeType().getTypeID());
4670  statement.setBytes(4, attr.getValueBytes());
4671  connection.executeUpdate(statement);
4672  }
4673  }
4674  connection.commitTransaction();
4675  return newSources;
4676  } catch (SQLException ex) {
4677  rollbackTransaction(connection);
4678  throw new TskCoreException(String.format("Error adding source module to attribute %s", attr.getDisplayString()), ex);
4679  } finally {
4680  closeResultSet(result);
4681  closeStatement(updateStmt);
4682  closeStatement(queryStmt);
4683  closeConnection(connection);
4685  }
4686  }
4687 
4702  public BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws TskCoreException, TskDataException {
4703  CaseDbConnection connection = null;
4705  Statement s = null;
4706  ResultSet rs = null;
4707  try {
4708  connection = connections.getConnection();
4709  connection.beginTransaction();
4710  s = connection.createStatement();
4711  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeString + "'"); //NON-NLS
4712  if (!rs.next()) {
4713  rs.close();
4714  rs = connection.executeQuery(s, "SELECT MAX(attribute_type_id) AS highest_id FROM blackboard_attribute_types");
4715  int maxID = 0;
4716  if (rs.next()) {
4717  maxID = rs.getInt("highest_id");
4718  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4719  maxID = MIN_USER_DEFINED_TYPE_ID;
4720  } else {
4721  maxID++;
4722  }
4723  }
4724  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
4725  BlackboardAttribute.Type type = new BlackboardAttribute.Type(maxID, attrTypeString, displayName, valueType);
4726  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4727  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4728  connection.commitTransaction();
4729  return type;
4730  } else {
4731  throw new TskDataException("The attribute type that was added was already within the system.");
4732  }
4733 
4734  } catch (SQLException ex) {
4735  rollbackTransaction(connection);
4736  throw new TskCoreException("Error adding attribute type", ex);
4737  } finally {
4738  closeResultSet(rs);
4739  closeStatement(s);
4740  closeConnection(connection);
4742  }
4743  }
4744 
4755  public BlackboardAttribute.Type getAttributeType(String attrTypeName) throws TskCoreException {
4756  if (this.typeNameToAttributeTypeMap.containsKey(attrTypeName)) {
4757  return this.typeNameToAttributeTypeMap.get(attrTypeName);
4758  }
4759  CaseDbConnection connection = null;
4760  Statement s = null;
4761  ResultSet rs = null;
4763  try {
4764  connection = connections.getConnection();
4765  s = connection.createStatement();
4766  rs = connection.executeQuery(s, "SELECT attribute_type_id, type_name, display_name, value_type FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
4767  BlackboardAttribute.Type type = null;
4768  if (rs.next()) {
4769  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4770  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4771  this.typeIdToAttributeTypeMap.put(type.getTypeID(), type);
4772  this.typeNameToAttributeTypeMap.put(attrTypeName, type);
4773  }
4774  return type;
4775  } catch (SQLException ex) {
4776  throw new TskCoreException("Error getting attribute type id", ex);
4777  } finally {
4778  closeResultSet(rs);
4779  closeStatement(s);
4780  closeConnection(connection);
4782  }
4783  }
4784 
4795  BlackboardAttribute.Type getAttributeType(int typeID) throws TskCoreException {
4796  if (this.typeIdToAttributeTypeMap.containsKey(typeID)) {
4797  return this.typeIdToAttributeTypeMap.get(typeID);
4798  }
4799  CaseDbConnection connection = null;
4800  Statement s = null;
4801  ResultSet rs = null;
4803  try {
4804  connection = connections.getConnection();
4805  s = connection.createStatement();
4806  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
4807  BlackboardAttribute.Type type = null;
4808  if (rs.next()) {
4809  type = new BlackboardAttribute.Type(rs.getInt("attribute_type_id"), rs.getString("type_name"),
4810  rs.getString("display_name"), TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getLong("value_type")));
4811  this.typeIdToAttributeTypeMap.put(typeID, type);
4812  this.typeNameToAttributeTypeMap.put(type.getTypeName(), type);
4813  }
4814  return type;
4815  } catch (SQLException ex) {
4816  throw new TskCoreException("Error getting attribute type id", ex);
4817  } finally {
4818  closeResultSet(rs);
4819  closeStatement(s);
4820  closeConnection(connection);
4822  }
4823  }
4824 
4835  public BlackboardArtifact.Type getArtifactType(String artTypeName) throws TskCoreException {
4836  if (this.typeNameToArtifactTypeMap.containsKey(artTypeName)) {
4837  return this.typeNameToArtifactTypeMap.get(artTypeName);
4838  }
4839  CaseDbConnection connection = null;
4840  Statement s = null;
4841  ResultSet rs = null;
4843  try {
4844  connection = connections.getConnection();
4845  s = connection.createStatement();
4846  rs = connection.executeQuery(s, "SELECT artifact_type_id, type_name, display_name, category_type FROM blackboard_artifact_types WHERE type_name = '" + artTypeName + "'"); //NON-NLS
4847  BlackboardArtifact.Type type = null;
4848  if (rs.next()) {
4849  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4850  rs.getString("type_name"), rs.getString("display_name"),
4851  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
4852  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4853  this.typeNameToArtifactTypeMap.put(artTypeName, type);
4854  }
4855  return type;
4856  } catch (SQLException ex) {
4857  throw new TskCoreException("Error getting artifact type from the database", ex);
4858  } finally {
4859  closeResultSet(rs);
4860  closeStatement(s);
4861  closeConnection(connection);
4863  }
4864  }
4865 
4877  BlackboardArtifact.Type getArtifactType(int artTypeId) throws TskCoreException {
4878  if (this.typeIdToArtifactTypeMap.containsKey(artTypeId)) {
4879  return typeIdToArtifactTypeMap.get(artTypeId);
4880  }
4881  CaseDbConnection connection = null;
4882  Statement s = null;
4883  ResultSet rs = null;
4885  try {
4886  connection = connections.getConnection();
4887  s = connection.createStatement();
4888  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
4889  BlackboardArtifact.Type type = null;
4890  if (rs.next()) {
4891  type = new BlackboardArtifact.Type(rs.getInt("artifact_type_id"),
4892  rs.getString("type_name"), rs.getString("display_name"),
4893  BlackboardArtifact.Category.fromID(rs.getInt("category_type")));
4894  this.typeIdToArtifactTypeMap.put(artTypeId, type);
4895  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4896  return type;
4897  } else {
4898  throw new TskCoreException("No artifact type found matching id: " + artTypeId);
4899  }
4900  } catch (SQLException ex) {
4901  throw new TskCoreException("Error getting artifact type from the database", ex);
4902  } finally {
4903  closeResultSet(rs);
4904  closeStatement(s);
4905  closeConnection(connection);
4907  }
4908  }
4909 
4925  public BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName) throws TskCoreException, TskDataException {
4926 
4927  return addBlackboardArtifactType(artifactTypeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
4928  }
4929 
4945  BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName, BlackboardArtifact.Category category) throws TskCoreException, TskDataException {
4946  CaseDbConnection connection = null;
4948  Statement s = null;
4949  ResultSet rs = null;
4950  try {
4951  connection = connections.getConnection();
4952  connection.beginTransaction();
4953  s = connection.createStatement();
4954  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
4955  if (!rs.next()) {
4956  rs.close();
4957  rs = connection.executeQuery(s, "SELECT MAX(artifact_type_id) AS highest_id FROM blackboard_artifact_types");
4958  int maxID = 0;
4959  if (rs.next()) {
4960  maxID = rs.getInt("highest_id");
4961  if (maxID < MIN_USER_DEFINED_TYPE_ID) {
4962  maxID = MIN_USER_DEFINED_TYPE_ID;
4963  } else {
4964  maxID++;
4965  }
4966  }
4967  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
4968  BlackboardArtifact.Type type = new BlackboardArtifact.Type(maxID, artifactTypeName, displayName, category);
4969  this.typeIdToArtifactTypeMap.put(type.getTypeID(), type);
4970  this.typeNameToArtifactTypeMap.put(type.getTypeName(), type);
4971  connection.commitTransaction();
4972  return type;
4973  } else {
4974  throw new TskDataException("The attribute type that was added was already within the system.");
4975  }
4976  } catch (SQLException ex) {
4977  rollbackTransaction(connection);
4978  throw new TskCoreException("Error adding artifact type", ex);
4979  } finally {
4980  closeResultSet(rs);
4981  closeStatement(s);
4982  closeConnection(connection);
4984  }
4985  }
4986 
4987  public ArrayList<BlackboardAttribute> getBlackboardAttributes(final BlackboardArtifact artifact) throws TskCoreException {
4988  CaseDbConnection connection = null;
4989  Statement statement = null;
4990  ResultSet rs = null;
4992  try {
4993  connection = connections.getConnection();
4994  statement = connection.createStatement();
4995  rs = connection.executeQuery(statement, "SELECT attrs.artifact_id AS artifact_id, "
4996  + "attrs.source AS source, attrs.context AS context, attrs.attribute_type_id AS attribute_type_id, "
4997  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
4998  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
4999  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
5000  + "types.type_name AS type_name, types.display_name AS display_name "
5001  + "FROM blackboard_attributes AS attrs, blackboard_attribute_types AS types WHERE attrs.artifact_id = " + artifact.getArtifactID()
5002  + " AND attrs.attribute_type_id = types.attribute_type_id");
5003  ArrayList<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
5004  while (rs.next()) {
5005  int attributeTypeId = rs.getInt("attribute_type_id");
5006  String attributeTypeName = rs.getString("type_name");
5007  BlackboardAttribute.Type attributeType;
5008  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
5009  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
5010  } else {
5011  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
5012  rs.getString("display_name"),
5014  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
5015  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
5016  }
5017 
5018  final BlackboardAttribute attr = new BlackboardAttribute(
5019  rs.getLong("artifact_id"),
5020  attributeType,
5021  rs.getString("source"),
5022  rs.getString("context"),
5023  rs.getInt("value_int32"),
5024  rs.getLong("value_int64"),
5025  rs.getDouble("value_double"),
5026  rs.getString("value_text"),
5027  rs.getBytes("value_byte"), this
5028  );
5029  attr.setParentDataSourceID(artifact.getDataSourceObjectID());
5030  attributes.add(attr);
5031  }
5032  return attributes;
5033  } catch (SQLException ex) {
5034  throw new TskCoreException("Error getting attributes for artifact, artifact id = " + artifact.getArtifactID(), ex);
5035  } finally {
5036  closeResultSet(rs);
5037  closeStatement(statement);
5038  closeConnection(connection);
5040  }
5041  }
5042 
5052  ArrayList<Attribute> getFileAttributes(final AbstractFile file) throws TskCoreException {
5053  CaseDbConnection connection = null;
5054  Statement statement = null;
5055  ResultSet rs = null;
5057  try {
5058  connection = connections.getConnection();
5059  statement = connection.createStatement();
5060  rs = connection.executeQuery(statement, "SELECT attrs.id as id, attrs.obj_id AS obj_id, "
5061  + "attrs.attribute_type_id AS attribute_type_id, "
5062  + "attrs.value_type AS value_type, attrs.value_byte AS value_byte, "
5063  + "attrs.value_text AS value_text, attrs.value_int32 AS value_int32, "
5064  + "attrs.value_int64 AS value_int64, attrs.value_double AS value_double, "
5065  + "types.type_name AS type_name, types.display_name AS display_name "
5066  + "FROM tsk_file_attributes AS attrs "
5067  + " INNER JOIN blackboard_attribute_types AS types "
5068  + " ON attrs.attribute_type_id = types.attribute_type_id "
5069  + " WHERE attrs.obj_id = " + file.getId());
5070 
5071  ArrayList<Attribute> attributes = new ArrayList<Attribute>();
5072  while (rs.next()) {
5073  int attributeTypeId = rs.getInt("attribute_type_id");
5074  String attributeTypeName = rs.getString("type_name");
5075  BlackboardAttribute.Type attributeType;
5076  if (this.typeIdToAttributeTypeMap.containsKey(attributeTypeId)) {
5077  attributeType = this.typeIdToAttributeTypeMap.get(attributeTypeId);
5078  } else {
5079  attributeType = new BlackboardAttribute.Type(attributeTypeId, attributeTypeName,
5080  rs.getString("display_name"),
5081  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromType(rs.getInt("value_type")));
5082  this.typeIdToAttributeTypeMap.put(attributeTypeId, attributeType);
5083  this.typeNameToAttributeTypeMap.put(attributeTypeName, attributeType);
5084  }
5085 
5086  final Attribute attr = new Attribute(
5087  rs.getLong("id"),
5088  rs.getLong("obj_id"),
5089  attributeType,
5090  rs.getInt("value_int32"),
5091  rs.getLong("value_int64"),
5092  rs.getDouble("value_double"),
5093  rs.getString("value_text"),
5094  rs.getBytes("value_byte"), this
5095  );
5096  attributes.add(attr);
5097  }
5098  return attributes;
5099  } catch (SQLException ex) {
5100  throw new TskCoreException("Error getting attributes for file, file id = " + file.getId(), ex);
5101  } finally {
5102  closeResultSet(rs);
5103  closeStatement(statement);
5104  closeConnection(connection);
5106  }
5107  }
5108 
5121  public ArrayList<BlackboardAttribute> getMatchingAttributes(String whereClause) throws TskCoreException {
5122  CaseDbConnection connection = null;
5123  Statement s = null;
5124  ResultSet rs = null;
5126  try {
5127  connection = connections.getConnection();
5128  s = connection.createStatement();
5129  rs = connection.executeQuery(s, "SELECT blackboard_attributes.artifact_id AS artifact_id, "
5130  + "blackboard_attributes.source AS source, blackboard_attributes.context AS context, "
5131  + "blackboard_attributes.attribute_type_id AS attribute_type_id, "
5132  + "blackboard_attributes.value_type AS value_type, blackboard_attributes.value_byte AS value_byte, "
5133  + "blackboard_attributes.value_text AS value_text, blackboard_attributes.value_int32 AS value_int32, "
5134  + "blackboard_attributes.value_int64 AS value_int64, blackboard_attributes.value_double AS value_double "
5135  + "FROM blackboard_attributes " + whereClause); //NON-NLS
5136  ArrayList<BlackboardAttribute> matches = new ArrayList<BlackboardAttribute>();
5137  while (rs.next()) {
5139  // attribute type is cached, so this does not necessarily call to the db
5140  type = this.getAttributeType(rs.getInt("attribute_type_id"));
5142  rs.getLong("artifact_id"),
5143  type,
5144  rs.getString("source"),
5145  rs.getString("context"),
5146  rs.getInt("value_int32"),
5147  rs.getLong("value_int64"),
5148  rs.getDouble("value_double"),
5149  rs.getString("value_text"),
5150  rs.getBytes("value_byte"), this
5151  );
5152  matches.add(attr);
5153  }
5154  return matches;
5155  } catch (SQLException ex) {
5156  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5157  } finally {
5158  closeResultSet(rs);
5159  closeStatement(s);
5160  closeConnection(connection);
5162  }
5163  }
5164 
5176  public ArrayList<BlackboardArtifact> getMatchingArtifacts(String whereClause) throws TskCoreException {
5177  String query = "SELECT blackboard_artifacts.artifact_id AS artifact_id, "
5178  + "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, "
5179  + "blackboard_artifacts.review_status_id AS review_status_id "
5180  + "FROM blackboard_artifacts " + whereClause;
5182  try (CaseDbConnection connection = connections.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
5183 
5184  List<Long> analysisArtifactObjIds = new ArrayList<>();
5185  List<Long> dataArtifactObjIds = new ArrayList<>();
5186  while (resultSet.next()) {
5187  BlackboardArtifact.Type type = this.getArtifactType(resultSet.getInt("artifact_type_id"));
5188  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5189  analysisArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5190  } else {
5191  dataArtifactObjIds.add(resultSet.getLong("artifact_obj_id"));
5192  }
5193  }
5194 
5195  ArrayList<BlackboardArtifact> matches = new ArrayList<>();
5196  if (!analysisArtifactObjIds.isEmpty()) {
5197  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.ANALYSIS_RESULT, "artifacts.artifact_obj_id", analysisArtifactObjIds, connection));
5198  }
5199 
5200  if (!dataArtifactObjIds.isEmpty()) {
5201  matches.addAll(getArtifactsForValues(BlackboardArtifact.Category.DATA_ARTIFACT, "artifacts.artifact_obj_id", dataArtifactObjIds, connection));
5202  }
5203 
5204  return matches;
5205  } catch (SQLException ex) {
5206  throw new TskCoreException("Error getting attributes using this where clause: " + whereClause, ex);
5207  } finally {
5209  }
5210  }
5211 
5226  @Deprecated
5227  public BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id) throws TskCoreException {
5228  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
5229  if (type == null) {
5230  throw new TskCoreException("Unknown artifact type for id: " + artifactTypeID);
5231  }
5232 
5233  Category category = type.getCategory();
5234  if (category == null) {
5235  throw new TskCoreException(String.format("No category for %s (id: %d)",
5236  type.getDisplayName() == null ? "<null>" : type.getDisplayName(),
5237  type.getTypeID()));
5238  }
5239 
5240  Content content = getContentById(obj_id);
5241  if (content == null) {
5242  throw new TskCoreException("No content found for object id: " + obj_id);
5243  }
5244 
5245  switch (category) {
5246  case ANALYSIS_RESULT:
5247  return content.newAnalysisResult(type, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList())
5248  .getAnalysisResult();
5249  case DATA_ARTIFACT:
5250  return content.newDataArtifact(type, Collections.emptyList());
5251  default:
5252  throw new TskCoreException("Unknown category type: " + category.getName());
5253  }
5254  }
5255 
5268  @Deprecated
5269  @SuppressWarnings("deprecation")
5270  public BlackboardArtifact newBlackboardArtifact(ARTIFACT_TYPE artifactType, long obj_id) throws TskCoreException {
5271  return newBlackboardArtifact(artifactType.getTypeID(), obj_id);
5272  }
5273 
5289  @Deprecated
5290  @SuppressWarnings("deprecation")
5291  BlackboardArtifact newBlackboardArtifact(int artifactTypeID, long obj_id, long data_source_obj_id) throws TskCoreException {
5292  BlackboardArtifact.Type type = getArtifactType(artifactTypeID);
5293  try (CaseDbConnection connection = connections.getConnection()) {
5294  return newBlackboardArtifact(artifactTypeID, obj_id, type.getTypeName(), type.getDisplayName(), data_source_obj_id, connection);
5295  }
5296  }
5297 
5298  @Deprecated
5299  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName) throws TskCoreException {
5300  try (CaseDbConnection connection = connections.getConnection()) {
5301  long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
5302  return this.newBlackboardArtifact(artifact_type_id, obj_id, artifactTypeName, artifactDisplayName, data_source_obj_id, connection);
5303  }
5304  }
5305 
5306  PreparedStatement createInsertArtifactStatement(int artifact_type_id, long obj_id, long artifact_obj_id, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException, SQLException {
5307 
5308  PreparedStatement statement;
5309  if (dbType == DbType.POSTGRESQL) {
5310  statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5311  statement.clearParameters();
5312  statement.setLong(1, obj_id);
5313  statement.setLong(2, artifact_obj_id);
5314  statement.setLong(3, data_source_obj_id);
5315  statement.setInt(4, artifact_type_id);
5316  } else {
5317  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
5318  statement.clearParameters();
5319  this.nextArtifactId++;
5320  statement.setLong(1, this.nextArtifactId);
5321  statement.setLong(2, obj_id);
5322  statement.setLong(3, artifact_obj_id);
5323  statement.setLong(4, data_source_obj_id);
5324  statement.setInt(5, artifact_type_id);
5325  }
5326 
5327  return statement;
5328  }
5329 
5346  @Deprecated
5347  private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_id, String artifactTypeName, String artifactDisplayName, long data_source_obj_id, CaseDbConnection connection) throws TskCoreException {
5348  BlackboardArtifact.Type type = getArtifactType(artifact_type_id);
5349  try {
5350  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
5351  return blackboard.newAnalysisResult(type, obj_id, data_source_obj_id, Score.SCORE_UNKNOWN, null, null, null, Collections.emptyList()).getAnalysisResult();
5352  } else {
5353  return blackboard.newDataArtifact(type, obj_id, data_source_obj_id, Collections.emptyList(), null);
5354  }
5355  } catch (BlackboardException ex) {
5356  throw new TskCoreException("Error creating a blackboard artifact", ex);
5357  }
5358  }
5359 
5378  AnalysisResult newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, CaseDbConnection connection) throws TskCoreException {
5379 
5380  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
5381  throw new TskCoreException(String.format("Artifact type (name = %s) is not of the AnalysisResult category. ", artifactType.getTypeName()));
5382  }
5383 
5384  long artifactID;
5386  try {
5387  // add a row in tsk_objects
5388  long artifactObjId = addObject(objId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
5389 
5390  // add a row in blackboard_artifacts table
5391  PreparedStatement insertArtifactstatement;
5392  ResultSet resultSet = null;
5393  try {
5394  insertArtifactstatement = createInsertArtifactStatement(artifactType.getTypeID(), objId, artifactObjId, dataSourceObjId, connection);
5395  connection.executeUpdate(insertArtifactstatement);
5396  resultSet = insertArtifactstatement.getGeneratedKeys();
5397  resultSet.next();
5398  artifactID = resultSet.getLong(1); //last_insert_rowid()
5399 
5400  // add a row in tsk_analysis_results if any data for it is set
5401  if (score.getSignificance() != Score.Significance.UNKNOWN
5402  || !StringUtils.isBlank(conclusion)
5403  || !StringUtils.isBlank(configuration)
5404  || !StringUtils.isBlank(justification)) {
5405 
5406  PreparedStatement analysisResultsStatement;
5407 
5408  analysisResultsStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_ANALYSIS_RESULT);
5409  analysisResultsStatement.clearParameters();
5410 
5411  analysisResultsStatement.setLong(1, artifactObjId);
5412  analysisResultsStatement.setString(2, (conclusion != null) ? conclusion : "");
5413  analysisResultsStatement.setInt(3, score.getSignificance().getId());
5414  analysisResultsStatement.setInt(4, score.getPriority().getId());
5415  analysisResultsStatement.setString(5, (configuration != null) ? configuration : "");
5416  analysisResultsStatement.setString(6, (justification != null) ? justification : "");
5417 
5418  connection.executeUpdate(analysisResultsStatement);
5419  }
5420 
5421  return new AnalysisResult(this, artifactID, objId, artifactObjId, dataSourceObjId, artifactType.getTypeID(),
5422  artifactType.getTypeName(), artifactType.getDisplayName(),
5423  BlackboardArtifact.ReviewStatus.UNDECIDED, true,
5424  score, (conclusion != null) ? conclusion : "",
5425  (configuration != null) ? configuration : "", (justification != null) ? justification : "");
5426 
5427  } finally {
5428  closeResultSet(resultSet);
5429  }
5430 
5431  } catch (SQLException ex) {
5432  throw new TskCoreException("Error creating a analysis result", ex);
5433  } finally {
5435  }
5436  }
5437 
5450  boolean getContentHasChildren(Content content) throws TskCoreException {
5451  CaseDbConnection connection = null;
5452  ResultSet rs = null;
5454  try {
5455  connection = connections.getConnection();
5456 
5457  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5458  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5459  statement.clearParameters();
5460  statement.setLong(1, content.getId());
5461  rs = connection.executeQuery(statement);
5462  boolean hasChildren = false;
5463  if (rs.next()) {
5464  hasChildren = rs.getInt("count") > 0;
5465  }
5466  return hasChildren;
5467  } catch (SQLException e) {
5468  throw new TskCoreException("Error checking for children of parent " + content, e);
5469  } finally {
5470  closeResultSet(rs);
5471  closeConnection(connection);
5473  }
5474  }
5475 
5488  int getContentChildrenCount(Content content) throws TskCoreException {
5489 
5490  if (!this.getHasChildren(content)) {
5491  return 0;
5492  }
5493 
5494  CaseDbConnection connection = null;
5495  ResultSet rs = null;
5497  try {
5498  connection = connections.getConnection();
5499 
5500  // SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?
5501  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CHILD_OBJECTS_BY_PARENT);
5502  statement.clearParameters();
5503  statement.setLong(1, content.getId());
5504  rs = connection.executeQuery(statement);
5505  int countChildren = -1;
5506  if (rs.next()) {
5507  countChildren = rs.getInt("count");
5508  }
5509  return countChildren;
5510  } catch (SQLException e) {
5511  throw new TskCoreException("Error checking for children of parent " + content, e);
5512  } finally {
5513  closeResultSet(rs);
5514  closeConnection(connection);
5516  }
5517  }
5518 
5530  List<Content> getAbstractFileChildren(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5531  CaseDbConnection connection = null;
5532  ResultSet rs = null;
5534  try {
5535  connection = connections.getConnection();
5536 
5537  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_TYPE);
5538  statement.clearParameters();
5539  long parentId = parent.getId();
5540  statement.setLong(1, parentId);
5541  statement.setShort(2, type.getFileType());
5542  rs = connection.executeQuery(statement);
5543  return fileChildren(rs, connection, parentId);
5544  } catch (SQLException ex) {
5545  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5546  } finally {
5547  closeResultSet(rs);
5548  closeConnection(connection);
5550  }
5551  }
5552 
5562  List<Content> getAbstractFileChildren(Content parent) throws TskCoreException {
5563  CaseDbConnection connection = null;
5564  ResultSet rs = null;
5566  try {
5567  connection = connections.getConnection();
5568 
5569  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT);
5570  statement.clearParameters();
5571  long parentId = parent.getId();
5572  statement.setLong(1, parentId);
5573  rs = connection.executeQuery(statement);
5574  return fileChildren(rs, connection, parentId);
5575  } catch (SQLException ex) {
5576  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5577  } finally {
5578  closeResultSet(rs);
5579  closeConnection(connection);
5581  }
5582  }
5583 
5595  List<Long> getAbstractFileChildrenIds(Content parent, TSK_DB_FILES_TYPE_ENUM type) throws TskCoreException {
5596  CaseDbConnection connection = null;
5597  ResultSet rs = null;
5599  try {
5600  connection = connections.getConnection();
5601 
5602  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT_AND_TYPE);
5603  statement.clearParameters();
5604  statement.setLong(1, parent.getId());
5605  statement.setShort(2, type.getFileType());
5606  rs = connection.executeQuery(statement);
5607  List<Long> children = new ArrayList<Long>();
5608  while (rs.next()) {
5609  children.add(rs.getLong("obj_id"));
5610  }
5611  return children;
5612  } catch (SQLException ex) {
5613  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5614  } finally {
5615  closeResultSet(rs);
5616  closeConnection(connection);
5618  }
5619  }
5620 
5630  List<Long> getAbstractFileChildrenIds(Content parent) throws TskCoreException {
5631  CaseDbConnection connection = null;
5632  ResultSet rs = null;
5634  try {
5635  connection = connections.getConnection();
5636 
5637  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_IDS_BY_PARENT);
5638  statement.clearParameters();
5639  statement.setLong(1, parent.getId());
5640  rs = connection.executeQuery(statement);
5641  List<Long> children = new ArrayList<Long>();
5642  while (rs.next()) {
5643  children.add(rs.getLong("obj_id"));
5644  }
5645  return children;
5646  } catch (SQLException ex) {
5647  throw new TskCoreException("Error getting AbstractFile children for Content", ex);
5648  } finally {
5649  closeResultSet(rs);
5650  closeConnection(connection);
5652  }
5653  }
5654 
5665  List<Long> getBlackboardArtifactChildrenIds(Content parent) throws TskCoreException {
5666  CaseDbConnection connection = null;
5667  ResultSet rs = null;
5669  try {
5670  connection = connections.getConnection();
5671 
5672  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_OBJECTIDS_BY_PARENT);
5673  statement.clearParameters();
5674  statement.setLong(1, parent.getId());
5675  rs = connection.executeQuery(statement);
5676  List<Long> children = new ArrayList<Long>();
5677  while (rs.next()) {
5678  children.add(rs.getLong("obj_id"));
5679  }
5680  return children;
5681  } catch (SQLException ex) {
5682  throw new TskCoreException("Error getting children for BlackboardArtifact", ex);
5683  } finally {
5684  closeResultSet(rs);
5685  closeConnection(connection);
5687  }
5688  }
5689 
5699  List<Content> getBlackboardArtifactChildren(Content parent) throws TskCoreException {
5700  long parentId = parent.getId();
5701  List<Content> lc = new ArrayList<>();
5702  lc.addAll(blackboard.getAnalysisResults(parentId));
5703  lc.addAll(blackboard.getDataArtifactsBySource(parentId));
5704  return lc;
5705  }
5706 
5715  Collection<ObjectInfo> getChildrenInfo(Content c) throws TskCoreException {
5716  CaseDbConnection connection = null;
5717  Statement s = null;
5718  ResultSet rs = null;
5720  try {
5721  connection = connections.getConnection();
5722  s = connection.createStatement();
5723  rs = connection.executeQuery(s, "SELECT tsk_objects.obj_id AS obj_id, tsk_objects.type AS type " //NON-NLS
5724  + "FROM tsk_objects LEFT JOIN tsk_files " //NON-NLS
5725  + "ON tsk_objects.obj_id = tsk_files.obj_id " //NON-NLS
5726  + "WHERE tsk_objects.par_obj_id = " + c.getId()
5727  + " ORDER BY tsk_objects.obj_id"); //NON-NLS
5728  Collection<ObjectInfo> infos = new ArrayList<ObjectInfo>();
5729  while (rs.next()) {
5730  infos.add(new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")))); //NON-NLS
5731  }
5732  return infos;
5733  } catch (SQLException ex) {
5734  throw new TskCoreException("Error getting Children Info for Content", ex);
5735  } finally {
5736  closeResultSet(rs);
5737  closeStatement(s);
5738  closeConnection(connection);
5740  }
5741  }
5742 
5753  ObjectInfo getParentInfo(Content c) throws TskCoreException {
5754  return getParentInfo(c.getId());
5755  }
5756 
5767  ObjectInfo getParentInfo(long contentId) throws TskCoreException {
5769  CaseDbConnection connection = null;
5770  Statement s = null;
5771  ResultSet rs = null;
5772  try {
5773  connection = connections.getConnection();
5774  s = connection.createStatement();
5775  rs = connection.executeQuery(s, "SELECT parent.obj_id AS obj_id, parent.type AS type " //NON-NLS
5776  + "FROM tsk_objects AS parent INNER JOIN tsk_objects AS child " //NON-NLS
5777  + "ON child.par_obj_id = parent.obj_id " //NON-NLS
5778  + "WHERE child.obj_id = " + contentId); //NON-NLS
5779  if (rs.next()) {
5780  return new ObjectInfo(rs.getLong("obj_id"), ObjectType.valueOf(rs.getShort("type")));
5781  } else {
5782  return null;
5783  }
5784  } catch (SQLException ex) {
5785  throw new TskCoreException("Error getting Parent Info for Content: " + contentId, ex);
5786  } finally {
5787  closeResultSet(rs);
5788  closeStatement(s);
5789  closeConnection(connection);
5791  }
5792  }
5793 
5804  Directory getParentDirectory(FsContent fsc) throws TskCoreException {
5805  if (fsc.isRoot()) {
5806  // Given FsContent is a root object and can't have parent directory
5807  return null;
5808  } else {
5809  ObjectInfo parentInfo = getParentInfo(fsc);
5810  if (parentInfo == null) {
5811  return null;
5812  }
5813  Directory parent = null;
5814  if (parentInfo.type == ObjectType.ABSTRACTFILE) {
5815  parent = getDirectoryById(parentInfo.id, fsc.getFileSystem());
5816  } else {
5817  throw new TskCoreException("Parent of FsContent (id: " + fsc.getId() + ") has wrong type to be directory: " + parentInfo.type);
5818  }
5819  return parent;
5820  }
5821  }
5822 
5834  public Content getContentById(long id) throws TskCoreException {
5835  // First check to see if this exists in our frequently used content cache.
5836  Content content = frequentlyUsedContentMap.get(id);
5837  if (null != content) {
5838  return content;
5839  }
5840 
5841  long parentId;
5842  TskData.ObjectType type;
5843 
5844  CaseDbConnection connection = null;
5845  Statement s = null;
5846  ResultSet rs = null;
5848  try {
5849  connection = connections.getConnection();
5850  s = connection.createStatement();
5851  rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE obj_id = " + id + " LIMIT 1"); //NON-NLS
5852  if (!rs.next()) {
5853  return null;
5854  }
5855  parentId = rs.getLong("par_obj_id"); //NON-NLS
5856  type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS
5857  } catch (SQLException ex) {
5858  throw new TskCoreException("Error getting Content by ID.", ex);
5859  } finally {
5860  closeResultSet(rs);
5861  closeStatement(s);
5862  closeConnection(connection);
5864  }
5865 
5866  // Construct the object
5867  switch (type) {
5868  case IMG:
5869  content = getImageById(id);
5870  frequentlyUsedContentMap.put(id, content);
5871  break;
5872  case VS:
5873  content = getVolumeSystemById(id, parentId);
5874  break;
5875  case VOL:
5876  content = getVolumeById(id, parentId);
5877  frequentlyUsedContentMap.put(id, content);
5878  break;
5879  case POOL:
5880  content = getPoolById(id, parentId);
5881  break;
5882  case FS:
5883  content = getFileSystemById(id, parentId);
5884  frequentlyUsedContentMap.put(id, content);
5885  break;
5886  case ABSTRACTFILE:
5887  content = getAbstractFileById(id);
5888 
5889  // Add virtual and root directories to frequently used map.
5890  // Calling isRoot() on local directories goes up the entire directory structure
5891  // and they can only be the root of portable cases, so skip trying to add
5892  // them to the cache.
5893  if (((AbstractFile) content).isVirtual()
5894  || ((!(content instanceof LocalDirectory)) && ((AbstractFile) content).isRoot())) {
5895  frequentlyUsedContentMap.put(id, content);
5896  }
5897  break;
5898  case ARTIFACT:
5899  content = getArtifactById(id);
5900  break;
5901  case REPORT:
5902  content = getReportById(id);
5903  break;
5904  case OS_ACCOUNT:
5905  content = this.osAccountManager.getOsAccountByObjectId(id);
5906  break;
5907  case HOST_ADDRESS:
5908  content = hostAddressManager.getHostAddress(id);
5909  break;
5910  default:
5911  content = new UnsupportedContent(this, id);
5912  }
5913 
5914  return content;
5915  }
5916 
5924  String getFilePath(long id) {
5925 
5926  String filePath = null;
5927  CaseDbConnection connection = null;
5928  ResultSet rs = null;
5930  try {
5931  connection = connections.getConnection();
5932 
5933  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_FOR_FILE);
5934  statement.clearParameters();
5935  statement.setLong(1, id);
5936  rs = connection.executeQuery(statement);
5937  if (rs.next()) {
5938  filePath = rs.getString("path");
5939  }
5940  } catch (SQLException | TskCoreException ex) {
5941  logger.log(Level.SEVERE, "Error getting file path for file " + id, ex); //NON-NLS
5942  } finally {
5943  closeResultSet(rs);
5944  closeConnection(connection);
5946  }
5947  return filePath;
5948  }
5949 
5957  TskData.EncodingType getEncodingType(long id) {
5958 
5959  TskData.EncodingType type = TskData.EncodingType.NONE;
5960  CaseDbConnection connection = null;
5961  ResultSet rs = null;
5963  try {
5964  connection = connections.getConnection();
5965  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ENCODING_FOR_FILE);
5966  statement.clearParameters();
5967  statement.setLong(1, id);
5968  rs = connection.executeQuery(statement);
5969  if (rs.next()) {
5970  type = TskData.EncodingType.valueOf(rs.getInt(1));
5971  }
5972  } catch (SQLException | TskCoreException ex) {
5973  logger.log(Level.SEVERE, "Error getting encoding type for file " + id, ex); //NON-NLS
5974  } finally {
5975  closeResultSet(rs);
5976  closeConnection(connection);
5978  }
5979  return type;
5980  }
5981 
5990  String getFileParentPath(long objectId, CaseDbConnection connection) {
5991  String parentPath = null;
5993  ResultSet rs = null;
5994  try {
5995  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_PATH_FOR_FILE);
5996  statement.clearParameters();
5997  statement.setLong(1, objectId);
5998  rs = connection.executeQuery(statement);
5999  if (rs.next()) {
6000  parentPath = rs.getString("parent_path");
6001  }
6002  } catch (SQLException ex) {
6003  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
6004  } finally {
6005  closeResultSet(rs);
6007  }
6008  return parentPath;
6009  }
6010 
6019  String getFileName(long objectId, CaseDbConnection connection) {
6020  String fileName = null;
6022  ResultSet rs = null;
6023  try {
6024  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_NAME);
6025  statement.clearParameters();
6026  statement.setLong(1, objectId);
6027  rs = connection.executeQuery(statement);
6028  if (rs.next()) {
6029  fileName = rs.getString("name");
6030  }
6031  } catch (SQLException ex) {
6032  logger.log(Level.SEVERE, "Error getting file parent_path for file " + objectId, ex); //NON-NLS
6033  } finally {
6034  closeResultSet(rs);
6036  }
6037  return fileName;
6038  }
6039 
6050  DerivedFile.DerivedMethod getDerivedMethod(long id) throws TskCoreException {
6051 
6052  DerivedFile.DerivedMethod method = null;
6053  CaseDbConnection connection = null;
6054  ResultSet rs1 = null;
6055  ResultSet rs2 = null;
6057  try {
6058  connection = connections.getConnection();
6059 
6060  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_DERIVED_FILE);
6061  statement.clearParameters();
6062  statement.setLong(1, id);
6063  rs1 = connection.executeQuery(statement);
6064  if (rs1.next()) {
6065  int method_id = rs1.getInt("derived_id");
6066  String rederive = rs1.getString("rederive");
6067  method = new DerivedFile.DerivedMethod(method_id, rederive);
6068  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_DERIVATION_METHOD);
6069  statement.clearParameters();
6070  statement.setInt(1, method_id);
6071  rs2 = connection.executeQuery(statement);
6072  if (rs2.next()) {
6073  method.setToolName(rs2.getString("tool_name"));
6074  method.setToolVersion(rs2.getString("tool_version"));
6075  method.setOther(rs2.getString("other"));
6076  }
6077  }
6078  } catch (SQLException e) {
6079  logger.log(Level.SEVERE, "Error getting derived method for file: " + id, e); //NON-NLS
6080  } finally {
6081  closeResultSet(rs2);
6082  closeResultSet(rs1);
6083  closeConnection(connection);
6085  }
6086  return method;
6087  }
6088 
6099  public AbstractFile getAbstractFileById(long id) throws TskCoreException {
6100  CaseDbConnection connection = connections.getConnection();
6101  try {
6102  return getAbstractFileById(id, connection);
6103  } finally {
6104  closeConnection(connection);
6105  }
6106  }
6107 
6120  AbstractFile getAbstractFileById(long objectId, CaseDbConnection connection) throws TskCoreException {
6122  ResultSet rs = null;
6123  try {
6124  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_BY_ID);
6125  statement.clearParameters();
6126  statement.setLong(1, objectId);
6127  rs = connection.executeQuery(statement);
6128  List<AbstractFile> files = resultSetToAbstractFiles(rs, connection);
6129  if (files.size() > 0) {
6130  return files.get(0);
6131  } else {
6132  return null;
6133  }
6134  } catch (SQLException ex) {
6135  throw new TskCoreException("Error getting file by id, id = " + objectId, ex);
6136  } finally {
6137  closeResultSet(rs);
6139  }
6140  }
6141 
6153  public BlackboardArtifact getArtifactById(long id) throws TskCoreException {
6154 
6155  CaseDbConnection connection = null;
6156  ResultSet rs = null;
6158  try {
6159  connection = connections.getConnection();
6160 
6161  // get the artifact type.
6162  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID);
6163  statement.clearParameters();
6164  statement.setLong(1, id);
6165 
6166  rs = connection.executeQuery(statement);
6167  if (!rs.next()) {
6168  throw new TskCoreException("Error getting artifacttype for artifact with artifact_obj_id = " + id);
6169  }
6170 
6171  // based on the artifact type category, get the analysis result or the data artifact
6172  BlackboardArtifact.Type artifactType = getArtifactType(rs.getInt("artifact_type_id"));
6173  switch (artifactType.getCategory()) {
6174  case ANALYSIS_RESULT:
6175  return blackboard.getAnalysisResultById(id);
6176  case DATA_ARTIFACT:
6177  return blackboard.getDataArtifactById(id);
6178  default:
6179  throw new TskCoreException(String.format("Unknown artifact category for artifact with artifact_obj_id = %d, and artifact type = %s", id, artifactType.getTypeName()));
6180  }
6181 
6182  } catch (SQLException ex) {
6183  throw new TskCoreException("Error getting artifacts by artifact_obj_id, artifact_obj_id = " + id, ex);
6184  } finally {
6185  closeResultSet(rs);
6186  closeConnection(connection);
6188  }
6189  }
6190 
6204  @Deprecated
6205  public BlackboardArtifact getArtifactByArtifactId(long id) throws TskCoreException {
6206  String query = "SELECT artifact_type_id, artifact_obj_id WHERE artifact_id = " + id;
6208 
6209  try (CaseDbConnection connection = connections.getConnection();
6210  Statement statement = connection.createStatement();
6211  ResultSet resultSet = statement.executeQuery(query);) {
6212  if (resultSet != null && resultSet.next()) {
6213  BlackboardArtifact.Type artifactType = this.getArtifactType(resultSet.getInt("artifact_type_id"));
6214  long artifactObjId = resultSet.getLong("artifact_obj_id");
6215  switch (artifactType.getCategory()) {
6216  case ANALYSIS_RESULT:
6217  return blackboard.getAnalysisResultById(artifactObjId);
6218  case DATA_ARTIFACT:
6219  return blackboard.getDataArtifactById(artifactObjId);
6220  }
6221  }
6222  return null;
6223  } catch (SQLException ex) {
6224  throw new TskCoreException("Error getting artifacts by artifact id, artifact id = " + id, ex);
6225  } finally {
6227  }
6228  }
6229 
6242  private long getFileSystemId(long fileId, CaseDbConnection connection) {
6244  ResultSet rs = null;
6245  long ret = -1;
6246  try {
6247  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILE_SYSTEM_BY_OBJECT);
6248  statement.clearParameters();
6249  statement.setLong(1, fileId);
6250  rs = connection.executeQuery(statement);
6251  if (rs.next()) {
6252  ret = rs.getLong("fs_obj_id");
6253  if (ret == 0) {
6254  ret = -1;
6255  }
6256  }
6257  } catch (SQLException e) {
6258  logger.log(Level.SEVERE, "Error checking file system id of a file, id = " + fileId, e); //NON-NLS
6259  } finally {
6260  closeResultSet(rs);
6262  }
6263  return ret;
6264  }
6265 
6277  public boolean isFileFromSource(Content dataSource, long fileId) throws TskCoreException {
6278  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
6279  CaseDbConnection connection = null;
6280  Statement statement = null;
6281  ResultSet resultSet = null;
6283  try {
6284  connection = connections.getConnection();
6285  statement = connection.createStatement();
6286  resultSet = connection.executeQuery(statement, query);
6287  resultSet.next();
6288  return (resultSet.getLong("count") > 0L);
6289  } catch (SQLException ex) {
6290  throw new TskCoreException(String.format("Error executing query %s", query), ex);
6291  } finally {
6292  closeResultSet(resultSet);
6293  closeStatement(statement);
6294  closeConnection(connection);
6296  }
6297  }
6298 
6308  private static boolean containsLikeWildcard(String str) {
6309  if (str == null) {
6310  return false;
6311  } else {
6312  return str.contains("%") || str.contains("_");
6313  }
6314  }
6315 
6327  public List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
6328  String ext = "";
6329  if (!containsLikeWildcard(fileName)) {
6330  ext = SleuthkitCase.extractExtension(fileName);
6331  }
6332 
6333  List<AbstractFile> files = new ArrayList<>();
6334  CaseDbConnection connection = null;
6335  ResultSet resultSet = null;
6337  try {
6338  connection = connections.getConnection();
6339 
6340  PreparedStatement statement;
6341  if (ext.isEmpty()) {
6342  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_NAME);
6343  statement.clearParameters();
6344  statement.setString(1, fileName.toLowerCase());
6345  statement.setLong(2, dataSource.getId());
6346  } else {
6347  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_NAME);
6348  statement.clearParameters();
6349  statement.setString(1, ext);
6350  statement.setString(2, fileName.toLowerCase());
6351  statement.setLong(3, dataSource.getId());
6352  }
6353 
6354  resultSet = connection.executeQuery(statement);
6355  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6356  } catch (SQLException e) {
6357  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles.exception.msg3.text"), e);
6358  } finally {
6359  closeResultSet(resultSet);
6360  closeConnection(connection);
6362  }
6363  return files;
6364  }
6365 
6379  public List<AbstractFile> findFiles(Content dataSource, String fileName, String dirSubString) throws TskCoreException {
6380  String ext = "";
6381  if (!containsLikeWildcard(fileName)) {
6382  ext = SleuthkitCase.extractExtension(fileName);
6383  }
6384 
6385  List<AbstractFile> files = new ArrayList<>();
6386  CaseDbConnection connection = null;
6387  ResultSet resultSet = null;
6389  try {
6390  connection = connections.getConnection();
6391  PreparedStatement statement;
6392  if (ext.isEmpty()) {
6393  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6394  statement.clearParameters();
6395  statement.setString(1, fileName.toLowerCase());
6396  statement.setString(2, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6397  statement.setLong(3, dataSource.getId());
6398  } else {
6399  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_DATA_SOURCE_AND_PARENT_PATH_AND_NAME);
6400  statement.clearParameters();
6401  statement.setString(1, ext);
6402  statement.setString(2, fileName.toLowerCase());
6403  statement.setString(3, "%" + dirSubString.toLowerCase() + "%"); //NON-NLS
6404  statement.setLong(4, dataSource.getId());
6405  }
6406 
6407  resultSet = connection.executeQuery(statement);
6408  files.addAll(resultSetToAbstractFiles(resultSet, connection));
6409  } catch (SQLException e) {
6410  throw new TskCoreException(bundle.getString("SleuthkitCase.findFiles3.exception.msg3.text"), e);
6411  } finally {
6412  closeResultSet(resultSet);
6413  closeConnection(connection);
6415  }
6416  return files;
6417  }
6418 
6430  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName) throws TskCoreException {
6431  CaseDbTransaction localTrans = beginTransaction();
6432  try {
6433  VirtualDirectory newVD = addVirtualDirectory(parentId, directoryName, localTrans);
6434  localTrans.commit();
6435  localTrans = null;
6436  return newVD;
6437  } finally {
6438  if (null != localTrans) {
6439  try {
6440  localTrans.rollback();
6441  } catch (TskCoreException ex2) {
6442  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
6443  }
6444  }
6445  }
6446  }
6447 
6460  long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
6461  ResultSet resultSet = null;
6463  try {
6464  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
6465  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
6466  statement.clearParameters();
6467  if (parentId != 0) {
6468  statement.setLong(1, parentId);
6469  } else {
6470  statement.setNull(1, java.sql.Types.BIGINT);
6471  }
6472  statement.setInt(2, objectType);
6473  connection.executeUpdate(statement);
6474  resultSet = statement.getGeneratedKeys();
6475 
6476  if (resultSet.next()) {
6477  if (parentId != 0) {
6478  setHasChildren(parentId);
6479  }
6480  return resultSet.getLong(1); //last_insert_rowid()
6481  } else {
6482  throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
6483  }
6484  } finally {
6485  closeResultSet(resultSet);
6487  }
6488  }
6489 
6507  public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6508  if (transaction == null) {
6509  throw new TskCoreException("Passed null CaseDbTransaction");
6510  }
6511 
6512  ResultSet resultSet = null;
6513  try {
6514  // Get the parent path.
6515  CaseDbConnection connection = transaction.getConnection();
6516 
6517  String parentPath;
6518  Content parent = this.getAbstractFileById(parentId, connection);
6519  if (parent instanceof AbstractFile) {
6520  if (isRootDirectory((AbstractFile) parent, transaction)) {
6521  parentPath = "/";
6522  } else {
6523  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + "/"; //NON-NLS
6524  }
6525  } else {
6526  // The parent was either null or not an abstract file
6527  parentPath = "/";
6528  }
6529 
6530  // Insert a row for the virtual directory into the tsk_objects table.
6531  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6532 
6533  // Insert a row for the virtual directory into the tsk_files table.
6534  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6535  // 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)
6536  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?)
6537  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6538  statement.clearParameters();
6539  statement.setLong(1, newObjId);
6540 
6541  // If the parent is part of a file system, grab its file system ID
6542  if (0 != parentId) {
6543  long parentFs = this.getFileSystemId(parentId, connection);
6544  if (parentFs != -1) {
6545  statement.setLong(2, parentFs);
6546  } else {
6547  statement.setNull(2, java.sql.Types.BIGINT);
6548  }
6549  } else {
6550  statement.setNull(2, java.sql.Types.BIGINT);
6551  }
6552 
6553  // name
6554  statement.setString(3, directoryName);
6555 
6556  //type
6557  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6558  statement.setShort(5, (short) 1);
6559 
6560  //flags
6562  statement.setShort(6, dirType.getValue());
6564  statement.setShort(7, metaType.getValue());
6565 
6566  //allocated
6568  statement.setShort(8, dirFlag.getValue());
6569  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6570  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6571  statement.setShort(9, metaFlags);
6572 
6573  //size
6574  statement.setLong(10, 0);
6575 
6576  // nulls for params 11-14
6577  statement.setNull(11, java.sql.Types.BIGINT);
6578  statement.setNull(12, java.sql.Types.BIGINT);
6579  statement.setNull(13, java.sql.Types.BIGINT);
6580  statement.setNull(14, java.sql.Types.BIGINT);
6581 
6582  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6583  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6584  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6585  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6586 
6587  // parent path
6588  statement.setString(19, parentPath);
6589 
6590  // data source object id (same as object id if this is a data source)
6591  long dataSourceObjectId;
6592  if (0 == parentId) {
6593  dataSourceObjectId = newObjId;
6594  } else {
6595  dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6596  }
6597  statement.setLong(20, dataSourceObjectId);
6598 
6599  //extension, since this is not really file we just set it to null
6600  statement.setString(21, null);
6601 
6602  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6603  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6604 
6605  connection.executeUpdate(statement);
6606 
6607  return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6608  metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN,
6609  parentPath);
6610  } catch (SQLException e) {
6611  throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e);
6612  } finally {
6613  closeResultSet(resultSet);
6614  }
6615  }
6616 
6629  public LocalDirectory addLocalDirectory(long parentId, String directoryName) throws TskCoreException {
6630  CaseDbTransaction localTrans = beginTransaction();
6631  try {
6632  LocalDirectory newLD = addLocalDirectory(parentId, directoryName, localTrans);
6633  localTrans.commit();
6634  return newLD;
6635  } catch (TskCoreException ex) {
6636  try {
6637  localTrans.rollback();
6638  } catch (TskCoreException ex2) {
6639  logger.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
6640  }
6641  throw ex;
6642  }
6643  }
6644 
6662  public LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction) throws TskCoreException {
6663  if (transaction == null) {
6664  throw new TskCoreException("Passed null CaseDbTransaction");
6665  }
6666 
6667  ResultSet resultSet = null;
6668  try {
6669  // Get the parent path.
6670  CaseDbConnection connection = transaction.getConnection();
6671  AbstractFile parent = getAbstractFileById(parentId, connection);
6672  String parentPath;
6673  if ((parent == null) || isRootDirectory(parent, transaction)) {
6674  parentPath = "/";
6675  } else {
6676  parentPath = parent.getParentPath() + parent.getName() + "/"; //NON-NLS
6677  }
6678 
6679  // Insert a row for the local directory into the tsk_objects table.
6680  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6681 
6682  // Insert a row for the local directory into the tsk_files table.
6683  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
6684  // 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)
6685  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6686  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6687  statement.clearParameters();
6688  statement.setLong(1, newObjId);
6689 
6690  // The parent of a local directory will never be a file system
6691  statement.setNull(2, java.sql.Types.BIGINT);
6692 
6693  // name
6694  statement.setString(3, directoryName);
6695 
6696  //type
6697  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType());
6698  statement.setShort(5, (short) 1);
6699 
6700  //flags
6702  statement.setShort(6, dirType.getValue());
6704  statement.setShort(7, metaType.getValue());
6705 
6706  //allocated
6708  statement.setShort(8, dirFlag.getValue());
6709  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6710  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6711  statement.setShort(9, metaFlags);
6712 
6713  //size
6714  statement.setLong(10, 0);
6715 
6716  // nulls for params 11-14
6717  statement.setNull(11, java.sql.Types.BIGINT);
6718  statement.setNull(12, java.sql.Types.BIGINT);
6719  statement.setNull(13, java.sql.Types.BIGINT);
6720  statement.setNull(14, java.sql.Types.BIGINT);
6721 
6722  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
6723  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6724  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6725  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6726 
6727  // parent path
6728  statement.setString(19, parentPath);
6729 
6730  // data source object id
6731  long dataSourceObjectId = getDataSourceObjectId(connection, parentId);
6732  statement.setLong(20, dataSourceObjectId);
6733 
6734  //extension, since this is a directory we just set it to null
6735  statement.setString(21, null);
6736 
6737  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6738  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6739 
6740  connection.executeUpdate(statement);
6741 
6742  return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType,
6743  metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN,
6744  parentPath);
6745  } catch (SQLException e) {
6746  throw new TskCoreException("Error creating local directory '" + directoryName + "'", e);
6747  } finally {
6748  closeResultSet(resultSet);
6749  }
6750  }
6751 
6771  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
6772  return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction);
6773  }
6774 
6795  public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException {
6796 
6797  Statement statement = null;
6798  try {
6799  CaseDbConnection connection = transaction.getConnection();
6800 
6801  // Insert a row for the root virtual directory of the data source
6802  // into the tsk_objects table.
6803  long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
6804 
6805  // If no host was supplied, make one
6806  if (host == null) {
6807  host = getHostManager().newHost("LogicalFileSet_" + newObjId + " Host", transaction);
6808  }
6809 
6810  // Insert a row for the virtual directory of the data source into
6811  // the data_source_info table.
6812  statement = connection.createStatement();
6813  statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) "
6814  + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getHostId() + ");");
6815 
6816  // Insert a row for the root virtual directory of the data source
6817  // into the tsk_files table. Note that its data source object id is
6818  // its own object id.
6819  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path,
6820  // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
6821  // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension, owner_uid, os_account_obj_id)
6822  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
6823  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
6824  preparedStatement.clearParameters();
6825  preparedStatement.setLong(1, newObjId);
6826  preparedStatement.setNull(2, java.sql.Types.BIGINT);
6827  preparedStatement.setString(3, rootDirectoryName);
6828  preparedStatement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
6829  preparedStatement.setShort(5, (short) 1);
6831  preparedStatement.setShort(6, TSK_FS_NAME_TYPE_ENUM.DIR.getValue());
6833  preparedStatement.setShort(7, metaType.getValue());
6835  preparedStatement.setShort(8, dirFlag.getValue());
6836  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
6837  | TSK_FS_META_FLAG_ENUM.USED.getValue());
6838  preparedStatement.setShort(9, metaFlags);
6839  preparedStatement.setLong(10, 0);
6840  preparedStatement.setNull(11, java.sql.Types.BIGINT);
6841  preparedStatement.setNull(12, java.sql.Types.BIGINT);
6842  preparedStatement.setNull(13, java.sql.Types.BIGINT);
6843  preparedStatement.setNull(14, java.sql.Types.BIGINT);
6844  preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5
6845  preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
6846  preparedStatement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
6847  preparedStatement.setNull(18, java.sql.Types.VARCHAR); // MIME type
6848  String parentPath = "/"; //NON-NLS
6849  preparedStatement.setString(19, parentPath);
6850  preparedStatement.setLong(20, newObjId);
6851  preparedStatement.setString(21, null); //extension, just set it to null
6852  preparedStatement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
6853  preparedStatement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
6854  connection.executeUpdate(preparedStatement);
6855 
6856  return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, FileKnown.UNKNOWN, parentPath);
6857 
6858  } catch (SQLException ex) {
6859  throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
6860  } finally {
6861  closeStatement(statement);
6862  }
6863  }
6864 
6884  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6885  String timezone, String md5, String sha1, String sha256,
6886  String deviceId,
6887  CaseDbTransaction transaction) throws TskCoreException {
6888  return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction);
6889  }
6890 
6911  public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths,
6912  String timezone, String md5, String sha1, String sha256,
6913  String deviceId, Host host,
6914  CaseDbTransaction transaction) throws TskCoreException {
6915  Statement statement = null;
6916  try {
6917  // Insert a row for the Image into the tsk_objects table.
6918  CaseDbConnection connection = transaction.getConnection();
6919  long newObjId = addObject(0, TskData.ObjectType.IMG.getObjectType(), connection);
6920 
6921  // Add a row to tsk_image_info
6922  // INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)
6923  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_INFO);
6924  preparedStatement.clearParameters();
6925  preparedStatement.setLong(1, newObjId);
6926  preparedStatement.setShort(2, (short) type.getValue());
6927  preparedStatement.setLong(3, sectorSize);
6928  preparedStatement.setString(4, timezone);
6929  //prevent negative size
6930  long savedSize = size < 0 ? 0 : size;
6931  preparedStatement.setLong(5, savedSize);
6932  preparedStatement.setString(6, md5);
6933  preparedStatement.setString(7, sha1);
6934  preparedStatement.setString(8, sha256);
6935  preparedStatement.setString(9, displayName);
6936  connection.executeUpdate(preparedStatement);
6937 
6938  // If there are paths, add them to tsk_image_names
6939  for (int i = 0; i < imagePaths.size(); i++) {
6940  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
6941  preparedStatement.clearParameters();
6942  preparedStatement.setLong(1, newObjId);
6943  preparedStatement.setString(2, imagePaths.get(i));
6944  preparedStatement.setLong(3, i);
6945  connection.executeUpdate(preparedStatement);
6946  }
6947 
6948  // Create the display name
6949  String name = displayName;
6950  if (name == null || name.isEmpty()) {
6951  if (imagePaths.size() > 0) {
6952  String path = imagePaths.get(0);
6953  name = (new java.io.File(path)).getName();
6954  } else {
6955  name = "";
6956  }
6957  }
6958 
6959  // Create a host if needed
6960  if (host == null) {
6961  if (name.isEmpty()) {
6962  host = getHostManager().newHost("Image_" + newObjId + " Host", transaction);
6963  } else {
6964  host = getHostManager().newHost(name + "_" + newObjId + " Host", transaction);
6965  }
6966  }
6967 
6968  // Add a row to data_source_info
6969  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
6970  statement = connection.createStatement();
6971  preparedStatement.setLong(1, newObjId);
6972  preparedStatement.setString(2, deviceId);
6973  preparedStatement.setString(3, timezone);
6974  preparedStatement.setLong(4, new Date().getTime());
6975  preparedStatement.setLong(5, host.getHostId());
6976  connection.executeUpdate(preparedStatement);
6977 
6978  // Create the new Image object
6979  return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
6980  imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
6981  } catch (SQLException ex) {
6982  if (!imagePaths.isEmpty()) {
6983  throw new TskCoreException(String.format("Error adding image with path %s to database", imagePaths.get(0)), ex);
6984  } else {
6985  throw new TskCoreException(String.format("Error adding image with display name %s to database", displayName), ex);
6986  }
6987  } finally {
6988  closeStatement(statement);
6989  }
6990  }
6991 
7005  public VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset,
7006  long blockSize, CaseDbTransaction transaction) throws TskCoreException {
7007  try {
7008  // Insert a row for the VolumeSystem into the tsk_objects table.
7009  CaseDbConnection connection = transaction.getConnection();
7010  long newObjId = addObject(parentObjId, TskData.ObjectType.VS.getObjectType(), connection);
7011 
7012  // Add a row to tsk_vs_info
7013  // INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size)
7014  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_INFO);
7015  preparedStatement.clearParameters();
7016  preparedStatement.setLong(1, newObjId);
7017  preparedStatement.setShort(2, (short) type.getVsType());
7018  preparedStatement.setLong(3, imgOffset);
7019  preparedStatement.setLong(4, blockSize);
7020  connection.executeUpdate(preparedStatement);
7021 
7022  // Create the new VolumeSystem object
7023  return new VolumeSystem(this, newObjId, "", type.getVsType(), imgOffset, blockSize);
7024  } catch (SQLException ex) {
7025  throw new TskCoreException(String.format("Error creating volume system with parent ID %d and image offset %d",
7026  parentObjId, imgOffset), ex);
7027  }
7028  }
7029 
7045  public Volume addVolume(long parentObjId, long addr, long start, long length, String desc,
7046  long flags, CaseDbTransaction transaction) throws TskCoreException {
7047  try {
7048  // Insert a row for the Volume into the tsk_objects table.
7049  CaseDbConnection connection = transaction.getConnection();
7050  long newObjId = addObject(parentObjId, TskData.ObjectType.VOL.getObjectType(), connection);
7051 
7052  // Add a row to tsk_vs_parts
7053  // INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)
7054  PreparedStatement preparedStatement;
7055  if (this.dbType == DbType.POSTGRESQL) {
7056  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_POSTGRESQL);
7057  } else {
7058  preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_VS_PART_SQLITE);
7059  }
7060  preparedStatement.clearParameters();
7061  preparedStatement.setLong(1, newObjId);
7062  preparedStatement.setLong(2, addr);
7063  preparedStatement.setLong(3, start);
7064  preparedStatement.setLong(4, length);
7065  preparedStatement.setString(5, desc);
7066  preparedStatement.setShort(6, (short) flags);
7067  connection.executeUpdate(preparedStatement);
7068 
7069  // Create the new Volume object
7070  return new Volume(this, newObjId, addr, start, length, flags, desc);
7071  } catch (SQLException ex) {
7072  throw new TskCoreException(String.format("Error creating volume with address %d and parent ID %d", addr, parentObjId), ex);
7073  }
7074  }
7075 
7087  public Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction) throws TskCoreException {
7088  try {
7089  // Insert a row for the Pool into the tsk_objects table.
7090  CaseDbConnection connection = transaction.getConnection();
7091  long newObjId = addObject(parentObjId, TskData.ObjectType.POOL.getObjectType(), connection);
7092 
7093  // Add a row to tsk_pool_info
7094  // INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)
7095  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_POOL_INFO);
7096  preparedStatement.clearParameters();
7097  preparedStatement.setLong(1, newObjId);
7098  preparedStatement.setShort(2, type.getValue());
7099  connection.executeUpdate(preparedStatement);
7100 
7101  // Create the new Pool object
7102  return new Pool(this, newObjId, type.getName(), type.getValue());
7103  } catch (SQLException ex) {
7104  throw new TskCoreException(String.format("Error creating pool with type %d and parent ID %d", type.getValue(), parentObjId), ex);
7105  }
7106  }
7107 
7126  public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount,
7127  long rootInum, long firstInum, long lastInum, String displayName,
7128  CaseDbTransaction transaction) throws TskCoreException {
7129  try {
7130  // Insert a row for the FileSystem into the tsk_objects table.
7131  CaseDbConnection connection = transaction.getConnection();
7132  long newObjId = addObject(parentObjId, TskData.ObjectType.FS.getObjectType(), connection);
7133 
7134  // Get the data source object ID
7135  long dataSourceId = getDataSourceObjectId(connection, newObjId);
7136 
7137  // Add a row to tsk_fs_info
7138  // 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)
7139  PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FS_INFO);
7140  preparedStatement.clearParameters();
7141  preparedStatement.setLong(1, newObjId);
7142  preparedStatement.setLong(2, dataSourceId);
7143  preparedStatement.setLong(3, imgOffset);
7144  preparedStatement.setInt(4, type.getValue());
7145  preparedStatement.setLong(5, blockSize);
7146  preparedStatement.setLong(6, blockCount);
7147  preparedStatement.setLong(7, rootInum);
7148  preparedStatement.setLong(8, firstInum);
7149  preparedStatement.setLong(9, lastInum);
7150  preparedStatement.setString(10, displayName);
7151  connection.executeUpdate(preparedStatement);
7152 
7153  // Create the new FileSystem object
7154  return new FileSystem(this, newObjId, displayName, imgOffset, type, blockSize, blockCount, rootInum,
7155  firstInum, lastInum);
7156  } catch (SQLException ex) {
7157  throw new TskCoreException(String.format("Error creating file system with image offset %d and parent ID %d",
7158  imgOffset, parentObjId), ex);
7159  }
7160  }
7161 
7187  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7188  String fileName,
7189  long metaAddr, int metaSeq,
7190  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7191  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7192  long ctime, long crtime, long atime, long mtime,
7193  boolean isFile, Content parent) throws TskCoreException {
7194 
7195  CaseDbTransaction transaction = beginTransaction();
7196  try {
7197 
7198  FsContent fileSystemFile = addFileSystemFile(dataSourceObjId, fsObjId, fileName,
7199  metaAddr, metaSeq, attrType, attrId, dirFlag, metaFlags, size,
7200  ctime, crtime, atime, mtime, null, null, null, isFile, parent,
7201  OsAccount.NO_OWNER_ID, null,
7202  Collections.emptyList(), transaction);
7203 
7204  transaction.commit();
7205  transaction = null;
7206  return fileSystemFile;
7207  } finally {
7208  if (null != transaction) {
7209  try {
7210  transaction.rollback();
7211  } catch (TskCoreException ex2) {
7212  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7213  }
7214  }
7215  }
7216  }
7217 
7255  public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId,
7256  String fileName,
7257  long metaAddr, int metaSeq,
7258  TSK_FS_ATTR_TYPE_ENUM attrType, int attrId,
7259  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size,
7260  long ctime, long crtime, long atime, long mtime,
7261  String md5Hash, String sha256Hash, String mimeType,
7262  boolean isFile, Content parent, String ownerUid,
7263  OsAccount osAccount, List<Attribute> fileAttributes,
7264  CaseDbTransaction transaction) throws TskCoreException {
7265 
7266  TimelineManager timelineManager = getTimelineManager();
7267 
7268  Statement queryStatement = null;
7269  String parentPath = "/";
7270  try {
7271  CaseDbConnection connection = transaction.getConnection();
7272 
7273  // Insert a row for the local/logical file into the tsk_objects table.
7274  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7275  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7276 
7277  if (parent instanceof AbstractFile) {
7278  AbstractFile parentFile = (AbstractFile) parent;
7279  if (isRootDirectory(parentFile, transaction)) {
7280  parentPath = "/";
7281  } else {
7282  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
7283  }
7284  } else {
7285  parentPath = "/";
7286  }
7287 
7288  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE);
7289  statement.clearParameters();
7290  statement.setLong(1, objectId); // obj_is
7291  statement.setLong(2, fsObjId); // fs_obj_id
7292  statement.setLong(3, dataSourceObjId); // data_source_obj_id
7293  statement.setShort(4, (short) attrType.getValue()); // attr_type
7294  statement.setInt(5, attrId); // attr_id
7295  statement.setString(6, fileName); // name
7296  statement.setLong(7, metaAddr); // meta_addr
7297  statement.setInt(8, metaSeq); // meta_addr
7298  statement.setShort(9, TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType()); //type
7299  statement.setShort(10, (short) 1); // has_path
7301  statement.setShort(11, dirType.getValue()); // dir_type
7303  statement.setShort(12, metaType.getValue()); // meta_type
7304  statement.setShort(13, dirFlag.getValue()); // dir_flags
7305  statement.setShort(14, metaFlags); // meta_flags
7306  statement.setLong(15, size < 0 ? 0 : size);
7307  statement.setLong(16, ctime);
7308  statement.setLong(17, crtime);
7309  statement.setLong(18, atime);
7310  statement.setLong(19, mtime);
7311  statement.setString(20, md5Hash);
7312  statement.setString(21, sha256Hash);
7313  statement.setString(22, mimeType);
7314  statement.setString(23, parentPath);
7315  final String extension = extractExtension(fileName);
7316  statement.setString(24, extension);
7317  statement.setString(25, ownerUid);
7318  if (null != osAccount) {
7319  statement.setLong(26, osAccount.getId());
7320  } else {
7321  statement.setNull(26, java.sql.Types.BIGINT); // osAccountObjId
7322  }
7323 
7324  connection.executeUpdate(statement);
7325 
7326  Long osAccountId = (osAccount != null) ? osAccount.getId() : null;
7327  DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7328  size, ctime, crtime, atime, mtime, md5Hash, sha256Hash, null, parentPath, null, parent.getId(), mimeType, null, extension, ownerUid, osAccountId);
7329 
7330  timelineManager.addEventsForNewFile(derivedFile, connection);
7331 
7332  for (Attribute fileAttribute : fileAttributes) {
7333  fileAttribute.setAttributeParentId(objectId);
7334  fileAttribute.setCaseDatabase(this);
7335  addFileAttribute(fileAttribute, connection);
7336  }
7337 
7338  if (osAccount != null) {
7339  osAccountManager.newOsAccountInstance(osAccount.getId(), dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, connection);
7340  }
7341 
7342  return new org.sleuthkit.datamodel.File(this, objectId, dataSourceObjId, fsObjId,
7343  attrType, attrId, fileName, metaAddr, metaSeq,
7344  dirType, metaType, dirFlag, metaFlags,
7345  size, ctime, crtime, atime, mtime,
7346  (short) 0, 0, 0, md5Hash, sha256Hash, null, parentPath, mimeType,
7347  extension, ownerUid, osAccountId, fileAttributes);
7348 
7349  } catch (SQLException ex) {
7350  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);
7351  } finally {
7352  closeStatement(queryStatement);
7353  }
7354  }
7355 
7364  public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException {
7365  CaseDbConnection connection = null;
7366  Statement s = null;
7367  ResultSet rs = null;
7369  try {
7370  connection = connections.getConnection();
7371  s = connection.createStatement();
7372  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE" //NON-NLS
7373  + " type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
7374  + " AND obj_id = data_source_obj_id"
7375  + " ORDER BY dir_type, LOWER(name)"); //NON-NLS
7376  List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>();
7377  while (rs.next()) {
7378  virtDirRootIds.add(virtualDirectory(rs, connection));
7379  }
7380  return virtDirRootIds;
7381  } catch (SQLException ex) {
7382  throw new TskCoreException("Error getting local files virtual folder id", ex);
7383  } finally {
7384  closeResultSet(rs);
7385  closeStatement(s);
7386  closeConnection(connection);
7388  }
7389  }
7390 
7403  public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> fileRanges) throws TskCoreException {
7404  assert (null != fileRanges);
7405  if (null == fileRanges) {
7406  throw new TskCoreException("TskFileRange object is null");
7407  }
7408 
7409  assert (null != parent);
7410  if (null == parent) {
7411  throw new TskCoreException("Conent is null");
7412  }
7413 
7414  CaseDbTransaction transaction = null;
7415  Statement statement = null;
7416  ResultSet resultSet = null;
7417 
7418  try {
7419  transaction = beginTransaction();
7420  CaseDbConnection connection = transaction.getConnection();
7421 
7422  List<LayoutFile> fileRangeLayoutFiles = new ArrayList<LayoutFile>();
7423  for (TskFileRange fileRange : fileRanges) {
7424  /*
7425  * Insert a row for the Tsk file range into the tsk_objects
7426  * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
7427  * ?)
7428  */
7429  long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7430  long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
7431  /*
7432  * Insert a row for the Tsk file range into the tsk_files table:
7433  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7434  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7435  * ctime, crtime, atime, mtime, md5, known, mime_type,
7436  * parent_path, data_source_obj_id,extension, owner_uid,
7437  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7438  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
7439  */
7440  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7441  prepStmt.clearParameters();
7442  prepStmt.setLong(1, fileRangeId); // obj_id from tsk_objects
7443  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7444  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]
7445  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()); // type
7446  prepStmt.setNull(5, java.sql.Types.BIGINT); // has_path
7447  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7448  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7449  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7450  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7451  prepStmt.setLong(10, fileRange.getByteLen()); // size
7452  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7453  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7454  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7455  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7456  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7457  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7458  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7459  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
7460  prepStmt.setNull(19, java.sql.Types.VARCHAR); // parent path
7461  prepStmt.setLong(20, parent.getId()); // data_source_obj_id
7462 
7463  //extension, since this is not a FS file we just set it to null
7464  prepStmt.setString(21, null);
7465 
7466  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7467  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7468 
7469  connection.executeUpdate(prepStmt);
7470 
7471  /*
7472  * Insert a row in the tsk_layout_file table for each chunk of
7473  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7474  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7475  */
7476  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7477  prepStmt.clearParameters();
7478  prepStmt.setLong(1, fileRangeId); // obj_id
7479  prepStmt.setLong(2, fileRange.getByteStart()); // byte_start
7480  prepStmt.setLong(3, fileRange.getByteLen()); // byte_len
7481  prepStmt.setLong(4, fileRange.getSequence()); // sequence
7482  connection.executeUpdate(prepStmt);
7483 
7484  /*
7485  * Create a layout file representation of the carved file.
7486  */
7487  fileRangeLayoutFiles.add(new LayoutFile(this,
7488  fileRangeId,
7489  parent.getId(),
7490  Long.toString(fileRange.getSequence()),
7495  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7496  fileRange.getByteLen(),
7497  0L, 0L, 0L, 0L,
7498  null, null,
7500  parent.getUniquePath(),
7501  null,
7502  OsAccount.NO_OWNER_ID,
7503  OsAccount.NO_ACCOUNT));
7504  }
7505 
7506  transaction.commit();
7507  transaction = null;
7508  return fileRangeLayoutFiles;
7509 
7510  } catch (SQLException ex) {
7511  throw new TskCoreException("Failed to add layout files to case database", ex);
7512  } finally {
7513  closeResultSet(resultSet);
7514  closeStatement(statement);
7515 
7516  if (null != transaction) {
7517  try {
7518  transaction.rollback();
7519  } catch (TskCoreException ex2) {
7520  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7521  }
7522  }
7523  }
7524  }
7525 
7537  public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException {
7538  assert (null != carvingResult);
7539  if (null == carvingResult) {
7540  throw new TskCoreException("Carving is null");
7541  }
7542  assert (null != carvingResult.getParent());
7543  if (null == carvingResult.getParent()) {
7544  throw new TskCoreException("Carving result has null parent");
7545  }
7546  assert (null != carvingResult.getCarvedFiles());
7547  if (null == carvingResult.getCarvedFiles()) {
7548  throw new TskCoreException("Carving result has null carved files");
7549  }
7550  CaseDbTransaction transaction = null;
7551  Statement statement = null;
7552  ResultSet resultSet = null;
7553  try {
7554 
7555  /*
7556  * Carved files are "re-parented" as children of the $CarvedFiles
7557  * virtual directory of the root file system, volume, or image
7558  * ancestor of the carved files parent, but if no such ancestor is
7559  * found, then the parent specified in the carving result is used.
7560  */
7561  Content root = carvingResult.getParent();
7562  while (null != root) {
7563  if (root instanceof FileSystem || root instanceof Volume || root instanceof Image) {
7564  break;
7565  }
7566  root = root.getParent();
7567  }
7568  if (null == root) {
7569  root = carvingResult.getParent();
7570  }
7571 
7572  /*
7573  * Get or create the $CarvedFiles virtual directory for the root
7574  * ancestor.
7575  */
7576  VirtualDirectory carvedFilesDir;
7577  synchronized (carvedFileDirsLock) {
7578  carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId());
7579  if (null == carvedFilesDir) {
7580  List<Content> rootChildren;
7581  if (root instanceof FileSystem) {
7582  rootChildren = ((FileSystem) root).getRootDirectory().getChildren();
7583  } else {
7584  rootChildren = root.getChildren();
7585  }
7586  for (Content child : rootChildren) {
7587  if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) {
7588  carvedFilesDir = (VirtualDirectory) child;
7589  break;
7590  }
7591  }
7592  if (null == carvedFilesDir) {
7593  long parId = root.getId();
7594  // $CarvedFiles should be a child of the root directory, not the file system
7595  if (root instanceof FileSystem) {
7596  Content rootDir = ((FileSystem) root).getRootDirectory();
7597  parId = rootDir.getId();
7598  }
7599  carvedFilesDir = addVirtualDirectory(parId, VirtualDirectory.NAME_CARVED);
7600  }
7601  rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDir);
7602  }
7603  }
7604 
7605  /*
7606  * Add the carved files to the database as children of the
7607  * $CarvedFile directory of the root ancestor.
7608  */
7609  transaction = beginTransaction();
7610  CaseDbConnection connection = transaction.getConnection();
7611  String parentPath = getFileParentPath(carvedFilesDir.getId(), connection) + carvedFilesDir.getName() + "/";
7612  List<LayoutFile> carvedFiles = new ArrayList<>();
7613  for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) {
7614  /*
7615  * Insert a row for the carved file into the tsk_objects table:
7616  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7617  */
7618  long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7619 
7620  /*
7621  * Insert a row for the carved file into the tsk_files table:
7622  * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type,
7623  * has_path, dir_type, meta_type, dir_flags, meta_flags, size,
7624  * ctime, crtime, atime, mtime, md5, known, mime_type,
7625  * parent_path, data_source_obj_id,extenion, owner_uid,
7626  * os_account_obj_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
7627  * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7628  */
7629  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7630  prepStmt.clearParameters();
7631  prepStmt.setLong(1, carvedFileId); // obj_id
7632  if (root instanceof FileSystem) {
7633  prepStmt.setLong(2, root.getId()); // fs_obj_id
7634  } else {
7635  prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id
7636  }
7637  prepStmt.setString(3, carvedFile.getName()); // name
7638  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); // type
7639  prepStmt.setShort(5, (short) 1); // has_path
7640  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
7641  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
7642  prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); // dir_flags
7643  prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); // nmeta_flags
7644  prepStmt.setLong(10, carvedFile.getSizeInBytes()); // size
7645  prepStmt.setNull(11, java.sql.Types.BIGINT); // ctime
7646  prepStmt.setNull(12, java.sql.Types.BIGINT); // crtime
7647  prepStmt.setNull(13, java.sql.Types.BIGINT); // atime
7648  prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime
7649  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
7650  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7651  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7652  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
7653  prepStmt.setString(19, parentPath); // parent path
7654  prepStmt.setLong(20, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id
7655  prepStmt.setString(21, extractExtension(carvedFile.getName())); //extension
7656 
7657  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7658  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7659 
7660  connection.executeUpdate(prepStmt);
7661 
7662  /*
7663  * Insert a row in the tsk_layout_file table for each chunk of
7664  * the carved file. INSERT INTO tsk_file_layout (obj_id,
7665  * byte_start, byte_len, sequence) VALUES (?, ?, ?, ?)
7666  */
7667  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
7668  for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) {
7669  prepStmt.clearParameters();
7670  prepStmt.setLong(1, carvedFileId); // obj_id
7671  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
7672  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
7673  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
7674  connection.executeUpdate(prepStmt);
7675  }
7676 
7677  /*
7678  * Create a layout file representation of the carved file.
7679  */
7680  carvedFiles.add(new LayoutFile(this,
7681  carvedFileId,
7682  carvedFilesDir.getDataSourceObjectId(),
7683  carvedFile.getName(),
7688  TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
7689  carvedFile.getSizeInBytes(),
7690  0L, 0L, 0L, 0L,
7691  null, null,
7693  parentPath,
7694  null,
7695  OsAccount.NO_OWNER_ID,
7696  OsAccount.NO_ACCOUNT));
7697  }
7698 
7699  transaction.commit();
7700  transaction = null;
7701  return carvedFiles;
7702 
7703  } catch (SQLException ex) {
7704  throw new TskCoreException("Failed to add carved files to case database", ex);
7705  } finally {
7706  closeResultSet(resultSet);
7707  closeStatement(statement);
7708 
7709  if (null != transaction) {
7710  try {
7711  transaction.rollback();
7712  } catch (TskCoreException ex2) {
7713  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
7714  }
7715  }
7716  }
7717  }
7718 
7749  public DerivedFile addDerivedFile(String fileName, String localPath,
7750  long size, long ctime, long crtime, long atime, long mtime,
7751  boolean isFile, Content parentObj,
7752  String rederiveDetails, String toolName, String toolVersion,
7753  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7754  CaseDbTransaction transaction = beginTransaction();
7755  try {
7756  DerivedFile df = addDerivedFile(fileName, localPath,
7757  size, ctime, crtime, atime, mtime,
7758  isFile, parentObj,
7759  rederiveDetails, toolName, toolVersion,
7760  otherDetails, encodingType, transaction);
7761  transaction.commit();
7762  return df;
7763  } catch (TskCoreException ex) {
7764  transaction.rollback();
7765  throw ex;
7766  }
7767  }
7768 
7769  public DerivedFile addDerivedFile(String fileName, String localPath,
7770  long size, long ctime, long crtime, long atime, long mtime,
7771  boolean isFile, Content parentObj,
7772  String rederiveDetails, String toolName, String toolVersion,
7773  String otherDetails, TskData.EncodingType encodingType, CaseDbTransaction transaction) throws TskCoreException {
7774  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7775  localPath = localPath.replaceAll("^[/\\\\]+", "");
7776 
7777  TimelineManager timelineManager = getTimelineManager();
7778 
7779  CaseDbConnection connection = transaction.getConnection();
7780  try {
7781  final long parentId = parentObj.getId();
7782  String parentPath = "";
7783  if (parentObj instanceof BlackboardArtifact) {
7784  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7785  } else if (parentObj instanceof AbstractFile) {
7786  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7787  }
7788 
7789  // Insert a row for the derived file into the tsk_objects table.
7790  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
7791  long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
7792 
7793  // Insert a row for the virtual directory into the tsk_files table.
7794  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
7795  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
7796  // parent_path, data_source_obj_id, extension)
7797  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
7798  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
7799  statement.clearParameters();
7800  statement.setLong(1, newObjId);
7801 
7802  // If the parentFile is part of a file system, use its file system object ID.
7803  long fsObjId = this.getFileSystemId(parentId, connection);
7804  if (fsObjId != -1) {
7805  statement.setLong(2, fsObjId);
7806  } else {
7807  statement.setNull(2, java.sql.Types.BIGINT);
7808  }
7809  statement.setString(3, fileName);
7810 
7811  //type, has_path
7812  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7813  statement.setShort(5, (short) 1);
7814 
7815  //flags
7817  statement.setShort(6, dirType.getValue());
7819  statement.setShort(7, metaType.getValue());
7820 
7821  //note: using alloc under assumption that derived files derive from alloc files
7823  statement.setShort(8, dirFlag.getValue());
7824  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7825  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7826  statement.setShort(9, metaFlags);
7827 
7828  //size
7829  //prevent negative size
7830  long savedSize = size < 0 ? 0 : size;
7831  statement.setLong(10, savedSize);
7832 
7833  //mactimes
7834  //long ctime, long crtime, long atime, long mtime,
7835  statement.setLong(11, ctime);
7836  statement.setLong(12, crtime);
7837  statement.setLong(13, atime);
7838  statement.setLong(14, mtime);
7839 
7840  statement.setNull(15, java.sql.Types.VARCHAR); // MD5
7841  statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256
7842  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
7843  statement.setNull(18, java.sql.Types.VARCHAR); // MIME type
7844 
7845  //parent path
7846  statement.setString(19, parentPath);
7847 
7848  // root data source object id
7849  long dataSourceObjId = getDataSourceObjectId(connection, parentObj);
7850  statement.setLong(20, dataSourceObjId);
7851  final String extension = extractExtension(fileName);
7852  //extension
7853  statement.setString(21, extension);
7854 
7855  statement.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
7856  statement.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
7857 
7858  connection.executeUpdate(statement);
7859 
7860  //add localPath
7861  addFilePath(connection, newObjId, localPath, encodingType);
7862 
7863  DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags,
7864  savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, OsAccount.NO_OWNER_ID, OsAccount.NO_ACCOUNT);
7865 
7866  timelineManager.addEventsForNewFile(derivedFile, connection);
7867 
7868  //TODO add derived method to tsk_files_derived and tsk_files_derived_method
7869  return derivedFile;
7870  } catch (SQLException ex) {
7871  throw new TskCoreException("Failed to add derived file to case database", ex);
7872  }
7873  }
7874 
7905  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7906  long size, long ctime, long crtime, long atime, long mtime,
7907  boolean isFile, String mimeType,
7908  String rederiveDetails, String toolName, String toolVersion,
7909  String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
7910 
7911  CaseDbTransaction trans = null;
7912  try {
7913  Content parentObj = derivedFile.getParent();
7914 
7915  trans = beginTransaction();
7916  DerivedFile updatedFile = updateDerivedFile(derivedFile, localPath,
7917  size, ctime, crtime, atime, mtime,
7918  isFile, mimeType,
7919  rederiveDetails, toolName, toolVersion,
7920  otherDetails, encodingType, parentObj, trans);
7921  trans.commit();
7922  return updatedFile;
7923  } catch (TskCoreException ex) {
7924  if (trans != null) {
7925  trans.rollback();
7926  }
7927  throw ex;
7928  }
7929  }
7930 
7931  public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath,
7932  long size, long ctime, long crtime, long atime, long mtime,
7933  boolean isFile, String mimeType,
7934  String rederiveDetails, String toolName, String toolVersion,
7935  String otherDetails, TskData.EncodingType encodingType,
7936  Content parentObj, CaseDbTransaction trans) throws TskCoreException {
7937 
7938  // Strip off any leading slashes from the local path (leading slashes indicate absolute paths)
7939  localPath = localPath.replaceAll("^[/\\\\]+", "");
7940 
7941  ResultSet rs = null;
7942  try {
7943  final long parentId = parentObj.getId();
7944  String parentPath = "";
7945  if (parentObj instanceof BlackboardArtifact) {
7946  parentPath = parentObj.getUniquePath() + '/' + parentObj.getName() + '/';
7947  } else if (parentObj instanceof AbstractFile) {
7948  parentPath = ((AbstractFile) parentObj).getParentPath() + parentObj.getName() + '/'; //NON-NLS
7949  }
7950  // UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, "
7951  // + "size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? WHERE obj_id = ?"), //NON-NLS
7952  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.UPDATE_DERIVED_FILE);
7953  statement.clearParameters();
7954 
7955  //type
7956  statement.setShort(1, TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType());
7957 
7958  //flags
7960  statement.setShort(2, dirType.getValue());
7962  statement.setShort(3, metaType.getValue());
7963 
7964  //note: using alloc under assumption that derived files derive from alloc files
7966  statement.setShort(4, dirFlag.getValue());
7967  final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue()
7968  | TSK_FS_META_FLAG_ENUM.USED.getValue());
7969  statement.setShort(5, metaFlags);
7970 
7971  //size
7972  //prevent negative size
7973  long savedSize = size < 0 ? 0 : size;
7974  statement.setLong(6, savedSize);
7975 
7976  //mactimes
7977  //long ctime, long crtime, long atime, long mtime,
7978  statement.setLong(7, ctime);
7979  statement.setLong(8, crtime);
7980  statement.setLong(9, atime);
7981  statement.setLong(10, mtime);
7982  statement.setString(11, mimeType);
7983  statement.setString(12, String.valueOf(derivedFile.getId()));
7984  trans.getConnection().executeUpdate(statement);
7985 
7986  //add localPath
7987  updateFilePath(trans.getConnection(), derivedFile.getId(), localPath, encodingType);
7988 
7989  long dataSourceObjId = getDataSourceObjectId(trans.getConnection(), parentObj);
7990  final String extension = extractExtension(derivedFile.getName());
7991  return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags,
7992  savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension, derivedFile.getOwnerUid().orElse(null), derivedFile.getOsAccountObjectId().orElse(null));
7993  } catch (SQLException ex) {
7994  throw new TskCoreException("Failed to add derived file to case database", ex);
7995  } finally {
7996  closeResultSet(rs);
7997  }
7998  }
7999 
8019  public LocalFile addLocalFile(String fileName, String localPath,
8020  long size, long ctime, long crtime, long atime, long mtime,
8021  boolean isFile, TskData.EncodingType encodingType,
8022  AbstractFile parent) throws TskCoreException {
8023 
8024  CaseDbTransaction localTrans = beginTransaction();
8025  try {
8026  LocalFile created = addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, encodingType, parent, localTrans);
8027  localTrans.commit();
8028  localTrans = null;
8029  return created;
8030  } finally {
8031  if (null != localTrans) {
8032  try {
8033  localTrans.rollback();
8034  } catch (TskCoreException ex2) {
8035  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8036  }
8037  }
8038  }
8039  }
8040 
8065  public LocalFile addLocalFile(String fileName, String localPath,
8066  long size, long ctime, long crtime, long atime, long mtime,
8067  boolean isFile, TskData.EncodingType encodingType,
8068  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8069 
8070  return addLocalFile(fileName, localPath,
8071  size, ctime, crtime, atime, mtime,
8072  null, null, null,
8073  isFile, encodingType,
8074  parent, transaction);
8075  }
8076 
8105  public LocalFile addLocalFile(String fileName, String localPath,
8106  long size, long ctime, long crtime, long atime, long mtime,
8107  String md5, String sha256, FileKnown known, String mimeType,
8108  boolean isFile, TskData.EncodingType encodingType,
8109  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8110 
8111  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
8112  md5, sha256, known, mimeType, isFile, encodingType,
8113  OsAccount.NO_ACCOUNT, OsAccount.NO_OWNER_ID, parent, transaction);
8114 
8115  }
8116 
8147  public LocalFile addLocalFile(String fileName, String localPath,
8148  long size, long ctime, long crtime, long atime, long mtime,
8149  String md5, String sha256, FileKnown known, String mimeType,
8150  boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount,
8151  Content parent, CaseDbTransaction transaction) throws TskCoreException {
8152  CaseDbConnection connection = transaction.getConnection();
8153  Statement queryStatement = null;
8154  try {
8155 
8156  // Insert a row for the local/logical file into the tsk_objects table.
8157  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8158  long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8159 
8160  // Insert a row for the local/logical file into the tsk_files table.
8161  // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
8162  // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type,
8163  // parent_path, data_source_obj_id,extension, uid_str, os_account_obj_id)
8164  // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?)
8165  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8166  statement.clearParameters();
8167  statement.setLong(1, objectId);
8168  statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
8169  statement.setString(3, fileName);
8170  statement.setShort(4, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType());
8171  statement.setShort(5, (short) 1);
8173  statement.setShort(6, dirType.getValue());
8175  statement.setShort(7, metaType.getValue());
8177  statement.setShort(8, dirFlag.getValue());
8178  short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue());
8179  statement.setShort(9, metaFlags);
8180  //prevent negative size
8181  long savedSize = size < 0 ? 0 : size;
8182  statement.setLong(10, savedSize);
8183  statement.setLong(11, ctime);
8184  statement.setLong(12, crtime);
8185  statement.setLong(13, atime);
8186  statement.setLong(14, mtime);
8187  statement.setString(15, md5);
8188  statement.setString(16, sha256);
8189  if (known != null) {
8190  statement.setByte(17, known.getFileKnownValue());
8191  } else {
8192  statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue());
8193  }
8194  statement.setString(18, mimeType);
8195  String parentPath;
8196  long dataSourceObjId;
8197 
8198  if (parent instanceof AbstractFile) {
8199  AbstractFile parentFile = (AbstractFile) parent;
8200  if (isRootDirectory(parentFile, transaction)) {
8201  parentPath = "/";
8202  } else {
8203  parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS
8204  }
8205  dataSourceObjId = parentFile.getDataSourceObjectId();
8206  } else {
8207  parentPath = "/";
8208  dataSourceObjId = getDataSourceObjectId(connection, parent);
8209  }
8210  statement.setString(19, parentPath);
8211  statement.setLong(20, dataSourceObjId);
8212  final String extension = extractExtension(fileName);
8213  statement.setString(21, extension);
8214 
8215  if (ownerAccount != null) {
8216  statement.setString(22, ownerAccount); // ownerUid
8217  } else {
8218  statement.setNull(22, java.sql.Types.VARCHAR);
8219  }
8220 
8221  if (osAccountId != null) {
8222  statement.setLong(23, osAccountId); // osAccountObjId
8223  } else {
8224  statement.setNull(23, java.sql.Types.BIGINT);
8225  }
8226 
8227  connection.executeUpdate(statement);
8228  addFilePath(connection, objectId, localPath, encodingType);
8229  LocalFile localFile = new LocalFile(this,
8230  objectId,
8231  fileName,
8233  dirType,
8234  metaType,
8235  dirFlag,
8236  metaFlags,
8237  savedSize,
8238  ctime, crtime, atime, mtime,
8239  mimeType, md5, sha256, known,
8240  parent.getId(), parentPath,
8241  dataSourceObjId,
8242  localPath,
8243  encodingType, extension,
8244  ownerAccount, osAccountId);
8245  getTimelineManager().addEventsForNewFile(localFile, connection);
8246  return localFile;
8247 
8248  } catch (SQLException ex) {
8249  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);
8250  } finally {
8251  closeStatement(queryStatement);
8252  }
8253  }
8254 
8260  private class RootDirectoryKey {
8261 
8262  private long dataSourceId;
8263  private Long fileSystemId;
8264 
8265  RootDirectoryKey(long dataSourceId, Long fileSystemId) {
8266  this.dataSourceId = dataSourceId;
8267  this.fileSystemId = fileSystemId;
8268  }
8269 
8270  @Override
8271  public int hashCode() {
8272  int hash = 7;
8273  hash = 41 * hash + Objects.hashCode(dataSourceId);
8274  hash = 41 * hash + Objects.hashCode(fileSystemId);
8275  return hash;
8276  }
8277 
8278  @Override
8279  public boolean equals(Object obj) {
8280  if (this == obj) {
8281  return true;
8282  }
8283  if (obj == null) {
8284  return false;
8285  }
8286  if (getClass() != obj.getClass()) {
8287  return false;
8288  }
8289 
8290  RootDirectoryKey otherKey = (RootDirectoryKey) obj;
8291  if (dataSourceId != otherKey.dataSourceId) {
8292  return false;
8293  }
8294 
8295  if (fileSystemId != null) {
8296  return fileSystemId.equals(otherKey.fileSystemId);
8297  }
8298  return (otherKey.fileSystemId == null);
8299  }
8300  }
8301 
8314  private boolean isRootDirectory(AbstractFile file, CaseDbTransaction transaction) throws TskCoreException {
8315 
8316  // First check if we know the root directory for this data source and optionally
8317  // file system. There is only one root, so if we know it we can simply compare
8318  // this file ID to the known root directory.
8319  Long fsObjId = null;
8320  if (file instanceof FsContent) {
8321  fsObjId = ((FsContent) file).getFileSystemId();
8322  }
8323  RootDirectoryKey key = new RootDirectoryKey(file.getDataSourceObjectId(), fsObjId);
8324  synchronized (rootDirectoryMapLock) {
8325  if (rootDirectoryMap.containsKey(key)) {
8326  return rootDirectoryMap.get(key).equals(file.getId());
8327  }
8328  }
8329 
8330  // Fallback cache. We store the result of each database lookup
8331  // so it won't be done multiple times in a row. In practice, this will
8332  // only be used if this method was never called on the root directory.
8333  Boolean isRoot = isRootDirectoryCache.getIfPresent(file.getId());
8334  if (isRoot != null) {
8335  return isRoot;
8336  }
8337 
8338  CaseDbConnection connection = transaction.getConnection();
8339  Statement statement = null;
8340  ResultSet resultSet = null;
8341 
8342  try {
8343  String query = String.format("SELECT ParentRow.type AS parent_type, ParentRow.obj_id AS parent_object_id "
8344  + "FROM tsk_objects ParentRow JOIN tsk_objects ChildRow ON ChildRow.par_obj_id = ParentRow.obj_id "
8345  + "WHERE ChildRow.obj_id = %s;", file.getId());
8346 
8347  statement = connection.createStatement();
8348  resultSet = statement.executeQuery(query);
8349  if (resultSet.next()) {
8350  long parentId = resultSet.getLong("parent_object_id");
8351  if (parentId == 0) {
8352  return true;
8353  }
8354  int type = resultSet.getInt("parent_type");
8355  boolean result = type == TskData.ObjectType.IMG.getObjectType()
8356  || type == TskData.ObjectType.VS.getObjectType()
8357  || type == TskData.ObjectType.VOL.getObjectType()
8358  || type == TskData.ObjectType.FS.getObjectType();
8359  if (result == true) {
8360  synchronized (rootDirectoryMapLock) {
8361  // This is a root directory so save it
8362  rootDirectoryMap.put(key, file.getId());
8363  }
8364  }
8365  isRootDirectoryCache.put(file.getId(), result);
8366  return result;
8367 
8368  } else {
8369  // This is a root directory so save it
8370  synchronized (rootDirectoryMapLock) {
8371  rootDirectoryMap.put(key, file.getId());
8372  }
8373  isRootDirectoryCache.put(file.getId(), true);
8374 
8375  return true; // The file has no parent
8376 
8377  }
8378  } catch (SQLException ex) {
8379  throw new TskCoreException(String.format("Failed to lookup parent of file (%s) with id %d", file.getName(), file.getId()), ex);
8380  } finally {
8381  closeResultSet(resultSet);
8382  closeStatement(statement);
8383  }
8384  }
8385 
8405  public LayoutFile addLayoutFile(String fileName,
8406  long size,
8407  TSK_FS_NAME_FLAG_ENUM dirFlag, TSK_FS_META_FLAG_ENUM metaFlag,
8408  long ctime, long crtime, long atime, long mtime,
8409  List<TskFileRange> fileRanges,
8410  Content parent) throws TskCoreException {
8411 
8412  if (null == parent) {
8413  throw new TskCoreException("Parent can not be null");
8414  }
8415 
8416  String parentPath;
8417  if (parent instanceof AbstractFile) {
8418  parentPath = ((AbstractFile) parent).getParentPath() + parent.getName() + '/'; //NON-NLS
8419  } else {
8420  parentPath = "/";
8421  }
8422 
8423  CaseDbTransaction transaction = null;
8424  Statement statement = null;
8425  ResultSet resultSet = null;
8426  try {
8427  transaction = beginTransaction();
8428  CaseDbConnection connection = transaction.getConnection();
8429 
8430  /*
8431  * Insert a row for the layout file into the tsk_objects table:
8432  * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
8433  */
8434  long newFileId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
8435 
8436  /*
8437  * Insert a row for the file into the tsk_files table: INSERT INTO
8438  * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type,
8439  * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime,
8440  * mtime, md5, known, mime_type, parent_path,
8441  * data_source_obj_id,extenion, owner_uid, os_account_obj_id) VALUES
8442  * (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8443  */
8444  PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
8445  prepStmt.clearParameters();
8446  prepStmt.setLong(1, newFileId); // obj_id
8447 
8448  // If the parent is part of a file system, grab its file system ID
8449  if (0 != parent.getId()) {
8450  long parentFs = this.getFileSystemId(parent.getId(), connection);
8451  if (parentFs != -1) {
8452  prepStmt.setLong(2, parentFs);
8453  } else {
8454  prepStmt.setNull(2, java.sql.Types.BIGINT);
8455  }
8456  } else {
8457  prepStmt.setNull(2, java.sql.Types.BIGINT);
8458  }
8459  prepStmt.setString(3, fileName); // name
8460  prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()); // type
8461  prepStmt.setShort(5, (short) 0); // has_path
8462  prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); // dir_type
8463  prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); // meta_type
8464  prepStmt.setShort(8, dirFlag.getValue()); // dir_flags
8465  prepStmt.setShort(9, metaFlag.getValue()); // meta_flags
8466  //prevent negative size
8467  long savedSize = size < 0 ? 0 : size;
8468  prepStmt.setLong(10, savedSize); // size
8469  prepStmt.setLong(11, ctime); // ctime
8470  prepStmt.setLong(12, crtime); // crtime
8471  prepStmt.setLong(13, atime); // atime
8472  prepStmt.setLong(14, mtime); // mtime
8473  prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5
8474  prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256
8475  prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known
8476  prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type
8477  prepStmt.setString(19, parentPath); // parent path
8478  prepStmt.setLong(20, parent.getDataSource().getId()); // data_source_obj_id
8479 
8480  prepStmt.setString(21, extractExtension(fileName)); //extension
8481 
8482  prepStmt.setString(22, OsAccount.NO_OWNER_ID); // ownerUid
8483  prepStmt.setNull(23, java.sql.Types.BIGINT); // osAccountObjId
8484 
8485  connection.executeUpdate(prepStmt);
8486 
8487  /*
8488  * Insert a row in the tsk_layout_file table for each chunk of the
8489  * carved file. INSERT INTO tsk_file_layout (obj_id, byte_start,
8490  * byte_len, sequence) VALUES (?, ?, ?, ?)
8491  */
8492  prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
8493  for (TskFileRange tskFileRange : fileRanges) {
8494  prepStmt.clearParameters();
8495  prepStmt.setLong(1, newFileId); // obj_id
8496  prepStmt.setLong(2, tskFileRange.getByteStart()); // byte_start
8497  prepStmt.setLong(3, tskFileRange.getByteLen()); // byte_len
8498  prepStmt.setLong(4, tskFileRange.getSequence()); // sequence
8499  connection.executeUpdate(prepStmt);
8500  }
8501 
8502  /*
8503  * Create a layout file representation of the carved file.
8504  */
8505  LayoutFile layoutFile = new LayoutFile(this,
8506  newFileId,
8507  parent.getDataSource().getId(),
8508  fileName,
8512  dirFlag,
8513  metaFlag.getValue(),
8514  savedSize,
8515  ctime, crtime, atime, mtime,
8516  null, null,
8518  parentPath,
8519  null,
8520  OsAccount.NO_OWNER_ID,
8521  OsAccount.NO_ACCOUNT);
8522 
8523  transaction.commit();
8524  transaction = null;
8525  return layoutFile;
8526 
8527  } catch (SQLException ex) {
8528  throw new TskCoreException("Failed to add layout file " + fileName + " to case database", ex);
8529  } finally {
8530  closeResultSet(resultSet);
8531  closeStatement(statement);
8532 
8533  if (null != transaction) {
8534  try {
8535  transaction.rollback();
8536  } catch (TskCoreException ex2) {
8537  logger.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
8538  }
8539  }
8540  }
8541  }
8542 
8552  private long getDataSourceObjectId(CaseDbConnection connection, Content content) throws TskCoreException {
8553  if (content == null) {
8554  throw new TskCoreException("Null Content parameter given");
8555  }
8556  if (content instanceof AbstractFile) {
8557  return ((AbstractFile) content).getDataSourceObjectId();
8558  } else {
8559  return getDataSourceObjectId(connection, content.getId());
8560  }
8561  }
8562 
8575  private long getDataSourceObjectId(CaseDbConnection connection, long objectId) throws TskCoreException {
8577  Statement statement = null;
8578  ResultSet resultSet = null;
8579  try {
8580  statement = connection.createStatement();
8581  long dataSourceObjId;
8582  long ancestorId = objectId;
8583  do {
8584  dataSourceObjId = ancestorId;
8585  String query = String.format("SELECT par_obj_id FROM tsk_objects WHERE obj_id = %s;", ancestorId);
8586  resultSet = statement.executeQuery(query);
8587  if (resultSet.next()) {
8588  ancestorId = resultSet.getLong("par_obj_id");
8589  } else {
8590  throw new TskCoreException(String.format("tsk_objects table is corrupt, SQL query returned no result: %s", query));
8591  }
8592  resultSet.close();
8593  resultSet = null;
8594  } while (0 != ancestorId); // Not NULL
8595  return dataSourceObjId;
8596  } catch (SQLException ex) {
8597  throw new TskCoreException(String.format("Error finding root data source for object (obj_id = %d)", objectId), ex);
8598  } finally {
8599  closeResultSet(resultSet);
8600  closeStatement(statement);
8602  }
8603  }
8604 
8616  private void addFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8617  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LOCAL_PATH);
8618  statement.clearParameters();
8619  statement.setLong(1, objId);
8620  statement.setString(2, path);
8621  statement.setInt(3, type.getType());
8622  connection.executeUpdate(statement);
8623  }
8624 
8636  private void updateFilePath(CaseDbConnection connection, long objId, String path, TskData.EncodingType type) throws SQLException {
8637  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_LOCAL_PATH);
8638  statement.clearParameters();
8639  statement.setString(1, path);
8640  statement.setInt(2, type.getType());
8641  statement.setLong(3, objId);
8642  connection.executeUpdate(statement);
8643  }
8644 
8658  public List<AbstractFile> findFilesInFolder(String fileName, AbstractFile parentFile) throws TskCoreException {
8659  String ext = "";
8660  if (!containsLikeWildcard(fileName)) {
8661  ext = SleuthkitCase.extractExtension(fileName);
8662  }
8663 
8664  CaseDbConnection connection = null;
8665  ResultSet rs = null;
8666  long parentId = parentFile.getId();
8667 
8669  try {
8670  connection = connections.getConnection();
8671 
8672  PreparedStatement statement;
8673  if (ext.isEmpty()) {
8674  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_PARENT_AND_NAME);
8675  statement.clearParameters();
8676  statement.setLong(1, parentId);
8677  statement.setString(2, fileName);
8678  } else {
8679  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME);
8680  statement.clearParameters();
8681  statement.setString(1, ext);
8682  statement.setLong(2, parentId);
8683  statement.setString(3, fileName);
8684  }
8685 
8686  rs = connection.executeQuery(statement);
8687  return resultSetToAbstractFiles(rs, connection);
8688  } catch (SQLException ex) {
8689  throw new TskCoreException("Error getting AbstractFile children with name=" + fileName + " for Content parent with ID=" + parentFile.getId(), ex);
8690  } finally {
8691  closeResultSet(rs);
8692  closeConnection(connection);
8694  }
8695  }
8696 
8708  public long countFilesWhere(String sqlWhereClause) throws TskCoreException {
8709  CaseDbConnection connection = null;
8710  Statement s = null;
8711  ResultSet rs = null;
8713  try {
8714  connection = connections.getConnection();
8715  s = connection.createStatement();
8716  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8717  rs.next();
8718  return rs.getLong("count");
8719  } catch (SQLException e) {
8720  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.countFilesWhere().", e);
8721  } finally {
8722  closeResultSet(rs);
8723  closeStatement(s);
8724  closeConnection(connection);
8726  }
8727  }
8728 
8746  public List<AbstractFile> findAllFilesWhere(String sqlWhereClause) throws TskCoreException {
8747  CaseDbConnection connection = null;
8748  Statement s = null;
8749  ResultSet rs = null;
8751  try {
8752  connection = connections.getConnection();
8753  s = connection.createStatement();
8754  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8755  return resultSetToAbstractFiles(rs, connection);
8756  } catch (SQLException e) {
8757  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesWhere(): " + sqlWhereClause, e);
8758  } finally {
8759  closeResultSet(rs);
8760  closeStatement(s);
8761  closeConnection(connection);
8763  }
8764  }
8765 
8784  public List<AbstractFile> findAllFilesInFolderWhere(long parentId, String sqlWhereClause) throws TskCoreException {
8785  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";
8787  try (CaseDbConnection connection = connections.getConnection()) {
8788  String query = String.format(queryTemplate, parentId, sqlWhereClause);
8789  try (Statement s = connection.createStatement(); ResultSet rs = connection.executeQuery(s, query)) {
8790  return resultSetToAbstractFiles(rs, connection);
8791  } catch (SQLException ex) {
8792  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFilesInFolderWhere(): " + query, ex);
8793  }
8794  } finally {
8796  }
8797  }
8798 
8811  public List<Long> findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException {
8812  CaseDbConnection connection = null;
8813  Statement s = null;
8814  ResultSet rs = null;
8816  try {
8817  connection = connections.getConnection();
8818  s = connection.createStatement();
8819  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
8820  List<Long> ret = new ArrayList<>();
8821  while (rs.next()) {
8822  ret.add(rs.getLong("obj_id"));
8823  }
8824  return ret;
8825  } catch (SQLException e) {
8826  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findAllFileIdsWhere(): " + sqlWhereClause, e);
8827  } finally {
8828  closeResultSet(rs);
8829  closeStatement(s);
8830  closeConnection(connection);
8832  }
8833  }
8834 
8846  public List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
8847 
8848  // get the non-unique path (strip of image and volume path segments, if
8849  // the exist.
8850  String path = AbstractFile.createNonUniquePath(filePath).toLowerCase();
8851 
8852  // split the file name from the parent path
8853  int lastSlash = path.lastIndexOf('/'); //NON-NLS
8854 
8855  // if the last slash is at the end, strip it off
8856  if (lastSlash == path.length()) {
8857  path = path.substring(0, lastSlash - 1);
8858  lastSlash = path.lastIndexOf('/'); //NON-NLS
8859  }
8860 
8861  String parentPath = path.substring(0, lastSlash);
8862  String fileName = path.substring(lastSlash);
8863 
8864  return findFiles(dataSource, fileName, parentPath);
8865  }
8866 
8877  public List<TskFileRange> getFileRanges(long id) throws TskCoreException {
8878  CaseDbConnection connection = null;
8879  Statement s = null;
8880  ResultSet rs = null;
8882  try {
8883  connection = connections.getConnection();
8884  s = connection.createStatement();
8885  rs = connection.executeQuery(s, "SELECT * FROM tsk_file_layout WHERE obj_id = " + id + " ORDER BY sequence");
8886  List<TskFileRange> ranges = new ArrayList<TskFileRange>();
8887  while (rs.next()) {
8888  TskFileRange range = new TskFileRange(rs.getLong("byte_start"), //NON-NLS
8889  rs.getLong("byte_len"), rs.getLong("sequence")); //NON-NLS
8890  ranges.add(range);
8891  }
8892  return ranges;
8893  } catch (SQLException ex) {
8894  throw new TskCoreException("Error getting TskFileLayoutRanges by id, id = " + id, ex);
8895  } finally {
8896  closeResultSet(rs);
8897  closeStatement(s);
8898  closeConnection(connection);
8900  }
8901  }
8902 
8913  public Image getImageById(long id) throws TskCoreException {
8914  CaseDbConnection connection = null;
8915  Statement s = null;
8916  ResultSet rs = null;
8918  try {
8919  connection = connections.getConnection();
8920  s = connection.createStatement();
8921  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 "
8922  + "FROM tsk_image_info "
8923  + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id "
8924  + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id "
8925  + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS
8926 
8927  List<String> imagePaths = new ArrayList<>();
8928  long type, ssize, size;
8929  String tzone, md5, sha1, sha256, name, device_id, imagePath;
8930 
8931  if (rs.next()) {
8932  imagePath = rs.getString("name");
8933  if (imagePath != null) {
8934  imagePaths.add(imagePath);
8935  }
8936  type = rs.getLong("type"); //NON-NLS
8937  ssize = rs.getLong("ssize"); //NON-NLS
8938  tzone = rs.getString("tzone"); //NON-NLS
8939  size = rs.getLong("size"); //NON-NLS
8940  md5 = rs.getString("md5"); //NON-NLS
8941  sha1 = rs.getString("sha1"); //NON-NLS
8942  sha256 = rs.getString("sha256"); //NON-NLS
8943  name = rs.getString("display_name");
8944  if (name == null) {
8945  if (imagePaths.size() > 0) {
8946  String path = imagePaths.get(0);
8947  name = (new java.io.File(path)).getName();
8948  } else {
8949  name = "";
8950  }
8951  }
8952  device_id = rs.getString("device_id");
8953  } else {
8954  throw new TskCoreException("No image found for id: " + id);
8955  }
8956 
8957  // image can have multiple paths, therefore there can be multiple rows in the result set
8958  while (rs.next()) {
8959  imagePath = rs.getString("name");
8960  if (imagePath != null) {
8961  imagePaths.add(imagePath);
8962  }
8963  }
8964 
8965  return new Image(this, id, type, device_id, ssize, name,
8966  imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size);
8967  } catch (SQLException ex) {
8968  throw new TskCoreException("Error getting Image by id, id = " + id, ex);
8969  } finally {
8970  closeResultSet(rs);
8971  closeStatement(s);
8972  closeConnection(connection);
8974  }
8975  }
8976 
8988  VolumeSystem getVolumeSystemById(long id, Content parent) throws TskCoreException {
8989  CaseDbConnection connection = null;
8990  Statement s = null;
8991  ResultSet rs = null;
8993  try {
8994  connection = connections.getConnection();
8995  s = connection.createStatement();
8996  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_info " //NON-NLS
8997  + "where obj_id = " + id); //NON-NLS
8998  if (rs.next()) {
8999  long type = rs.getLong("vs_type"); //NON-NLS
9000  long imgOffset = rs.getLong("img_offset"); //NON-NLS
9001  long blockSize = rs.getLong("block_size"); //NON-NLS
9002  VolumeSystem vs = new VolumeSystem(this, id, "", type, imgOffset, blockSize);
9003  vs.setParent(parent);
9004  return vs;
9005  } else {
9006  throw new TskCoreException("No volume system found for id:" + id);
9007  }
9008  } catch (SQLException ex) {
9009  throw new TskCoreException("Error getting Volume System by ID.", ex);
9010  } finally {
9011  closeResultSet(rs);
9012  closeStatement(s);
9013  closeConnection(connection);
9015  }
9016  }
9017 
9026  VolumeSystem getVolumeSystemById(long id, long parentId) throws TskCoreException {
9027  VolumeSystem vs = getVolumeSystemById(id, null);
9028  vs.setParentId(parentId);
9029  return vs;
9030  }
9031 
9043  FileSystem getFileSystemById(long id, Image parent) throws TskCoreException {
9044  return getFileSystemByIdHelper(id, parent);
9045  }
9046 
9055  FileSystem getFileSystemById(long id, long parentId) throws TskCoreException {
9056  Volume vol = null;
9057  FileSystem fs = getFileSystemById(id, vol);
9058  fs.setParentId(parentId);
9059  return fs;
9060  }
9061 
9073  FileSystem getFileSystemById(long id, Volume parent) throws TskCoreException {
9074  return getFileSystemByIdHelper(id, parent);
9075  }
9076 
9088  Pool getPoolById(long id, Content parent) throws TskCoreException {
9089  return getPoolByIdHelper(id, parent);
9090  }
9091 
9100  Pool getPoolById(long id, long parentId) throws TskCoreException {
9101  Pool pool = getPoolById(id, null);
9102  pool.setParentId(parentId);
9103  return pool;
9104  }
9105 
9117  private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException {
9118 
9120  try (CaseDbConnection connection = connections.getConnection();
9121  Statement s = connection.createStatement();
9122  ResultSet rs = connection.executeQuery(s, "SELECT * FROM tsk_pool_info " //NON-NLS
9123  + "where obj_id = " + id);) { //NON-NLS
9124  if (rs.next()) {
9125  Pool pool = new Pool(this, rs.getLong("obj_id"), TskData.TSK_POOL_TYPE_ENUM.valueOf(rs.getLong("pool_type")).getName(), rs.getLong("pool_type"));
9126  pool.setParent(parent);
9127 
9128  return pool;
9129  } else {
9130  throw new TskCoreException("No pool found for ID:" + id);
9131  }
9132  } catch (SQLException ex) {
9133  throw new TskCoreException("Error getting Pool by ID", ex);
9134  } finally {
9136  }
9137  }
9138 
9150  private FileSystem getFileSystemByIdHelper(long id, Content parent) throws TskCoreException {
9151  // see if we already have it
9152  // @@@ NOTE: this is currently kind of bad in that we are ignoring the parent value,
9153  // but it should be the same...
9154  synchronized (fileSystemIdMap) {
9155  if (fileSystemIdMap.containsKey(id)) {
9156  return fileSystemIdMap.get(id);
9157  }
9158  }
9159  CaseDbConnection connection = null;
9160  Statement s = null;
9161  ResultSet rs = null;
9163  try {
9164  connection = connections.getConnection();
9165  s = connection.createStatement();
9166  rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS
9167  + "where obj_id = " + id); //NON-NLS
9168  if (rs.next()) {
9169  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9170  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9171  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9172  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9173  fs.setParent(parent);
9174  // save it for the next call
9175  synchronized (fileSystemIdMap) {
9176  fileSystemIdMap.put(id, fs);
9177  }
9178  return fs;
9179  } else {
9180  throw new TskCoreException("No file system found for id:" + id);
9181  }
9182  } catch (SQLException ex) {
9183  throw new TskCoreException("Error getting File System by ID", ex);
9184  } finally {
9185  closeResultSet(rs);
9186  closeStatement(s);
9187  closeConnection(connection);
9189  }
9190  }
9191 
9203  Volume getVolumeById(long id, VolumeSystem parent) throws TskCoreException {
9204  CaseDbConnection connection = null;
9205  Statement s = null;
9206  ResultSet rs = null;
9208  try {
9209  connection = connections.getConnection();
9210  s = connection.createStatement();
9211  rs = connection.executeQuery(s, "SELECT * FROM tsk_vs_parts " //NON-NLS
9212  + "where obj_id = " + id); //NON-NLS
9213  if (rs.next()) {
9221  String description;
9222  try {
9223  description = rs.getString("desc");
9224  } catch (Exception ex) {
9225  description = rs.getString("descr");
9226  }
9227  Volume vol = new Volume(this, rs.getLong("obj_id"), rs.getLong("addr"), //NON-NLS
9228  rs.getLong("start"), rs.getLong("length"), rs.getLong("flags"), //NON-NLS
9229  description);
9230  vol.setParent(parent);
9231  return vol;
9232  } else {
9233  throw new TskCoreException("No volume found for id:" + id);
9234  }
9235  } catch (SQLException ex) {
9236  throw new TskCoreException("Error getting Volume by ID", ex);
9237  } finally {
9238  closeResultSet(rs);
9239  closeStatement(s);
9240  closeConnection(connection);
9242  }
9243  }
9244 
9253  Volume getVolumeById(long id, long parentId) throws TskCoreException {
9254  Volume vol = getVolumeById(id, null);
9255  vol.setParentId(parentId);
9256  return vol;
9257  }
9258 
9270  Directory getDirectoryById(long id, FileSystem parentFs) throws TskCoreException {
9271  CaseDbConnection connection = null;
9272  Statement s = null;
9273  ResultSet rs = null;
9275  try {
9276  connection = connections.getConnection();
9277  s = connection.createStatement();
9278  rs = connection.executeQuery(s, "SELECT * FROM tsk_files " //NON-NLS
9279  + "WHERE obj_id = " + id);
9280  Directory temp = null; //NON-NLS
9281  if (rs.next()) {
9282  final short type = rs.getShort("type"); //NON-NLS
9283  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()) {
9284  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
9285  || rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) { //NON-NLS
9286  temp = directory(rs, parentFs);
9287  }
9288  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()) {
9289  throw new TskCoreException("Expecting an FS-type directory, got virtual, id: " + id);
9290  }
9291  } else {
9292  throw new TskCoreException("No Directory found for id:" + id);
9293  }
9294  return temp;
9295  } catch (SQLException ex) {
9296  throw new TskCoreException("Error getting Directory by ID", ex);
9297  } finally {
9298  closeResultSet(rs);
9299  closeStatement(s);
9300  closeConnection(connection);
9302  }
9303  }
9304 
9314  public Collection<FileSystem> getImageFileSystems(Image image) throws TskCoreException {
9315  List<FileSystem> fileSystems = new ArrayList<>();
9316  String queryStr = "SELECT * FROM tsk_fs_info WHERE data_source_obj_id = " + image.getId();
9317 
9318  CaseDbConnection connection = null;
9319  Statement s = null;
9320  ResultSet rs = null;
9322  try {
9323  connection = connections.getConnection();
9324  s = connection.createStatement();
9325  rs = connection.executeQuery(s, queryStr); //NON-NLS
9326  while (rs.next()) {
9327  TskData.TSK_FS_TYPE_ENUM fsType = TskData.TSK_FS_TYPE_ENUM.valueOf(rs.getInt("fs_type")); //NON-NLS
9328  FileSystem fs = new FileSystem(this, rs.getLong("obj_id"), "", rs.getLong("img_offset"), //NON-NLS
9329  fsType, rs.getLong("block_size"), rs.getLong("block_count"), //NON-NLS
9330  rs.getLong("root_inum"), rs.getLong("first_inum"), rs.getLong("last_inum")); //NON-NLS
9331  fs.setParent(null);
9332  fileSystems.add(fs);
9333  }
9334  } catch (SQLException ex) {
9335  throw new TskCoreException("Error looking up files systems. Query: " + queryStr, ex); //NON-NLS
9336  } finally {
9337  closeResultSet(rs);
9338  closeStatement(s);
9339  closeConnection(connection);
9341  }
9342  return fileSystems;
9343  }
9344 
9355  List<Content> getImageChildren(Image img) throws TskCoreException {
9356  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9357  List<Content> children = new ArrayList<Content>();
9358  for (ObjectInfo info : childInfos) {
9359  if (null != info.type) {
9360  switch (info.type) {
9361  case VS:
9362  children.add(getVolumeSystemById(info.id, img));
9363  break;
9364  case POOL:
9365  children.add(getPoolById(info.id, img));
9366  break;
9367  case FS:
9368  children.add(getFileSystemById(info.id, img));
9369  break;
9370  case ABSTRACTFILE:
9371  AbstractFile f = getAbstractFileById(info.id);
9372  if (f != null) {
9373  children.add(f);
9374  }
9375  break;
9376  case ARTIFACT:
9377  BlackboardArtifact art = getArtifactById(info.id);
9378  if (art != null) {
9379  children.add(art);
9380  }
9381  break;
9382  case REPORT:
9383  // Do nothing for now - see JIRA-3673
9384  break;
9385  default:
9386  throw new TskCoreException("Image has child of invalid type: " + info.type);
9387  }
9388  }
9389  }
9390  return children;
9391  }
9392 
9403  List<Long> getImageChildrenIds(Image img) throws TskCoreException {
9404  Collection<ObjectInfo> childInfos = getChildrenInfo(img);
9405  List<Long> children = new ArrayList<Long>();
9406  for (ObjectInfo info : childInfos) {
9407  if (info.type == ObjectType.VS
9408  || info.type == ObjectType.POOL
9409  || info.type == ObjectType.FS
9410  || info.type == ObjectType.ABSTRACTFILE
9411  || info.type == ObjectType.ARTIFACT) {
9412  children.add(info.id);
9413  } else if (info.type == ObjectType.REPORT) {
9414  // Do nothing for now - see JIRA-3673
9415  } else {
9416  throw new TskCoreException("Image has child of invalid type: " + info.type);
9417  }
9418  }
9419  return children;
9420  }
9421 
9432  List<Content> getPoolChildren(Pool pool) throws TskCoreException {
9433  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9434  List<Content> children = new ArrayList<Content>();
9435  for (ObjectInfo info : childInfos) {
9436  if (null != info.type) {
9437  switch (info.type) {
9438  case VS:
9439  children.add(getVolumeSystemById(info.id, pool));
9440  break;
9441  case ABSTRACTFILE:
9442  AbstractFile f = getAbstractFileById(info.id);
9443  if (f != null) {
9444  children.add(f);
9445  }
9446  break;
9447  case ARTIFACT:
9448  BlackboardArtifact art = getArtifactById(info.id);
9449  if (art != null) {
9450  children.add(art);
9451  }
9452  break;
9453  default:
9454  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9455  }
9456  }
9457  }
9458  return children;
9459  }
9460 
9471  List<Long> getPoolChildrenIds(Pool pool) throws TskCoreException {
9472  Collection<ObjectInfo> childInfos = getChildrenInfo(pool);
9473  List<Long> children = new ArrayList<Long>();
9474  for (ObjectInfo info : childInfos) {
9475  if (info.type == ObjectType.VS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9476  children.add(info.id);
9477  } else {
9478  throw new TskCoreException("Pool has child of invalid type: " + info.type);
9479  }
9480  }
9481  return children;
9482  }
9483 
9494  List<Content> getVolumeSystemChildren(VolumeSystem vs) throws TskCoreException {
9495  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9496  List<Content> children = new ArrayList<Content>();
9497  for (ObjectInfo info : childInfos) {
9498  if (null != info.type) {
9499  switch (info.type) {
9500  case VOL:
9501  children.add(getVolumeById(info.id, vs));
9502  break;
9503  case ABSTRACTFILE:
9504  AbstractFile f = getAbstractFileById(info.id);
9505  if (f != null) {
9506  children.add(f);
9507  }
9508  break;
9509  case ARTIFACT:
9510  BlackboardArtifact art = getArtifactById(info.id);
9511  if (art != null) {
9512  children.add(art);
9513  }
9514  break;
9515  default:
9516  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9517  }
9518  }
9519  }
9520  return children;
9521  }
9522 
9533  List<Long> getVolumeSystemChildrenIds(VolumeSystem vs) throws TskCoreException {
9534  Collection<ObjectInfo> childInfos = getChildrenInfo(vs);
9535  List<Long> children = new ArrayList<Long>();
9536  for (ObjectInfo info : childInfos) {
9537  if (info.type == ObjectType.VOL || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9538  children.add(info.id);
9539  } else {
9540  throw new TskCoreException("VolumeSystem has child of invalid type: " + info.type);
9541  }
9542  }
9543  return children;
9544  }
9545 
9556  List<Content> getVolumeChildren(Volume vol) throws TskCoreException {
9557  Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9558  List<Content> children = new ArrayList<Content>();
9559  for (ObjectInfo info : childInfos) {
9560  if (null != info.type) {
9561  switch (info.type) {
9562  case POOL:
9563  children.add(getPoolById(info.id, vol));
9564  break;
9565  case FS:
9566  children.add(getFileSystemById(info.id, vol));
9567  break;
9568  case ABSTRACTFILE:
9569  AbstractFile f = getAbstractFileById(info.id);
9570  if (f != null) {
9571  children.add(f);
9572  }
9573  break;
9574  case ARTIFACT:
9575  BlackboardArtifact art = getArtifactById(info.id);
9576  if (art != null) {
9577  children.add(art);
9578  }
9579  break;
9580  default:
9581  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9582  }
9583  }
9584  }
9585  return children;
9586  }
9587 
9598  List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException {
9599  final Collection<ObjectInfo> childInfos = getChildrenInfo(vol);
9600  final List<Long> children = new ArrayList<Long>();
9601  for (ObjectInfo info : childInfos) {
9602  if (info.type == ObjectType.FS || info.type == ObjectType.ABSTRACTFILE || info.type == ObjectType.ARTIFACT) {
9603  children.add(info.id);
9604  } else {
9605  throw new TskCoreException("Volume has child of invalid type: " + info.type);
9606  }
9607  }
9608  return children;
9609  }
9610 
9624  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException {
9625  return addImageInfo(deviceObjId, imageFilePaths, timeZone, null);
9626  }
9627 
9642  public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException {
9643  long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this);
9644  return getImageById(imageId);
9645  }
9646 
9656  public Map<Long, List<String>> getImagePaths() throws TskCoreException {
9657  CaseDbConnection connection = null;
9658  Statement s1 = null;
9659  ResultSet rs1 = null;
9661  try {
9662  connection = connections.getConnection();
9663  s1 = connection.createStatement();
9664  rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info "
9665  + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS
9666  Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>();
9667  while (rs1.next()) {
9668  long obj_id = rs1.getLong("obj_id"); //NON-NLS
9669  String name = rs1.getString("name"); //NON-NLS
9670  List<String> imagePaths = imgPaths.get(obj_id);
9671  if (imagePaths == null) {
9672  List<String> paths = new ArrayList<String>();
9673  if (name != null) {
9674  paths.add(name);
9675  }
9676  imgPaths.put(obj_id, paths);
9677  } else {
9678  if (name != null) {
9679  imagePaths.add(name);
9680  }
9681  }
9682  }
9683  return imgPaths;
9684  } catch (SQLException ex) {
9685  throw new TskCoreException("Error getting image paths.", ex);
9686  } finally {
9687  closeResultSet(rs1);
9688  closeStatement(s1);
9689  closeConnection(connection);
9691  }
9692  }
9693 
9705  private List<String> getImagePathsById(long objectId, CaseDbConnection connection) throws TskCoreException {
9706  List<String> imagePaths = new ArrayList<>();
9708  Statement statement = null;
9709  ResultSet resultSet = null;
9710  try {
9711  statement = connection.createStatement();
9712  resultSet = connection.executeQuery(statement, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + objectId); //NON-NLS
9713  while (resultSet.next()) {
9714  imagePaths.add(resultSet.getString("name"));
9715  }
9716  } catch (SQLException ex) {
9717  throw new TskCoreException(String.format("Error getting image names with obj_id = %d", objectId), ex);
9718  } finally {
9719  closeResultSet(resultSet);
9720  closeStatement(statement);
9722  }
9723 
9724  return imagePaths;
9725  }
9726 
9733  public List<Image> getImages() throws TskCoreException {
9734  CaseDbConnection connection = null;
9735  Statement s = null;
9736  ResultSet rs = null;
9738  try {
9739  connection = connections.getConnection();
9740  s = connection.createStatement();
9741  rs = connection.executeQuery(s, "SELECT obj_id FROM tsk_image_info"); //NON-NLS
9742  Collection<Long> imageIDs = new ArrayList<Long>();
9743  while (rs.next()) {
9744  imageIDs.add(rs.getLong("obj_id")); //NON-NLS
9745  }
9746  List<Image> images = new ArrayList<Image>();
9747  for (long id : imageIDs) {
9748  images.add(getImageById(id));
9749  }
9750  return images;
9751  } catch (SQLException ex) {
9752  throw new TskCoreException("Error retrieving images.", ex);
9753  } finally {
9754  closeResultSet(rs);
9755  closeStatement(s);
9756  closeConnection(connection);
9758  }
9759  }
9760 
9771  public void setImagePaths(long obj_id, List<String> paths) throws TskCoreException {
9772  CaseDbConnection connection = null;
9774  PreparedStatement statement;
9775  try {
9776  connection = connections.getConnection();
9777  connection.beginTransaction();
9778  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_IMAGE_NAME);
9779  statement.clearParameters();
9780  statement.setLong(1, obj_id);
9781  connection.executeUpdate(statement);
9782  for (int i = 0; i < paths.size(); i++) {
9783  statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_IMAGE_NAME);
9784  statement.clearParameters();
9785  statement.setLong(1, obj_id);
9786  statement.setString(2, paths.get(i));
9787  statement.setLong(3, i);
9788  connection.executeUpdate(statement);
9789  }
9790  connection.commitTransaction();
9791  } catch (SQLException ex) {
9792  rollbackTransaction(connection);
9793  throw new TskCoreException("Error updating image paths.", ex);
9794  } finally {
9795  closeConnection(connection);
9797  }
9798  }
9799 
9811  void deleteDataSource(long dataSourceObjectId) throws TskCoreException {
9812 
9813  // Check if this data source is the only one associated with its host. If so,
9814  // we will delete the host and other associated data.
9815  // Note that the cascading deletes were only added in schema 9.1, so we
9816  // would get an error trying to delete a host from older cases.
9817  Host hostToDelete = null;
9819  int major = version.getMajor();
9820  int minor = version.getMinor();
9821  if (major > 9 || (major == 9 && minor >= 1)) {
9822  hostToDelete = getHostManager().getHostByDataSource(dataSourceObjectId);
9823  if (getHostManager().getDataSourcesForHost(hostToDelete).size() != 1) {
9824  hostToDelete = null;
9825  }
9826  }
9827 
9828  CaseDbConnection connection = null;
9829  Statement statement;
9831  try {
9832  connection = connections.getConnection();
9833  statement = connection.createStatement();
9834  connection.beginTransaction();
9835  // The following delete(s) uses a foreign key delete with cascade in the DB so that it will delete
9836  // all associated rows from tsk_object and its children. For large data sources this may take some time.
9837  statement.execute("DELETE FROM tsk_objects WHERE obj_id = " + dataSourceObjectId);
9838  // The following delete uses a foreign key delete with cascade in the DB so that it will delete all
9839  // associated rows from accounts table and its children.
9840  String accountSql = "DELETE FROM accounts WHERE account_id in (SELECT account_id FROM accounts "
9841  + "WHERE account_id NOT IN (SELECT account1_id FROM account_relationships) "
9842  + "AND account_id NOT IN (SELECT account2_id FROM account_relationships))";
9843  statement.execute(accountSql);
9844 
9845  // Now delete any host that was only associated with this data source. This will cascade to delete
9846  // realms, os accounts, and os account attributes that were associated with the host.
9847  if (hostToDelete != null) {
9848  statement.execute("DELETE FROM tsk_hosts WHERE id = " + hostToDelete.getHostId());
9849 
9850  // Clean up any stray OS Account objects
9851  String deleteOsAcctObjectsQuery = "DELETE FROM tsk_objects "
9852  + "WHERE type=" + TskData.ObjectType.OS_ACCOUNT.getObjectType() + " "
9853  + "AND obj_id NOT IN (SELECT os_account_obj_id FROM tsk_os_accounts WHERE os_account_obj_id IS NOT NULL)";
9854  statement.execute(deleteOsAcctObjectsQuery);
9855  }
9856 
9857  connection.commitTransaction();
9858  } catch (SQLException ex) {
9859  rollbackTransaction(connection);
9860  throw new TskCoreException("Error deleting data source.", ex);
9861  } finally {
9862  closeConnection(connection);
9864  }
9865  }
9866 
9892  List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnection connection) throws SQLException {
9893  ArrayList<AbstractFile> results = new ArrayList<AbstractFile>();
9894  try {
9895  while (rs.next()) {
9896  final short type = rs.getShort("type"); //NON-NLS
9897  if (type == TSK_DB_FILES_TYPE_ENUM.FS.getFileType()
9898  && (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) {
9899  FsContent result;
9900  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) { //NON-NLS
9901  result = directory(rs, null);
9902  } else {
9903  result = file(rs, null);
9904  }
9905  results.add(result);
9906  } else if (type == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
9907  || (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue())) { //NON-NLS
9908  final VirtualDirectory virtDir = virtualDirectory(rs, connection);
9909  results.add(virtDir);
9910  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR.getFileType()) {
9911  final LocalDirectory localDir = localDirectory(rs);
9912  results.add(localDir);
9913  } else if (type == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
9914  || type == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
9915  || type == TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()
9916  || type == TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType()) {
9917  TSK_DB_FILES_TYPE_ENUM atype = TSK_DB_FILES_TYPE_ENUM.valueOf(type);
9918  String parentPath = rs.getString("parent_path"); //NON-NLS
9919  if (parentPath == null) {
9920  parentPath = "/"; //NON-NLS
9921  }
9922 
9923  Long osAccountObjId = rs.getLong("os_account_obj_id");
9924  if (rs.wasNull()) {
9925  osAccountObjId = null;
9926  }
9927 
9928  LayoutFile lf = new LayoutFile(this,
9929  rs.getLong("obj_id"), //NON-NLS
9930  rs.getLong("data_source_obj_id"),
9931  rs.getString("name"), //NON-NLS
9932  atype,
9933  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9934  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
9935  rs.getLong("size"), //NON-NLS
9936  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
9937  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath,
9938  rs.getString("mime_type"),
9939  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
9940  results.add(lf);
9941  } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) {
9942  final DerivedFile df;
9943  df = derivedFile(rs, connection, AbstractContent.UNKNOWN_ID);
9944  results.add(df);
9945  } else if (type == TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()) {
9946  final LocalFile lf;
9947  lf = localFile(rs, connection, AbstractContent.UNKNOWN_ID);
9948  results.add(lf);
9949  } else if (type == TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()) {
9950  final SlackFile sf = slackFile(rs, null);
9951  results.add(sf);
9952  }
9953  } //end for each resultSet
9954  } catch (SQLException e) {
9955  logger.log(Level.SEVERE, "Error getting abstract files from result set", e); //NON-NLS
9956  }
9957 
9958  return results;
9959  }
9960 
9961  // This following methods generate AbstractFile objects from a ResultSet
9973  org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLException {
9974  Long osAccountObjId = rs.getLong("os_account_obj_id");
9975  if (rs.wasNull()) {
9976  osAccountObjId = null;
9977  }
9978 
9979  org.sleuthkit.datamodel.File f = new org.sleuthkit.datamodel.File(this, rs.getLong("obj_id"), //NON-NLS
9980  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
9981  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
9982  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
9983  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
9984  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
9985  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
9986  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
9987  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
9988  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
9989  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
9990  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"), rs.getString("owner_uid"), osAccountObjId, Collections.emptyList()); //NON-NLS
9991  f.setFileSystem(fs);
9992  return f;
9993  }
9994 
10006  Directory directory(ResultSet rs, FileSystem fs) throws SQLException {
10007  Long osAccountObjId = rs.getLong("os_account_obj_id");
10008  if (rs.wasNull()) {
10009  osAccountObjId = null;
10010  }
10011 
10012  Directory dir = new Directory(this, rs.getLong("obj_id"), rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10013  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10014  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10015  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10016  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10017  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10018  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10019  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10020  rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10021  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10022  rs.getString("parent_path"), rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10023  dir.setFileSystem(fs);
10024  return dir;
10025  }
10026 
10037  VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) throws SQLException {
10038  String parentPath = rs.getString("parent_path"); //NON-NLS
10039  if (parentPath == null) {
10040  parentPath = "";
10041  }
10042 
10043  long objId = rs.getLong("obj_id");
10044  long dsObjId = rs.getLong("data_source_obj_id");
10045  if (objId == dsObjId) { // virtual directory is a data source
10046 
10047  String deviceId = "";
10048  String timeZone = "";
10049  Statement s = null;
10050  ResultSet rsDataSourceInfo = null;
10051 
10053  try {
10054  s = connection.createStatement();
10055  rsDataSourceInfo = connection.executeQuery(s, "SELECT device_id, time_zone FROM data_source_info WHERE obj_id = " + objId);
10056  if (rsDataSourceInfo.next()) {
10057  deviceId = rsDataSourceInfo.getString("device_id");
10058  timeZone = rsDataSourceInfo.getString("time_zone");
10059  }
10060  } catch (SQLException ex) {
10061  logger.log(Level.SEVERE, "Error data source info for datasource id " + objId, ex); //NON-NLS
10062  } finally {
10063  closeResultSet(rsDataSourceInfo);
10064  closeStatement(s);
10066  }
10067 
10068  return new LocalFilesDataSource(this,
10069  objId, dsObjId,
10070  deviceId,
10071  rs.getString("name"),
10072  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10073  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10074  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")),
10075  rs.getShort("meta_flags"),
10076  timeZone,
10077  rs.getString("md5"),
10078  rs.getString("sha256"),
10079  FileKnown.valueOf(rs.getByte("known")),
10080  parentPath);
10081  } else {
10082  final VirtualDirectory vd = new VirtualDirectory(this,
10083  objId, dsObjId,
10084  rs.getString("name"), //NON-NLS
10085  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10086  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10087  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10088  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS
10089  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10090  return vd;
10091  }
10092  }
10093 
10103  LocalDirectory localDirectory(ResultSet rs) throws SQLException {
10104  String parentPath = rs.getString("parent_path"); //NON-NLS
10105  if (parentPath == null) {
10106  parentPath = "";
10107  }
10108  final LocalDirectory ld = new LocalDirectory(this, rs.getLong("obj_id"), //NON-NLS
10109  rs.getLong("data_source_obj_id"), rs.getString("name"), //NON-NLS
10110  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10111  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10112  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10113  rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS
10114  FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS
10115  return ld;
10116  }
10117 
10131  private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10132  boolean hasLocalPath = rs.getBoolean("has_path"); //NON-NLS
10133  long objId = rs.getLong("obj_id"); //NON-NLS
10134  String localPath = null;
10135  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10136  if (hasLocalPath) {
10137  ResultSet rsFilePath = null;
10139  try {
10140  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10141  statement.clearParameters();
10142  statement.setLong(1, objId);
10143  rsFilePath = connection.executeQuery(statement);
10144  if (rsFilePath.next()) {
10145  localPath = rsFilePath.getString("path");
10146  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10147  }
10148  } catch (SQLException ex) {
10149  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10150  } finally {
10151  closeResultSet(rsFilePath);
10153  }
10154  }
10155  String parentPath = rs.getString("parent_path"); //NON-NLS
10156  if (parentPath == null) {
10157  parentPath = "";
10158  }
10159 
10160  Long osAccountObjId = rs.getLong("os_account_obj_id");
10161  if (rs.wasNull()) {
10162  osAccountObjId = null;
10163  }
10164 
10165  final DerivedFile df = new DerivedFile(this, objId, rs.getLong("data_source_obj_id"),
10166  rs.getString("name"), //NON-NLS
10167  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10168  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10169  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10170  rs.getLong("size"), //NON-NLS
10171  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10172  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10173  parentPath, localPath, parentId, rs.getString("mime_type"),
10174  encodingType, rs.getString("extension"),
10175  rs.getString("owner_uid"), osAccountObjId);
10176  return df;
10177  }
10178 
10192  private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10193  long objId = rs.getLong("obj_id"); //NON-NLS
10194  String localPath = null;
10195  TskData.EncodingType encodingType = TskData.EncodingType.NONE;
10196  if (rs.getBoolean("has_path")) {
10197  ResultSet rsFilePath = null;
10199  try {
10200  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE);
10201  statement.clearParameters();
10202  statement.setLong(1, objId);
10203  rsFilePath = connection.executeQuery(statement);
10204  if (rsFilePath.next()) {
10205  localPath = rsFilePath.getString("path");
10206  encodingType = TskData.EncodingType.valueOf(rsFilePath.getInt("encoding_type"));
10207  }
10208  } catch (SQLException ex) {
10209  logger.log(Level.SEVERE, "Error getting encoding type for file " + objId, ex); //NON-NLS
10210  } finally {
10211  closeResultSet(rsFilePath);
10213  }
10214  }
10215  String parentPath = rs.getString("parent_path"); //NON-NLS
10216  if (null == parentPath) {
10217  parentPath = "";
10218  }
10219  Long osAccountObjId = rs.getLong("os_account_obj_id");
10220  if (rs.wasNull()) {
10221  osAccountObjId = null;
10222  }
10223 
10224  LocalFile file = new LocalFile(this, objId, rs.getString("name"), //NON-NLS
10225  TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type")), //NON-NLS
10226  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10227  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10228  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS
10229  rs.getLong("size"), //NON-NLS
10230  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10231  rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10232  parentId, parentPath, rs.getLong("data_source_obj_id"),
10233  localPath, encodingType, rs.getString("extension"),
10234  rs.getString("owner_uid"), osAccountObjId);
10235  return file;
10236  }
10237 
10249  org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws SQLException {
10250  Long osAccountObjId = rs.getLong("os_account_obj_id");
10251  if (rs.wasNull()) {
10252  osAccountObjId = null;
10253  }
10254  org.sleuthkit.datamodel.SlackFile f = new org.sleuthkit.datamodel.SlackFile(this, rs.getLong("obj_id"), //NON-NLS
10255  rs.getLong("data_source_obj_id"), rs.getLong("fs_obj_id"), //NON-NLS
10256  TskData.TSK_FS_ATTR_TYPE_ENUM.valueOf(rs.getShort("attr_type")), //NON-NLS
10257  rs.getInt("attr_id"), rs.getString("name"), rs.getLong("meta_addr"), rs.getInt("meta_seq"), //NON-NLS
10258  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS
10259  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS
10260  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS
10261  rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS
10262  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS
10263  (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS
10264  rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS
10265  rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension"),
10266  rs.getString("owner_uid"), osAccountObjId); //NON-NLS
10267  f.setFileSystem(fs);
10268  return f;
10269  }
10270 
10282  List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long parentId) throws SQLException {
10283  List<Content> children = new ArrayList<Content>();
10284 
10285  while (rs.next()) {
10286  TskData.TSK_DB_FILES_TYPE_ENUM type = TskData.TSK_DB_FILES_TYPE_ENUM.valueOf(rs.getShort("type"));
10287 
10288  if (null != type) {
10289  switch (type) {
10290  case FS:
10291  if (rs.getShort("meta_type") != TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()) {
10292  FsContent result;
10293  if (rs.getShort("meta_type") == TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()) {
10294  result = directory(rs, null);
10295  } else {
10296  result = file(rs, null);
10297  }
10298  children.add(result);
10299  } else {
10300  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10301  children.add(virtDir);
10302  }
10303  break;
10304  case VIRTUAL_DIR:
10305  VirtualDirectory virtDir = virtualDirectory(rs, connection);
10306  children.add(virtDir);
10307  break;
10308  case LOCAL_DIR:
10309  LocalDirectory localDir = localDirectory(rs);
10310  children.add(localDir);
10311  break;
10312  case UNALLOC_BLOCKS:
10313  case UNUSED_BLOCKS:
10314  case CARVED:
10315  case LAYOUT_FILE: {
10316  String parentPath = rs.getString("parent_path");
10317  if (parentPath == null) {
10318  parentPath = "";
10319  }
10320  Long osAccountObjId = rs.getLong("os_account_obj_id");
10321  if (rs.wasNull()) {
10322  osAccountObjId = null;
10323  }
10324  final LayoutFile lf = new LayoutFile(this, rs.getLong("obj_id"),
10325  rs.getLong("data_source_obj_id"), rs.getString("name"), type,
10326  TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")),
10327  TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")),
10328  TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"),
10329  rs.getLong("size"),
10330  rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"),
10331  rs.getString("md5"), rs.getString("sha256"),
10332  FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type"),
10333  rs.getString("owner_uid"), osAccountObjId);
10334  children.add(lf);
10335  break;
10336  }
10337  case DERIVED:
10338  final DerivedFile df = derivedFile(rs, connection, parentId);
10339  children.add(df);
10340  break;
10341  case LOCAL: {
10342  final LocalFile lf = localFile(rs, connection, parentId);
10343  children.add(lf);
10344  break;
10345  }
10346  case SLACK: {
10347  final SlackFile sf = slackFile(rs, null);
10348  children.add(sf);
10349  break;
10350  }
10351  default:
10352  break;
10353  }
10354  }
10355  }
10356  return children;
10357  }
10358 
10380  public CaseDbQuery executeQuery(String query) throws TskCoreException {
10381  return new CaseDbQuery(query);
10382  }
10383 
10405  public CaseDbQuery executeInsertOrUpdate(String query) throws TskCoreException {
10406  return new CaseDbQuery(query, true);
10407  }
10408 
10416  CaseDbConnection getConnection() throws TskCoreException {
10417  return connections.getConnection();
10418  }
10419 
10427  String getCaseHandleIdentifier() {
10428  return caseHandleIdentifier;
10429  }
10430 
10431  @Override
10432  protected void finalize() throws Throwable {
10433  try {
10434  close();
10435  } finally {
10436  super.finalize();
10437  }
10438  }
10439 
10443  public synchronized void close() {
10445 
10446  try {
10447  connections.close();
10448  } catch (TskCoreException ex) {
10449  logger.log(Level.SEVERE, "Error closing database connection pool.", ex); //NON-NLS
10450  }
10451 
10452  fileSystemIdMap.clear();
10453 
10454  try {
10455  if (this.caseHandle != null) {
10456  this.caseHandle.free();
10457  this.caseHandle = null;
10458  }
10459  } catch (TskCoreException ex) {
10460  logger.log(Level.SEVERE, "Error freeing case handle.", ex); //NON-NLS
10461  } finally {
10463  }
10464  }
10465 
10478  public boolean setKnown(AbstractFile file, FileKnown fileKnown) throws TskCoreException {
10479  long id = file.getId();
10480  FileKnown currentKnown = file.getKnown();
10481  if (currentKnown.compareTo(fileKnown) > 0) {
10482  return false;
10483  }
10485  try (CaseDbConnection connection = connections.getConnection();
10486  Statement statement = connection.createStatement();) {
10487  connection.executeUpdate(statement, "UPDATE tsk_files " //NON-NLS
10488  + "SET known='" + fileKnown.getFileKnownValue() + "' " //NON-NLS
10489  + "WHERE obj_id=" + id); //NON-NLS
10490 
10491  file.setKnown(fileKnown);
10492  } catch (SQLException ex) {
10493  throw new TskCoreException("Error setting Known status.", ex);
10494  } finally {
10496  }
10497  return true;
10498  }
10499 
10508  void setFileName(String name, long objId) throws TskCoreException {
10510  try (CaseDbConnection connection = connections.getConnection();) {
10511  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_FILE_NAME);
10512  preparedStatement.clearParameters();
10513  preparedStatement.setString(1, name);
10514  preparedStatement.setLong(2, objId);
10515  connection.executeUpdate(preparedStatement);
10516  } catch (SQLException ex) {
10517  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10518  } finally {
10520  }
10521  }
10522 
10531  void setImageName(String name, long objId) throws TskCoreException {
10533  try (CaseDbConnection connection = connections.getConnection();) {
10534  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_NAME);
10535  preparedStatement.clearParameters();
10536  preparedStatement.setString(1, name);
10537  preparedStatement.setLong(2, objId);
10538  connection.executeUpdate(preparedStatement);
10539  } catch (SQLException ex) {
10540  throw new TskCoreException(String.format("Error updating while the name for object ID %d to %s", objId, name), ex);
10541  } finally {
10543  }
10544  }
10545 
10560  void setImageSizes(Image image, long totalSize, long sectorSize) throws TskCoreException {
10561 
10563  try (CaseDbConnection connection = connections.getConnection();) {
10564  PreparedStatement preparedStatement = connection.getPreparedStatement(SleuthkitCase.PREPARED_STATEMENT.UPDATE_IMAGE_SIZES);
10565  preparedStatement.clearParameters();
10566  preparedStatement.setLong(1, totalSize);
10567  preparedStatement.setLong(2, sectorSize);
10568  preparedStatement.setLong(3, image.getId());
10569  connection.executeUpdate(preparedStatement);
10570  } catch (SQLException ex) {
10571  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);
10572  } finally {
10574  }
10575  }
10576 
10586  public void setFileMIMEType(AbstractFile file, String mimeType) throws TskCoreException {
10588  try (CaseDbConnection connection = connections.getConnection();
10589  Statement statement = connection.createStatement()) {
10590  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET mime_type = '%s' WHERE obj_id = %d", mimeType, file.getId()));
10591  file.setMIMEType(mimeType);
10592  } catch (SQLException ex) {
10593  throw new TskCoreException(String.format("Error setting MIME type for file (obj_id = %s)", file.getId()), ex);
10594  } finally {
10596  }
10597  }
10598 
10609  public void setFileUnalloc(AbstractFile file) throws TskCoreException {
10610 
10611  // get the flags, reset the ALLOC flag, and set the UNALLOC flag
10612  short metaFlag = file.getMetaFlagsAsInt();
10613  Set<TSK_FS_META_FLAG_ENUM> metaFlagAsSet = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlag);
10614  metaFlagAsSet.remove(TSK_FS_META_FLAG_ENUM.ALLOC);
10615  metaFlagAsSet.add(TSK_FS_META_FLAG_ENUM.UNALLOC);
10616 
10617  short newMetaFlgs = TSK_FS_META_FLAG_ENUM.toInt(metaFlagAsSet);
10618  short newDirFlags = TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue();
10619 
10621  try (CaseDbConnection connection = connections.getConnection();
10622  Statement statement = connection.createStatement();) {
10623  connection.executeUpdate(statement, String.format("UPDATE tsk_files SET meta_flags = '%d', dir_flags = '%d' WHERE obj_id = %d", newMetaFlgs, newDirFlags, file.getId()));
10624 
10625  file.removeMetaFlag(TSK_FS_META_FLAG_ENUM.ALLOC);
10626  file.setMetaFlag(TSK_FS_META_FLAG_ENUM.UNALLOC);
10627 
10628  file.setDirFlag(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
10629 
10630  } catch (SQLException ex) {
10631  throw new TskCoreException(String.format("Error setting unalloc meta flag for file (obj_id = %s)", file.getId()), ex);
10632  } finally {
10634  }
10635  }
10636 
10646  void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
10647  if (md5Hash == null) {
10648  return;
10649  }
10650  long id = file.getId();
10652  try (CaseDbConnection connection = connections.getConnection();) {
10653  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_FILE_MD5);
10654  statement.clearParameters();
10655  statement.setString(1, md5Hash.toLowerCase());
10656  statement.setLong(2, id);
10657  connection.executeUpdate(statement);
10658  file.setMd5Hash(md5Hash.toLowerCase());
10659  } catch (SQLException ex) {
10660  throw new TskCoreException("Error setting MD5 hash", ex);
10661  } finally {
10663  }
10664  }
10665 
10675  void setMd5ImageHash(Image img, String md5Hash) throws TskCoreException {
10676  if (md5Hash == null) {
10677  return;
10678  }
10679  long id = img.getId();
10681  try (CaseDbConnection connection = connections.getConnection();) {
10682  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_MD5);
10683  statement.clearParameters();
10684  statement.setString(1, md5Hash.toLowerCase());
10685  statement.setLong(2, id);
10686  connection.executeUpdate(statement);
10687  } catch (SQLException ex) {
10688  throw new TskCoreException("Error setting MD5 hash", ex);
10689  } finally {
10691  }
10692  }
10693 
10704  String getMd5ImageHash(Image img) throws TskCoreException {
10705  long id = img.getId();
10706  CaseDbConnection connection = null;
10707  ResultSet rs = null;
10708  String hash = "";
10710  try {
10711  connection = connections.getConnection();
10712 
10713  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_MD5);
10714  statement.clearParameters();
10715  statement.setLong(1, id);
10716  rs = connection.executeQuery(statement);
10717  if (rs.next()) {
10718  hash = rs.getString("md5");
10719  }
10720  return hash;
10721  } catch (SQLException ex) {
10722  throw new TskCoreException("Error getting MD5 hash", ex);
10723  } finally {
10724  closeResultSet(rs);
10725  closeConnection(connection);
10727  }
10728  }
10729 
10739  void setSha1ImageHash(Image img, String sha1Hash) throws TskCoreException {
10740  if (sha1Hash == null) {
10741  return;
10742  }
10743  long id = img.getId();
10745  try (CaseDbConnection connection = connections.getConnection();) {
10746  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA1);
10747  statement.clearParameters();
10748  statement.setString(1, sha1Hash.toLowerCase());
10749  statement.setLong(2, id);
10750  connection.executeUpdate(statement);
10751  } catch (SQLException ex) {
10752  throw new TskCoreException("Error setting SHA1 hash", ex);
10753  } finally {
10755  }
10756  }
10757 
10768  String getSha1ImageHash(Image img) throws TskCoreException {
10769  long id = img.getId();
10770  CaseDbConnection connection = null;
10771  ResultSet rs = null;
10772  String hash = "";
10774  try {
10775  connection = connections.getConnection();
10776 
10777  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA1);
10778  statement.clearParameters();
10779  statement.setLong(1, id);
10780  rs = connection.executeQuery(statement);
10781  if (rs.next()) {
10782  hash = rs.getString("sha1");
10783  }
10784  return hash;
10785  } catch (SQLException ex) {
10786  throw new TskCoreException("Error getting SHA1 hash", ex);
10787  } finally {
10788  closeResultSet(rs);
10789  closeConnection(connection);
10791  }
10792  }
10793 
10803  void setSha256ImageHash(Image img, String sha256Hash) throws TskCoreException {
10804  if (sha256Hash == null) {
10805  return;
10806  }
10807  long id = img.getId();
10809  try (CaseDbConnection connection = connections.getConnection();) {
10810  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_SHA256);
10811  statement.clearParameters();
10812  statement.setString(1, sha256Hash.toLowerCase());
10813  statement.setLong(2, id);
10814  connection.executeUpdate(statement);
10815  } catch (SQLException ex) {
10816  throw new TskCoreException("Error setting SHA256 hash", ex);
10817  } finally {
10819  }
10820  }
10821 
10832  String getSha256ImageHash(Image img) throws TskCoreException {
10833  long id = img.getId();
10834  CaseDbConnection connection = null;
10835  ResultSet rs = null;
10836  String hash = "";
10838  try {
10839  connection = connections.getConnection();
10840 
10841  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_IMAGE_SHA256);
10842  statement.clearParameters();
10843  statement.setLong(1, id);
10844  rs = connection.executeQuery(statement);
10845  if (rs.next()) {
10846  hash = rs.getString("sha256");
10847  }
10848  return hash;
10849  } catch (SQLException ex) {
10850  throw new TskCoreException("Error setting SHA256 hash", ex);
10851  } finally {
10852  closeResultSet(rs);
10853  closeConnection(connection);
10855  }
10856  }
10857 
10866  void setAcquisitionDetails(DataSource datasource, String details) throws TskCoreException {
10867 
10868  long id = datasource.getId();
10870  try (CaseDbConnection connection = connections.getConnection();) {
10871  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
10872  statement.clearParameters();
10873  statement.setString(1, details);
10874  statement.setLong(2, id);
10875  connection.executeUpdate(statement);
10876  } catch (SQLException ex) {
10877  throw new TskCoreException("Error setting acquisition details", ex);
10878  } finally {
10880  }
10881  }
10882 
10894  void setAcquisitionToolDetails(DataSource datasource, String name, String version, String settings) throws TskCoreException {
10895 
10896  long id = datasource.getId();
10898  try (CaseDbConnection connection = connections.getConnection();) {
10899  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_TOOL_SETTINGS);
10900  statement.clearParameters();
10901  statement.setString(1, settings);
10902  statement.setString(2, name);
10903  statement.setString(3, version);
10904  statement.setLong(4, id);
10905  connection.executeUpdate(statement);
10906  } catch (SQLException ex) {
10907  throw new TskCoreException("Error setting acquisition details", ex);
10908  } finally {
10910  }
10911  }
10912 
10922  void setAcquisitionDetails(long dataSourceId, String details, CaseDbTransaction trans) throws TskCoreException {
10923  try {
10924  CaseDbConnection connection = trans.getConnection();
10925  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_ACQUISITION_DETAILS);
10926  statement.clearParameters();
10927  statement.setString(1, details);
10928  statement.setLong(2, dataSourceId);
10929  connection.executeUpdate(statement);
10930  } catch (SQLException ex) {
10931  throw new TskCoreException("Error setting acquisition details", ex);
10932  }
10933  }
10934 
10944  String getAcquisitionDetails(DataSource datasource) throws TskCoreException {
10945  long id = datasource.getId();
10946  CaseDbConnection connection = null;
10947  ResultSet rs = null;
10948  String hash = "";
10950  try {
10951  connection = connections.getConnection();
10952 
10953  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_DETAILS);
10954  statement.clearParameters();
10955  statement.setLong(1, id);
10956  rs = connection.executeQuery(statement);
10957  if (rs.next()) {
10958  hash = rs.getString("acquisition_details");
10959  }
10960  return hash;
10961  } catch (SQLException ex) {
10962  throw new TskCoreException("Error setting acquisition details", ex);
10963  } finally {
10964  closeResultSet(rs);
10965  closeConnection(connection);
10967  }
10968  }
10969 
10980  String getDataSourceInfoString(DataSource datasource, String columnName) throws TskCoreException {
10981  long id = datasource.getId();
10982  CaseDbConnection connection = null;
10983  ResultSet rs = null;
10984  String returnValue = "";
10986  try {
10987  connection = connections.getConnection();
10988 
10989  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
10990  statement.clearParameters();
10991  statement.setLong(1, id);
10992  rs = connection.executeQuery(statement);
10993  if (rs.next()) {
10994  returnValue = rs.getString(columnName);
10995  }
10996  return returnValue;
10997  } catch (SQLException ex) {
10998  throw new TskCoreException("Error setting acquisition details", ex);
10999  } finally {
11000  closeResultSet(rs);
11001  closeConnection(connection);
11003  }
11004  }
11005 
11016  Long getDataSourceInfoLong(DataSource datasource, String columnName) throws TskCoreException {
11017  long id = datasource.getId();
11018  CaseDbConnection connection = null;
11019  ResultSet rs = null;
11020  Long returnValue = null;
11022  try {
11023  connection = connections.getConnection();
11024 
11025  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ACQUISITION_TOOL_SETTINGS);
11026  statement.clearParameters();
11027  statement.setLong(1, id);
11028  rs = connection.executeQuery(statement);
11029  if (rs.next()) {
11030  returnValue = rs.getLong(columnName);
11031  }
11032  return returnValue;
11033  } catch (SQLException ex) {
11034  throw new TskCoreException("Error setting acquisition details", ex);
11035  } finally {
11036  closeResultSet(rs);
11037  closeConnection(connection);
11039  }
11040  }
11041 
11052  public void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus) throws TskCoreException {
11053  if (newStatus == null) {
11054  return;
11055  }
11057  try (CaseDbConnection connection = connections.getConnection();
11058  Statement statement = connection.createStatement();) {
11059  connection.executeUpdate(statement, "UPDATE blackboard_artifacts "
11060  + " SET review_status_id=" + newStatus.getID()
11061  + " WHERE blackboard_artifacts.artifact_id = " + artifact.getArtifactID());
11062  } catch (SQLException ex) {
11063  throw new TskCoreException("Error setting review status", ex);
11064  } finally {
11066  }
11067  }
11068 
11079  public int countFsContentType(TskData.TSK_FS_META_TYPE_ENUM contentType) throws TskCoreException {
11080  CaseDbConnection connection = null;
11081  Statement s = null;
11082  ResultSet rs = null;
11084  try {
11085  connection = connections.getConnection();
11086  s = connection.createStatement();
11087  Short contentShort = contentType.getValue();
11088  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files WHERE meta_type = '" + contentShort.toString() + "'"); //NON-NLS
11089  int count = 0;
11090  if (rs.next()) {
11091  count = rs.getInt("count");
11092  }
11093  return count;
11094  } catch (SQLException ex) {
11095  throw new TskCoreException("Error getting number of objects.", ex);
11096  } finally {
11097  closeResultSet(rs);
11098  closeStatement(s);
11099  closeConnection(connection);
11101  }
11102  }
11103 
11112  public static String escapeSingleQuotes(String text) {
11113  String escapedText = null;
11114  if (text != null) {
11115  escapedText = text.replaceAll("'", "''");
11116  }
11117  return escapedText;
11118  }
11119 
11127  public List<AbstractFile> findFilesByMd5(String md5Hash) {
11128  if (md5Hash == null) {
11129  return Collections.<AbstractFile>emptyList();
11130  }
11131 
11132  CaseDbConnection connection = null;
11133  Statement s = null;
11134  ResultSet rs = null;
11136  try {
11137  connection = connections.getConnection();
11138  s = connection.createStatement();
11139  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " //NON-NLS
11140  + " md5 = '" + md5Hash.toLowerCase() + "' " //NON-NLS
11141  + "AND size > 0"); //NON-NLS
11142  return resultSetToAbstractFiles(rs, connection);
11143  } catch (SQLException | TskCoreException ex) {
11144  logger.log(Level.WARNING, "Error querying database.", ex); //NON-NLS
11145  } finally {
11146  closeResultSet(rs);
11147  closeStatement(s);
11148  closeConnection(connection);
11150  }
11151  return Collections.<AbstractFile>emptyList();
11152  }
11153 
11160  public boolean allFilesMd5Hashed() {
11161  boolean allFilesAreHashed = false;
11162 
11163  CaseDbConnection connection = null;
11164  Statement s = null;
11165  ResultSet rs = null;
11167  try {
11168  connection = connections.getConnection();
11169  s = connection.createStatement();
11170  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11171  + "WHERE dir_type = '" + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + "' " //NON-NLS
11172  + "AND md5 IS NULL " //NON-NLS
11173  + "AND size > '0'"); //NON-NLS
11174  if (rs.next() && rs.getInt("count") == 0) {
11175  allFilesAreHashed = true;
11176  }
11177  } catch (SQLException | TskCoreException ex) {
11178  logger.log(Level.WARNING, "Failed to query whether all files have MD5 hashes", ex); //NON-NLS
11179  } finally {
11180  closeResultSet(rs);
11181  closeStatement(s);
11182  closeConnection(connection);
11184  }
11185  return allFilesAreHashed;
11186  }
11187 
11193  public int countFilesMd5Hashed() {
11194  int count = 0;
11195 
11197  CaseDbConnection connection = null;
11198  Statement s = null;
11199  ResultSet rs = null;
11200  try {
11201  connection = connections.getConnection();
11202  s = connection.createStatement();
11203  rs = connection.executeQuery(s, "SELECT COUNT(*) AS count FROM tsk_files " //NON-NLS
11204  + "WHERE md5 IS NOT NULL " //NON-NLS
11205  + "AND size > '0'"); //NON-NLS
11206  if (rs.next()) {
11207  count = rs.getInt("count");
11208  }
11209  } catch (SQLException | TskCoreException ex) {
11210  logger.log(Level.WARNING, "Failed to query for all the files.", ex); //NON-NLS
11211  } finally {
11212  closeResultSet(rs);
11213  closeStatement(s);
11214  closeConnection(connection);
11216  }
11217  return count;
11218 
11219  }
11220 
11229  public List<TagName> getAllTagNames() throws TskCoreException {
11230  CaseDbConnection connection = null;
11231  ResultSet resultSet = null;
11233  try {
11234  connection = connections.getConnection();
11235 
11236  // SELECT * FROM tag_names
11237  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES);
11238  resultSet = connection.executeQuery(statement);
11239  ArrayList<TagName> tagNames = new ArrayList<>();
11240  while (resultSet.next()) {
11241  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11242  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11243  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11244  }
11245  return tagNames;
11246  } catch (SQLException ex) {
11247  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11248  } finally {
11249  closeResultSet(resultSet);
11250  closeConnection(connection);
11252  }
11253  }
11254 
11265  public List<TagName> getTagNamesInUse() throws TskCoreException {
11266  CaseDbConnection connection = null;
11267  ResultSet resultSet = null;
11269  try {
11270  connection = connections.getConnection();
11271 
11272  // 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)
11273  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE);
11274  resultSet = connection.executeQuery(statement);
11275  ArrayList<TagName> tagNames = new ArrayList<>();
11276  while (resultSet.next()) {
11277  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11278  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11279  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11280  }
11281  return tagNames;
11282  } catch (SQLException ex) {
11283  throw new TskCoreException("Error selecting rows from tag_names table", ex);
11284  } finally {
11285  closeResultSet(resultSet);
11286  closeConnection(connection);
11288  }
11289  }
11290 
11303  public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
11304 
11305  ArrayList<TagName> tagNames = new ArrayList<>();
11306  // SELECT * FROM tag_names WHERE tag_name_id IN
11307  // ( 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 = ? "
11308  // UNION
11309  // 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 = ? )
11310  // )
11311  CaseDbConnection connection = null;
11312  ResultSet resultSet = null;
11314  try {
11315  connection = connections.getConnection();
11316 
11317  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE);
11318  statement.setLong(1, dsObjId);
11319  statement.setLong(2, dsObjId);
11320  resultSet = connection.executeQuery(statement); //NON-NLS
11321  while (resultSet.next()) {
11322  tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11323  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11324  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"))); //NON-NLS
11325  }
11326  return tagNames;
11327  } catch (SQLException ex) {
11328  throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex);
11329  } finally {
11330  closeResultSet(resultSet);
11331  closeConnection(connection);
11333  }
11334  }
11335 
11349  @Deprecated
11350  @SuppressWarnings("deprecation")
11351  public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TskCoreException {
11352  return addOrUpdateTagName(displayName, description, color, TskData.FileKnown.UNKNOWN);
11353  }
11354 
11371  @Deprecated
11372  public TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TskCoreException {
11373  return getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus);
11374  }
11375 
11390  @Deprecated
11391  public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
11392  return taggingMgr.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset).getAddedTag();
11393  }
11394 
11395  /*
11396  * Deletes a row from the content_tags table in the case database. @param
11397  * tag A ContentTag data transfer object (DTO) for the row to delete.
11398  * @throws TskCoreException
11399  */
11400  public void deleteContentTag(ContentTag tag) throws TskCoreException {
11402  try {
11403  // DELETE FROM content_tags WHERE tag_id = ?
11404  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_CONTENT_TAG);
11405  statement.clearParameters();
11406  statement.setLong(1, tag.getId());
11407  trans.getConnection().executeUpdate(statement);
11408 
11409  // update the aggregate score for the content
11410  Long contentId = tag.getContent() != null ? tag.getContent().getId() : null;
11411  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11412  ? tag.getContent().getDataSource().getId()
11413  : null;
11414 
11415  this.getScoringManager().updateAggregateScoreAfterDeletion(contentId, dataSourceId, trans);
11416 
11417  trans.commit();
11418  trans = null;
11419  } catch (SQLException ex) {
11420  throw new TskCoreException("Error deleting row from content_tags table (id = " + tag.getId() + ")", ex);
11421  } finally {
11422  if (trans != null) {
11423  trans.rollback();
11424  }
11425  }
11426  }
11427 
11436  public List<ContentTag> getAllContentTags() throws TskCoreException {
11437  CaseDbConnection connection = null;
11438  ResultSet resultSet = null;
11440  try {
11441  connection = connections.getConnection();
11442 
11443  // 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
11444  // FROM content_tags
11445  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11446  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11447  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS);
11448  resultSet = connection.executeQuery(statement);
11449  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11450  while (resultSet.next()) {
11451  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11452  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11453  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11454  Content content = getContentById(resultSet.getLong("obj_id")); //NON-NLS
11455  tags.add(new ContentTag(resultSet.getLong("tag_id"), content, tagName, resultSet.getString("comment"),
11456  resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"))); //NON-NLS
11457  }
11458  return tags;
11459  } catch (SQLException ex) {
11460  throw new TskCoreException("Error selecting rows from content_tags table", ex);
11461  } finally {
11462  closeResultSet(resultSet);
11463  closeConnection(connection);
11465  }
11466  }
11467 
11478  public long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
11479  if (tagName.getId() == Tag.ID_NOT_SET) {
11480  throw new TskCoreException("TagName object is invalid, id not set");
11481  }
11482  CaseDbConnection connection = null;
11483  ResultSet resultSet = null;
11485  try {
11486  connection = connections.getConnection();
11487 
11488  // SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?
11489  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME);
11490  statement.clearParameters();
11491  statement.setLong(1, tagName.getId());
11492  resultSet = connection.executeQuery(statement);
11493  if (resultSet.next()) {
11494  return resultSet.getLong("count");
11495  } else {
11496  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11497  }
11498  } catch (SQLException ex) {
11499  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11500  } finally {
11501  closeResultSet(resultSet);
11502  closeConnection(connection);
11504  }
11505  }
11506 
11522  public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11523 
11524  if (tagName.getId() == Tag.ID_NOT_SET) {
11525  throw new TskCoreException("TagName object is invalid, id not set");
11526  }
11527 
11528  CaseDbConnection connection = null;
11529  ResultSet resultSet = null;
11531  try {
11532  connection = connections.getConnection();
11533 
11534  // "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
11535  // + " AND content_tags.tag_name_id = ? "
11536  // + " AND tsk_files.data_source_obj_id = ? "
11537  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11538  statement.clearParameters();
11539  statement.setLong(1, tagName.getId());
11540  statement.setLong(2, dsObjId);
11541 
11542  resultSet = connection.executeQuery(statement);
11543  if (resultSet.next()) {
11544  return resultSet.getLong("count");
11545  } else {
11546  throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11547  }
11548  } catch (SQLException ex) {
11549  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11550  } finally {
11551  closeResultSet(resultSet);
11552  closeConnection(connection);
11554  }
11555  }
11556 
11567  public ContentTag getContentTagByID(long contentTagID) throws TskCoreException {
11568 
11569  CaseDbConnection connection = null;
11570  ResultSet resultSet = null;
11571  ContentTag tag = null;
11573  try {
11574  connection = connections.getConnection();
11575 
11576  // 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
11577  // FROM content_tags
11578  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11579  // UTER LEFT JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11580  // WHERE tag_id = ?
11581  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAG_BY_ID);
11582  statement.clearParameters();
11583  statement.setLong(1, contentTagID);
11584  resultSet = connection.executeQuery(statement);
11585 
11586  while (resultSet.next()) {
11587  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11588  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11589  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
11590  tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")), tagName,
11591  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name"));
11592  }
11593  resultSet.close();
11594 
11595  } catch (SQLException ex) {
11596  throw new TskCoreException("Error getting content tag with id = " + contentTagID, ex);
11597  } finally {
11598  closeResultSet(resultSet);
11599  closeConnection(connection);
11601  }
11602  return tag;
11603  }
11604 
11616  public List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
11617  if (tagName.getId() == Tag.ID_NOT_SET) {
11618  throw new TskCoreException("TagName object is invalid, id not set");
11619  }
11620  CaseDbConnection connection = null;
11621  ResultSet resultSet = null;
11623  try {
11624  connection = connections.getConnection();
11625 
11626  // 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
11627  // FROM content_tags
11628  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11629  // WHERE tag_name_id = ?
11630  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME);
11631  statement.clearParameters();
11632  statement.setLong(1, tagName.getId());
11633  resultSet = connection.executeQuery(statement);
11634  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11635  while (resultSet.next()) {
11636  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11637  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11638  tags.add(tag);
11639  }
11640  resultSet.close();
11641  return tags;
11642  } catch (SQLException ex) {
11643  throw new TskCoreException("Error getting content_tags rows (tag_name_id = " + tagName.getId() + ")", ex);
11644  } finally {
11645  closeResultSet(resultSet);
11646  closeConnection(connection);
11648  }
11649  }
11650 
11663  public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11664 
11665  CaseDbConnection connection = null;
11666  ResultSet resultSet = null;
11668  try {
11669  connection = connections.getConnection();
11670 
11671  // 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
11672  // FROM content_tags as content_tags, tsk_files as tsk_files
11673  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11674  // WHERE content_tags.obj_id = tsk_files.obj_id
11675  // AND content_tags.tag_name_id = ?
11676  // AND tsk_files.data_source_obj_id = ?
11677  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
11678  statement.clearParameters();
11679  statement.setLong(1, tagName.getId());
11680  statement.setLong(2, dsObjId);
11681  resultSet = connection.executeQuery(statement);
11682  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11683  while (resultSet.next()) {
11684  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), getContentById(resultSet.getLong("obj_id")),
11685  tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11686  tags.add(tag);
11687  }
11688  resultSet.close();
11689  return tags;
11690  } catch (SQLException ex) {
11691  throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + " data source objID : " + dsObjId, ex);
11692  } finally {
11693  closeResultSet(resultSet);
11694  closeConnection(connection);
11696  }
11697  }
11698 
11710  public List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
11711  CaseDbConnection connection = null;
11712  ResultSet resultSet = null;
11714  try {
11715  connection = connections.getConnection();
11716 
11717  // 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
11718  // FROM content_tags
11719  // INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id
11720  // LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id
11721  // WHERE content_tags.obj_id = ?
11722  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_CONTENT_TAGS_BY_CONTENT);
11723  statement.clearParameters();
11724  statement.setLong(1, content.getId());
11725  resultSet = connection.executeQuery(statement);
11726  ArrayList<ContentTag> tags = new ArrayList<ContentTag>();
11727  while (resultSet.next()) {
11728  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11729  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11730  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11731  ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), content, tagName,
11732  resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset"), resultSet.getString("login_name")); //NON-NLS
11733  tags.add(tag);
11734  }
11735  return tags;
11736  } catch (SQLException ex) {
11737  throw new TskCoreException("Error getting content tags data for content (obj_id = " + content.getId() + ")", ex);
11738  } finally {
11739  closeResultSet(resultSet);
11740  closeConnection(connection);
11742  }
11743  }
11744 
11759  @Deprecated
11760  public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
11761  return taggingMgr.addArtifactTag(artifact, tagName, comment).getAddedTag();
11762  }
11763 
11764  /*
11765  * Deletes a row from the blackboard_artifact_tags table in the case
11766  * database. @param tag A BlackboardArtifactTag data transfer object (DTO)
11767  * representing the row to delete. @throws TskCoreException
11768  */
11769  public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
11771  try {
11772  // DELETE FROM blackboard_artifact_tags WHERE tag_id = ?
11773  PreparedStatement statement = trans.getConnection().getPreparedStatement(PREPARED_STATEMENT.DELETE_ARTIFACT_TAG);
11774  statement.clearParameters();
11775  statement.setLong(1, tag.getId());
11776  trans.getConnection().executeUpdate(statement);
11777 
11778  // update the aggregate score for the artifact
11779  Long artifactObjId = tag.getArtifact().getId();
11780  Long dataSourceId = tag.getContent() != null && tag.getContent().getDataSource() != null
11781  ? tag.getContent().getDataSource().getId()
11782  : null;
11783 
11784  this.getScoringManager().updateAggregateScoreAfterDeletion(artifactObjId, dataSourceId, trans);
11785 
11786  trans.commit();
11787  trans = null;
11788  } catch (SQLException ex) {
11789  throw new TskCoreException("Error deleting row from blackboard_artifact_tags table (id = " + tag.getId() + ")", ex);
11790  } finally {
11791  if (trans != null) {
11792  trans.rollback();
11793  }
11794  }
11795  }
11796 
11806  public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
11807  CaseDbConnection connection = null;
11808  ResultSet resultSet = null;
11810  try {
11811  connection = connections.getConnection();
11812 
11813  // 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
11814  // FROM blackboard_artifact_tags
11815  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
11816  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11817  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS);
11818  resultSet = connection.executeQuery(statement);
11819  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
11820  while (resultSet.next()) {
11821  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
11822  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
11823  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
11824  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11825  Content content = getContentById(artifact.getObjectID());
11826  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11827  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11828  tags.add(tag);
11829  }
11830  return tags;
11831  } catch (SQLException ex) {
11832  throw new TskCoreException("Error selecting rows from blackboard_artifact_tags table", ex);
11833  } finally {
11834  closeResultSet(resultSet);
11835  closeConnection(connection);
11837  }
11838  }
11839 
11850  public long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
11851  if (tagName.getId() == Tag.ID_NOT_SET) {
11852  throw new TskCoreException("TagName object is invalid, id not set");
11853  }
11854  CaseDbConnection connection = null;
11855  ResultSet resultSet = null;
11857  try {
11858  connection = connections.getConnection();
11859 
11860  // SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?
11861  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME);
11862  statement.clearParameters();
11863  statement.setLong(1, tagName.getId());
11864  resultSet = connection.executeQuery(statement);
11865  if (resultSet.next()) {
11866  return resultSet.getLong("count");
11867  } else {
11868  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")");
11869  }
11870  } catch (SQLException ex) {
11871  throw new TskCoreException("Error getting blackboard artifact_content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")", ex);
11872  } finally {
11873  closeResultSet(resultSet);
11874  closeConnection(connection);
11876  }
11877  }
11878 
11893  public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11894 
11895  if (tagName.getId() == Tag.ID_NOT_SET) {
11896  throw new TskCoreException("TagName object is invalid, id not set");
11897  }
11898 
11899  CaseDbConnection connection = null;
11900  ResultSet resultSet = null;
11902  try {
11903  connection = connections.getConnection();
11904 
11905  // "SELECT COUNT(*) AS count FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts WHERE artifact_tags.artifact_id = arts.artifact_id"
11906  // + " AND artifact_tags.tag_name_id = ?"
11907  // + " AND arts.data_source_obj_id = ? "
11908  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.COUNT_ARTIFACTS_BY_TAG_NAME_BY_DATASOURCE);
11909  statement.clearParameters();
11910  statement.setLong(1, tagName.getId());
11911  statement.setLong(2, dsObjId);
11912  resultSet = connection.executeQuery(statement);
11913  if (resultSet.next()) {
11914  return resultSet.getLong("count");
11915  } else {
11916  throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId);
11917  }
11918  } catch (SQLException ex) {
11919  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
11920  } finally {
11921  closeResultSet(resultSet);
11922  closeConnection(connection);
11924  }
11925  }
11926 
11938  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
11939  if (tagName.getId() == Tag.ID_NOT_SET) {
11940  throw new TskCoreException("TagName object is invalid, id not set");
11941  }
11942  CaseDbConnection connection = null;
11943  ResultSet resultSet = null;
11945  try {
11946  connection = connections.getConnection();
11947 
11948  // 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
11949  // FROM blackboard_artifact_tags
11950  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
11951  // WHERE tag_name_id = ?
11952  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME);
11953  statement.clearParameters();
11954  statement.setLong(1, tagName.getId());
11955  resultSet = connection.executeQuery(statement);
11956  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
11957  while (resultSet.next()) {
11958  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
11959  Content content = getContentById(artifact.getObjectID());
11960  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
11961  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
11962  tags.add(tag);
11963  }
11964  return tags;
11965  } catch (SQLException ex) {
11966  throw new TskCoreException("Error getting blackboard artifact tags data (tag_name_id = " + tagName.getId() + ")", ex);
11967  } finally {
11968  closeResultSet(resultSet);
11969  closeConnection(connection);
11971  }
11972  }
11973 
11988  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
11989 
11990  if (tagName.getId() == Tag.ID_NOT_SET) {
11991  throw new TskCoreException("TagName object is invalid, id not set");
11992  }
11993 
11994  CaseDbConnection connection = null;
11995  ResultSet resultSet = null;
11997  try {
11998  connection = connections.getConnection();
11999 
12000  // 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
12001  // FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts
12002  // LEFT OUTER JOIN tsk_examiners ON artifact_tags.examiner_id = tsk_examiners.examiner_id
12003  // WHERE artifact_tags.artifact_id = arts.artifact_id
12004  // AND artifact_tags.tag_name_id = ?
12005  // AND arts.data_source_obj_id = ?
12006  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_TAG_NAME_BY_DATASOURCE);
12007  statement.clearParameters();
12008  statement.setLong(1, tagName.getId());
12009  statement.setLong(2, dsObjId);
12010  resultSet = connection.executeQuery(statement);
12011  ArrayList<BlackboardArtifactTag> tags = new ArrayList<BlackboardArtifactTag>();
12012  while (resultSet.next()) {
12013  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12014  Content content = getContentById(artifact.getObjectID());
12015  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12016  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12017  tags.add(tag);
12018  }
12019  return tags;
12020  } catch (SQLException ex) {
12021  throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex);
12022  } finally {
12023  closeResultSet(resultSet);
12024  closeConnection(connection);
12026  }
12027 
12028  }
12029 
12041  public BlackboardArtifactTag getBlackboardArtifactTagByID(long artifactTagID) throws TskCoreException {
12042 
12043  CaseDbConnection connection = null;
12044  ResultSet resultSet = null;
12045  BlackboardArtifactTag tag = null;
12047  try {
12048  connection = connections.getConnection();
12049 
12050  //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
12051  // FROM blackboard_artifact_tags
12052  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12053  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12054  // WHERE blackboard_artifact_tags.tag_id = ?
12055  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAG_BY_ID);
12056  statement.clearParameters();
12057  statement.setLong(1, artifactTagID);
12058  resultSet = connection.executeQuery(statement);
12059 
12060  while (resultSet.next()) {
12061  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12062  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12063  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank"));
12064  BlackboardArtifact artifact = getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS
12065  Content content = getContentById(artifact.getObjectID());
12066  tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12067  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name"));
12068  }
12069  resultSet.close();
12070 
12071  } catch (SQLException ex) {
12072  throw new TskCoreException("Error getting blackboard artifact tag with id = " + artifactTagID, ex);
12073  } finally {
12074  closeResultSet(resultSet);
12075  closeConnection(connection);
12077  }
12078  return tag;
12079  }
12080 
12093  public List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
12094  CaseDbConnection connection = null;
12095  ResultSet resultSet = null;
12097  try {
12098  connection = connections.getConnection();
12099 
12100  // 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
12101  // FROM blackboard_artifact_tags
12102  // INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id
12103  // LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id
12104  // WHERE blackboard_artifact_tags.artifact_id = ?
12105  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_ARTIFACT_TAGS_BY_ARTIFACT);
12106  statement.clearParameters();
12107  statement.setLong(1, artifact.getArtifactID());
12108  resultSet = connection.executeQuery(statement);
12109  ArrayList<BlackboardArtifactTag> tags = new ArrayList<>();
12110  while (resultSet.next()) {
12111  TagName tagName = new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"),
12112  resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")),
12113  TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")), resultSet.getLong("tag_set_id"), resultSet.getInt("rank")); //NON-NLS
12114  Content content = getContentById(artifact.getObjectID());
12115  BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"),
12116  artifact, content, tagName, resultSet.getString("comment"), resultSet.getString("login_name")); //NON-NLS
12117  tags.add(tag);
12118  }
12119  return tags;
12120  } catch (SQLException ex) {
12121  throw new TskCoreException("Error getting blackboard artifact tags data (artifact_id = " + artifact.getArtifactID() + ")", ex);
12122  } finally {
12123  closeResultSet(resultSet);
12124  closeConnection(connection);
12126  }
12127  }
12128 
12137  public void updateImagePath(String newPath, long objectId) throws TskCoreException {
12139  try (CaseDbConnection connection = connections.getConnection();) {
12140  // UPDATE tsk_image_names SET name = ? WHERE obj_id = ?
12141  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.UPDATE_IMAGE_PATH);
12142  statement.clearParameters();
12143  statement.setString(1, newPath);
12144  statement.setLong(2, objectId);
12145  connection.executeUpdate(statement);
12146  } catch (SQLException ex) {
12147  throw new TskCoreException("Error updating image path in database for object " + objectId, ex);
12148  } finally {
12150  }
12151  }
12152 
12166  public Report addReport(String localPath, String sourceModuleName, String reportName) throws TskCoreException {
12167  return addReport(localPath, sourceModuleName, reportName, null);
12168  }
12169 
12185  public Report addReport(String localPath, String sourceModuleName, String reportName, Content parent) throws TskCoreException {
12186  // Make sure the local path of the report is in the database directory
12187  // or one of its subdirectories.
12188  String relativePath = ""; //NON-NLS
12189  long createTime = 0;
12190  String localPathLower = localPath.toLowerCase();
12191 
12192  if (localPathLower.startsWith("http")) {
12193  relativePath = localPathLower;
12194  createTime = System.currentTimeMillis() / 1000;
12195  } else {
12196  /*
12197  * Note: The following call to .relativize() may be dangerous in
12198  * case-sensitive operating systems and should be looked at. For
12199  * now, we are simply relativizing the paths as all lower case, then
12200  * using the length of the result to pull out the appropriate number
12201  * of characters from the localPath String.
12202  */
12203  try {
12204  String casePathLower = getDbDirPath().toLowerCase();
12205  int length = new File(casePathLower).toURI().relativize(new File(localPathLower).toURI()).getPath().length();
12206  relativePath = new File(localPath.substring(localPathLower.length() - length)).getPath();
12207  } catch (IllegalArgumentException ex) {
12208  String errorMessage = String.format("Local path %s not in the database directory or one of its subdirectories", localPath);
12209  throw new TskCoreException(errorMessage, ex);
12210  }
12211  try {
12212  // get its file time
12213  java.io.File tempFile = new java.io.File(localPath);
12214  // Convert to UNIX epoch (seconds, not milliseconds).
12215  createTime = tempFile.lastModified() / 1000;
12216  } catch (Exception ex) {
12217  throw new TskCoreException("Could not get create time for report at " + localPath, ex);
12218  }
12219  }
12220 
12221  // Write the report data to the database.
12223  try (CaseDbConnection connection = connections.getConnection();) {
12224  // Insert a row for the report into the tsk_objects table.
12225  // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
12226  long parentObjId = 0;
12227  if (parent != null) {
12228  parentObjId = parent.getId();
12229  }
12230  long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
12231 
12232  // INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
12233  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
12234  statement.clearParameters();
12235  statement.setLong(1, objectId);
12236  statement.setString(2, relativePath);
12237  statement.setLong(3, createTime);
12238  statement.setString(4, sourceModuleName);
12239  statement.setString(5, reportName);
12240  connection.executeUpdate(statement);
12241  return new Report(this, objectId, localPath, createTime, sourceModuleName, reportName, parent);
12242  } catch (SQLException ex) {
12243  throw new TskCoreException("Error adding report " + localPath + " to reports table", ex);
12244  } finally {
12246  }
12247  }
12248 
12257  public List<Report> getAllReports() throws TskCoreException {
12258  CaseDbConnection connection = null;
12259  ResultSet resultSet = null;
12260  ResultSet parentResultSet = null;
12261  PreparedStatement statement = null;
12262  Statement parentStatement = null;
12264  try {
12265  connection = connections.getConnection();
12266 
12267  // SELECT * FROM reports
12268  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORTS);
12269  parentStatement = connection.createStatement();
12270  resultSet = connection.executeQuery(statement);
12271  ArrayList<Report> reports = new ArrayList<Report>();
12272  while (resultSet.next()) {
12273  String localpath = resultSet.getString("path");
12274  if (localpath.toLowerCase().startsWith("http") == false) {
12275  // make path absolute
12276  localpath = Paths.get(getDbDirPath(), localpath).normalize().toString(); //NON-NLS
12277  }
12278 
12279  // get the report parent
12280  Content parent = null;
12281  long reportId = resultSet.getLong("obj_id"); // NON-NLS
12282  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", reportId);
12283  parentResultSet = parentStatement.executeQuery(parentQuery);
12284  if (parentResultSet.next()) {
12285  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12286  parent = this.getContentById(parentId);
12287  }
12288  parentResultSet.close();
12289 
12290  reports.add(new Report(this,
12291  reportId,
12292  localpath,
12293  resultSet.getLong("crtime"), //NON-NLS
12294  resultSet.getString("src_module_name"), //NON-NLS
12295  resultSet.getString("report_name"),
12296  parent)); //NON-NLS
12297  }
12298  return reports;
12299  } catch (SQLException ex) {
12300  throw new TskCoreException("Error querying reports table", ex);
12301  } finally {
12302  closeResultSet(resultSet);
12303  closeResultSet(parentResultSet);
12304  closeStatement(statement);
12305  closeStatement(parentStatement);
12306 
12307  closeConnection(connection);
12309  }
12310  }
12311 
12321  public Report getReportById(long id) throws TskCoreException {
12322  CaseDbConnection connection = null;
12323  PreparedStatement statement = null;
12324  Statement parentStatement = null;
12325  ResultSet resultSet = null;
12326  ResultSet parentResultSet = null;
12327  Report report = null;
12329  try {
12330  connection = connections.getConnection();
12331 
12332  // SELECT * FROM reports WHERE obj_id = ?
12333  statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_REPORT_BY_ID);
12334  parentStatement = connection.createStatement();
12335  statement.clearParameters();
12336  statement.setLong(1, id);
12337  resultSet = connection.executeQuery(statement);
12338 
12339  if (resultSet.next()) {
12340  // get the report parent
12341  Content parent = null;
12342  String parentQuery = String.format("SELECT * FROM tsk_objects WHERE obj_id = %s;", id);
12343  parentResultSet = parentStatement.executeQuery(parentQuery);
12344  if (parentResultSet.next()) {
12345  long parentId = parentResultSet.getLong("par_obj_id"); // NON-NLS
12346  parent = this.getContentById(parentId);
12347  }
12348 
12349  report = new Report(this, resultSet.getLong("obj_id"), //NON-NLS
12350  Paths.get(getDbDirPath(), resultSet.getString("path")).normalize().toString(), //NON-NLS
12351  resultSet.getLong("crtime"), //NON-NLS
12352  resultSet.getString("src_module_name"), //NON-NLS
12353  resultSet.getString("report_name"),
12354  parent); //NON-NLS
12355  } else {
12356  throw new TskCoreException("No report found for id: " + id);
12357  }
12358  } catch (SQLException ex) {
12359  throw new TskCoreException("Error querying reports table for id: " + id, ex);
12360  } finally {
12361  closeResultSet(resultSet);
12362  closeResultSet(parentResultSet);
12363  closeStatement(statement);
12364  closeStatement(parentStatement);
12365  closeConnection(connection);
12367  }
12368 
12369  return report;
12370  }
12371 
12379  public void deleteReport(Report report) throws TskCoreException {
12381  try (CaseDbConnection connection = connections.getConnection();) {
12382  // DELETE FROM reports WHERE reports.obj_id = ?
12383  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT);
12384  statement.setLong(1, report.getId());
12385  connection.executeUpdate(statement);
12386  // DELETE FROM tsk_objects WHERE tsk_objects.obj_id = ?
12387  statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT_TSK_OBJECT);
12388  statement.setLong(1, report.getId());
12389  statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
12390  connection.executeUpdate(statement);
12391  } catch (SQLException ex) {
12392  throw new TskCoreException("Error querying reports table", ex);
12393  } finally {
12395  }
12396  }
12397 
12398  static void closeResultSet(ResultSet resultSet) {
12399  if (resultSet != null) {
12400  try {
12401  resultSet.close();
12402  } catch (SQLException ex) {
12403  logger.log(Level.SEVERE, "Error closing ResultSet", ex); //NON-NLS
12404  }
12405  }
12406  }
12407 
12408  static void closeStatement(Statement statement) {
12409  if (statement != null) {
12410  try {
12411  statement.close();
12412  } catch (SQLException ex) {
12413  logger.log(Level.SEVERE, "Error closing Statement", ex); //NON-NLS
12414 
12415  }
12416  }
12417  }
12418 
12419  static void closeConnection(CaseDbConnection connection) {
12420  if (connection != null) {
12421  connection.close();
12422  }
12423  }
12424 
12425  private static void rollbackTransaction(CaseDbConnection connection) {
12426  if (connection != null) {
12427  connection.rollbackTransaction();
12428  }
12429  }
12430 
12439  void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException {
12441  try (CaseDbConnection connection = connections.getConnection();) {
12442  Statement statement = connection.createStatement();
12443  statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";");
12444  } catch (SQLException ex) {
12445  throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex);
12446  } finally {
12448  }
12449  }
12450 
12451  void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException {
12453  try (CaseDbConnection connection = connections.getConnection();
12454  Statement statement = connection.createStatement();) {
12455  statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";");
12456  } catch (SQLException ex) {
12457  throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex);
12458  } finally {
12460  }
12461  }
12462 
12479  public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException {
12480  CaseDbConnection connection = null;
12482  ResultSet resultSet = null;
12483  Statement statement;
12484  try {
12485  connection = connections.getConnection();
12486  connection.beginTransaction();
12487  statement = connection.createStatement();
12488  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS);
12489  insertStatement.setLong(1, dataSource.getId());
12490  insertStatement.setString(2, hostName);
12491  insertStatement.setLong(3, jobStart.getTime());
12492  insertStatement.setLong(4, jobEnd.getTime());
12493  insertStatement.setInt(5, status.ordinal());
12494  insertStatement.setString(6, settingsDir);
12495  connection.executeUpdate(insertStatement);
12496  resultSet = insertStatement.getGeneratedKeys();
12497  resultSet.next();
12498  long id = resultSet.getLong(1); //last_insert_rowid()
12499  for (int i = 0; i < ingestModules.size(); i++) {
12500  IngestModuleInfo ingestModule = ingestModules.get(i);
12501  statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) "
12502  + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");");
12503  }
12504  resultSet.close();
12505  resultSet = null;
12506  connection.commitTransaction();
12507  return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this);
12508  } catch (SQLException ex) {
12509  rollbackTransaction(connection);
12510  throw new TskCoreException("Error adding the ingest job.", ex);
12511  } finally {
12512  closeResultSet(resultSet);
12513  closeConnection(connection);
12515  }
12516  }
12517 
12531  public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException {
12532  CaseDbConnection connection = null;
12533  ResultSet resultSet = null;
12534  Statement statement = null;
12535  String uniqueName = factoryClassName + "-" + displayName + "-" + version;
12537  try {
12538  connection = connections.getConnection();
12539  statement = connection.createStatement();
12540  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12541  if (!resultSet.next()) {
12542  resultSet.close();
12543  resultSet = null;
12544  PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS);
12545  insertStatement.setString(1, displayName);
12546  insertStatement.setString(2, uniqueName);
12547  insertStatement.setInt(3, type.ordinal());
12548  insertStatement.setString(4, version);
12549  connection.executeUpdate(insertStatement);
12550  resultSet = statement.getGeneratedKeys();
12551  resultSet.next();
12552  long id = resultSet.getLong(1); //last_insert_rowid()
12553  resultSet.close();
12554  resultSet = null;
12555  return new IngestModuleInfo(id, displayName, uniqueName, type, version);
12556  } else {
12557  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12558  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12559  }
12560  } catch (SQLException ex) {
12561  try {
12562  closeStatement(statement);
12563  if (connection != null) {
12564  statement = connection.createStatement();
12565  resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'");
12566  if (resultSet.next()) {
12567  return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12568  uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"));
12569  }
12570  }
12571  throw new TskCoreException("Couldn't add new module to database.", ex);
12572  } catch (SQLException ex1) {
12573  throw new TskCoreException("Couldn't add new module to database.", ex1);
12574  }
12575  } finally {
12576  closeResultSet(resultSet);
12577  closeStatement(statement);
12578  closeConnection(connection);
12580  }
12581  }
12582 
12590  public final List<IngestJobInfo> getIngestJobs() throws TskCoreException {
12591  CaseDbConnection connection = null;
12592  ResultSet resultSet = null;
12593  Statement statement = null;
12594  List<IngestJobInfo> ingestJobs = new ArrayList<>();
12596  try {
12597  connection = connections.getConnection();
12598  statement = connection.createStatement();
12599  resultSet = statement.executeQuery("SELECT * FROM ingest_jobs");
12600  while (resultSet.next()) {
12601  ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"),
12602  resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")),
12603  new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")),
12604  resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this));
12605  }
12606  return ingestJobs;
12607  } catch (SQLException ex) {
12608  throw new TskCoreException("Couldn't get the ingest jobs.", ex);
12609  } finally {
12610  closeResultSet(resultSet);
12611  closeStatement(statement);
12612  closeConnection(connection);
12614  }
12615  }
12616 
12627  private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException {
12628  ResultSet resultSet = null;
12629  Statement statement = null;
12630  List<IngestModuleInfo> ingestModules = new ArrayList<>();
12632  try {
12633  statement = connection.createStatement();
12634  resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id AS ingest_module_id, "
12635  + "ingest_job_modules.pipeline_position AS pipeline_position, "
12636  + "ingest_modules.display_name AS display_name, ingest_modules.unique_name AS unique_name, "
12637  + "ingest_modules.type_id AS type_id, ingest_modules.version AS version "
12638  + "FROM ingest_job_modules, ingest_modules "
12639  + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " "
12640  + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id "
12641  + "ORDER BY (ingest_job_modules.pipeline_position);");
12642  while (resultSet.next()) {
12643  ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"),
12644  resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")));
12645  }
12646  return ingestModules;
12647  } finally {
12648  closeResultSet(resultSet);
12649  closeStatement(statement);
12651 
12652  }
12653  }
12654 
12664  String getInsertOrIgnoreSQL(String sql) {
12665  switch (getDatabaseType()) {
12666  case POSTGRESQL:
12667  return " INSERT " + sql + " ON CONFLICT DO NOTHING "; //NON-NLS
12668  case SQLITE:
12669  return " INSERT OR IGNORE " + sql; //NON-NLS
12670  default:
12671  throw new UnsupportedOperationException("Unsupported DB type: " + getDatabaseType().name());
12672  }
12673  }
12674 
12695  private List<? extends BlackboardArtifact> getArtifactsForValues(BlackboardArtifact.Category category, String dbColumn, List<? extends Number> values, CaseDbConnection connection) throws TskCoreException {
12696  String where = "";
12697  // This look creates the OR statment with the following format:
12698  // <dbColumn> = <value> OR <dbColumn> = <value2> OR ...
12699  for (Number value : values) {
12700  if (!where.isEmpty()) {
12701  where += " OR ";
12702  }
12703  where += dbColumn + " = " + value;
12704  }
12705 
12706  // Base on the category pass the OR statement to the approprate method
12707  // that will retrieve the artifacts.
12708  if (category == BlackboardArtifact.Category.DATA_ARTIFACT) {
12709  return blackboard.getDataArtifactsWhere(where, connection);
12710  } else {
12711  return blackboard.getAnalysisResultsWhere(where, connection);
12712  }
12713  }
12714 
12718  static class ObjectInfo {
12719 
12720  private long id;
12721  private TskData.ObjectType type;
12722 
12723  ObjectInfo(long id, ObjectType type) {
12724  this.id = id;
12725  this.type = type;
12726  }
12727 
12728  long getId() {
12729  return id;
12730  }
12731 
12732  TskData.ObjectType getType() {
12733  return type;
12734  }
12735  }
12736 
12737  private interface DbCommand {
12738 
12739  void execute() throws SQLException;
12740  }
12741 
12742  private enum PREPARED_STATEMENT {
12743 
12744  SELECT_ARTIFACTS_BY_TYPE("SELECT artifact_id, obj_id FROM blackboard_artifacts " //NON-NLS
12745  + "WHERE artifact_type_id = ?"), //NON-NLS
12746  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
12747  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
12748  COUNT_ARTIFACTS_FROM_SOURCE("SELECT COUNT(*) AS count FROM blackboard_artifacts WHERE obj_id = ? AND review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()), //NON-NLS
12749  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
12750  SELECT_FILES_BY_PARENT("SELECT tsk_files.* " //NON-NLS
12751  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12752  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12753  + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS
12754  + "ORDER BY tsk_files.meta_type DESC, LOWER(tsk_files.name)"), //NON-NLS
12755  SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS
12756  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12757  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12758  + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS
12759  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12760  SELECT_FILES_BY_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12761  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12762  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12763  + "WHERE (tsk_objects.par_obj_id = ? AND " //NON-NLS
12764  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12765  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12766  SELECT_FILES_BY_EXTENSION_AND_PARENT_AND_NAME("SELECT tsk_files.* " //NON-NLS
12767  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12768  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12769  + "WHERE tsk_files.extension = ? AND "
12770  + "(tsk_objects.par_obj_id = ? AND " //NON-NLS
12771  + "LOWER(tsk_files.name) LIKE LOWER(?) AND LOWER(tsk_files.name) NOT LIKE LOWER('%journal%')) "//NON-NLS
12772  + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS
12773  SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12774  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12775  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12776  + "WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS
12777  SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id AS obj_id " //NON-NLS
12778  + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS
12779  + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS
12780  + "WHERE (tsk_objects.par_obj_id = ? " //NON-NLS
12781  + "AND tsk_files.type = ? )"), //NON-NLS
12782  SELECT_FILE_BY_ID("SELECT * FROM tsk_files WHERE obj_id = ? LIMIT 1"), //NON-NLS
12783  SELECT_ARTIFACT_BY_ARTIFACT_OBJ_ID("SELECT * FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12784  SELECT_ARTIFACT_TYPE_BY_ARTIFACT_OBJ_ID("SELECT artifact_type_id FROM blackboard_artifacts WHERE artifact_obj_id = ? LIMIT 1"),
12785  SELECT_ARTIFACT_BY_ARTIFACT_ID("SELECT * FROM blackboard_artifacts WHERE artifact_id = ? LIMIT 1"),
12786  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
12787  + "VALUES (?, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12788  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
12789  + "VALUES (DEFAULT, ?, ?, ?, ?," + BlackboardArtifact.ReviewStatus.UNDECIDED.getID() + ")"), //NON-NLS
12790  INSERT_ANALYSIS_RESULT("INSERT INTO tsk_analysis_results (artifact_obj_id, conclusion, significance, priority, configuration, justification) " //NON-NLS
12791  + "VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12792  INSERT_STRING_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_text) " //NON-NLS
12793  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12794  INSERT_BYTE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte) " //NON-NLS
12795  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12796  INSERT_INT_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int32) " //NON-NLS
12797  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12798  INSERT_LONG_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_int64) " //NON-NLS
12799  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12800  INSERT_DOUBLE_ATTRIBUTE("INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_double) " //NON-NLS
12801  + "VALUES (?,?,?,?,?,?,?)"), //NON-NLS
12802  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
12803  + "VALUES (?,?,?,?,?,?,?,?)"), //NON-NLS
12804  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
12805  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
12806  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
12807  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
12808  UPDATE_FILE_MD5("UPDATE tsk_files SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12809  UPDATE_IMAGE_MD5("UPDATE tsk_image_info SET md5 = ? WHERE obj_id = ?"), //NON-NLS
12810  UPDATE_IMAGE_SHA1("UPDATE tsk_image_info SET sha1 = ? WHERE obj_id = ?"), //NON-NLS
12811  UPDATE_IMAGE_SHA256("UPDATE tsk_image_info SET sha256 = ? WHERE obj_id = ?"), //NON-NLS
12812  SELECT_IMAGE_MD5("SELECT md5 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12813  SELECT_IMAGE_SHA1("SELECT sha1 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12814  SELECT_IMAGE_SHA256("SELECT sha256 FROM tsk_image_info WHERE obj_id = ?"), //NON-NLS
12815  UPDATE_ACQUISITION_DETAILS("UPDATE data_source_info SET acquisition_details = ? WHERE obj_id = ?"), //NON-NLS
12816  UPDATE_ACQUISITION_TOOL_SETTINGS("UPDATE data_source_info SET acquisition_tool_settings = ?, acquisition_tool_name = ?, acquisition_tool_version = ? WHERE obj_id = ?"), //NON-NLS
12817  SELECT_ACQUISITION_DETAILS("SELECT acquisition_details FROM data_source_info WHERE obj_id = ?"), //NON-NLS
12818  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
12819  SELECT_LOCAL_PATH_FOR_FILE("SELECT path FROM tsk_files_path WHERE obj_id = ?"), //NON-NLS
12820  SELECT_ENCODING_FOR_FILE("SELECT encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON-NLS
12821  SELECT_LOCAL_PATH_AND_ENCODING_FOR_FILE("SELECT path, encoding_type FROM tsk_files_path WHERE obj_id = ?"), // NON_NLS
12822  SELECT_PATH_FOR_FILE("SELECT parent_path FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12823  SELECT_FILE_NAME("SELECT name FROM tsk_files WHERE obj_id = ?"), //NON-NLS
12824  SELECT_DERIVED_FILE("SELECT derived_id, rederive FROM tsk_files_derived WHERE obj_id = ?"), //NON-NLS
12825  SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS
12826  SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS
12827  INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS
12828  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
12829  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
12830  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 )"
12831  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
12832  UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? "
12833  + "WHERE obj_id = ?"), //NON-NLS
12834  INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
12835  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12836  INSERT_LOCAL_PATH("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (?, ?, ?)"), //NON-NLS
12837  UPDATE_LOCAL_PATH("UPDATE tsk_files_path SET path = ?, encoding_type = ? WHERE obj_id = ?"), //NON-NLS
12838  COUNT_CHILD_OBJECTS_BY_PARENT("SELECT COUNT(obj_id) AS count FROM tsk_objects WHERE par_obj_id = ?"), //NON-NLS
12839  SELECT_FILE_SYSTEM_BY_OBJECT("SELECT fs_obj_id from tsk_files WHERE obj_id=?"), //NON-NLS
12840  SELECT_TAG_NAMES("SELECT * FROM tag_names"), //NON-NLS
12841  SELECT_TAG_NAMES_IN_USE("SELECT * FROM tag_names " //NON-NLS
12842  + "WHERE tag_name_id IN " //NON-NLS
12843  + "(SELECT tag_name_id from content_tags UNION SELECT tag_name_id FROM blackboard_artifact_tags)"), //NON-NLS
12844  SELECT_TAG_NAMES_IN_USE_BY_DATASOURCE("SELECT * FROM tag_names "
12845  + "WHERE tag_name_id IN "
12846  + "( SELECT content_tags.tag_name_id as tag_name_id "
12847  + "FROM content_tags as content_tags, tsk_files as tsk_files"
12848  + " WHERE content_tags.obj_id = tsk_files.obj_id"
12849  + " AND tsk_files.data_source_obj_id = ?"
12850  + " UNION "
12851  + "SELECT artifact_tags.tag_name_id as tag_name_id "
12852  + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts "
12853  + " WHERE artifact_tags.artifact_id = arts.artifact_id"
12854  + " AND arts.data_source_obj_id = ?"
12855  + " )"),
12856  INSERT_TAG_NAME("INSERT INTO tag_names (display_name, description, color, knownStatus) VALUES (?, ?, ?, ?)"), //NON-NLS
12857  INSERT_CONTENT_TAG("INSERT INTO content_tags (obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12858  DELETE_CONTENT_TAG("DELETE FROM content_tags WHERE tag_id = ?"), //NON-NLS
12859  COUNT_CONTENT_TAGS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM content_tags WHERE tag_name_id = ?"), //NON-NLS
12860  COUNT_CONTENT_TAGS_BY_TAG_NAME_BY_DATASOURCE(
12861  "SELECT COUNT(*) AS count FROM content_tags as content_tags, tsk_files as tsk_files WHERE content_tags.obj_id = tsk_files.obj_id"
12862  + " AND content_tags.tag_name_id = ? "
12863  + " AND tsk_files.data_source_obj_id = ? "
12864  ),
12865  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 "
12866  + "FROM content_tags "
12867  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12868  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12869  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 "
12870  + "FROM content_tags "
12871  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12872  + "WHERE tag_name_id = ?"), //NON-NLS
12873  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 "
12874  + "FROM content_tags as content_tags, tsk_files as tsk_files, tag_names as tag_names, tsk_examiners as tsk_examiners "
12875  + "WHERE content_tags.examiner_id = tsk_examiners.examiner_id"
12876  + " AND content_tags.obj_id = tsk_files.obj_id"
12877  + " AND content_tags.tag_name_id = tag_names.tag_name_id"
12878  + " AND content_tags.tag_name_id = ?"
12879  + " AND tsk_files.data_source_obj_id = ? "),
12880  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 "
12881  + "FROM content_tags "
12882  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12883  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12884  + "WHERE tag_id = ?"), //NON-NLS
12885  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 "
12886  + "FROM content_tags "
12887  + "INNER JOIN tag_names ON content_tags.tag_name_id = tag_names.tag_name_id "
12888  + "LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id "
12889  + "WHERE content_tags.obj_id = ?"), //NON-NLS
12890  INSERT_ARTIFACT_TAG("INSERT INTO blackboard_artifact_tags (artifact_id, tag_name_id, comment, examiner_id) "
12891  + "VALUES (?, ?, ?, ?)"), //NON-NLS
12892  DELETE_ARTIFACT_TAG("DELETE FROM blackboard_artifact_tags WHERE tag_id = ?"), //NON-NLS
12893  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 "
12894  + "FROM blackboard_artifact_tags "
12895  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12896  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id"), //NON-NLS
12897  COUNT_ARTIFACTS_BY_TAG_NAME("SELECT COUNT(*) AS count FROM blackboard_artifact_tags WHERE tag_name_id = ?"), //NON-NLS
12898  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"
12899  + " AND artifact_tags.tag_name_id = ?"
12900  + " AND arts.data_source_obj_id = ? "),
12901  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 "
12902  + "FROM blackboard_artifact_tags "
12903  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12904  + "WHERE tag_name_id = ?"), //NON-NLS
12905  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 "
12906  + "FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts, tsk_examiners AS tsk_examiners "
12907  + "WHERE artifact_tags.examiner_id = tsk_examiners.examiner_id"
12908  + " AND artifact_tags.artifact_id = arts.artifact_id"
12909  + " AND artifact_tags.tag_name_id = ? "
12910  + " AND arts.data_source_obj_id = ? "),
12911  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 "
12912  + "FROM blackboard_artifact_tags "
12913  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12914  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12915  + "WHERE blackboard_artifact_tags.tag_id = ?"), //NON-NLS
12916  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 "
12917  + "FROM blackboard_artifact_tags "
12918  + "INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id "
12919  + "LEFT OUTER JOIN tsk_examiners ON blackboard_artifact_tags.examiner_id = tsk_examiners.examiner_id "
12920  + "WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS
12921  SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS
12922  SELECT_REPORT_BY_ID("SELECT * FROM reports WHERE obj_id = ?"), //NON-NLS
12923  INSERT_REPORT("INSERT INTO reports (obj_id, path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?, ?)"), //NON-NLS
12924  DELETE_REPORT("DELETE FROM reports WHERE reports.obj_id = ?"), //NON-NLS
12925  DELETE_REPORT_TSK_OBJECT("DELETE FROM tsk_objects where tsk_objects.obj_id = ? and tsk_objects.type = ?"),
12926  INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS
12927  INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"), //NON-NLS
12928  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
12929  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
12930  UPDATE_IMAGE_PATH("UPDATE tsk_image_names SET name = ? WHERE obj_id = ?"), // NON-NLS
12931  SELECT_ARTIFACT_OBJECTIDS_BY_PARENT("SELECT blackboard_artifacts.artifact_obj_id AS artifact_obj_id " //NON-NLS
12932  + "FROM tsk_objects INNER JOIN blackboard_artifacts " //NON-NLS
12933  + "ON tsk_objects.obj_id=blackboard_artifacts.obj_id " //NON-NLS
12934  + "WHERE (tsk_objects.par_obj_id = ?)"),
12935  SELECT_EXAMINER_BY_ID("SELECT * FROM tsk_examiners WHERE examiner_id = ?"),
12936  SELECT_EXAMINER_BY_LOGIN_NAME("SELECT * FROM tsk_examiners WHERE login_name = ?"),
12937  INSERT_EXAMINER_POSTGRESQL("INSERT INTO tsk_examiners (login_name) VALUES (?) ON CONFLICT DO NOTHING"),
12938  INSERT_EXAMINER_SQLITE("INSERT OR IGNORE INTO tsk_examiners (login_name) VALUES (?)"),
12939  UPDATE_FILE_NAME("UPDATE tsk_files SET name = ? WHERE obj_id = ?"),
12940  UPDATE_IMAGE_NAME("UPDATE tsk_image_info SET display_name = ? WHERE obj_id = ?"),
12941  UPDATE_IMAGE_SIZES("UPDATE tsk_image_info SET size = ?, ssize = ? WHERE obj_id = ?"),
12942  DELETE_IMAGE_NAME("DELETE FROM tsk_image_names WHERE obj_id = ?"),
12943  INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"),
12944  INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
12945  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
12946  INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"),
12947  INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
12948  INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
12949  INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
12950  INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"),
12951  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)"
12952  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
12953  SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?");
12954 
12955  private final String sql;
12956 
12957  private PREPARED_STATEMENT(String sql) {
12958  this.sql = sql;
12959  }
12960 
12961  String getSQL() {
12962  return sql;
12963  }
12964  }
12965 
12971  abstract private class ConnectionPool {
12972 
12973  private PooledDataSource pooledDataSource;
12974 
12975  public ConnectionPool() {
12976  pooledDataSource = null;
12977  }
12978 
12979  CaseDbConnection getConnection() throws TskCoreException {
12980  if (pooledDataSource == null) {
12981  throw new TskCoreException("Error getting case database connection - case is closed");
12982  }
12983  try {
12984  return getPooledConnection();
12985  } catch (SQLException exp) {
12986  throw new TskCoreException(exp.getMessage());
12987  }
12988  }
12989 
12990  void close() throws TskCoreException {
12991  if (pooledDataSource != null) {
12992  try {
12993  pooledDataSource.close();
12994  } catch (SQLException exp) {
12995  throw new TskCoreException(exp.getMessage());
12996  } finally {
12997  pooledDataSource = null;
12998  }
12999  }
13000  }
13001 
13002  abstract CaseDbConnection getPooledConnection() throws SQLException;
13003 
13004  public PooledDataSource getPooledDataSource() {
13005  return pooledDataSource;
13006  }
13007 
13008  public void setPooledDataSource(PooledDataSource pooledDataSource) {
13009  this.pooledDataSource = pooledDataSource;
13010  }
13011  }
13012 
13017  private final class SQLiteConnections extends ConnectionPool {
13018 
13019  private final Map<String, String> configurationOverrides = new HashMap<String, String>();
13020 
13021  SQLiteConnections(String dbPath) throws SQLException {
13022  configurationOverrides.put("acquireIncrement", "2");
13023  configurationOverrides.put("initialPoolSize", "5");
13024  configurationOverrides.put("minPoolSize", "5");
13025  /*
13026  * NOTE: max pool size and max statements are related. If you
13027  * increase max pool size, then also increase statements.
13028  */
13029  configurationOverrides.put("maxPoolSize", "20");
13030  configurationOverrides.put("maxStatements", "200");
13031  configurationOverrides.put("maxStatementsPerConnection", "20");
13032 
13033  SQLiteConfig config = new SQLiteConfig();
13034  config.setSynchronous(SQLiteConfig.SynchronousMode.OFF); // Reduce I/O operations, we have no OS crash recovery anyway.
13035  config.setReadUncommited(true);
13036  config.enforceForeignKeys(true); // Enforce foreign key constraints.
13037  SQLiteDataSource unpooled = new SQLiteDataSource(config);
13038  unpooled.setUrl("jdbc:sqlite:" + dbPath);
13039  setPooledDataSource((PooledDataSource) DataSources.pooledDataSource(unpooled, configurationOverrides));
13040  }
13041 
13042  @Override
13043  public CaseDbConnection getPooledConnection() throws SQLException {
13044  // If the requesting thread already has an open transaction, the new connection may get SQLITE_BUSY errors.
13045  if (CaseDbTransaction.hasOpenTransaction(Thread.currentThread().getId())) {
13046  // Temporarily filter out Image Gallery threads
13047  if (!Thread.currentThread().getName().contains("ImageGallery")) {
13048  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());
13049  }
13050  }
13051  return new SQLiteConnection(getPooledDataSource().getConnection());
13052  }
13053  }
13054 
13059  private final class PostgreSQLConnections extends ConnectionPool {
13060 
13061  PostgreSQLConnections(String host, int port, String dbName, String userName, String password) throws PropertyVetoException, UnsupportedEncodingException {
13062  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
13063  comboPooledDataSource.setDriverClass("org.postgresql.Driver"); //loads the jdbc driver
13064  comboPooledDataSource.setJdbcUrl("jdbc:postgresql://" + host + ":" + port + "/"
13065  + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()));
13066  comboPooledDataSource.setUser(userName);
13067  comboPooledDataSource.setPassword(password);
13068  comboPooledDataSource.setAcquireIncrement(2);
13069  comboPooledDataSource.setInitialPoolSize(5);
13070  comboPooledDataSource.setMinPoolSize(5);
13071  /*
13072  * NOTE: max pool size and max statements are related. If you
13073  * increase max pool size, then also increase statements.
13074  */
13075  comboPooledDataSource.setMaxPoolSize(20);
13076  comboPooledDataSource.setMaxStatements(200);
13077  comboPooledDataSource.setMaxStatementsPerConnection(20);
13078  setPooledDataSource(comboPooledDataSource);
13079  }
13080 
13081  @Override
13082  public CaseDbConnection getPooledConnection() throws SQLException {
13083  return new PostgreSQLConnection(getPooledDataSource().getConnection());
13084  }
13085  }
13086 
13090  abstract class CaseDbConnection implements AutoCloseable {
13091 
13092  static final int SLEEP_LENGTH_IN_MILLISECONDS = 5000;
13093  static final int MAX_RETRIES = 20; //MAX_RETRIES * SLEEP_LENGTH_IN_MILLESECONDS = max time to hang attempting connection
13094 
13095  private class CreateStatement implements DbCommand {
13096 
13097  private final Connection connection;
13098  private Statement statement = null;
13099 
13100  CreateStatement(Connection connection) {
13101  this.connection = connection;
13102  }
13103 
13104  Statement getStatement() {
13105  return statement;
13106  }
13107 
13108  @Override
13109  public void execute() throws SQLException {
13110  statement = connection.createStatement();
13111  }
13112  }
13113 
13114  private class SetAutoCommit implements DbCommand {
13115 
13116  private final Connection connection;
13117  private final boolean mode;
13118 
13119  SetAutoCommit(Connection connection, boolean mode) {
13120  this.connection = connection;
13121  this.mode = mode;
13122  }
13123 
13124  @Override
13125  public void execute() throws SQLException {
13126  connection.setAutoCommit(mode);
13127  }
13128  }
13129 
13130  private class Commit implements DbCommand {
13131 
13132  private final Connection connection;
13133 
13134  Commit(Connection connection) {
13135  this.connection = connection;
13136  }
13137 
13138  @Override
13139  public void execute() throws SQLException {
13140  connection.commit();
13141  }
13142  }
13143 
13152  private class AggregateScoreTablePostgreSQLWriteLock implements DbCommand {
13153 
13154  private final Connection connection;
13155 
13156  AggregateScoreTablePostgreSQLWriteLock(Connection connection) {
13157  this.connection = connection;
13158  }
13159 
13160  @Override
13161  public void execute() throws SQLException {
13162  PreparedStatement preparedStatement = connection.prepareStatement("LOCK TABLE ONLY tsk_aggregate_score in SHARE ROW EXCLUSIVE MODE");
13163  preparedStatement.execute();
13164 
13165  }
13166  }
13167 
13168  private class ExecuteQuery implements DbCommand {
13169 
13170  private final Statement statement;
13171  private final String query;
13172  private ResultSet resultSet;
13173 
13174  ExecuteQuery(Statement statement, String query) {
13175  this.statement = statement;
13176  this.query = query;
13177  }
13178 
13179  ResultSet getResultSet() {
13180  return resultSet;
13181  }
13182 
13183  @Override
13184  public void execute() throws SQLException {
13185  resultSet = statement.executeQuery(query);
13186  }
13187  }
13188 
13189  private class ExecutePreparedStatementQuery implements DbCommand {
13190 
13191  private final PreparedStatement preparedStatement;
13192  private ResultSet resultSet;
13193 
13194  ExecutePreparedStatementQuery(PreparedStatement preparedStatement) {
13195  this.preparedStatement = preparedStatement;
13196  }
13197 
13198  ResultSet getResultSet() {
13199  return resultSet;
13200  }
13201 
13202  @Override
13203  public void execute() throws SQLException {
13204  resultSet = preparedStatement.executeQuery();
13205  }
13206  }
13207 
13208  private class ExecutePreparedStatementUpdate implements DbCommand {
13209 
13210  private final PreparedStatement preparedStatement;
13211 
13212  ExecutePreparedStatementUpdate(PreparedStatement preparedStatement) {
13213  this.preparedStatement = preparedStatement;
13214  }
13215 
13216  @Override
13217  public void execute() throws SQLException {
13218  preparedStatement.executeUpdate();
13219  }
13220  }
13221 
13222  private class ExecuteStatementUpdate implements DbCommand {
13223 
13224  private final Statement statement;
13225  private final String updateCommand;
13226 
13227  ExecuteStatementUpdate(Statement statement, String updateCommand) {
13228  this.statement = statement;
13229  this.updateCommand = updateCommand;
13230  }
13231 
13232  @Override
13233  public void execute() throws SQLException {
13234  statement.executeUpdate(updateCommand);
13235  }
13236  }
13237 
13238  private class ExecuteStatementUpdateGenerateKeys implements DbCommand {
13239 
13240  private final Statement statement;
13241  private final int generateKeys;
13242  private final String updateCommand;
13243 
13244  ExecuteStatementUpdateGenerateKeys(Statement statement, String updateCommand, int generateKeys) {
13245  this.statement = statement;
13246  this.generateKeys = generateKeys;
13247  this.updateCommand = updateCommand;
13248  }
13249 
13250  @Override
13251  public void execute() throws SQLException {
13252  statement.executeUpdate(updateCommand, generateKeys);
13253  }
13254  }
13255 
13256  private class PrepareStatement implements DbCommand {
13257 
13258  private final Connection connection;
13259  private final String input;
13260  private PreparedStatement preparedStatement = null;
13261 
13262  PrepareStatement(Connection connection, String input) {
13263  this.connection = connection;
13264  this.input = input;
13265  }
13266 
13267  PreparedStatement getPreparedStatement() {
13268  return preparedStatement;
13269  }
13270 
13271  @Override
13272  public void execute() throws SQLException {
13273  preparedStatement = connection.prepareStatement(input);
13274  }
13275  }
13276 
13277  private class PrepareStatementGenerateKeys implements DbCommand {
13278 
13279  private final Connection connection;
13280  private final String input;
13281  private final int generateKeys;
13282  private PreparedStatement preparedStatement = null;
13283 
13284  PrepareStatementGenerateKeys(Connection connection, String input, int generateKeysInput) {
13285  this.connection = connection;
13286  this.input = input;
13287  this.generateKeys = generateKeysInput;
13288  }
13289 
13290  PreparedStatement getPreparedStatement() {
13291  return preparedStatement;
13292  }
13293 
13294  @Override
13295  public void execute() throws SQLException {
13296  preparedStatement = connection.prepareStatement(input, generateKeys);
13297  }
13298  }
13299 
13300  abstract void executeCommand(DbCommand command) throws SQLException;
13301 
13302  private final Connection connection;
13303  private final Map<PREPARED_STATEMENT, PreparedStatement> preparedStatements;
13304  private final Map<String, PreparedStatement> adHocPreparedStatements;
13305 
13306  CaseDbConnection(Connection connection) {
13307  this.connection = connection;
13308  preparedStatements = new EnumMap<PREPARED_STATEMENT, PreparedStatement>(PREPARED_STATEMENT.class);
13309  adHocPreparedStatements = new HashMap<>();
13310  }
13311 
13312  boolean isOpen() {
13313  return this.connection != null;
13314  }
13315 
13316  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey) throws SQLException {
13317  return getPreparedStatement(statementKey, Statement.NO_GENERATED_KEYS);
13318  }
13319 
13320  PreparedStatement getPreparedStatement(PREPARED_STATEMENT statementKey, int generateKeys) throws SQLException {
13321  // Lazy statement preparation.
13322  PreparedStatement statement;
13323  if (this.preparedStatements.containsKey(statementKey)) {
13324  statement = this.preparedStatements.get(statementKey);
13325  } else {
13326  statement = prepareStatement(statementKey.getSQL(), generateKeys);
13327  this.preparedStatements.put(statementKey, statement);
13328  }
13329  return statement;
13330  }
13331 
13343  PreparedStatement getPreparedStatement(String sqlStatement, int generateKeys) throws SQLException {
13344  PreparedStatement statement;
13345  String statementKey = "SQL:" + sqlStatement + " Key:" + generateKeys;
13346  if (adHocPreparedStatements.containsKey(statementKey)) {
13347  statement = this.adHocPreparedStatements.get(statementKey);
13348  } else {
13349  statement = prepareStatement(sqlStatement, generateKeys);
13350  this.adHocPreparedStatements.put(statementKey, statement);
13351  }
13352  return statement;
13353  }
13354 
13355  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13356  PrepareStatement prepareStatement = new PrepareStatement(this.getConnection(), sqlStatement);
13357  executeCommand(prepareStatement);
13358  return prepareStatement.getPreparedStatement();
13359  }
13360 
13361  Statement createStatement() throws SQLException {
13362  CreateStatement createStatement = new CreateStatement(this.connection);
13363  executeCommand(createStatement);
13364  return createStatement.getStatement();
13365  }
13366 
13367  void beginTransaction() throws SQLException {
13368  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, false);
13369  executeCommand(setAutoCommit);
13370  }
13371 
13372  void commitTransaction() throws SQLException {
13373  Commit commit = new Commit(connection);
13374  executeCommand(commit);
13375  // You must turn auto commit back on when done with the transaction.
13376  SetAutoCommit setAutoCommit = new SetAutoCommit(connection, true);
13377  executeCommand(setAutoCommit);
13378  }
13379 
13385  void rollbackTransaction() {
13386  try {
13387  connection.rollback();
13388  } catch (SQLException e) {
13389  logger.log(Level.SEVERE, "Error rolling back transaction", e);
13390  }
13391  try {
13392  connection.setAutoCommit(true);
13393  } catch (SQLException e) {
13394  logger.log(Level.SEVERE, "Error restoring auto-commit", e);
13395  }
13396  }
13397 
13405  void rollbackTransactionWithThrow() throws SQLException {
13406  try {
13407  connection.rollback();
13408  } finally {
13409  connection.setAutoCommit(true);
13410  }
13411  }
13412 
13421  void getAggregateScoreTableWriteLock() throws SQLException, TskCoreException {
13422  switch (getDatabaseType()) {
13423  case POSTGRESQL:
13424  AggregateScoreTablePostgreSQLWriteLock tableWriteLock = new AggregateScoreTablePostgreSQLWriteLock(connection);
13425  executeCommand(tableWriteLock);
13426  break;
13427  case SQLITE:
13428  // We do nothing here because we assume the entire SQLite DB is already locked from
13429  // when the analysis results were added/deleted in the same transaction.
13430  break;
13431  default:
13432  throw new TskCoreException("Unknown DB Type: " + getDatabaseType().name());
13433  }
13434  }
13435 
13436  ResultSet executeQuery(Statement statement, String query) throws SQLException {
13437  ExecuteQuery queryCommand = new ExecuteQuery(statement, query);
13438  executeCommand(queryCommand);
13439  return queryCommand.getResultSet();
13440  }
13441 
13451  ResultSet executeQuery(PreparedStatement statement) throws SQLException {
13452  ExecutePreparedStatementQuery executePreparedStatementQuery = new ExecutePreparedStatementQuery(statement);
13453  executeCommand(executePreparedStatementQuery);
13454  return executePreparedStatementQuery.getResultSet();
13455  }
13456 
13457  void executeUpdate(Statement statement, String update) throws SQLException {
13458  executeUpdate(statement, update, Statement.NO_GENERATED_KEYS);
13459  }
13460 
13461  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13462  ExecuteStatementUpdate executeStatementUpdate = new ExecuteStatementUpdate(statement, update);
13463  executeCommand(executeStatementUpdate);
13464  }
13465 
13466  void executeUpdate(PreparedStatement statement) throws SQLException {
13467  ExecutePreparedStatementUpdate executePreparedStatementUpdate = new ExecutePreparedStatementUpdate(statement);
13468  executeCommand(executePreparedStatementUpdate);
13469  }
13470 
13474  @Override
13475  public void close() {
13476  try {
13477  for (PreparedStatement stmt : preparedStatements.values()) {
13478  closeStatement(stmt);
13479  }
13480  for (PreparedStatement stmt : adHocPreparedStatements.values()) {
13481  closeStatement(stmt);
13482  }
13483  connection.close();
13484  } catch (SQLException ex) {
13485  logger.log(Level.SEVERE, "Unable to close connection to case database", ex);
13486  }
13487  }
13488 
13489  Connection getConnection() {
13490  return this.connection;
13491  }
13492  }
13493 
13497  private final class SQLiteConnection extends CaseDbConnection {
13498 
13499  private static final int DATABASE_LOCKED_ERROR = 0; // This should be 6 according to documentation, but it has been observed to be 0.
13500  private static final int SQLITE_BUSY_ERROR = 5;
13501 
13502  SQLiteConnection(Connection conn) {
13503  super(conn);
13504  }
13505 
13506  @Override
13507  void executeCommand(DbCommand command) throws SQLException {
13508  int retryCounter = 0;
13509  while (true) {
13510  try {
13511  command.execute(); // Perform the operation
13512  break;
13513  } catch (SQLException ex) {
13514  if ((ex.getErrorCode() == SQLITE_BUSY_ERROR || ex.getErrorCode() == DATABASE_LOCKED_ERROR) && retryCounter < MAX_RETRIES) {
13515  try {
13516 
13517  // We do not notify of error here, as this is not an
13518  // error condition. It is likely a temporary busy or
13519  // locked issue and we will retry.
13520  retryCounter++;
13521  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13522  } catch (InterruptedException exp) {
13523  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13524  }
13525  } else {
13526  throw ex;
13527  }
13528  }
13529  }
13530  }
13531  }
13532 
13536  private final class PostgreSQLConnection extends CaseDbConnection {
13537 
13538  private final String COMMUNICATION_ERROR = PSQLState.COMMUNICATION_ERROR.getState();
13539  private final String SYSTEM_ERROR = PSQLState.SYSTEM_ERROR.getState();
13540  private final String UNKNOWN_STATE = PSQLState.UNKNOWN_STATE.getState();
13541  private static final int MAX_RETRIES = 3;
13542 
13543  PostgreSQLConnection(Connection conn) {
13544  super(conn);
13545  }
13546 
13547  @Override
13548  void executeUpdate(Statement statement, String update, int generateKeys) throws SQLException {
13549  CaseDbConnection.ExecuteStatementUpdateGenerateKeys executeStatementUpdateGenerateKeys = new CaseDbConnection.ExecuteStatementUpdateGenerateKeys(statement, update, generateKeys);
13550  executeCommand(executeStatementUpdateGenerateKeys);
13551  }
13552 
13553  @Override
13554  PreparedStatement prepareStatement(String sqlStatement, int generateKeys) throws SQLException {
13555  CaseDbConnection.PrepareStatementGenerateKeys prepareStatementGenerateKeys = new CaseDbConnection.PrepareStatementGenerateKeys(this.getConnection(), sqlStatement, generateKeys);
13556  executeCommand(prepareStatementGenerateKeys);
13557  return prepareStatementGenerateKeys.getPreparedStatement();
13558  }
13559 
13560  @Override
13561  void executeCommand(DbCommand command) throws SQLException {
13562  SQLException lastException = null;
13563  for (int retries = 0; retries < MAX_RETRIES; retries++) {
13564  try {
13565  command.execute();
13566  lastException = null; // reset since we had a successful execution
13567  break;
13568  } catch (SQLException ex) {
13569  lastException = ex;
13570  String sqlState = ex.getSQLState();
13571  if (sqlState == null || sqlState.equals(COMMUNICATION_ERROR) || sqlState.equals(SYSTEM_ERROR) || sqlState.equals(UNKNOWN_STATE)) {
13572  try {
13573  Thread.sleep(SLEEP_LENGTH_IN_MILLISECONDS);
13574  } catch (InterruptedException exp) {
13575  Logger.getLogger(SleuthkitCase.class.getName()).log(Level.WARNING, "Unexpectedly unable to wait for database.", exp);
13576  }
13577  } else {
13578  throw ex;
13579  }
13580  }
13581  }
13582 
13583  // rethrow the exception if we bailed because of too many retries
13584  if (lastException != null) {
13585  throw lastException;
13586  }
13587  }
13588  }
13589 
13604  public static final class CaseDbTransaction {
13605 
13606  private final CaseDbConnection connection;
13607  private SleuthkitCase sleuthkitCase;
13608 
13609  // A collection of object score changes that ocuured as part of this transaction.
13610  // When the transaction is committed, events are fired to notify any listeners.
13611  // Score changes are stored as a map keyed by objId to prevent duplicates.
13612  private Map<Long, ScoreChange> scoreChangeMap = new HashMap<>();
13613  private List<Host> hostsAdded = new ArrayList<>();
13614  private List<OsAccount> accountsChanged = new ArrayList<>();
13615  private List<OsAccount> accountsAdded = new ArrayList<>();
13616  private List<Long> deletedOsAccountObjectIds = new ArrayList<>();
13617  private List<Long> deletedResultObjectIds = new ArrayList<>();
13618 
13619  private static Set<Long> threadsWithOpenTransaction = new HashSet<>();
13620  private static final Object threadsWithOpenTransactionLock = new Object();
13621 
13622  private CaseDbTransaction(SleuthkitCase sleuthkitCase) throws TskCoreException {
13623  this.sleuthkitCase = sleuthkitCase;
13624 
13625  sleuthkitCase.acquireSingleUserCaseWriteLock();
13626  this.connection = sleuthkitCase.getConnection();
13627  try {
13628  synchronized (threadsWithOpenTransactionLock) {
13629  this.connection.beginTransaction();
13630  threadsWithOpenTransaction.add(Thread.currentThread().getId());
13631  }
13632  } catch (SQLException ex) {
13633  sleuthkitCase.releaseSingleUserCaseWriteLock();
13634  throw new TskCoreException("Failed to create transaction on case database", ex);
13635  }
13636 
13637  }
13638 
13646  CaseDbConnection getConnection() {
13647  return this.connection;
13648  }
13649 
13655  void registerScoreChange(ScoreChange scoreChange) {
13656  scoreChangeMap.put(scoreChange.getObjectId(), scoreChange);
13657  }
13658 
13664  void registerAddedHost(Host host) {
13665  if (host != null) {
13666  this.hostsAdded.add(host);
13667  }
13668  }
13669 
13675  void registerChangedOsAccount(OsAccount account) {
13676  if (account != null) {
13677  accountsChanged.add(account);
13678  }
13679  }
13680 
13686  void registerDeletedOsAccount(long osAccountObjId) {
13687  deletedOsAccountObjectIds.add(osAccountObjId);
13688  }
13689 
13695  void registerAddedOsAccount(OsAccount account) {
13696  if (account != null) {
13697  accountsAdded.add(account);
13698  }
13699  }
13700 
13707  void registerDeletedAnalysisResult(long analysisResultObjId) {
13708  this.deletedResultObjectIds.add(analysisResultObjId);
13709  }
13710 
13719  private static boolean hasOpenTransaction(long threadId) {
13720  synchronized (threadsWithOpenTransactionLock) {
13721  return threadsWithOpenTransaction.contains(threadId);
13722  }
13723  }
13724 
13731  public void commit() throws TskCoreException {
13732  try {
13733  this.connection.commitTransaction();
13734  } catch (SQLException ex) {
13735  throw new TskCoreException("Failed to commit transaction on case database", ex);
13736  } finally {
13737  close();
13738 
13739  if (!scoreChangeMap.isEmpty()) {
13740  Map<Long, List<ScoreChange>> changesByDataSource = scoreChangeMap.values().stream()
13741  .collect(Collectors.groupingBy(ScoreChange::getDataSourceObjectId));
13742  for (Map.Entry<Long, List<ScoreChange>> entry : changesByDataSource.entrySet()) {
13743  sleuthkitCase.fireTSKEvent(new TskEvent.AggregateScoresChangedEvent(entry.getKey(), ImmutableSet.copyOf(entry.getValue())));
13744  }
13745  }
13746  if (!hostsAdded.isEmpty()) {
13747  sleuthkitCase.fireTSKEvent(new TskEvent.HostsAddedTskEvent(hostsAdded));
13748  }
13749  if (!accountsAdded.isEmpty()) {
13750  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsAddedTskEvent(accountsAdded));
13751  }
13752  if (!accountsChanged.isEmpty()) {
13753  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsUpdatedTskEvent(accountsChanged));
13754  }
13755  if (!deletedOsAccountObjectIds.isEmpty()) {
13756  sleuthkitCase.fireTSKEvent(new TskEvent.OsAccountsDeletedTskEvent(deletedOsAccountObjectIds));
13757  }
13758  if (!deletedResultObjectIds.isEmpty()) {
13759  sleuthkitCase.fireTSKEvent(new TskEvent.AnalysisResultsDeletedTskEvent(deletedResultObjectIds));
13760  }
13761  }
13762  }
13763 
13770  public void rollback() throws TskCoreException {
13771  try {
13772  this.connection.rollbackTransactionWithThrow();
13773  } catch (SQLException ex) {
13774  throw new TskCoreException("Case database transaction rollback failed", ex);
13775  } finally {
13776  close();
13777  }
13778  }
13779 
13784  void close() {
13785  this.connection.close();
13786  sleuthkitCase.releaseSingleUserCaseWriteLock();
13787  synchronized (threadsWithOpenTransactionLock) {
13788  threadsWithOpenTransaction.remove(Thread.currentThread().getId());
13789  }
13790  }
13791  }
13792 
13802  public final class CaseDbQuery implements AutoCloseable {
13803 
13804  private ResultSet resultSet;
13805  private CaseDbConnection connection;
13806 
13807  private CaseDbQuery(String query) throws TskCoreException {
13808  this(query, false);
13809  }
13810 
13811  private CaseDbQuery(String query, boolean allowWriteQuery) throws TskCoreException {
13812  if (!allowWriteQuery) {
13813  if (!query.regionMatches(true, 0, "SELECT", 0, "SELECT".length())) {
13814  throw new TskCoreException("Unsupported query: Only SELECT queries are supported.");
13815  }
13816  }
13817 
13819  try {
13820  connection = connections.getConnection();
13821  resultSet = connection.executeQuery(connection.createStatement(), query);
13822  } catch (SQLException ex) {
13824  throw new TskCoreException("Error executing query: ", ex);
13825  } catch (TskCoreException ex) {
13827  throw ex;
13828  }
13829  }
13830 
13836  public ResultSet getResultSet() {
13837  return resultSet;
13838  }
13839 
13840  @Override
13841  public void close() throws TskCoreException {
13842  try {
13843  if (resultSet != null) {
13844  final Statement statement = resultSet.getStatement();
13845  if (statement != null) {
13846  statement.close();
13847  }
13848  resultSet.close();
13849  }
13850  closeConnection(connection);
13851  } catch (SQLException ex) {
13852  throw new TskCoreException("Error closing query: ", ex);
13853  } finally {
13855  }
13856  }
13857  }
13858 
13866  @Deprecated
13867  public void addErrorObserver(ErrorObserver observer) {
13868  sleuthkitCaseErrorObservers.add(observer);
13869  }
13870 
13878  @Deprecated
13879  public void removeErrorObserver(ErrorObserver observer) {
13880  int i = sleuthkitCaseErrorObservers.indexOf(observer);
13881  if (i >= 0) {
13882  sleuthkitCaseErrorObservers.remove(i);
13883  }
13884  }
13885 
13894  @Deprecated
13895  public void submitError(String context, String errorMessage) {
13896  for (ErrorObserver observer : sleuthkitCaseErrorObservers) {
13897  if (observer != null) {
13898  try {
13899  observer.receiveError(context, errorMessage);
13900  } catch (Exception ex) {
13901  logger.log(Level.SEVERE, "Observer client unable to receive message: {0}, {1}", new Object[]{context, errorMessage, ex});
13902 
13903  }
13904  }
13905  }
13906  }
13907 
13913  @Deprecated
13914  public interface ErrorObserver {
13915 
13922  public enum Context {
13923 
13927  IMAGE_READ_ERROR("Image File Read Error"),
13931  DATABASE_READ_ERROR("Database Read Error");
13932 
13933  private final String contextString;
13934 
13935  private Context(String context) {
13936  this.contextString = context;
13937  }
13938 
13939  public String getContextString() {
13940  return contextString;
13941  }
13942  };
13943 
13944  void receiveError(String context, String errorMessage);
13945  }
13946 
13957  @Deprecated
13958  long getDataSourceObjectId(long objectId) {
13959  try {
13960  CaseDbConnection connection = connections.getConnection();
13961  try {
13962  return getDataSourceObjectId(connection, objectId);
13963  } finally {
13964  closeConnection(connection);
13965  }
13966  } catch (TskCoreException ex) {
13967  logger.log(Level.SEVERE, "Error getting data source object id for a file", ex);
13968  return 0;
13969  }
13970  }
13971 
13981  @Deprecated
13982  public long getLastObjectId() throws TskCoreException {
13983  CaseDbConnection connection = null;
13984  ResultSet rs = null;
13986  try {
13987  connection = connections.getConnection();
13988 
13989  // SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects
13990  PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_MAX_OBJECT_ID);
13991  rs = connection.executeQuery(statement);
13992  long id = -1;
13993  if (rs.next()) {
13994  id = rs.getLong("max_obj_id");
13995  }
13996  return id;
13997  } catch (SQLException e) {
13998  throw new TskCoreException("Error getting last object id", e);
13999  } finally {
14000  closeResultSet(rs);
14001  closeConnection(connection);
14003  }
14004  }
14005 
14019  @Deprecated
14020  public List<FsContent> findFilesWhere(String sqlWhereClause) throws TskCoreException {
14021  CaseDbConnection connection = null;
14022  Statement s = null;
14023  ResultSet rs = null;
14025  try {
14026  connection = connections.getConnection();
14027  s = connection.createStatement();
14028  rs = connection.executeQuery(s, "SELECT * FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS
14029  List<FsContent> results = new ArrayList<FsContent>();
14030  List<AbstractFile> temp = resultSetToAbstractFiles(rs, connection);
14031  for (AbstractFile f : temp) {
14032  final TSK_DB_FILES_TYPE_ENUM type = f.getType();
14033  if (type.equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
14034  results.add((FsContent) f);
14035  }
14036  }
14037  return results;
14038  } catch (SQLException e) {
14039  throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e);
14040  } finally {
14041  closeResultSet(rs);
14042  closeStatement(s);
14043  closeConnection(connection);
14045  }
14046  }
14047 
14059  @Deprecated
14060  public int getArtifactTypeID(String artifactTypeName) throws TskCoreException {
14061  CaseDbConnection connection = null;
14062  Statement s = null;
14063  ResultSet rs = null;
14065  try {
14066  connection = connections.getConnection();
14067  s = connection.createStatement();
14068  rs = connection.executeQuery(s, "SELECT artifact_type_id FROM blackboard_artifact_types WHERE type_name = '" + artifactTypeName + "'"); //NON-NLS
14069  int typeId = -1;
14070  if (rs.next()) {
14071  typeId = rs.getInt("artifact_type_id");
14072  }
14073  return typeId;
14074  } catch (SQLException ex) {
14075  throw new TskCoreException("Error getting artifact type id", ex);
14076  } finally {
14077  closeResultSet(rs);
14078  closeStatement(s);
14079  closeConnection(connection);
14081  }
14082  }
14083 
14093  @Deprecated
14094  public ArrayList<BlackboardArtifact.ARTIFACT_TYPE> getBlackboardArtifactTypes() throws TskCoreException {
14095  return new ArrayList<BlackboardArtifact.ARTIFACT_TYPE>(Arrays.asList(BlackboardArtifact.ARTIFACT_TYPE.values()));
14096  }
14097 
14111  @Deprecated
14112  public int addArtifactType(String artifactTypeName, String displayName) throws TskCoreException {
14113  try {
14114  return addBlackboardArtifactType(artifactTypeName, displayName).getTypeID();
14115  } catch (TskDataException ex) {
14116  throw new TskCoreException("Failed to add artifact type.", ex);
14117  }
14118  }
14119 
14133  @Deprecated
14134  public int addAttrType(String attrTypeString, String displayName) throws TskCoreException {
14135  try {
14136  return addArtifactAttributeType(attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, displayName).getTypeID();
14137  } catch (TskDataException ex) {
14138  throw new TskCoreException("Couldn't add new attribute type");
14139  }
14140  }
14141 
14152  @Deprecated
14153  public int getAttrTypeID(String attrTypeName) throws TskCoreException {
14154  CaseDbConnection connection = null;
14155  Statement s = null;
14156  ResultSet rs = null;
14158  try {
14159  connection = connections.getConnection();
14160  s = connection.createStatement();
14161  rs = connection.executeQuery(s, "SELECT attribute_type_id FROM blackboard_attribute_types WHERE type_name = '" + attrTypeName + "'"); //NON-NLS
14162  int typeId = -1;
14163  if (rs.next()) {
14164  typeId = rs.getInt("attribute_type_id");
14165  }
14166  return typeId;
14167  } catch (SQLException ex) {
14168  throw new TskCoreException("Error getting attribute type id", ex);
14169  } finally {
14170  closeResultSet(rs);
14171  closeStatement(s);
14172  closeConnection(connection);
14174  }
14175  }
14176 
14189  @Deprecated
14190  public String getAttrTypeString(int attrTypeID) throws TskCoreException {
14191  CaseDbConnection connection = null;
14192  Statement s = null;
14193  ResultSet rs = null;
14195  try {
14196  connection = connections.getConnection();
14197  s = connection.createStatement();
14198  rs = connection.executeQuery(s, "SELECT type_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14199  if (rs.next()) {
14200  return rs.getString("type_name");
14201  } else {
14202  throw new TskCoreException("No type with that id");
14203  }
14204  } catch (SQLException ex) {
14205  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14206  } finally {
14207  closeResultSet(rs);
14208  closeStatement(s);
14209  closeConnection(connection);
14211  }
14212  }
14213 
14226  @Deprecated
14227  public String getAttrTypeDisplayName(int attrTypeID) throws TskCoreException {
14228  CaseDbConnection connection = null;
14229  Statement s = null;
14230  ResultSet rs = null;
14232  try {
14233  connection = connections.getConnection();
14234  s = connection.createStatement();
14235  rs = connection.executeQuery(s, "SELECT display_name FROM blackboard_attribute_types WHERE attribute_type_id = " + attrTypeID); //NON-NLS
14236  if (rs.next()) {
14237  return rs.getString("display_name");
14238  } else {
14239  throw new TskCoreException("No type with that id");
14240  }
14241  } catch (SQLException ex) {
14242  throw new TskCoreException("Error getting or creating a attribute type name", ex);
14243  } finally {
14244  closeResultSet(rs);
14245  closeStatement(s);
14246  closeConnection(connection);
14248  }
14249  }
14250 
14260  @Deprecated
14261  public ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE> getBlackboardAttributeTypes() throws TskCoreException {
14262  return new ArrayList<BlackboardAttribute.ATTRIBUTE_TYPE>(Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.values()));
14263  }
14264 
14280  @Deprecated
14281  public ResultSet runQuery(String query) throws SQLException {
14282  CaseDbConnection connection = null;
14284  try {
14285  connection = connections.getConnection();
14286  return connection.executeQuery(connection.createStatement(), query);
14287  } catch (TskCoreException ex) {
14288  throw new SQLException("Error getting connection for ad hoc query", ex);
14289  } finally {
14290  //TODO unlock should be done in closeRunQuery()
14291  //but currently not all code calls closeRunQuery - need to fix this
14292  closeConnection(connection);
14294  }
14295  }
14296 
14306  @Deprecated
14307  public void closeRunQuery(ResultSet resultSet) throws SQLException {
14308  final Statement statement = resultSet.getStatement();
14309  resultSet.close();
14310  if (statement != null) {
14311  statement.close();
14312  }
14313  }
14314 
14331  @Deprecated
14332  public LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize, long containerId, List<TskFileRange> data) throws TskCoreException {
14333  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(carvedFileName, carvedFileSize, data);
14334  List<CarvingResult.CarvedFile> files = new ArrayList<CarvingResult.CarvedFile>();
14335  files.add(carvedFile);
14336  CarvingResult carvingResult;
14337  Content parent = getContentById(containerId);
14338  if (parent instanceof FileSystem
14339  || parent instanceof Volume
14340  || parent instanceof Image) {
14341  carvingResult = new CarvingResult(parent, files);
14342  } else {
14343  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", containerId));
14344  }
14345  return addCarvedFiles(carvingResult).get(0);
14346  }
14347 
14361  @Deprecated
14362  public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
14363  List<CarvingResult.CarvedFile> carvedFiles = new ArrayList<CarvingResult.CarvedFile>();
14364  for (CarvedFileContainer container : filesToAdd) {
14365  CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges());
14366  carvedFiles.add(carvedFile);
14367  }
14368  CarvingResult carvingResult;
14369  Content parent = getContentById(filesToAdd.get(0).getId());
14370  if (parent instanceof FileSystem
14371  || parent instanceof Volume
14372  || parent instanceof Image) {
14373  carvingResult = new CarvingResult(parent, carvedFiles);
14374  } else {
14375  throw new TskCoreException(String.format("Parent (id =%d) is not an file system, volume or image", parent.getId()));
14376  }
14377  return addCarvedFiles(carvingResult);
14378  }
14379 
14409  @Deprecated
14410  public DerivedFile addDerivedFile(String fileName, String localPath,
14411  long size, long ctime, long crtime, long atime, long mtime,
14412  boolean isFile, AbstractFile parentFile,
14413  String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
14414  return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14415  isFile, parentFile, rederiveDetails, toolName, toolVersion,
14416  otherDetails, TskData.EncodingType.NONE);
14417  }
14418 
14448  @Deprecated
14449  public LocalFile addLocalFile(String fileName, String localPath,
14450  long size, long ctime, long crtime, long atime, long mtime,
14451  String md5, FileKnown known, String mimeType,
14452  boolean isFile, TskData.EncodingType encodingType,
14453  Content parent, CaseDbTransaction transaction) throws TskCoreException {
14454 
14455  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14456  md5, null, known, mimeType, isFile, encodingType,
14457  parent, transaction);
14458  }
14459 
14484  @Deprecated
14485  public LocalFile addLocalFile(String fileName, String localPath,
14486  long size, long ctime, long crtime, long atime, long mtime,
14487  boolean isFile,
14488  AbstractFile parent, CaseDbTransaction transaction) throws TskCoreException {
14489  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile,
14490  TskData.EncodingType.NONE, parent, transaction);
14491  }
14492 
14512  @Deprecated
14513  public LocalFile addLocalFile(String fileName, String localPath,
14514  long size, long ctime, long crtime, long atime, long mtime,
14515  boolean isFile,
14516  AbstractFile parent) throws TskCoreException {
14517  return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime,
14518  isFile, TskData.EncodingType.NONE, parent);
14519  }
14520 
14537  @Deprecated
14538  public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) {
14539  return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, "", this);
14540  }
14541 
14552  @Deprecated
14553  public Collection<FileSystem> getFileSystems(Image image) {
14554  try {
14555  return getImageFileSystems(image);
14556  } catch (TskCoreException ex) {
14557  logger.log(Level.SEVERE, "Error loading all file systems for image with ID {0}", image.getId());
14558  return new ArrayList<>();
14559  }
14560  }
14561 
14579  @Deprecated
14580  public List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
14581  return findFilesInFolder(fileName, parentFile);
14582  }
14583 
14591  @Deprecated
14592  public void acquireExclusiveLock() {
14594  }
14595 
14603  @Deprecated
14604  public void releaseExclusiveLock() {
14606  }
14607 
14615  @Deprecated
14616  public void acquireSharedLock() {
14618  }
14619 
14627  @Deprecated
14628  public void releaseSharedLock() {
14630  }
14631 };
Image addImageInfo(long deviceObjId, List< String > imageFilePaths, String timeZone, Host host)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, long value)
final IngestJobInfo addIngestJob(Content dataSource, String hostName, List< IngestModuleInfo > ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir)
static Priority fromID(int id)
Definition: Score.java:184
FS
File that can be found in file system tree.
Definition: TskData.java:685
static FileKnown valueOf(byte known)
Definition: TskData.java:810
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
static Significance fromID(int id)
Definition: Score.java:118
BlackboardArtifact getArtifactByArtifactId(long id)
AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans)
BlackboardArtifact getArtifactById(long id)
ArrayList< BlackboardAttribute > getBlackboardAttributes(final BlackboardArtifact artifact)
int getArtifactTypeID(String artifactTypeName)
Type(int typeID, String typeName, String displayName, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType)
Host getHostByDataSource(DataSource dataSource)
long getBlackboardArtifactTagsCountByTagName(TagName tagName)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(ARTIFACT_TYPE artifactType)
LocalDirectory addLocalDirectory(long parentId, String directoryName, CaseDbTransaction transaction)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(String artifactTypeName)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, int value)
void addBlackboardAttributes(Collection< BlackboardAttribute > attributes, int artifactTypeId)
Optional< HostAddress > getHostAddress(HostAddress.HostAddressType type, String address)
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID, long obj_id)
static final Score SCORE_UNKNOWN
Definition: Score.java:213
CommunicationsManager getCommunicationsManager()
AnalysisResult getAnalysisResultById(long artifactObjId)
static Set< TSK_FS_META_FLAG_ENUM > valuesOf(short metaFlags)
Definition: TskData.java:247
DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails)
OsAccount getOsAccountByObjectId(long osAccountObjId)
boolean isCompatible(CaseDbSchemaVersionNumber dbSchemaVersion)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:206
static TSK_FS_TYPE_ENUM valueOf(int fsTypeValue)
Definition: TskData.java:501
CaseDbSchemaVersionNumber getDBSchemaCreationVersion()
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
void addErrorObserver(ErrorObserver observer)
DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType, Content parentObj, CaseDbTransaction trans)
DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction)
List< AbstractFile > findFiles(Content dataSource, String fileName, AbstractFile parentFile)
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
void setFileMIMEType(AbstractFile file, String mimeType)
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:207
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Long osAccountId, String ownerAccount, Content parent, CaseDbTransaction transaction)
void addBlackboardAttribute(BlackboardAttribute attr, int artifactTypeId)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parent, CaseDbTransaction transaction)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
final List< LayoutFile > addLayoutFiles(Content parent, List< TskFileRange > fileRanges)
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:694
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()
List< AnalysisResult > getAnalysisResults(long sourceObjId)
ContentTag getContentTagByID(long contentTagID)
LOCAL
Local file that was added (not from a disk image)
Definition: TskData.java:688
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:686
BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
long countFilesWhere(String sqlWhereClause)
List< AnalysisResult > getAnalysisResultsWhere(String whereClause)
long getBlackboardArtifactsCount(ARTIFACT_TYPE artifactType, long obj_id)
FS
File System - see tsk_fs_info for more details.
Definition: TskData.java: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:693
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)
OsAccountInstance newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
long getBlackboardArtifactsTypeCount(int artifactTypeID, long dataSourceID)
BlackboardArtifact.Type getArtifactType(String artTypeName)
DERIVED
File derived from a parent file (i.e. from ZIP)
Definition: TskData.java:687
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:689
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
ArrayList< BlackboardAttribute > getMatchingAttributes(String whereClause)
List< BlackboardArtifact > getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value)
long getBlackboardArtifactsTypeCount(int artifactTypeID)
List< ContentTag > getContentTagsByTagName(TagName tagName, long dsObjId)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
static ObjectType valueOf(short objectType)
Definition: TskData.java:669
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:791
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:691
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.