diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java index fc3c0ab9c0650b043b9fcdc5cafb1cf6c6744505..c885c0714fa14ecbc5017204c066e2e61280b607 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.datamodel; -import com.google.common.annotations.Beta; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -42,8 +41,6 @@ import static org.sleuthkit.datamodel.SleuthkitCase.closeConnection; import static org.sleuthkit.datamodel.SleuthkitCase.closeResultSet; import static org.sleuthkit.datamodel.SleuthkitCase.closeStatement; -import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; -import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments; /** * Provides an API to create Accounts and communications/relationships between @@ -199,15 +196,17 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam if (this.accountTypeToTypeIdMap.containsKey(accountType)) { return accountType; } - + CaseDbTransaction transaction = this.db.beginTransaction(); try { org.sleuthkit.datamodel.Account.Type retAccountType = addAccountType(accountTypeName, displayName, transaction); transaction.commit(); + transaction = null; return retAccountType; - } catch (TskCoreException ex) { - transaction.rollback(); - throw ex; + } finally { + if (transaction != null) { + transaction.rollback(); + } } } @@ -235,12 +234,12 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam try { PreparedStatement initialSelectStmt = trans.getConnection().getPreparedStatement( - "SELECT * FROM account_types WHERE type_name = ?", + "SELECT * FROM account_types WHERE type_name = ?", Statement.RETURN_GENERATED_KEYS ); initialSelectStmt.clearParameters(); initialSelectStmt.setString(1, accountTypeName); - + // try to get cached account type try (ResultSet initialSelectRs = initialSelectStmt.executeQuery()) { if (initialSelectRs.next()) { @@ -253,14 +252,14 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam // if not in database, insert PreparedStatement insertStmt = trans.getConnection().getPreparedStatement( - "INSERT INTO account_types (type_name, display_name) VALUES (?, ?)", - Statement.RETURN_GENERATED_KEYS + "INSERT INTO account_types (type_name, display_name) VALUES (?, ?)", + Statement.RETURN_GENERATED_KEYS ); insertStmt.clearParameters(); - insertStmt.setString(1, accountTypeName); + insertStmt.setString(1, accountTypeName); insertStmt.setString(2, displayName); - + int affectedRows = insertStmt.executeUpdate(); if (affectedRows > 0) { try (ResultSet insertRsKeys = insertStmt.getGeneratedKeys()) { @@ -272,7 +271,7 @@ public org.sleuthkit.datamodel.Account.Type addAccountType(String accountTypeNam } } } - + throw new SQLException(MessageFormat.format("Account with type name: {0} and display name: {1} could not be created", accountTypeName, displayName)); } catch (SQLException ex) { throw new TskCoreException("Error adding account type", ex); @@ -312,9 +311,11 @@ public AccountFileInstance createAccountFileInstance(org.sleuthkit.datamodel.Acc sourceFile, attributes, ingestJobId, transaction); transaction.commit(); - } catch (TskCoreException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } if (accountFileInstance != null) { @@ -451,21 +452,21 @@ public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, Stri public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, String accountUniqueID, CaseDbConnection caseDbConnection) throws TskCoreException, InvalidAccountIDException { try { PreparedStatement stmt = caseDbConnection.getPreparedStatement( - "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?", + "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?", Statement.NO_GENERATED_KEYS ); - + stmt.clearParameters(); stmt.setInt(1, getAccountTypeId(accountType)); stmt.setString(2, normalizeAccountID(accountType, accountUniqueID)); - + try (ResultSet rs = stmt.executeQuery()) { if (rs.next()) { return new Account(rs.getInt("account_id"), accountType, rs.getString("account_unique_identifier")); } else { return null; - } + } } } catch (SQLException ex) { throw new TskCoreException("Error adding an account", ex); @@ -483,17 +484,18 @@ public Account getAccount(org.sleuthkit.datamodel.Account.Type accountType, Stri * * @throws TskCoreException */ - private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type artType, + private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type artType, Collection<BlackboardAttribute> attributes, CaseDbTransaction trans) throws TskCoreException { - - Long dataSourceObjId; + + long dataSourceObjId; if (content instanceof AbstractFile) { dataSourceObjId = ((AbstractFile) content).getDataSourceObjectId(); + } else if (content instanceof BlackboardArtifact) { + dataSourceObjId = ((BlackboardArtifact) content).getDataSourceObjectID(); } else if (content instanceof DataSource) { dataSourceObjId = content.getId(); } else { - // can be null for anything else - dataSourceObjId = null; + dataSourceObjId = getDataSourceObjId(trans.getConnection(), content.getId()); } return getSleuthkitCase().getBlackboard().newDataArtifact( @@ -505,7 +507,63 @@ private DataArtifact newDataArtifact(Content content, BlackboardArtifact.Type ar trans); } - + /** + * Iteratively checks tsk_objects table for parents until arriving at a + * tsk_objects entry that is of type IMG. If no IMG type is reached, returns + * 0. + * + * @param conn The database connection. + * @param objId The starting object id. + * + * @return The object id of the parent data source or 0. + * + * @throws TskCoreException + */ + private long getDataSourceObjId(CaseDbConnection conn, long objId) throws TskCoreException { + + this.db.acquireSingleUserCaseReadLock(); + try { + while (objId > 0) { + try (PreparedStatement pStmt = conn.getPreparedStatement( + "SELECT par_obj_id, type FROM tsk_objects WHERE obj_id = ?", + Statement.NO_GENERATED_KEYS)) { + + pStmt.clearParameters(); + pStmt.setLong(1, objId); + try (ResultSet rs = pStmt.executeQuery()) { + if (rs.next()) { + TskData.ObjectType type = TskData.ObjectType.valueOf(rs.getShort("type")); //NON-NLS + // if the current id is an image, we have found the data source id. + if (type == TskData.ObjectType.IMG) { + return objId; + } + + Long parId = rs.getLong("par_obj_id"); + // if no parent id, there is no data source associated with this content. + if (rs.wasNull()) { + return 0; + } + + // otherwise, keep iterating + objId = parId; + + } else { + // if no record matching the object id, set the data source object id to 0. + return 0; + } + } + } + } + } catch (SQLException ex) { + throw new TskCoreException("Error getting Content by ID.", ex); + } finally { + this.db.releaseSingleUserCaseReadLock(); + } + + // in this event, simply return 0. + return 0; + } + /** * Adds relationships between the sender and each of the recipient account * instances and between all recipient account instances. All account @@ -537,9 +595,11 @@ public void addRelationships(AccountFileInstance sender, List<AccountFileInstanc try { addRelationships(sender, recipients, sourceArtifact, relationshipType, dateTime, transaction); transaction.commit(); - } catch (TskCoreException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } } @@ -678,7 +738,7 @@ private Account getOrCreateAccount(Account.Type accountType, String accountUniqu } try { - PreparedStatement insertStmt = trans.getConnection().getPreparedStatement(query, Statement.NO_GENERATED_KEYS); + PreparedStatement insertStmt = trans.getConnection().getPreparedStatement(query, Statement.RETURN_GENERATED_KEYS); insertStmt.clearParameters(); insertStmt.setInt(1, getAccountTypeId(accountType)); String accountUniqueIdentifier = normalizeAccountID(accountType, accountUniqueID); @@ -687,14 +747,14 @@ private Account getOrCreateAccount(Account.Type accountType, String accountUniqu try (ResultSet rs = insertStmt.getGeneratedKeys()) { if (rs.next()) { return new Account( - rs.getInt(1), + rs.getInt(1), accountType, accountUniqueIdentifier ); } } - } - + } + return null; } catch (SQLException ex) { throw new TskCoreException("Error adding an account", ex); @@ -790,7 +850,7 @@ private BlackboardArtifact getAccountFileInstanceArtifact(Account.Type accountTy try { PreparedStatement pStatement = transaction.getConnection().getPreparedStatement(queryStr, Statement.NO_GENERATED_KEYS); pStatement.clearParameters(); - + int paramIdx = 0; pStatement.setInt(++paramIdx, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID.getTypeID()); pStatement.setString(++paramIdx, accountUniqueID); @@ -1170,7 +1230,7 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev for (Map.Entry<Long, Set<Long>> entry : accountIdToDatasourceObjIdMap.entrySet()) { final Long accountID = entry.getKey(); String datasourceObjIdsCSV = CommManagerSqlStringUtils.buildCSVString(entry.getValue()); - + adiSQLClauses.add( "( " + (!datasourceObjIdsCSV.isEmpty() ? "( relationships.data_source_obj_id IN ( " + datasourceObjIdsCSV + " ) ) AND" : "") @@ -1179,8 +1239,8 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev ); } String adiSQLClause = CommManagerSqlStringUtils.joinAsStrings(adiSQLClauses, " OR "); - - if(adiSQLClause.isEmpty()) { + + if (adiSQLClause.isEmpty()) { LOGGER.log(Level.SEVERE, "There set of AccountDeviceInstances had no valid data source ids."); return Collections.emptySet(); } @@ -1196,7 +1256,7 @@ public Set<Content> getRelationshipSources(Set<AccountDeviceInstance> accountDev // Basic join. String limitQuery = " account_relationships AS relationships"; - + // If the user set filters expand this to be a subquery that selects // accounts based on the filter. String limitStr = getMostRecentFilterLimitSQL(filter); diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index fe35bc0ac907198d88bfeba3f5a0a3da7cb8c538..11002c2d978356091580c73b3e1a21c94ccb098f 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -8480,10 +8480,12 @@ public LayoutFile addLayoutFile(String fileName, LayoutFile lf = addLayoutFile(fileName, size, dirFlag, metaFlag, ctime, crtime, atime, mtime, fileRanges, parent, dataSourceId, transaction); transaction.commit(); + transaction = null; return lf; - } catch (TskCoreException ex) { - transaction.rollback(); - throw ex; + } finally { + if (transaction != null) { + transaction.rollback(); + } } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java index 3243cbf970e2d82e3595c4d9654129152ba99c79..d738ac8f9b99ff652357f2287d2b86de3400c256 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/CommunicationArtifactsHelper.java @@ -315,9 +315,11 @@ public BlackboardArtifact addContact(String contactName, try { contactArt = addContact(contactName, phoneNumber, homePhoneNumber, mobilePhoneNumber, emailAddr, transaction, additionalAttributes); transaction.commit(); - } catch (TskCoreException | BlackboardException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } if (contactArt != null) { @@ -615,9 +617,11 @@ public BlackboardArtifact addMessage(String messageType, try { msgArt = addMessage(messageType, direction, senderId, recipientIdsList, dateTime, readStatus, subject, messageText, threadId, transaction, otherAttributesList); transaction.commit(); - } catch (TskCoreException | BlackboardException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } if (msgArt != null) { @@ -943,9 +947,11 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, try { callLogArt = addCalllog(direction, callerId, calleeIdsList, startDateTime, endDateTime, mediaType, transaction, otherAttributesList); transaction.commit(); - } catch (TskCoreException | BlackboardException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } if (callLogArt != null) { @@ -1084,8 +1090,6 @@ public BlackboardArtifact addCalllog(CommunicationDirection direction, Content content = getContent(); BlackboardArtifact callLogArtifact = newDataArtifact(content, CALLOG_TYPE, attributes, trans); - callLogArtifact.addAttributes(attributes); - // create relationships between caller/callees try { getSleuthkitCase().getCommunicationsManager().addRelationships(callerAccountInstance, @@ -1130,9 +1134,11 @@ public void addAttachments(BlackboardArtifact message, MessageAttachments attach dataSourceObjId = dataSourceObjId == null ? 0L : dataSourceObjId; attachmentArts = addAttachments(message, dataSourceObjId, attachments, getModuleName(), transaction); transaction.commit(); - } catch (TskCoreException ex) { - transaction.rollback(); - throw ex; + transaction = null; + } finally { + if (transaction != null) { + transaction.rollback(); + } } attachmentArts = (attachmentArts == null) ? Collections.emptyList() : attachmentArts;