19 package org.sleuthkit.datamodel;
 
   21 import org.apache.commons.lang3.StringUtils;
 
   22 import java.util.List;
 
   23 import java.util.Arrays;
 
   24 import java.util.ArrayList;
 
   25 import java.util.HashMap;
 
   26 import java.util.LinkedList;
 
   28 import java.util.Objects;
 
   29 import java.util.Queue;
 
   30 import java.util.logging.Level;
 
   31 import java.util.logging.Logger;
 
   45     private static final Logger logger = Logger.getLogger(JniDbHelper.class.getName());
 
   47     private final SleuthkitCase caseDb;
 
   48     private CaseDbTransaction trans = null;
 
   49     private final AddDataSourceCallbacks addDataSourceCallbacks;
 
   51     private final Map<Long, Long> fsIdToRootDir = 
new HashMap<>();
 
   52     private final Map<Long, TskData.TSK_FS_TYPE_ENUM> fsIdToFsType = 
new HashMap<>();
 
   53     private final Map<ParentCacheKey, Long> parentDirCache = 
new HashMap<>();
 
   55     private static final long BATCH_FILE_THRESHOLD = 500;
 
   56     private final Queue<FileInfo> batchedFiles = 
new LinkedList<>();
 
   57     private final Queue<LayoutRangeInfo> batchedLayoutRanges = 
new LinkedList<>();
 
   58     private final List<Long> layoutFileIds = 
