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;