Sleuth Kit Java Bindings (JNI)  4.6
Java bindings for using The Sleuth Kit
SleuthkitJNI.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-2018 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 java.io.BufferedReader;
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.text.DateFormat;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.GregorianCalendar;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.TimeZone;
35 import java.util.UUID;
36 import java.util.concurrent.locks.ReadWriteLock;
37 import java.util.concurrent.locks.ReentrantReadWriteLock;
39 
48 public class SleuthkitJNI {
49 
56  private static final ReadWriteLock tskLock = new ReentrantReadWriteLock();
57 
58  /*
59  * Loads the SleuthKit libraries.
60  */
61  static {
63  }
64 
69  private SleuthkitJNI() {
70  }
71 
75  private static class CaseHandles {
76  /*
77  * A SleuthKit image handle cache implemented as a mappng of
78  * concatenated image file paths to image handles.
79  */
80  private final Map<String, Long> imageHandleCache = new HashMap<>();
81 
82  /*
83  * A SleuthKit file system handles cache implemented as a mapping of
84  * image handles to image offset and file system handle pairs.
85  */
86  private final Map<Long, Map<Long, Long>> fsHandleCache = new HashMap<>();
87 
88  /*
89  * The collection of open file handles. We will only allow requests
90  * through to the C code if the file handle exists in this collection.
91  */
92  private final Set<Long> fileHandleCache = new HashSet<>();
93 
94  private final Map<Long, List<Long>> fileSystemToFileHandles = new HashMap<>();
95 
96  private final Map<Long, Map<Long, Long>> poolHandleCache = new HashMap<>();
97 
98  // The poolImgCache is only used to close the images later.
99  private final List<Long> poolImgCache = new ArrayList<>();
100 
101  /*
102  * Currently, our APFS code is not thread-safe and it is the only code
103  * that uses pools. To prevent crashes, we make any reads to a file system
104  * contained in a pool single-threaded. This cache keeps track of which
105  * open file system handles are contained in a pool so we can set the locks
106  * appropriately.
107  */
108  private final List<Long> poolFsList = new ArrayList<>();
109 
110  private CaseHandles() {
111  // Nothing to do here
112  }
113  }
114 
121  private static class HandleCache {
122 
123  /*
124  * A monitor used to guard access to cached Sleuthkit JNI handles.
125  */
126  private static final Object cacheLock = new Object();
127 
128  private static final Map<Long, CaseHandles> caseHandlesCache = new HashMap<>();
129 
130  private static final String INVALID_FILE_HANDLE = "Invalid file handle."; //NON-NLS
131 
132  /*
133  * Currently, our APFS code is not thread-safe and it is the only code
134  * that uses pools. To prevent crashes, we make any reads to a file system
135  * contained in a pool single-threaded. This cache keeps track of which
136  * open file handles are contained in a pool so we can set the locks
137  * appropriately.
138  *
139  * Access to this list should be guarded by cacheLock.
140  */
141  private static final List<Long> poolFileHandles = new ArrayList<>();
142 
148  private static void createCaseHandleCache(long caseDbPointer) {
149  caseHandlesCache.put(caseDbPointer, new CaseHandles());
150  }
151 
160  private static long getDefaultCaseDbPointer() throws TskCoreException {
161  synchronized (cacheLock) {
162  if (caseHandlesCache.keySet().size() > 1) {
163  throw new TskCoreException("Can not get default case handle with multiple open cases");
164  } else if (caseHandlesCache.keySet().isEmpty()) {
165  throw new TskCoreException("Can not get default case handle with no open case");
166  }
167 
168  return (caseHandlesCache.keySet().iterator().next());
169  }
170  }
171 
179  private static CaseHandles getCaseHandles(long caseDbPointer) {
180  synchronized (cacheLock) {
181  return caseHandlesCache.get(caseDbPointer);
182  }
183  }
184 
190  private static void removeCaseHandlesCache(long caseDbPointer) {
191  synchronized (cacheLock) {
192  if (caseHandlesCache.containsKey(caseDbPointer)) {
193  caseHandlesCache.get(caseDbPointer).fsHandleCache.clear();
194  caseHandlesCache.get(caseDbPointer).imageHandleCache.clear();
195  caseHandlesCache.get(caseDbPointer).fileHandleCache.clear();
196  caseHandlesCache.get(caseDbPointer).fileSystemToFileHandles.clear();
197  caseHandlesCache.get(caseDbPointer).poolHandleCache.clear();
198  caseHandlesCache.remove(caseDbPointer);
199  }
200  }
201  }
202 
210  private static boolean isImageInAnyCache(long imgHandle) {
211  synchronized (cacheLock) {
212  for (long caseDbPointer:caseHandlesCache.keySet()) {
213  if (caseHandlesCache.get(caseDbPointer).fsHandleCache.keySet().contains(imgHandle)) {
214  return true;
215  }
216  }
217  return false;
218  }
219  }
220 
227  private static void addFileHandle(long caseDbPointer, long fileHandle, long fsHandle) {
228  synchronized (cacheLock) {
229  // Add to collection of open file handles.
230  getCaseHandles(caseDbPointer).fileHandleCache.add(fileHandle);
231 
232  // Add to map of file system to file handles.
233  if (getCaseHandles(caseDbPointer).fileSystemToFileHandles.containsKey(fsHandle)) {
234  getCaseHandles(caseDbPointer).fileSystemToFileHandles.get(fsHandle).add(fileHandle);
235  } else {
236  getCaseHandles(caseDbPointer).fileSystemToFileHandles.put(fsHandle, new ArrayList<Long>(Arrays.asList(fileHandle)));
237  }
238  }
239  }
240 
247  private static void removeFileHandle(long fileHandle, SleuthkitCase skCase) {
248  synchronized (cacheLock) {
249  // Remove from collection of open file handles.
250  if (skCase != null) {
251  try {
252  getCaseHandles(skCase.getCaseDbPointer()).fileHandleCache.remove(fileHandle);
253  } catch (TskCoreException ex) {
254  // This exception will only occur if a file handle is closed as the case is being closed.
255  // The file will be closed by the case closing code.
256  }
257  } else {
258  // If we don't know what case the handle is from, delete the first one we find
259  for (long caseDbPointer:caseHandlesCache.keySet()) {
260  if (caseHandlesCache.get(caseDbPointer).fileHandleCache.contains(fileHandle)) {
261  caseHandlesCache.get(caseDbPointer).fileHandleCache.remove(fileHandle);
262  return;
263  }
264  }
265  }
266  }
267  }
268 
276  private static boolean isValidFileHandle(long fileHandle) {
277  synchronized (cacheLock) {
278  for (long caseDbPointer:caseHandlesCache.keySet()) {
279  if (caseHandlesCache.get(caseDbPointer).fileHandleCache.contains(fileHandle)) {
280  return true;
281  }
282  }
283  return false;
284  }
285  }
286 
287  private static void closeHandlesAndClearCache(long caseDbPointer) throws TskCoreException {
288  synchronized (cacheLock) {
289  /*
290  * Close any cached file system handles.
291  */
292  for (Map<Long, Long> imageToFsMap : getCaseHandles(caseDbPointer).fsHandleCache.values()) {
293  for (Long fsHandle : imageToFsMap.values()) {
294  // First close all open file handles for the file system.
295  if (getCaseHandles(caseDbPointer).fileSystemToFileHandles.containsKey(fsHandle)) {
296  for (Long fileHandle : getCaseHandles(caseDbPointer).fileSystemToFileHandles.get(fsHandle)) {
297  // Update the cache of file handles contained in pools
298  if (poolFileHandles.contains(fileHandle)) {
299  poolFileHandles.remove(fileHandle);
300  }
301  closeFile(fileHandle);
302  }
303  }
304  // Then close the file system handle.
305  closeFsNat(fsHandle);
306  }
307  }
308 
309  /*
310  * Clear out the list of pool file systems.
311  */
312  getCaseHandles(caseDbPointer).poolFsList.clear();
313 
314  /*
315  * Close any cached pools
316  */
317  for (Long imgHandle : getCaseHandles(caseDbPointer).poolHandleCache.keySet()) {
318  for (Long poolHandle : getCaseHandles(caseDbPointer).poolHandleCache.get(imgHandle).values()) {
319  closePoolNat(poolHandle);
320  }
321  }
322 
323  /*
324  * Close any open pool images
325  */
326  for (Long imageHandle : getCaseHandles(caseDbPointer).poolImgCache) {
327  closeImgNat(imageHandle);
328  }
329 
330  /*
331  * Close any cached image handles.
332  */
333  for (Long imageHandle : getCaseHandles(caseDbPointer).imageHandleCache.values()) {
334  closeImgNat(imageHandle);
335  }
336 
337  removeCaseHandlesCache(caseDbPointer);
338  }
339 
340  }
341  }
342 
347  public static class CaseDbHandle {
348 
349  /*
350  * A pointer to a TskCaseDb object.
351  */
352  private final long caseDbPointer;
353 
360  private CaseDbHandle(long caseDbPointer) {
361  this.caseDbPointer = caseDbPointer;
362  HandleCache.createCaseHandleCache(caseDbPointer);
363  }
364 
370  long getCaseDbPointer() {
371  return caseDbPointer;
372  }
373 
380  void free() throws TskCoreException {
381  tskLock.writeLock().lock();
382  try {
383  HandleCache.closeHandlesAndClearCache(caseDbPointer);
384  SleuthkitJNI.closeCaseDbNat(caseDbPointer);
385  } finally {
386  tskLock.writeLock().unlock();
387  }
388  }
389 
413  long addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, SleuthkitCase skCase) throws TskCoreException {
414  try {
415  long tskAutoDbPointer = initializeAddImgNat(caseDbPointer, timezoneLongToShort(timeZone), false, false, false);
416  runOpenAndAddImgNat(tskAutoDbPointer, UUID.randomUUID().toString(), imageFilePaths.toArray(new String[0]), imageFilePaths.size(), timeZone);
417  long id = commitAddImgNat(tskAutoDbPointer);
418  skCase.addDataSourceToHasChildrenMap();
419  return id;
420  } catch (TskDataException ex) {
421  throw new TskCoreException("Error adding image to case database", ex);
422  }
423  }
424 
441  AddImageProcess initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageCopyPath, SleuthkitCase skCase) {
442  return new AddImageProcess(timeZone, addUnallocSpace, skipFatFsOrphans, imageCopyPath, skCase);
443  }
444 
449  public class AddImageProcess {
450 
451  private final String timeZone;
452  private final boolean addUnallocSpace;
453  private final boolean skipFatFsOrphans;
454  private final String imageWriterPath;
455  private volatile long tskAutoDbPointer;
456  private boolean isCanceled;
457  private final SleuthkitCase skCase;
458 
472  private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageWriterPath, SleuthkitCase skCase) {
473  this.timeZone = timeZone;
474  this.addUnallocSpace = addUnallocSpace;
475  this.skipFatFsOrphans = skipFatFsOrphans;
476  this.imageWriterPath = imageWriterPath;
477  tskAutoDbPointer = 0;
478  this.isCanceled = false;
479  this.skCase = skCase;
480  }
481 
500  public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws TskCoreException, TskDataException {
501  getTSKReadLock();
502  try {
503  long imageHandle = 0;
504 
505  synchronized (this) {
506  if (0 != tskAutoDbPointer) {
507  throw new TskCoreException("Add image process already started");
508  }
509  if (!isCanceled) { //with isCanceled being guarded by this it will have the same value everywhere in this synchronized block
510  imageHandle = openImage(imageFilePaths, sectorSize, false, caseDbPointer);
511  tskAutoDbPointer = initAddImgNat(caseDbPointer, timezoneLongToShort(timeZone), addUnallocSpace, skipFatFsOrphans);
512  }
513  if (0 == tskAutoDbPointer) {
514  throw new TskCoreException("initAddImgNat returned a NULL TskAutoDb pointer");
515  }
516  }
517  if (imageHandle != 0) {
518  runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, timeZone, imageWriterPath);
519  }
520  } finally {
521  releaseTSKReadLock();
522  }
523  }
524 
534  public synchronized void stop() throws TskCoreException {
535  getTSKReadLock();
536  try {
537  isCanceled = true;
538  if (tskAutoDbPointer != 0) {
539  stopAddImgNat(tskAutoDbPointer);
540  }
541  } finally {
542  releaseTSKReadLock();
543  }
544  }
545 
553  public synchronized void revert() throws TskCoreException {
554  getTSKReadLock();
555  try {
556  if (tskAutoDbPointer == 0) {
557  throw new TskCoreException("AddImgProcess::revert: AutoDB pointer is NULL");
558  }
559 
560  revertAddImgNat(tskAutoDbPointer);
561  // the native code deleted the object
562  tskAutoDbPointer = 0;
563  } finally {
564  releaseTSKReadLock();
565  }
566  }
567 
577  public synchronized long commit() throws TskCoreException {
578  getTSKReadLock();
579  try {
580  if (tskAutoDbPointer == 0) {
581  throw new TskCoreException("AddImgProcess::commit: AutoDB pointer is NULL");
582  }
583 
584  long id = commitAddImgNat(tskAutoDbPointer);
585 
586  skCase.addDataSourceToHasChildrenMap();
587 
588  // the native code deleted the object
589  tskAutoDbPointer = 0;
590  return id;
591  } finally {
592  releaseTSKReadLock();
593  }
594  }
595 
602  public synchronized String currentDirectory() {
603  return tskAutoDbPointer == 0 ? "" : getCurDirNat(tskAutoDbPointer); //NON-NLS
604  }
605 
621  @Deprecated
622  public void run(String[] imageFilePaths) throws TskCoreException, TskDataException {
623  run(null, imageFilePaths, 0);
624  }
625 
643  public void run(String deviceId, String[] imageFilePaths) throws TskCoreException, TskDataException {
644  run(deviceId, imageFilePaths, 0);
645  }
646  }
647 
648  }
649 
661  static CaseDbHandle newCaseDb(String path) throws TskCoreException {
662  return new CaseDbHandle(newCaseDbNat(path));
663  }
664 
677  static CaseDbHandle newCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException {
678  return new CaseDbHandle(newCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName));
679  }
680 
692  static CaseDbHandle openCaseDb(String path) throws TskCoreException {
693  return new CaseDbHandle(openCaseDbNat(path));
694  }
695 
708  static CaseDbHandle openCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException {
709  return new CaseDbHandle(openCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName));
710  }
711 
717  public static String getVersion() {
718  return getVersionNat();
719  }
720 
726  public static void startVerboseLogging(String logPath) {
727  startVerboseLoggingNat(logPath);
728  }
729 
741  public static long openImage(String[] imageFiles, SleuthkitCase skCase) throws TskCoreException {
742  if (skCase == null) {
743  throw new TskCoreException("SleuthkitCase can not be null");
744  }
745  return openImage(imageFiles, 0, true, skCase.getCaseDbPointer());
746  }
747 
761  public static long openImage(String[] imageFiles, int sSize, SleuthkitCase skCase) throws TskCoreException {
762  if (skCase == null) {
763  throw new TskCoreException("SleuthkitCase can not be null");
764  }
765  return openImage(imageFiles, sSize, true, skCase.getCaseDbPointer());
766  }
767 
785  private static long openImage(String[] imageFiles, int sSize, boolean useCache, Long caseDbPointer) throws TskCoreException {
786 
787  getTSKReadLock();
788  try {
789  long imageHandle;
790 
791  StringBuilder keyBuilder = new StringBuilder();
792  for (int i = 0; i < imageFiles.length; ++i) {
793  keyBuilder.append(imageFiles[i]);
794  }
795  final String imageKey = keyBuilder.toString();
796 
797  synchronized (HandleCache.cacheLock) {
798  Long nonNullCaseDbPointer = caseDbPointer;
799  if (nonNullCaseDbPointer == null) {
800  nonNullCaseDbPointer = HandleCache.getDefaultCaseDbPointer();
801  }
802 
803  // If we're getting a fresh copy, remove any existing cache references
804  if (!useCache && HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.containsKey(imageKey)) {
805  long tempImageHandle = HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.get(imageKey);
806  HandleCache.getCaseHandles(nonNullCaseDbPointer).fsHandleCache.remove(tempImageHandle);
807  HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.remove(imageKey);
808  }
809 
810  if (useCache && HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.containsKey(imageKey)) //get from cache
811  {
812  imageHandle = HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.get(imageKey);
813  } else {
814  //open new handle and cache it
815  imageHandle = openImgNat(imageFiles, imageFiles.length, sSize);
816  HandleCache.getCaseHandles(nonNullCaseDbPointer).fsHandleCache.put(imageHandle, new HashMap<Long, Long>());
817  HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.put(imageKey, imageHandle);
818  }
819  }
820  return imageHandle;
821  } finally {
822  releaseTSKReadLock();
823  }
824  }
825 
838  public static long openVs(long imgHandle, long vsOffset) throws TskCoreException {
839  getTSKReadLock();
840  try {
841  if(! imgHandleIsValid(imgHandle)) {
842  throw new TskCoreException("Image handle " + imgHandle + " is closed");
843  }
844  return openVsNat(imgHandle, vsOffset);
845  } finally {
846  releaseTSKReadLock();
847  }
848  }
849 
850  //get pointers
862  public static long openVsPart(long vsHandle, long volId) throws TskCoreException {
863  getTSKReadLock();
864  try {
865  //returned long is ptr to vs Handle object in tsk
866  return openVolNat(vsHandle, volId);
867  } finally {
868  releaseTSKReadLock();
869  }
870  }
871 
883  static long openPool(long imgHandle, long offset, SleuthkitCase skCase) throws TskCoreException {
884  getTSKReadLock();
885  try {
886  if(! imgHandleIsValid(imgHandle)) {
887  throw new TskCoreException("Image handle " + imgHandle + " is closed");
888  }
889 
890  synchronized (HandleCache.cacheLock) {
891  long caseDbPointer;
892  if (skCase == null) {
893  caseDbPointer = HandleCache.getDefaultCaseDbPointer();
894  } else {
895  caseDbPointer = skCase.getCaseDbPointer();
896  }
897 
898  // If a pool handle cache for this image does not exist, make one
899  if (! HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.containsKey(imgHandle)) {
900  HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.put(imgHandle, new HashMap<>());
901  }
902 
903  // Get the pool handle cache for this image
904  Map<Long, Long> poolCacheForImage = HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.get(imgHandle);
905 
906  if (poolCacheForImage.containsKey(offset)) {
907  return poolCacheForImage.get(offset);
908  } else {
909  //returned long is ptr to pool Handle object in tsk
910  long poolHandle = openPoolNat(imgHandle, offset);
911  poolCacheForImage.put(offset, poolHandle);
912  return poolHandle;
913  }
914  }
915  } finally {
916  releaseTSKReadLock();
917  }
918  }
919 
933  public static long openFs(long imgHandle, long fsOffset, SleuthkitCase skCase) throws TskCoreException {
934  getTSKReadLock();
935  try {
936  long fsHandle;
937  synchronized (HandleCache.cacheLock) {
938  long caseDbPointer;
939  if (skCase == null) {
940  caseDbPointer = HandleCache.getDefaultCaseDbPointer();
941  } else {
942  caseDbPointer = skCase.getCaseDbPointer();
943  }
944  final Map<Long, Long> imgOffSetToFsHandle = HandleCache.getCaseHandles(caseDbPointer).fsHandleCache.get(imgHandle);
945  if (imgOffSetToFsHandle == null) {
946  throw new TskCoreException("Missing image offset to file system handle cache for image handle " + imgHandle);
947  }
948  if (imgOffSetToFsHandle.containsKey(fsOffset)) {
949  //return cached
950  fsHandle = imgOffSetToFsHandle.get(fsOffset);
951  } else {
952  fsHandle = openFsNat(imgHandle, fsOffset);
953  //cache it
954  imgOffSetToFsHandle.put(fsOffset, fsHandle);
955  }
956  }
957  return fsHandle;
958  } finally {
959  releaseTSKReadLock();
960  }
961  }
962 
979  static long openFsPool(long imgHandle, long fsOffset, long poolHandle, long poolBlock, SleuthkitCase skCase) throws TskCoreException {
980  /*
981  * Currently, our APFS code is not thread-safe and it is the only code
982  * that uses pools. To prevent crashes, we make any reads to a file system
983  * contained in a pool single-threaded.
984  */
985  getTSKWriteLock();
986  try {
987  long fsHandle;
988  synchronized (HandleCache.cacheLock) {
989  long caseDbPointer;
990  if (skCase == null) {
991  caseDbPointer = HandleCache.getDefaultCaseDbPointer();
992  } else {
993  caseDbPointer = skCase.getCaseDbPointer();
994  }
995  final Map<Long, Long> imgOffSetToFsHandle = HandleCache.getCaseHandles(caseDbPointer).fsHandleCache.get(imgHandle);
996  if (imgOffSetToFsHandle == null) {
997  throw new TskCoreException("Missing image offset to file system handle cache for image handle " + imgHandle);
998  }
999 
1000  if (imgOffSetToFsHandle.containsKey(poolBlock)) {
1001  //return cached
1002  fsHandle = imgOffSetToFsHandle.get(poolBlock);
1003  } else {
1004  long poolImgHandle = getImgInfoForPoolNat(poolHandle, poolBlock);
1005  HandleCache.getCaseHandles(caseDbPointer).poolImgCache.add(poolImgHandle);
1006  fsHandle = openFsNat(poolImgHandle, fsOffset);
1007  //cache it
1008  imgOffSetToFsHandle.put(poolBlock, fsHandle);
1009  HandleCache.getCaseHandles(caseDbPointer).poolFsList.add(fsHandle);
1010  }
1011  }
1012  return fsHandle;
1013  } finally {
1014  releaseTSKWriteLock();
1015  }
1016  }
1017 
1032  public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, SleuthkitCase skCase) throws TskCoreException {
1033  /*
1034  * NOTE: previously attrId used to be stored in AbstractFile as (signed)
1035  * short even though it is stored as uint16 in TSK. In extremely rare
1036  * occurrences attrId can be larger than what a signed short can hold
1037  * (2^15). Changes were made to AbstractFile to store attrId as integer.
1038  * However, a depricated method still exists in AbstractFile to get
1039  * attrId as short. In that method we convert attribute ids that are
1040  * larger than 32K to a negative number. Therefore if encountered, we
1041  * need to convert negative attribute id to uint16 which is what TSK is
1042  * using to store attribute id.
1043  */
1044  boolean withinPool = false;
1045  synchronized (HandleCache.cacheLock) {
1046  long caseDbPointer;
1047  if (skCase == null) {
1048  caseDbPointer = HandleCache.getDefaultCaseDbPointer();
1049  } else {
1050  caseDbPointer = skCase.getCaseDbPointer();
1051  }
1052  if (HandleCache.getCaseHandles(caseDbPointer).poolFsList.contains(fsHandle)) {
1053  withinPool = true;
1054  }
1055  }
1056 
1057  /*
1058  * The current APFS code is not thread-safe. To compensate, we make any
1059  * reads to the APFS pool single-threaded by obtaining a write
1060  * lock instead of a read lock.
1061  */
1062  if (withinPool) {
1063  getTSKWriteLock();
1064  } else {
1065  getTSKReadLock();
1066  }
1067  try {
1068  long fileHandle = openFileNat(fsHandle, fileId, attrType.getValue(), convertSignedToUnsigned(attrId));
1069  synchronized (HandleCache.cacheLock) {
1070  long caseDbPointer;
1071  if (skCase == null) {
1072  caseDbPointer = HandleCache.getDefaultCaseDbPointer();
1073  } else {
1074  caseDbPointer = skCase.getCaseDbPointer();
1075  }
1076  HandleCache.addFileHandle(caseDbPointer, fileHandle, fsHandle);
1077 
1078  // If this file is in a pool file system, record it so the locks
1079  // can be set appropriately when reading it.
1080  if (withinPool) {
1081  HandleCache.poolFileHandles.add(fileHandle);
1082  }
1083  }
1084  return fileHandle;
1085  } finally {
1086  if (withinPool) {
1087  releaseTSKWriteLock();
1088  } else {
1089  releaseTSKReadLock();
1090  }
1091  }
1092  }
1093 
1101  private static int convertSignedToUnsigned(int val) {
1102  if (val >= 0) {
1103  return val;
1104  }
1105 
1106  return val & 0xffff; // convert negative value to positive value
1107  }
1108 
1114  private static boolean imgHandleIsValid(long imgHandle) {
1115  synchronized(HandleCache.cacheLock) {
1116  return HandleCache.isImageInAnyCache(imgHandle);
1117  }
1118  }
1119 
1120  //do reads
1135  public static int readImg(long imgHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1136  getTSKReadLock();
1137  try {
1138  if(! imgHandleIsValid(imgHandle)) {
1139  throw new TskCoreException("Image handle " + imgHandle + " is closed");
1140  }
1141  //returned byte[] is the data buffer
1142  return readImgNat(imgHandle, readBuffer, offset, len);
1143  } finally {
1144  releaseTSKReadLock();
1145  }
1146  }
1147 
1162  public static int readVs(long vsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1163  getTSKReadLock();
1164  try {
1165  return readVsNat(vsHandle, readBuffer, offset, len);
1166  } finally {
1167  releaseTSKReadLock();
1168  }
1169  }
1170 
1183  static int readPool(long poolHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1184  getTSKReadLock();
1185  try {
1186  return readPoolNat(poolHandle, readBuffer, offset, len);
1187  } finally {
1188  releaseTSKReadLock();
1189  }
1190  }
1191 
1206  public static int readVsPart(long volHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1207  getTSKReadLock();
1208  try {
1209  //returned byte[] is the data buffer
1210  return readVolNat(volHandle, readBuffer, offset, len);
1211  } finally {
1212  releaseTSKReadLock();
1213  }
1214  }
1215 
1230  public static int readFs(long fsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1231  getTSKReadLock();
1232  try {
1233  //returned byte[] is the data buffer
1234  return readFsNat(fsHandle, readBuffer, offset, len);
1235  } finally {
1236  releaseTSKReadLock();
1237  }
1238  }
1239 
1244  private enum TSK_FS_FILE_READ_OFFSET_TYPE_ENUM {
1245  START_OF_FILE(0),
1246  START_OF_SLACK(1);
1247 
1248  private final int val;
1249 
1250  TSK_FS_FILE_READ_OFFSET_TYPE_ENUM(int val) {
1251  this.val = val;
1252  }
1253 
1254  int getValue() {
1255  return val;
1256  }
1257  }
1258 
1273  public static int readFile(long fileHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1274  boolean withinPool = false;
1275  synchronized (HandleCache.cacheLock) {
1276  if (HandleCache.poolFileHandles.contains(fileHandle)) {
1277  withinPool = true;
1278  }
1279  }
1280 
1281  /*
1282  * The current APFS code is not thread-safe. To compensate, we make any
1283  * reads to the APFS pool single-threaded by obtaining a write
1284  * lock instead of a read lock.
1285  */
1286  if (withinPool) {
1287  getTSKWriteLock();
1288  } else {
1289  getTSKReadLock();
1290  }
1291  try {
1292  if (!HandleCache.isValidFileHandle(fileHandle)) {
1293  throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1294  }
1295 
1296  return readFileNat(fileHandle, readBuffer, offset, TSK_FS_FILE_READ_OFFSET_TYPE_ENUM.START_OF_FILE.getValue(), len);
1297  } finally {
1298  if (withinPool) {
1299  releaseTSKWriteLock();
1300  } else {
1301  releaseTSKReadLock();
1302  }
1303  }
1304  }
1305 
1320  public static int readFileSlack(long fileHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1321  getTSKReadLock();
1322  try {
1323  if (!HandleCache.isValidFileHandle(fileHandle)) {
1324  throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1325  }
1326 
1327  return readFileNat(fileHandle, readBuffer, offset, TSK_FS_FILE_READ_OFFSET_TYPE_ENUM.START_OF_SLACK.getValue(), len);
1328  } finally {
1329  releaseTSKReadLock();
1330  }
1331  }
1332 
1343  public static List<String> getFileMetaDataText(long fileHandle) throws TskCoreException {
1344  getTSKReadLock();
1345  try {
1346  if (!HandleCache.isValidFileHandle(fileHandle)) {
1347  throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1348  }
1349 
1350  try {
1351  java.io.File tmp = java.io.File.createTempFile("tsk", ".txt");
1352 
1353  saveFileMetaDataTextNat(fileHandle, tmp.getAbsolutePath());
1354 
1355  FileReader fr = new FileReader(tmp.getAbsolutePath());
1356  BufferedReader textReader = new BufferedReader(fr);
1357 
1358  List<String> lines = new ArrayList<String>();
1359  while (true) {
1360  String line = textReader.readLine();
1361  if (line == null) {
1362  break;
1363  }
1364  lines.add(line);
1365  }
1366  textReader.close();
1367  fr.close();
1368  tmp.delete();
1369  return lines;
1370  } catch (IOException ex) {
1371  throw new TskCoreException("Error reading istat output: " + ex.getLocalizedMessage());
1372  }
1373  } finally {
1374  releaseTSKReadLock();
1375  }
1376  }
1377 
1383  public static void closeFile(long fileHandle) {
1384  closeFile(fileHandle, null);
1385  }
1386 
1393  public static void closeFile(long fileHandle, SleuthkitCase skCase) {
1394  boolean withinPool = false;
1395  synchronized (HandleCache.cacheLock) {
1396  if (HandleCache.poolFileHandles.contains(fileHandle)) {
1397  withinPool = true;
1398  }
1399  }
1400 
1401  /*
1402  * The current APFS code is not thread-safe. To compensate, we make any
1403  * reads to the APFS pool single-threaded by obtaining a write
1404  * lock instead of a read lock.
1405  */
1406  if (withinPool) {
1407  getTSKWriteLock();
1408  } else {
1409  getTSKReadLock();
1410  }
1411  try {
1412  synchronized (HandleCache.cacheLock) {
1413  if (!HandleCache.isValidFileHandle(fileHandle)) {
1414  // File handle is not open so this is a no-op.
1415  return;
1416  }
1417  closeFileNat(fileHandle);
1418  HandleCache.removeFileHandle(fileHandle, skCase);
1419  if (HandleCache.poolFileHandles.contains(fileHandle)) {
1420  HandleCache.poolFileHandles.remove(fileHandle);
1421  }
1422  }
1423  } finally {
1424  if (withinPool) {
1425  releaseTSKWriteLock();
1426  } else {
1427  releaseTSKReadLock();
1428  }
1429  }
1430  }
1431 
1439  public static void createLookupIndexForHashDatabase(int dbHandle) throws TskCoreException {
1440  hashDbCreateIndexNat(dbHandle);
1441  }
1442 
1452  public static boolean hashDatabaseHasLookupIndex(int dbHandle) throws TskCoreException {
1453  return hashDbIndexExistsNat(dbHandle);
1454  }
1455 
1466  public static boolean hashDatabaseCanBeReindexed(int dbHandle) throws TskCoreException {
1467  return hashDbIsReindexableNat(dbHandle);
1468  }
1469 
1479  public static String getHashDatabasePath(int dbHandle) throws TskCoreException {
1480  return hashDbPathNat(dbHandle);
1481  }
1482 
1492  public static String getHashDatabaseIndexPath(int dbHandle) throws TskCoreException {
1493  return hashDbIndexPathNat(dbHandle);
1494  }
1495 
1502  public static int openHashDatabase(String path) throws TskCoreException {
1503  return hashDbOpenNat(path);
1504  }
1505 
1515  public static int createHashDatabase(String path) throws TskCoreException {
1516  return hashDbNewNat(path);
1517  }
1518 
1525  public static void closeAllHashDatabases() throws TskCoreException {
1526  hashDbCloseAll();
1527  }
1528 
1538  public static void closeHashDatabase(int dbHandle) throws TskCoreException {
1539  hashDbClose(dbHandle);
1540  }
1541 
1551  public static String getHashDatabaseDisplayName(int dbHandle) throws TskCoreException {
1552  return hashDbGetDisplayName(dbHandle);
1553  }
1554 
1565  public static boolean lookupInHashDatabase(String hash, int dbHandle) throws TskCoreException {
1566  return hashDbLookup(hash, dbHandle);
1567  }
1568 
1580  public static HashHitInfo lookupInHashDatabaseVerbose(String hash, int dbHandle) throws TskCoreException {
1581  return hashDbLookupVerbose(hash, dbHandle);
1582  }
1583 
1596  public static void addToHashDatabase(String filename, String md5, String sha1, String sha256, String comment, int dbHandle) throws TskCoreException {
1597  hashDbAddEntryNat(filename, md5, sha1, sha256, comment, dbHandle);
1598  }
1599 
1600  public static void addToHashDatabase(List<HashEntry> hashes, int dbHandle) throws TskCoreException {
1601  hashDbBeginTransactionNat(dbHandle);
1602  try {
1603  for (HashEntry entry : hashes) {
1604  hashDbAddEntryNat(entry.getFileName(), entry.getMd5Hash(), entry.getSha1Hash(), entry.getSha256Hash(), entry.getComment(), dbHandle);
1605  }
1606  hashDbCommitTransactionNat(dbHandle);
1607  } catch (TskCoreException ex) {
1608  try {
1609  hashDbRollbackTransactionNat(dbHandle);
1610  } catch (TskCoreException ex2) {
1611  ex2.initCause(ex);
1612  throw ex2;
1613  }
1614  throw ex;
1615  }
1616  }
1617 
1618  public static boolean isUpdateableHashDatabase(int dbHandle) throws TskCoreException {
1619  return hashDbIsUpdateableNat(dbHandle);
1620  }
1621 
1622  public static boolean hashDatabaseIsIndexOnly(int dbHandle) throws TskCoreException {
1623  return hashDbIsIdxOnlyNat(dbHandle);
1624  }
1625 
1635  private static String timezoneLongToShort(String timezoneLongForm) {
1636  if (timezoneLongForm == null || timezoneLongForm.isEmpty()) {
1637  return "";
1638  }
1639 
1640  String timezoneShortForm;
1641  TimeZone zone = TimeZone.getTimeZone(timezoneLongForm);
1642  int offset = zone.getRawOffset() / 1000;
1643  int hour = offset / 3600;
1644  int min = (offset % 3600) / 60;
1645  DateFormat dfm = new SimpleDateFormat("z");
1646  dfm.setTimeZone(zone);
1647  boolean hasDaylight = zone.useDaylightTime();
1648  String first = dfm.format(new GregorianCalendar(2010, 1, 1).getTime()).substring(0, 3); // make it only 3 letters code
1649  String second = dfm.format(new GregorianCalendar(2011, 6, 6).getTime()).substring(0, 3); // make it only 3 letters code
1650  int mid = hour * -1;
1651  timezoneShortForm = first + Integer.toString(mid);
1652  if (min != 0) {
1653  timezoneShortForm = timezoneShortForm + ":" + (min < 10 ? "0" : "") + Integer.toString(min);
1654  }
1655  if (hasDaylight) {
1656  timezoneShortForm += second;
1657  }
1658  return timezoneShortForm;
1659  }
1660 
1671  public static int finishImageWriter(long imgHandle) throws TskCoreException {
1672  getTSKReadLock();
1673  try {
1674  if(! imgHandleIsValid(imgHandle)) {
1675  throw new TskCoreException("Image handle " + imgHandle + " is closed");
1676  }
1677  return finishImageWriterNat(imgHandle);
1678  } finally {
1679  releaseTSKReadLock();
1680  }
1681  }
1682 
1690  public static int getFinishImageProgress(long imgHandle) {
1691  getTSKReadLock();
1692  try {
1693  if (imgHandleIsValid(imgHandle)) {
1694  return getFinishImageProgressNat(imgHandle);
1695  } else {
1696  return 0;
1697  }
1698  } finally {
1699  releaseTSKReadLock();
1700  }
1701  }
1702 
1708  public static void cancelFinishImage(long imgHandle) {
1709  getTSKReadLock();
1710  try {
1711  if (imgHandleIsValid(imgHandle)) {
1712  cancelFinishImageNat(imgHandle);
1713  }
1714  } finally {
1715  releaseTSKReadLock();
1716  }
1717  }
1718 
1730  public static long findDeviceSize(String devPath) throws TskCoreException {
1731  return findDeviceSizeNat(devPath);
1732  }
1733 
1734  public static boolean isImageSupported(String imagePath) {
1735  return isImageSupportedNat(imagePath);
1736  }
1737 
1742  private static void getTSKReadLock() {
1743  tskLock.readLock().lock();
1744  }
1745 
1749  private static void releaseTSKReadLock() {
1750  tskLock.readLock().unlock();
1751  }
1752 
1760  private static void getTSKWriteLock() {
1761  tskLock.writeLock().lock();
1762  }
1763 
1767  private static void releaseTSKWriteLock() {
1768  tskLock.writeLock().unlock();
1769  }
1770 
1771  //free pointers
1778  @Deprecated
1779  public static void closeImg(long imgHandle) {
1780  //closeImgNat(imgHandle);
1781  }
1782 
1788  @Deprecated
1789  public static void closeVs(long vsHandle) {
1790  // closeVsNat(vsHandle); TODO JIRA-3829
1791  }
1792 
1799  @Deprecated
1800  public static void closeFs(long fsHandle) {
1801  //closeFsNat(fsHandle);
1802  }
1803 
1815  @Deprecated
1816  public static long openImage(String[] imageFiles) throws TskCoreException {
1817 
1818  return openImage(imageFiles, 0, true, null);
1819  }
1820 
1834  @Deprecated
1835  public static long openImage(String[] imageFiles, int sSize) throws TskCoreException {
1836  return openImage(imageFiles, sSize, true, null);
1837  }
1838 
1839 
1853  @Deprecated
1854  public static long openFs(long imgHandle, long fsOffset) throws TskCoreException {
1855  return openFs(imgHandle, fsOffset, null);
1856  }
1857 
1872  @Deprecated
1873  public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId) throws TskCoreException {
1874  return openFile(fsHandle, fileId, attrType, attrId, null);
1875  }
1876 
1877 
1878  private static native String getVersionNat();
1879 
1880  private static native void startVerboseLoggingNat(String logPath);
1881 
1882  private static native long newCaseDbNat(String dbPath) throws TskCoreException;
1883 
1884  private static native long newCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName);
1885 
1886  private static native long openCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName);
1887 
1888  private static native long openCaseDbNat(String path) throws TskCoreException;
1889 
1890  private static native void closeCaseDbNat(long db) throws TskCoreException;
1891 
1892  private static native int hashDbOpenNat(String hashDbPath) throws TskCoreException;
1893 
1894  private static native int hashDbNewNat(String hashDbPath) throws TskCoreException;
1895 
1896  private static native int hashDbBeginTransactionNat(int dbHandle) throws TskCoreException;
1897 
1898  private static native int hashDbCommitTransactionNat(int dbHandle) throws TskCoreException;
1899 
1900  private static native int hashDbRollbackTransactionNat(int dbHandle) throws TskCoreException;
1901 
1902  private static native int hashDbAddEntryNat(String filename, String hashMd5, String hashSha1, String hashSha256, String comment, int dbHandle) throws TskCoreException;
1903 
1904  private static native boolean hashDbIsUpdateableNat(int dbHandle);
1905 
1906  private static native boolean hashDbIsReindexableNat(int dbHandle);
1907 
1908  private static native String hashDbPathNat(int dbHandle);
1909 
1910  private static native String hashDbIndexPathNat(int dbHandle);
1911 
1912  private static native String hashDbGetDisplayName(int dbHandle) throws TskCoreException;
1913 
1914  private static native void hashDbCloseAll() throws TskCoreException;
1915 
1916  private static native void hashDbClose(int dbHandle) throws TskCoreException;
1917 
1918  private static native void hashDbCreateIndexNat(int dbHandle) throws TskCoreException;
1919 
1920  private static native boolean hashDbIndexExistsNat(int dbHandle) throws TskCoreException;
1921 
1922  private static native boolean hashDbIsIdxOnlyNat(int dbHandle) throws TskCoreException;
1923 
1924  private static native boolean hashDbLookup(String hash, int dbHandle) throws TskCoreException;
1925 
1926  private static native HashHitInfo hashDbLookupVerbose(String hash, int dbHandle) throws TskCoreException;
1927 
1928  private static native long initAddImgNat(long db, String timezone, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException;
1929 
1930  private static native long initializeAddImgNat(long db, String timezone, boolean addFileSystems, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException;
1931 
1932  private static native void runOpenAndAddImgNat(long process, String deviceId, String[] imgPath, int splits, String timezone) throws TskCoreException, TskDataException;
1933 
1934  private static native void runAddImgNat(long process, String deviceId, long a_img_info, String timeZone, String imageWriterPath) throws TskCoreException, TskDataException;
1935 
1936  private static native void stopAddImgNat(long process) throws TskCoreException;
1937 
1938  private static native void revertAddImgNat(long process) throws TskCoreException;
1939 
1940  private static native long commitAddImgNat(long process) throws TskCoreException;
1941 
1942  private static native long openImgNat(String[] imgPath, int splits, int sSize) throws TskCoreException;
1943 
1944  private static native long openVsNat(long imgHandle, long vsOffset) throws TskCoreException;
1945 
1946  private static native long openVolNat(long vsHandle, long volId) throws TskCoreException;
1947 
1948  private static native long openPoolNat(long imgHandle, long offset) throws TskCoreException;
1949 
1950  private static native long getImgInfoForPoolNat(long poolHandle, long poolOffset) throws TskCoreException;
1951 
1952  private static native long openFsNat(long imgHandle, long fsId) throws TskCoreException;
1953 
1954  private static native long openFileNat(long fsHandle, long fileId, int attrType, int attrId) throws TskCoreException;
1955 
1956  private static native int readImgNat(long imgHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1957 
1958  private static native int readVsNat(long vsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1959 
1960  private static native int readPoolNat(long poolHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1961 
1962  private static native int readVolNat(long volHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1963 
1964  private static native int readFsNat(long fsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1965 
1966  private static native int readFileNat(long fileHandle, byte[] readBuffer, long offset, int offset_type, long len) throws TskCoreException;
1967 
1968  private static native int saveFileMetaDataTextNat(long fileHandle, String fileName) throws TskCoreException;
1969 
1970  private static native void closeImgNat(long imgHandle);
1971 
1972  private static native void closePoolNat(long poolHandle);
1973 
1974  private static native void closeVsNat(long vsHandle);
1975 
1976  private static native void closeFsNat(long fsHandle);
1977 
1978  private static native void closeFileNat(long fileHandle);
1979 
1980  private static native long findDeviceSizeNat(String devicePath) throws TskCoreException;
1981 
1982  private static native String getCurDirNat(long process);
1983 
1984  private static native boolean isImageSupportedNat(String imagePath);
1985 
1986  private static native int finishImageWriterNat(long a_img_info);
1987 
1988  private static native int getFinishImageProgressNat(long a_img_info);
1989 
1990  private static native void cancelFinishImageNat(long a_img_info);
1991 
1992 }
static int readImg(long imgHandle, byte[] readBuffer, long offset, long len)
static String getHashDatabaseIndexPath(int dbHandle)
static int readVs(long vsHandle, byte[] readBuffer, long offset, long len)
static void createLookupIndexForHashDatabase(int dbHandle)
static void addToHashDatabase(String filename, String md5, String sha1, String sha256, String comment, int dbHandle)
static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, SleuthkitCase skCase)
static int createHashDatabase(String path)
static void closeFs(long fsHandle)
static void cancelFinishImage(long imgHandle)
static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId)
void run(String deviceId, String[] imageFilePaths)
static int readFile(long fileHandle, byte[] readBuffer, long offset, long len)
static int finishImageWriter(long imgHandle)
static HashHitInfo lookupInHashDatabaseVerbose(String hash, int dbHandle)
static long openVs(long imgHandle, long vsOffset)
static long openImage(String[] imageFiles, SleuthkitCase skCase)
static boolean hashDatabaseIsIndexOnly(int dbHandle)
static boolean isImageSupported(String imagePath)
static int readVsPart(long volHandle, byte[] readBuffer, long offset, long len)
static void closeFile(long fileHandle, SleuthkitCase skCase)
static long openImage(String[] imageFiles, int sSize)
static void closeVs(long vsHandle)
static long openImage(String[] imageFiles)
static long openFs(long imgHandle, long fsOffset, SleuthkitCase skCase)
static long openImage(String[] imageFiles, int sSize, SleuthkitCase skCase)
void run(String deviceId, String[] imageFilePaths, int sectorSize)
Definition: HashEntry.java:25
static long findDeviceSize(String devPath)
static String getHashDatabaseDisplayName(int dbHandle)
static List< String > getFileMetaDataText(long fileHandle)
static void closeImg(long imgHandle)
static long openFs(long imgHandle, long fsOffset)
static int getFinishImageProgress(long imgHandle)
static int openHashDatabase(String path)
static void closeFile(long fileHandle)
static boolean lookupInHashDatabase(String hash, int dbHandle)
static boolean hashDatabaseHasLookupIndex(int dbHandle)
static long openVsPart(long vsHandle, long volId)
static int readFileSlack(long fileHandle, byte[] readBuffer, long offset, long len)
static boolean isUpdateableHashDatabase(int dbHandle)
static void addToHashDatabase(List< HashEntry > hashes, int dbHandle)
static boolean hashDatabaseCanBeReindexed(int dbHandle)
static void startVerboseLogging(String logPath)
static int readFs(long fsHandle, byte[] readBuffer, long offset, long len)
static String getHashDatabasePath(int dbHandle)
static void closeHashDatabase(int dbHandle)

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