new ArrayList<>();
 
   60     JniDbHelper(SleuthkitCase caseDb, AddDataSourceCallbacks addDataSourceCallbacks) {
 
   62         this.addDataSourceCallbacks = addDataSourceCallbacks;
 
   71     private void beginTransaction() throws TskCoreException {
 
   72         trans = caseDb.beginTransaction();
 
   80     private void commitTransaction() throws TskCoreException {
 
   88     private void revertTransaction() {
 
   94         } 
catch (TskCoreException ex) {
 
   95             logger.log(Level.SEVERE, 
"Error rolling back transaction", ex);
 
  103         addBatchedFilesToDb();
 
  104         addBatchedLayoutRangesToDb();
 
  105         processLayoutFiles();
 
  126     long addImageInfo(
int type, 
long ssize, String timezone, 
 
  127             long size, String md5, String sha1, String sha256, String deviceId, 
 
  128             String collectionDetails, String[] paths) {    
 
  131             long objId = caseDb.addImageJNI(TskData.TSK_IMG_TYPE_ENUM.valueOf(type), ssize, size,
 
  132                     timezone, md5, sha1, sha256, deviceId, collectionDetails, trans);
 
  133             for (
int i = 0;i < paths.length;i++) {
 
  134                 caseDb.addImageNameJNI(objId, paths[i], i, trans);
 
  138         } 
catch (TskCoreException ex) {
 
  139             logger.log(Level.SEVERE, 
"Error adding image to the database", ex);
 
  151         void addAcquisitionDetails(
long imgId, String details) {
 
  154             caseDb.setAcquisitionDetails(imgId, details, trans);
 
  156         } 
catch (TskCoreException ex) {
 
  157             logger.log(Level.SEVERE, 
"Error adding image details \"" + details + 
"\" to image with ID " + imgId, ex);
 
  173     long addVsInfo(
long parentObjId, 
int vsType, 
long imgOffset, 
long blockSize) {
 
  176             VolumeSystem vs = caseDb.addVolumeSystem(parentObjId, TskData.TSK_VS_TYPE_ENUM.valueOf(vsType), imgOffset, blockSize, trans);
 
  179         } 
catch (TskCoreException ex) {
 
  180             logger.log(Level.SEVERE, 
"Error adding volume system to the database - parent obj ID: " + parentObjId 
 
  181                     + 
", image offset: " + imgOffset, ex);
 
  200     long addVolume(
long parentObjId, 
long addr, 
long start, 
long length, String desc,
 
  204             Volume vol = caseDb.addVolume(parentObjId, addr, start, length, desc, flags, trans);
 
  207         } 
catch (TskCoreException ex) {
 
  208             logger.log(Level.SEVERE, 
"Error adding volume to the database - parent object ID: " + parentObjId
 
  209                 + 
", addr: " + addr, ex);
 
  224     long addPool(
long parentObjId, 
int poolType) {
 
  227             Pool pool = caseDb.addPool(parentObjId, TskData.TSK_POOL_TYPE_ENUM.valueOf(poolType), trans);
 
  230         } 
catch (TskCoreException ex) {
 
  231             logger.log(Level.SEVERE, 
"Error adding pool to the database - parent object ID: " + parentObjId, ex);
 
  252     long addFileSystem(
long parentObjId, 
long imgOffset, 
int fsType, 
long blockSize, 
long blockCount,
 
  253             long rootInum, 
long firstInum, 
long lastInum) {
 
  256             FileSystem fs = caseDb.addFileSystem(parentObjId, imgOffset, TskData.TSK_FS_TYPE_ENUM.valueOf(fsType), blockSize, blockCount,
 
  257                     rootInum, firstInum, lastInum, null, trans);
 
  259             fsIdToFsType.put(fs.getId(), TskData.TSK_FS_TYPE_ENUM.valueOf(fsType));
 
  261         } 
catch (TskCoreException ex) {
 
  262             logger.log(Level.SEVERE, 
"Error adding file system to the database - parent object ID: " + parentObjId
 
  263                     + 
", offset: " + imgOffset, ex);
 
  309     long addFile(
long parentObjId, 
 
  310         long fsObjId, 
long dataSourceObjId,
 
  312         int attrType, 
int attrId, String name,
 
  313         long metaAddr, 
long metaSeq,
 
  314         int dirType, 
int metaType, 
int dirFlags, 
int metaFlags,
 
  316         long crtime, 
long ctime, 
long atime, 
long mtime,
 
  317         int meta_mode, 
int gid, 
int uid,
 
  318         String escaped_path, String extension, 
 
  319         long seq, 
long parMetaAddr, 
long parSeq) {
 
  322         batchedFiles.add(
new FileInfo(parentObjId,
 
  323                 fsObjId, dataSourceObjId,
 
  325                 attrType, attrId, name,
 
  327                 dirType, metaType, dirFlags, metaFlags,
 
  329                 crtime, ctime, atime, mtime,
 
  331                 escaped_path, extension,
 
  332                 seq, parMetaAddr, parSeq));
 
  336         if ((fsObjId == parentObjId)
 
  337                 || (batchedFiles.size() > BATCH_FILE_THRESHOLD)) {
 
  338             return addBatchedFilesToDb();
 
  348     private long addBatchedFilesToDb() {
 
  349         List<Long> newObjIds = 
new ArrayList<>();
 
  353             while ((fileInfo = batchedFiles.poll()) != null) {
 
  354                 long computedParentObjId = fileInfo.parentObjId;
 
  357                     if (fileInfo.parentObjId == 0) {
 
  358                         computedParentObjId = getParentObjId(fileInfo);
 
  361                     long objId = caseDb.addFileJNI(computedParentObjId, 
 
  362                         fileInfo.fsObjId, fileInfo.dataSourceObjId,
 
  364                         fileInfo.attrType, fileInfo.attrId, fileInfo.name,
 
  365                         fileInfo.metaAddr, fileInfo.metaSeq,
 
  366                         fileInfo.dirType, fileInfo.metaType, fileInfo.dirFlags, fileInfo.metaFlags,
 
  368                         fileInfo.crtime, fileInfo.ctime, fileInfo.atime, fileInfo.mtime,
 
  369                         fileInfo.meta_mode, fileInfo.gid, fileInfo.uid,
 
  370                         null, TskData.FileKnown.UNKNOWN,
 
  371                         fileInfo.escaped_path, fileInfo.extension, 
 
  373                     if (fileInfo.fsObjId != fileInfo.parentObjId) {
 
  375                         newObjIds.add(objId);
 
  379                     if (fileInfo.parentObjId == fileInfo.fsObjId) {
 
  380                         fsIdToRootDir.put(fileInfo.fsObjId, objId);
 
  384                     if ((fileInfo.metaType == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
 
  385                             || (fileInfo.metaType == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()))
 
  386                             && (fileInfo.name != null)
 
  387                             && ! fileInfo.name.equals(
".")
 
  388                             && ! fileInfo.name.equals(
"..")) {
 
  389                         String dirName = fileInfo.escaped_path + fileInfo.name;
 
  390                         ParentCacheKey key = 
new ParentCacheKey(fileInfo.fsObjId, fileInfo.metaAddr, fileInfo.seq, dirName);
 
  391                         parentDirCache.put(key, objId);
 
  393                 } 
catch (TskCoreException ex) {
 
  394                     logger.log(Level.SEVERE, 
"Error adding file to the database - parent object ID: " + computedParentObjId
 
  395                             + 
", file system object ID: " + fileInfo.fsObjId + 
", name: " + fileInfo.name, ex);
 
  400                 addDataSourceCallbacks.onFilesAdded(newObjIds);
 
  401                         } 
catch (Exception ex) {
 
  403                 logger.log(Level.SEVERE, 
"Unexpected error from files added callback", ex);
 
  405         } 
catch (TskCoreException ex) {
 
  406             logger.log(Level.SEVERE, 
"Error adding batched files to database", ex);
 
  422     private long getParentObjId(FileInfo fileInfo) 
throws TskCoreException {
 
  424         String parentPath = fileInfo.escaped_path;
 
  425         if(parentPath.endsWith(
"/") && ! parentPath.equals(
"/")) {
 
  426             parentPath =  parentPath.substring(0, parentPath.lastIndexOf(
'/'));
 
  430         ParentCacheKey key = 
new ParentCacheKey(fileInfo.fsObjId, fileInfo.parMetaAddr, fileInfo.parSeq, parentPath);
 
  431         if (parentDirCache.containsKey(key)) {
 
  432             return parentDirCache.get(key);
 
  436             throw new TskCoreException(
"Parent not found in cache (fsObjId: " +fileInfo.fsObjId + 
", parMetaAddr: " + fileInfo.parMetaAddr
 
  437                 + 
", parSeq: " + fileInfo.parSeq + 
", parentPath: " + parentPath + 
")");
 
  454     long addLayoutFile(
long parentObjId, 
 
  455         long fsObjId, 
long dataSourceObjId,
 
  457         String name, 
long size) {
 
  461             Long fsObjIdForDb = fsObjId;
 
  467             long objId = caseDb.addFileJNI(parentObjId, 
 
  468                 fsObjIdForDb, dataSourceObjId,
 
  472                 TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue(), 
 
  473                 TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(), 
 
  474                 TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue(), 
 
  475                 TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
 
  477                 null, null, null, null,
 
  479                 null, TskData.FileKnown.UNKNOWN,
 
  485             layoutFileIds.add(objId);
 
  488         } 
catch (TskCoreException ex) {
 
  489             logger.log(Level.SEVERE, 
"Error adding layout file to the database - parent object ID: " + parentObjId
 
  490                     + 
", file system object ID: " + fsObjId + 
", name: " + name, ex);
 
  507     long addLayoutFileRange(
long objId, 
long byteStart, 
long byteLen, 
long seq) {
 
  508         batchedLayoutRanges.add(
new LayoutRangeInfo(objId, byteStart, byteLen, seq));
 
  510         if (batchedLayoutRanges.size() > BATCH_FILE_THRESHOLD) {
 
  511             return addBatchedLayoutRangesToDb();
 
  521     private long addBatchedLayoutRangesToDb() {
 
  524                 LayoutRangeInfo range;
 
  525             while ((range = batchedLayoutRanges.poll()) != null) {
 
  527                     caseDb.addLayoutFileRangeJNI(range.objId, range.byteStart, range.byteLen, range.seq, trans);
 
  528                 } 
catch (TskCoreException ex) {
 
  529                     logger.log(Level.SEVERE, 
"Error adding layout file range to the database - layout file ID: " + range.objId 
 
  530                         + 
", byte start: " + range.byteStart + 
", length: " + range.byteLen + 
", seq: " + range.seq, ex);
 
  535         } 
catch (TskCoreException ex) {
 
  536             logger.log(Level.SEVERE, 
"Error adding batched files to database", ex);
 
  547     void processLayoutFiles() {
 
  548         addDataSourceCallbacks.onFilesAdded(layoutFileIds);
 
  549         layoutFileIds.clear();
 
  561     long addUnallocFsBlockFilesParent(
long fsObjId, String name) {
 
  563             if (! fsIdToRootDir.containsKey(fsObjId)) {
 
  564                 logger.log(Level.SEVERE, 
"Error - root directory for file system ID {0} not found", fsObjId);
 
  568             VirtualDirectory dir = caseDb.addVirtualDirectory(fsIdToRootDir.get(fsObjId), name, trans);
 
  570             addDataSourceCallbacks.onFilesAdded(Arrays.asList(dir.getId()));
 
  572         } 
catch (TskCoreException ex) {
 
  573             logger.log(Level.SEVERE, 
"Error creating virtual directory " + name + 
" under file system ID " + fsObjId, ex);
 
  582     private class ParentCacheKey {
 
  597         ParentCacheKey(
long fsObjId, 
long metaAddr, 
long seqNum, String path) {
 
  598             this.fsObjId = fsObjId;
 
  599             this.metaAddr = metaAddr;
 
  600             if (fsIdToFsType.containsKey(fsObjId) 
 
  601                     && (fsIdToFsType.get(fsObjId).equals(TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS)
 
  602                         || fsIdToFsType.get(fsObjId).equals(TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS_DETECT))) {
 
  603                 this.seqNum = seqNum;
 
  611         public boolean equals(Object obj) {
 
  612             if (! (obj instanceof ParentCacheKey)) {
 
  616             ParentCacheKey otherKey = (ParentCacheKey) obj;
 
  617             if (this.fsObjId != otherKey.fsObjId 
 
  618                     || 
this.metaAddr != otherKey.metaAddr
 
  619                     || 
this.seqNum != otherKey.seqNum) {
 
  623             return StringUtils.equals(this.path, otherKey.path);
 
  627         public int hashCode() {
 
  629             hash = 31 * hash + (int) (this.fsObjId ^ (this.fsObjId >>> 32));
 
  630             hash = 31 * hash + (int) (this.metaAddr ^ (this.metaAddr >>> 32));
 
  631             hash = 31 * hash + (int) (this.seqNum ^ (this.seqNum >>> 32));
 
  632             hash = 31 * hash + Objects.hashCode(this.path);
 
  641     private class LayoutRangeInfo {
 
  647         LayoutRangeInfo(
long objId, 
long byteStart, 
long byteLen, 
long seq) {
 
  649             this.byteStart = byteStart;
 
  650             this.byteLen = byteLen;
 
  659     private class FileInfo {
 
  662         long dataSourceObjId;
 
  687         FileInfo(
long parentObjId, 
 
  688             long fsObjId, 
long dataSourceObjId,
 
  690             int attrType, 
int attrId, String name,
 
  691             long metaAddr, 
long metaSeq,
 
  692             int dirType, 
int metaType, 
int dirFlags, 
int metaFlags,
 
  694             long crtime, 
long ctime, 
long atime, 
long mtime,
 
  695             int meta_mode, 
int gid, 
int uid,
 
  696             String escaped_path, String extension, 
 
  697             long seq, 
long parMetaAddr, 
long parSeq) {
 
  699             this.parentObjId = parentObjId;
 
  700             this.fsObjId = fsObjId;
 
  701             this.dataSourceObjId = dataSourceObjId;
 
  702             this.fsType = fsType;
 
  703             this.attrType = attrType;
 
  704             this.attrId = attrId;
 
  706             this.metaAddr = metaAddr; 
 
  707             this.metaSeq = metaSeq;
 
  708             this.dirType = dirType;
 
  709             this.metaType = metaType;
 
  710             this.dirFlags = dirFlags;
 
  711             this.metaFlags = metaFlags;
 
  713             this.crtime = crtime;
 
  717             this.meta_mode = meta_mode;
 
  720             this.escaped_path = escaped_path;
 
  721             this.extension = extension;
 
  723             this.parMetaAddr = parMetaAddr;
 
  724             this.parSeq = parSeq;