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;
38 import org.sleuthkit.datamodel.TskData.TSK_FS_ATTR_TYPE_ENUM;
39 
40 /**
41  * A utility class that provides a interface to the SleuthKit via JNI. Supports
42  * case management, add image process, reading data off content objects Setting
43  * up Hash database parameters and updating / reading values
44  *
45  * Caches image and filesystem handles and reuses them for the duration of the
46  * application
47  */
48 public class SleuthkitJNI {
49 
50 	/**
51 	 * Lock to protect against the TSK data structures being closed while
52 	 * another thread is in the C++ code. Do not use this lock after obtaining
53 	 * HandleCache.cacheLock. Additionally, the only code that should acquire
54 	 * the write lock is CaseDbHandle.free().
55 	 */
56 	private static final ReadWriteLock tskLock = new ReentrantReadWriteLock();
57 
58 	/*
59 	 * Loads the SleuthKit libraries.
60 	 */
61 	static {
LibraryUtils.loadSleuthkitJNI()62 		LibraryUtils.loadSleuthkitJNI();
63 	}
64 
65 	/**
66 	 * Constructor for the utility class that provides a interface to the
67 	 * SleuthKit via JNI.
68 	 */
SleuthkitJNI()69 	private SleuthkitJNI() {
70 	}
71 
72 	/**
73 	 * Utility class to hold the handles for a single case.
74 	 */
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 
CaseHandles()96 		private CaseHandles() {
97 			// Nothing to do here
98 		}
99 	}
100 
101 	/**
102 	 * Cache of all handles allocated in the JNI layer. Used for: (a) quick
103 	 * lookup of frequently used handles (e.g. file system and image) (b)
104 	 * ensuring all handles passed in by clients of SleuthkitJNI are valid. (c)
105 	 * consistent cleanup of handles on closure.
106 	 */
107 	private static class HandleCache {
108 
109 		/*
110 		 * A monitor used to guard access to cached Sleuthkit JNI handles.
111 		 */
112 		private static final Object cacheLock = new Object();
113 
114 		private static final Map<Long, CaseHandles> caseHandlesCache = new HashMap<>();
115 
116 		private static final String INVALID_FILE_HANDLE = "Invalid file handle."; //NON-NLS
117 
118 		/**
119 		 * Create the empty cache for a new case
120 		 *
121 		 * @param caseDbPointer
122 		 */
createCaseHandleCache(long caseDbPointer)123 		private static void createCaseHandleCache(long caseDbPointer) {
124 			caseHandlesCache.put(caseDbPointer, new CaseHandles());
125 		}
126 
127 		/**
128 		 * If there is one case open return its handle.
129 		 * This is to support deprecated methods that don't have a case parameter.
130 		 *
131 		 * @return the open case pointer
132 		 *
133 		 * @throws TskCoreException If there are no cases open or if multiple cases are open
134 		 */
getDefaultCaseDbPointer()135 		private static long getDefaultCaseDbPointer() throws TskCoreException {
136 			synchronized (cacheLock) {
137 				if (caseHandlesCache.keySet().size() > 1) {
138 					throw new TskCoreException("Can not get default case handle with multiple open cases");
139 				} else if (caseHandlesCache.keySet().isEmpty()) {
140 					throw new TskCoreException("Can not get default case handle with no open case");
141 				}
142 
143 				return (caseHandlesCache.keySet().iterator().next());
144 			}
145 		}
146 
147 		/**
148 		 * Gets the case handle cache for a given case.
149 		 *
150 		 * @param caseDbPointer
151 		 *
152 		 * @return the case handle cache
153 		 */
getCaseHandles(long caseDbPointer)154 		private static CaseHandles getCaseHandles(long caseDbPointer) {
155 			synchronized (cacheLock) {
156 				return caseHandlesCache.get(caseDbPointer);
157 			}
158 		}
159 
160 		/**
161 		 * Removes the case handle cache for a given case.
162 		 *
163 		 * @param caseDbPointer
164 		 */
removeCaseHandlesCache(long caseDbPointer)165 		private static void removeCaseHandlesCache(long caseDbPointer) {
166 			synchronized (cacheLock) {
167 				if (caseHandlesCache.containsKey(caseDbPointer)) {
168 					caseHandlesCache.get(caseDbPointer).fsHandleCache.clear();
169 					caseHandlesCache.get(caseDbPointer).imageHandleCache.clear();
170 					caseHandlesCache.get(caseDbPointer).fileHandleCache.clear();
171 					caseHandlesCache.get(caseDbPointer).fileSystemToFileHandles.clear();
172 					caseHandlesCache.remove(caseDbPointer);
173 				}
174 			}
175 		}
176 
177 		/**
178 		 * Searches all the open caches for an image handle.
179 		 *
180 		 * @param imgHandle
181 		 *
182 		 * @return true if the handle is found in any cache, false otherwise
183 		 */
isImageInAnyCache(long imgHandle)184 		private static boolean isImageInAnyCache(long imgHandle) {
185 			synchronized (cacheLock) {
186 				for (long caseDbPointer:caseHandlesCache.keySet()) {
187 					if (caseHandlesCache.get(caseDbPointer).fsHandleCache.keySet().contains(imgHandle)) {
188 						return true;
189 					}
190 				}
191 				return false;
192 			}
193 		}
194 
195 		/**
196 		 * Add a new file handle to the cache.
197 		 *
198 		 * @param fileHandle The new file handle.
199 		 * @param fsHandle   The file system handle in which the file lives.
200 		 */
addFileHandle(long caseDbPointer, long fileHandle, long fsHandle)201 		private static void addFileHandle(long caseDbPointer, long fileHandle, long fsHandle) {
202 			synchronized (cacheLock) {
203 				// Add to collection of open file handles.
204 				getCaseHandles(caseDbPointer).fileHandleCache.add(fileHandle);
205 
206 				// Add to map of file system to file handles.
207 				if (getCaseHandles(caseDbPointer).fileSystemToFileHandles.containsKey(fsHandle)) {
208 					getCaseHandles(caseDbPointer).fileSystemToFileHandles.get(fsHandle).add(fileHandle);
209 				} else {
210 					getCaseHandles(caseDbPointer).fileSystemToFileHandles.put(fsHandle, new ArrayList<Long>(Arrays.asList(fileHandle)));
211 				}
212 			}
213 		}
214 
215 		/**
216 		 * Removes a file handle from the cache for the given case
217 		 *
218 		 * @param fileHandle
219 		 * @param skCase     Can be null. If so, the first matching handle will be removed.
220 		 */
removeFileHandle(long fileHandle, SleuthkitCase skCase)221 		private static void removeFileHandle(long fileHandle, SleuthkitCase skCase) {
222 			synchronized (cacheLock) {
223 				// Remove from collection of open file handles.
224 				if (skCase != null) {
225 					getCaseHandles(skCase.getCaseHandle().caseDbPointer).fileHandleCache.remove(fileHandle);
226 				} else {
227 					// If we don't know what case the handle is from, delete the first one we find
228 					for (long caseDbPointer:caseHandlesCache.keySet()) {
229 						if (caseHandlesCache.get(caseDbPointer).fileHandleCache.contains(fileHandle)) {
230 							caseHandlesCache.get(caseDbPointer).fileHandleCache.remove(fileHandle);
231 							return;
232 						}
233 					}
234 				}
235 			}
236 		}
237 
238 		/**
239 		 * Searches all the open caches for a file handle.
240 		 *
241 		 * @param fileHandle
242 		 *
243 		 * @return true if the handle is found in any cache, false otherwise
244 		 */
isValidFileHandle(long fileHandle)245 		private static boolean isValidFileHandle(long fileHandle) {
246 			synchronized (cacheLock) {
247 				for (long caseDbPointer:caseHandlesCache.keySet()) {
248 					if (caseHandlesCache.get(caseDbPointer).fileHandleCache.contains(fileHandle)) {
249 						return true;
250 					}
251 				}
252 				return false;
253 			}
254 		}
255 
closeHandlesAndClearCache(long caseDbPointer)256 		private static void closeHandlesAndClearCache(long caseDbPointer) throws TskCoreException {
257 			synchronized (cacheLock) {
258 				/*
259 				 * Close any cached file system handles.
260 				 */
261 				for (Map<Long, Long> imageToFsMap : getCaseHandles(caseDbPointer).fsHandleCache.values()) {
262 					for (Long fsHandle : imageToFsMap.values()) {
263 						// First close all open file handles for the file system.
264 						if (getCaseHandles(caseDbPointer).fileSystemToFileHandles.containsKey(fsHandle)) {
265 							for (Long fileHandle : getCaseHandles(caseDbPointer).fileSystemToFileHandles.get(fsHandle)) {
266 								closeFile(fileHandle);
267 							}
268 						}
269 						// Then close the file system handle.
270 						closeFsNat(fsHandle);
271 					}
272 				}
273 
274 				/*
275 				 * Close any cached image handles.
276 				 */
277 				for (Long imageHandle : getCaseHandles(caseDbPointer).imageHandleCache.values()) {
278 					closeImgNat(imageHandle);
279 				}
280 
281 				removeCaseHandlesCache(caseDbPointer);
282 			}
283 
284 		}
285 	}
286 
287 	/**
288 	 * Encapsulates a handle to a SleuthKit case database with support for
289 	 * adding images to the database.
290 	 */
291 	public static class CaseDbHandle {
292 
293 		/*
294 		 * A pointer to a TskCaseDb object.
295 		 */
296 		private final long caseDbPointer;
297 
298 		/**
299 		 * Constructs an object that encapsulates a handle to a SleuthKit case
300 		 * database with support for adding images to the database.
301 		 *
302 		 * @param caseDbPointer A pointer to a TskCaseDb object.
303 		 */
CaseDbHandle(long caseDbPointer)304 		private CaseDbHandle(long caseDbPointer) {
305 			this.caseDbPointer = caseDbPointer;
306 			HandleCache.createCaseHandleCache(caseDbPointer);
307 		}
308 
309 		/**
310 		 * Closes the case database and any open image and file system handles.
311 		 *
312 		 * @throws TskCoreException if there is a problem competing the
313 		 *                          operation.
314 		 */
free()315 		void free() throws TskCoreException {
316 			tskLock.writeLock().lock();
317 			try {
318 				HandleCache.closeHandlesAndClearCache(caseDbPointer);
319 				SleuthkitJNI.closeCaseDbNat(caseDbPointer);
320 			} finally {
321 				tskLock.writeLock().unlock();
322 			}
323 		}
324 
325 		/**
326 		 * Adds an image to the case database. For finer-grained control of the
327 		 * process of adding the image, call CaseDbHandle.initAddImageProcess
328 		 * instead.
329 		 *
330 		 * @param deviceObjId      The object id of the device associated with
331 		 *                         the image.
332 		 * @param imageFilePaths   The image file paths.
333 		 * @param timeZone         The time zone for the image.
334 		 * @param addFileSystems   Pass true to attempt to add file systems
335 		 *                         within the image to the case database.
336 		 * @param addUnallocSpace  Pass true to create virtual files for
337 		 *                         unallocated space. Ignored if addFileSystems
338 		 *                         is false.
339 		 * @param skipFatFsOrphans Pass true to skip processing of orphan files
340 		 *                         for FAT file systems. Ignored if
341 		 *                         addFileSystems is false.
342 		 *
343 		 * @return The object id of the image.
344 		 *
345 		 * @throws TskCoreException if there is an error adding the image to
346 		 *                          case database.
347 		 */
addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, SleuthkitCase skCase)348 		long addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, SleuthkitCase skCase) throws TskCoreException {
349 			try {
350 				long tskAutoDbPointer = initializeAddImgNat(caseDbPointer, timezoneLongToShort(timeZone), false, false, false);
351 				runOpenAndAddImgNat(tskAutoDbPointer, UUID.randomUUID().toString(), imageFilePaths.toArray(new String[0]), imageFilePaths.size(), timeZone);
352 				long id = commitAddImgNat(tskAutoDbPointer);
353 				skCase.addDataSourceToHasChildrenMap();
354 				return id;
355 			} catch (TskDataException ex) {
356 				throw new TskCoreException("Error adding image to case database", ex);
357 			}
358 		}
359 
360 		/**
361 		 * Initializes a multi-step process for adding an image to the case
362 		 * database.
363 		 *
364 		 * @param timeZone         The time zone of the image.
365 		 * @param addUnallocSpace  Pass true to create virtual files for
366 		 *                         unallocated space.
367 		 * @param skipFatFsOrphans Pass true to skip processing of orphan files
368 		 *                         for FAT file systems.
369 		 * @param imageCopyPath    Path to which a copy of the image should be
370 		 *                         written. Use the empty string to disable
371 		 *                         image writing.
372 		 *
373 		 * @return An object that can be used to exercise fine-grained control
374 		 *         of the process of adding the image to the case database.
375 		 */
initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageCopyPath, SleuthkitCase skCase)376 		AddImageProcess initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageCopyPath, SleuthkitCase skCase) {
377 			return new AddImageProcess(timeZone, addUnallocSpace, skipFatFsOrphans, imageCopyPath, skCase);
378 		}
379 
380 		/**
381 		 * Encapsulates a multi-step process to add an image to the case
382 		 * database.
383 		 */
384 		public class AddImageProcess {
385 
386 			private final String timeZone;
387 			private final boolean addUnallocSpace;
388 			private final boolean skipFatFsOrphans;
389 			private final String imageWriterPath;
390 			private volatile long tskAutoDbPointer;
391 			private boolean isCanceled;
392 			private final SleuthkitCase skCase;
393 
394 			/**
395 			 * Constructs an object that encapsulates a multi-step process to
396 			 * add an image to the case database.
397 			 *
398 			 * @param timeZone         The time zone of the image.
399 			 * @param addUnallocSpace  Pass true to create virtual files for
400 			 *                         unallocated space.
401 			 * @param skipFatFsOrphans Pass true to skip processing of orphan
402 			 *                         files for FAT file systems.
403 			 * @param imageWriterPath  Path that a copy of the image should be
404 			 *                         written to. Use empty string to disable
405 			 *                         image writing
406 			 */
AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageWriterPath, SleuthkitCase skCase)407 			private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageWriterPath, SleuthkitCase skCase) {
408 				this.timeZone = timeZone;
409 				this.addUnallocSpace = addUnallocSpace;
410 				this.skipFatFsOrphans = skipFatFsOrphans;
411 				this.imageWriterPath = imageWriterPath;
412 				tskAutoDbPointer = 0;
413 				this.isCanceled = false;
414 				this.skCase = skCase;
415 			}
416 
417 			/**
418 			 * Starts the process of adding an image to the case database.
419 			 * Either AddImageProcess.commit or AddImageProcess.revert MUST be
420 			 * called after calling AddImageProcess.run.
421 			 *
422 			 * @param deviceId       An ASCII-printable identifier for the
423 			 *                       device associated with the image that
424 			 *                       should be unique across multiple cases
425 			 *                       (e.g., a UUID).
426 			 * @param imageFilePaths Full path(s) to the image file(s).
427 			 * @param sectorSize     The sector size (use '0' for autodetect).
428 			 *
429 			 * @throws TskCoreException if a critical error occurs within the
430 			 *                          SleuthKit.
431 			 * @throws TskDataException if a non-critical error occurs within
432 			 *                          the SleuthKit (should be OK to continue
433 			 *                          the process)
434 			 */
run(String deviceId, String[] imageFilePaths, int sectorSize)435 			public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws TskCoreException, TskDataException {
436 				getTSKReadLock();
437 				try {
438 					long imageHandle = 0;
439 
440 					synchronized (this) {
441 						if (0 != tskAutoDbPointer) {
442 							throw new TskCoreException("Add image process already started");
443 						}
444 						if (!isCanceled) { //with isCanceled being guarded by this it will have the same value everywhere in this synchronized block
445 							imageHandle = openImage(imageFilePaths, sectorSize, false, caseDbPointer);
446 							tskAutoDbPointer = initAddImgNat(caseDbPointer, timezoneLongToShort(timeZone), addUnallocSpace, skipFatFsOrphans);
447 						}
448 						if (0 == tskAutoDbPointer) {
449 							throw new TskCoreException("initAddImgNat returned a NULL TskAutoDb pointer");
450 						}
451 					}
452 					if (imageHandle != 0) {
453 						runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, timeZone, imageWriterPath);
454 					}
455 				} finally {
456 					releaseTSKReadLock();
457 				}
458 			}
459 
460 			/**
461 			 * Stops the process of adding the image to the case database that
462 			 * was started by calling AddImageProcess.run.
463 			 * AddImageProcess.revert should be called after calling
464 			 * AddImageProcess.stop.
465 			 *
466 			 * @throws TskCoreException if a critical error occurs within the
467 			 *                          SleuthKit.
468 			 */
stop()469 			public synchronized void stop() throws TskCoreException {
470 				getTSKReadLock();
471 				try {
472 					isCanceled = true;
473 					if (tskAutoDbPointer != 0) {
474 						stopAddImgNat(tskAutoDbPointer);
475 					}
476 				} finally {
477 					releaseTSKReadLock();
478 				}
479 			}
480 
481 			/**
482 			 * Rolls back the process of adding an image to the case database
483 			 * that was started by calling AddImageProcess.run.
484 			 *
485 			 * @throws TskCoreException if a critical error occurs within the
486 			 *                          SleuthKit.
487 			 */
revert()488 			public synchronized void revert() throws TskCoreException {
489 				getTSKReadLock();
490 				try {
491 					if (tskAutoDbPointer == 0) {
492 						throw new TskCoreException("AddImgProcess::revert: AutoDB pointer is NULL");
493 					}
494 
495 					revertAddImgNat(tskAutoDbPointer);
496 					// the native code deleted the object
497 					tskAutoDbPointer = 0;
498 				} finally {
499 					releaseTSKReadLock();
500 				}
501 			}
502 
503 			/**
504 			 * Completes the process of adding an image to the case database
505 			 * that was started by calling AddImageProcess.run.
506 			 *
507 			 * @return The object id of the image that was added.
508 			 *
509 			 * @throws TskCoreException if a critical error occurs within the
510 			 *                          SleuthKit.
511 			 */
commit()512 			public synchronized long commit() throws TskCoreException {
513 				getTSKReadLock();
514 				try {
515 					if (tskAutoDbPointer == 0) {
516 						throw new TskCoreException("AddImgProcess::commit: AutoDB pointer is NULL");
517 					}
518 
519 					long id = commitAddImgNat(tskAutoDbPointer);
520 
521 					skCase.addDataSourceToHasChildrenMap();
522 
523 					// the native code deleted the object
524 					tskAutoDbPointer = 0;
525 					return id;
526 				} finally {
527 					releaseTSKReadLock();
528 				}
529 			}
530 
531 			/**
532 			 * Gets the file system directory currently being processed by the
533 			 * SleuthKit.
534 			 *
535 			 * @return The directory
536 			 */
currentDirectory()537 			public synchronized String currentDirectory() {
538 				return tskAutoDbPointer == 0 ? "" : getCurDirNat(tskAutoDbPointer); //NON-NLS
539 			}
540 
541 			/**
542 			 * Starts the process of adding an image to the case database.
543 			 * Either commit() or revert() MUST be called after calling run().
544 			 *
545 			 * @param imageFilePaths Full path(s) to the image file(s).
546 			 *
547 			 * @throws TskCoreException if a critical error occurs within the
548 			 *                          SleuthKit.
549 			 * @throws TskDataException if a non-critical error occurs within
550 			 *                          the SleuthKit (should be OK to continue
551 			 *                          the process)
552 			 *
553 			 * @deprecated Use run(String dataSourceId, String[] imageFilePaths)
554 			 * instead
555 			 */
556 			@Deprecated
run(String[] imageFilePaths)557 			public void run(String[] imageFilePaths) throws TskCoreException, TskDataException {
558 				run(null, imageFilePaths, 0);
559 			}
560 
561 			/**
562 			 * Starts the process of adding an image to the case database.
563 			 * Either AddImageProcess.commit or AddImageProcess.revert MUST be
564 			 * called after calling AddImageProcess.run.
565 			 *
566 			 * @param deviceId       An ASCII-printable identifier for the
567 			 *                       device associated with the image that
568 			 *                       should be unique across multiple cases
569 			 *                       (e.g., a UUID).
570 			 * @param imageFilePaths Full path(s) to the image file(s).
571 			 *
572 			 * @throws TskCoreException if a critical error occurs within the
573 			 *                          SleuthKit.
574 			 * @throws TskDataException if a non-critical error occurs within
575 			 *                          the SleuthKit (should be OK to continue
576 			 *                          the process)
577 			 */
run(String deviceId, String[] imageFilePaths)578 			public void run(String deviceId, String[] imageFilePaths) throws TskCoreException, TskDataException {
579 				run(deviceId, imageFilePaths, 0);
580 			}
581 		}
582 
583 	}
584 
585 	/**
586 	 * Creates a new case database. Must call .free() on CaseDbHandle instance
587 	 * when done.
588 	 *
589 	 * @param path Location to create the database at.
590 	 *
591 	 * @return Handle for a new TskCaseDb instance.
592 	 *
593 	 * @throws TskCoreException exception thrown if critical error occurs within
594 	 *                          TSK
595 	 */
newCaseDb(String path)596 	static CaseDbHandle newCaseDb(String path) throws TskCoreException {
597 		return new CaseDbHandle(newCaseDbNat(path));
598 	}
599 
600 	/**
601 	 * Creates a new case database. Must call .free() on CaseDbHandle instance
602 	 * when done.
603 	 *
604 	 * @param databaseName the name of the database to create
605 	 * @param info         the connection info class for the database to create
606 	 *
607 	 * @return Handle for a new TskCaseDb instance.
608 	 *
609 	 * @throws TskCoreException exception thrown if critical error occurs within
610 	 *                          TSK
611 	 */
newCaseDb(String databaseName, CaseDbConnectionInfo info)612 	static CaseDbHandle newCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException {
613 		return new CaseDbHandle(newCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName));
614 	}
615 
616 	/**
617 	 * Opens an existing case database. Must call .free() on CaseDbHandle
618 	 * instance when done.
619 	 *
620 	 * @param path Location of the existing database.
621 	 *
622 	 * @return Handle for a new TskCaseDb instance.
623 	 *
624 	 * @throws TskCoreException exception thrown if critical error occurs within
625 	 *                          TSK
626 	 */
openCaseDb(String path)627 	static CaseDbHandle openCaseDb(String path) throws TskCoreException {
628 		return new CaseDbHandle(openCaseDbNat(path));
629 	}
630 
631 	/**
632 	 * Opens an existing case database. Must call .free() on CaseDbHandle
633 	 * instance when done.
634 	 *
635 	 * @param databaseName the name of the database to open
636 	 * @param info         the connection info class for the database to open
637 	 *
638 	 * @return Handle for a new TskCaseDb instance.
639 	 *
640 	 * @throws TskCoreException exception thrown if critical error occurs within
641 	 *                          TSK
642 	 */
openCaseDb(String databaseName, CaseDbConnectionInfo info)643 	static CaseDbHandle openCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException {
644 		return new CaseDbHandle(openCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName));
645 	}
646 
647 	/**
648 	 * get the Sleuth Kit version string
649 	 *
650 	 * @return the version string
651 	 */
getVersion()652 	public static String getVersion() {
653 		return getVersionNat();
654 	}
655 
656 	/**
657 	 * Enable verbose logging and redirect stderr to the given log file.
658 	 *
659 	 * @param logPath the log file path
660 	 */
startVerboseLogging(String logPath)661 	public static void startVerboseLogging(String logPath) {
662 		startVerboseLoggingNat(logPath);
663 	}
664 
665 	/**
666 	 * Open the image and return the image info pointer.
667 	 *
668 	 * @param imageFiles the paths to the images
669 	 * @param skCase     the case this image belongs to
670 	 *
671 	 * @return the image info pointer
672 	 *
673 	 * @throws TskCoreException exception thrown if critical error occurs within
674 	 *                          TSK
675 	 */
openImage(String[] imageFiles, SleuthkitCase skCase)676 	public static long openImage(String[] imageFiles, SleuthkitCase skCase) throws TskCoreException {
677 		if (skCase == null) {
678 			throw new TskCoreException("SleuthkitCase can not be null");
679 		}
680 		return openImage(imageFiles, 0, true, skCase.getCaseHandle().caseDbPointer);
681 	}
682 
683 	/**
684 	 * Open the image with a specified sector size and return the image info
685 	 * pointer.
686 	 *
687 	 * @param imageFiles the paths to the images
688 	 * @param sSize      the sector size (use '0' for autodetect)
689 	 * @param skCase     the case this image belongs to
690 	 *
691 	 * @return the image info pointer
692 	 *
693 	 * @throws TskCoreException exception thrown if critical error occurs within
694 	 *                          TSK
695 	 */
openImage(String[] imageFiles, int sSize, SleuthkitCase skCase)696 	public static long openImage(String[] imageFiles, int sSize, SleuthkitCase skCase) throws TskCoreException {
697 		if (skCase == null) {
698 			throw new TskCoreException("SleuthkitCase can not be null");
699 		}
700 		return openImage(imageFiles, sSize, true, skCase.getCaseHandle().caseDbPointer);
701 	}
702 
703 	/**
704 	 * Open the image and return the image info pointer. This is a temporary
705 	 * measure to allow ingest of multiple local disks on the same drive letter.
706 	 * We need to clear the cache to make sure cached data from the first drive
707 	 * is not used.
708 	 *
709 	 * @param imageFiles the paths to the images
710 	 * @param sSize      the sector size (use '0' for autodetect)
711 	 * @param useCache   true if the image handle cache should be used, false to
712 	 *                   always go to TSK to open a fresh copy
713 	 * @param caseDbPointer The caseDbPointer for this case. Can be null to support deprecated methods.
714 	 *
715 	 * @return the image info pointer
716 	 *
717 	 * @throws TskCoreException exception thrown if critical error occurs within
718 	 *                          TSK
719 	 */
openImage(String[] imageFiles, int sSize, boolean useCache, Long caseDbPointer)720 	private static long openImage(String[] imageFiles, int sSize, boolean useCache, Long caseDbPointer) throws TskCoreException {
721 
722 		getTSKReadLock();
723 		try {
724 			long imageHandle;
725 
726 			StringBuilder keyBuilder = new StringBuilder();
727 			for (int i = 0; i < imageFiles.length; ++i) {
728 				keyBuilder.append(imageFiles[i]);
729 			}
730 			final String imageKey = keyBuilder.toString();
731 
732 			synchronized (HandleCache.cacheLock) {
733 				Long nonNullCaseDbPointer = caseDbPointer;
734 				if (nonNullCaseDbPointer == null) {
735 					nonNullCaseDbPointer = HandleCache.getDefaultCaseDbPointer();
736 				}
737 
738 				// If we're getting a fresh copy, remove any existing cache references
739 				if (!useCache && HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.containsKey(imageKey)) {
740 					long tempImageHandle = HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.get(imageKey);
741 					HandleCache.getCaseHandles(nonNullCaseDbPointer).fsHandleCache.remove(tempImageHandle);
742 					HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.remove(imageKey);
743 				}
744 
745 				if (useCache && HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.containsKey(imageKey)) //get from cache
746 				{
747 					imageHandle = HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.get(imageKey);
748 				} else {
749 					//open new handle and cache it
750 					imageHandle = openImgNat(imageFiles, imageFiles.length, sSize);
751 					HandleCache.getCaseHandles(nonNullCaseDbPointer).fsHandleCache.put(imageHandle, new HashMap<Long, Long>());
752 					HandleCache.getCaseHandles(nonNullCaseDbPointer).imageHandleCache.put(imageKey, imageHandle);
753 				}
754 			}
755 			return imageHandle;
756 		} finally {
757 			releaseTSKReadLock();
758 		}
759 	}
760 
761 	/**
762 	 * Get volume system Handle
763 	 *
764 	 * @param imgHandle a handle to previously opened image
765 	 * @param vsOffset  byte offset in the image to the volume system (usually
766 	 *                  0)
767 	 *
768 	 * @return pointer to a vsHandle structure in the sleuthkit
769 	 *
770 	 * @throws TskCoreException exception thrown if critical error occurs within
771 	 *                          TSK
772 	 */
openVs(long imgHandle, long vsOffset)773 	public static long openVs(long imgHandle, long vsOffset) throws TskCoreException {
774 		getTSKReadLock();
775 		try {
776 			if(! imgHandleIsValid(imgHandle)) {
777 				throw new TskCoreException("Image handle " + imgHandle + " is closed");
778 			}
779 			return openVsNat(imgHandle, vsOffset);
780 		} finally {
781 			releaseTSKReadLock();
782 		}
783 	}
784 
785 	//get pointers
786 	/**
787 	 * Get volume Handle
788 	 *
789 	 * @param vsHandle pointer to the volume system structure in the sleuthkit
790 	 * @param volId    id of the volume
791 	 *
792 	 * @return pointer to a volHandle structure in the sleuthkit
793 	 *
794 	 * @throws TskCoreException exception thrown if critical error occurs within
795 	 *                          TSK
796 	 */
openVsPart(long vsHandle, long volId)797 	public static long openVsPart(long vsHandle, long volId) throws TskCoreException {
798 		getTSKReadLock();
799 		try {
800 			//returned long is ptr to vs Handle object in tsk
801 			return openVolNat(vsHandle, volId);
802 		} finally {
803 			releaseTSKReadLock();
804 		}
805 	}
806 
807 	/**
808 	 * Get file system Handle Opened handle is cached (transparently) so it does
809 	 * not need be reopened next time for the duration of the application
810 	 *
811 	 * @param imgHandle pointer to imgHandle in sleuthkit
812 	 * @param fsOffset  byte offset to the file system
813 	 * @param skCase    the case containing the file system
814 	 *
815 	 * @return pointer to a fsHandle structure in the sleuthkit
816 	 *
817 	 * @throws TskCoreException exception thrown if critical error occurs within
818 	 *                          TSK
819 	 */
openFs(long imgHandle, long fsOffset, SleuthkitCase skCase)820 	public static long openFs(long imgHandle, long fsOffset, SleuthkitCase skCase) throws TskCoreException {
821 		getTSKReadLock();
822 		try {
823 			long fsHandle;
824 			synchronized (HandleCache.cacheLock) {
825 				long caseDbPointer;
826 				if (skCase == null) {
827 					caseDbPointer = HandleCache.getDefaultCaseDbPointer();
828 				} else {
829 					caseDbPointer = skCase.getCaseHandle().caseDbPointer;
830 				}
831 				final Map<Long, Long> imgOffSetToFsHandle = HandleCache.getCaseHandles(caseDbPointer).fsHandleCache.get(imgHandle);
832 				if (imgOffSetToFsHandle == null) {
833 					throw new TskCoreException("Missing image offset to file system handle cache for image handle " + imgHandle);
834 				}
835 				if (imgOffSetToFsHandle.containsKey(fsOffset)) {
836 					//return cached
837 					fsHandle = imgOffSetToFsHandle.get(fsOffset);
838 				} else {
839 					fsHandle = openFsNat(imgHandle, fsOffset);
840 					//cache it
841 					imgOffSetToFsHandle.put(fsOffset, fsHandle);
842 				}
843 			}
844 			return fsHandle;
845 		} finally {
846 			releaseTSKReadLock();
847 		}
848 	}
849 
850 	/**
851 	 * Get file Handle
852 	 *
853 	 * @param fsHandle fsHandle pointer in the sleuthkit
854 	 * @param fileId   id of the file
855 	 * @param attrType file attribute type to open
856 	 * @param attrId   file attribute id to open
857 	 * @param skCase   the case associated with this file
858 	 *
859 	 * @return pointer to a file structure in the sleuthkit
860 	 *
861 	 * @throws TskCoreException exception thrown if critical error occurs within
862 	 *                          TSK
863 	 */
openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, SleuthkitCase skCase)864 	public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, SleuthkitCase skCase) throws TskCoreException {
865 		/*
866 		 * NOTE: previously attrId used to be stored in AbstractFile as (signed)
867 		 * short even though it is stored as uint16 in TSK. In extremely rare
868 		 * occurrences attrId can be larger than what a signed short can hold
869 		 * (2^15). Changes were made to AbstractFile to store attrId as integer.
870 		 * However, a depricated method still exists in AbstractFile to get
871 		 * attrId as short. In that method we convert attribute ids that are
872 		 * larger than 32K to a negative number. Therefore if encountered, we
873 		 * need to convert negative attribute id to uint16 which is what TSK is
874 		 * using to store attribute id.
875 		 */
876 		getTSKReadLock();
877 		try {
878 			long fileHandle = openFileNat(fsHandle, fileId, attrType.getValue(), convertSignedToUnsigned(attrId));
879 			synchronized (HandleCache.cacheLock) {
880 				long caseDbPointer;
881 				if (skCase == null) {
882 					caseDbPointer = HandleCache.getDefaultCaseDbPointer();
883 				} else {
884 					caseDbPointer = skCase.getCaseHandle().caseDbPointer;
885 				}
886 				HandleCache.addFileHandle(caseDbPointer, fileHandle, fsHandle);
887 			}
888 			return fileHandle;
889 		} finally {
890 			releaseTSKReadLock();
891 		}
892 	}
893 
894 	/**
895 	 * Converts signed integer to an unsigned integer.
896 	 *
897 	 * @param val value to be converter
898 	 *
899 	 * @return unsigned integer value
900 	 */
convertSignedToUnsigned(int val)901 	private static int convertSignedToUnsigned(int val) {
902 		if (val >= 0) {
903 			return val;
904 		}
905 
906 		return val & 0xffff;	// convert negative value to positive value
907 	}
908 
909 	/**
910 	 * Test that the given image handle is valid.
911 	 * @param imgHandle
912 	 * @return true if it is valid, false otherwise
913 	 */
imgHandleIsValid(long imgHandle)914 	private static boolean imgHandleIsValid(long imgHandle) {
915 		synchronized(HandleCache.cacheLock) {
916 			return HandleCache.isImageInAnyCache(imgHandle);
917 		}
918 	}
919 
920 	//do reads
921 	/**
922 	 * reads data from an image
923 	 *
924 	 * @param imgHandle
925 	 * @param readBuffer buffer to read to
926 	 * @param offset     byte offset in the image to start at
927 	 * @param len        amount of data to read
928 	 *
929 	 * @return the number of characters read, or -1 if the end of the stream has
930 	 *         been reached
931 	 *
932 	 * @throws TskCoreException exception thrown if critical error occurs within
933 	 *                          TSK
934 	 */
readImg(long imgHandle, byte[] readBuffer, long offset, long len)935 	public static int readImg(long imgHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
936 		getTSKReadLock();
937 		try {
938 			if(! imgHandleIsValid(imgHandle)) {
939 				throw new TskCoreException("Image handle " + imgHandle + " is closed");
940 			}
941 			//returned byte[] is the data buffer
942 			return readImgNat(imgHandle, readBuffer, offset, len);
943 		} finally {
944 			releaseTSKReadLock();
945 		}
946 	}
947 
948 	/**
949 	 * reads data from an volume system
950 	 *
951 	 * @param vsHandle   pointer to a volume system structure in the sleuthkit
952 	 * @param readBuffer buffer to read to
953 	 * @param offset     sector offset in the image to start at
954 	 * @param len        amount of data to read
955 	 *
956 	 * @return the number of characters read, or -1 if the end of the stream has
957 	 *         been reached
958 	 *
959 	 * @throws TskCoreException exception thrown if critical error occurs within
960 	 *                          TSK
961 	 */
readVs(long vsHandle, byte[] readBuffer, long offset, long len)962 	public static int readVs(long vsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
963 		getTSKReadLock();
964 		try {
965 			return readVsNat(vsHandle, readBuffer, offset, len);
966 		} finally {
967 			releaseTSKReadLock();
968 		}
969 	}
970 
971 	/**
972 	 * reads data from an volume
973 	 *
974 	 * @param volHandle  pointer to a volume structure in the sleuthkit
975 	 * @param readBuffer buffer to read to
976 	 * @param offset     byte offset in the image to start at
977 	 * @param len        amount of data to read
978 	 *
979 	 * @return the number of characters read, or -1 if the end of the stream has
980 	 *         been reached
981 	 *
982 	 * @throws TskCoreException exception thrown if critical error occurs within
983 	 *                          TSK
984 	 */
readVsPart(long volHandle, byte[] readBuffer, long offset, long len)985 	public static int readVsPart(long volHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
986 		getTSKReadLock();
987 		try {
988 			//returned byte[] is the data buffer
989 			return readVolNat(volHandle, readBuffer, offset, len);
990 		} finally {
991 			releaseTSKReadLock();
992 		}
993 	}
994 
995 	/**
996 	 * reads data from an file system
997 	 *
998 	 * @param fsHandle   pointer to a file system structure in the sleuthkit
999 	 * @param readBuffer buffer to read to
1000 	 * @param offset     byte offset in the image to start at
1001 	 * @param len        amount of data to read
1002 	 *
1003 	 * @return the number of characters read, or -1 if the end of the stream has
1004 	 *         been reached
1005 	 *
1006 	 * @throws TskCoreException exception thrown if critical error occurs within
1007 	 *                          TSK
1008 	 */
readFs(long fsHandle, byte[] readBuffer, long offset, long len)1009 	public static int readFs(long fsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1010 		getTSKReadLock();
1011 		try {
1012 			//returned byte[] is the data buffer
1013 			return readFsNat(fsHandle, readBuffer, offset, len);
1014 		} finally {
1015 			releaseTSKReadLock();
1016 		}
1017 	}
1018 
1019 	/**
1020 	 * enum used to tell readFileNat whether the offset is from the beginning of
1021 	 * the file or from the beginning of the slack space.
1022 	 */
1023 	private enum TSK_FS_FILE_READ_OFFSET_TYPE_ENUM {
1024 		START_OF_FILE(0),
1025 		START_OF_SLACK(1);
1026 
1027 		private final int val;
1028 
TSK_FS_FILE_READ_OFFSET_TYPE_ENUM(int val)1029 		TSK_FS_FILE_READ_OFFSET_TYPE_ENUM(int val) {
1030 			this.val = val;
1031 		}
1032 
getValue()1033 		int getValue() {
1034 			return val;
1035 		}
1036 	}
1037 
1038 	/**
1039 	 * reads data from an file
1040 	 *
1041 	 * @param fileHandle pointer to a file structure in the sleuthkit
1042 	 * @param readBuffer pre-allocated buffer to read to
1043 	 * @param offset     byte offset in the image to start at
1044 	 * @param len        amount of data to read
1045 	 *
1046 	 * @return the number of characters read, or -1 if the end of the stream has
1047 	 *         been reached
1048 	 *
1049 	 * @throws TskCoreException exception thrown if critical error occurs within
1050 	 *                          TSK
1051 	 */
readFile(long fileHandle, byte[] readBuffer, long offset, long len)1052 	public static int readFile(long fileHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1053 		getTSKReadLock();
1054 		try {
1055 			if (!HandleCache.isValidFileHandle(fileHandle)) {
1056 				throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1057 			}
1058 
1059 			return readFileNat(fileHandle, readBuffer, offset, TSK_FS_FILE_READ_OFFSET_TYPE_ENUM.START_OF_FILE.getValue(), len);
1060 		} finally {
1061 			releaseTSKReadLock();
1062 		}
1063 	}
1064 
1065 	/**
1066 	 * reads data from the slack space of a file
1067 	 *
1068 	 * @param fileHandle pointer to a file structure in the sleuthkit
1069 	 * @param readBuffer pre-allocated buffer to read to
1070 	 * @param offset     byte offset in the slack to start at
1071 	 * @param len        amount of data to read
1072 	 *
1073 	 * @return the number of characters read, or -1 if the end of the stream has
1074 	 *         been reached
1075 	 *
1076 	 * @throws TskCoreException exception thrown if critical error occurs within
1077 	 *                          TSK
1078 	 */
readFileSlack(long fileHandle, byte[] readBuffer, long offset, long len)1079 	public static int readFileSlack(long fileHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
1080 		getTSKReadLock();
1081 		try {
1082 			if (!HandleCache.isValidFileHandle(fileHandle)) {
1083 				throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1084 			}
1085 
1086 			return readFileNat(fileHandle, readBuffer, offset, TSK_FS_FILE_READ_OFFSET_TYPE_ENUM.START_OF_SLACK.getValue(), len);
1087 		} finally {
1088 			releaseTSKReadLock();
1089 		}
1090 	}
1091 
1092 	/**
1093 	 * Get human readable (some what) details about a file. This is the same as
1094 	 * the 'istat' TSK tool
1095 	 *
1096 	 * @param fileHandle pointer to file structure in the sleuthkit
1097 	 *
1098 	 * @return text
1099 	 *
1100 	 * @throws TskCoreException if errors occurred
1101 	 */
getFileMetaDataText(long fileHandle)1102 	public static List<String> getFileMetaDataText(long fileHandle) throws TskCoreException {
1103 		getTSKReadLock();
1104 		try {
1105 			if (!HandleCache.isValidFileHandle(fileHandle)) {
1106 				throw new TskCoreException(HandleCache.INVALID_FILE_HANDLE);
1107 			}
1108 
1109 			try {
1110 				java.io.File tmp = java.io.File.createTempFile("tsk", ".txt");
1111 
1112 				saveFileMetaDataTextNat(fileHandle, tmp.getAbsolutePath());
1113 
1114 				FileReader fr = new FileReader(tmp.getAbsolutePath());
1115 				BufferedReader textReader = new BufferedReader(fr);
1116 
1117 				List<String> lines = new ArrayList<String>();
1118 				while (true) {
1119 					String line = textReader.readLine();
1120 					if (line == null) {
1121 						break;
1122 					}
1123 					lines.add(line);
1124 				}
1125 				textReader.close();
1126 				fr.close();
1127 				tmp.delete();
1128 				return lines;
1129 			} catch (IOException ex) {
1130 				throw new TskCoreException("Error reading istat output: " + ex.getLocalizedMessage());
1131 			}
1132 		} finally {
1133 			releaseTSKReadLock();
1134 		}
1135 	}
1136 
1137 	/**
1138 	 * frees the fileHandle pointer
1139 	 *
1140 	 * @param fileHandle pointer to file structure in sleuthkit
1141 	 */
closeFile(long fileHandle)1142 	public static void closeFile(long fileHandle) {
1143 		closeFile(fileHandle, null);
1144 	}
1145 
1146 	/**
1147 	 * frees the fileHandle pointer
1148 	 *
1149 	 * @param fileHandle pointer to file structure in sleuthkit
1150 	 * @param skCase     the case containing the file
1151 	 */
closeFile(long fileHandle, SleuthkitCase skCase)1152 	public static void closeFile(long fileHandle, SleuthkitCase skCase) {
1153 		getTSKReadLock();
1154 		try {
1155 			synchronized (HandleCache.cacheLock) {
1156 				if (!HandleCache.isValidFileHandle(fileHandle)) {
1157 					// File handle is not open so this is a no-op.
1158 					return;
1159 				}
1160 				closeFileNat(fileHandle);
1161 				HandleCache.removeFileHandle(fileHandle, skCase);
1162 			}
1163 		} finally {
1164 			releaseTSKReadLock();
1165 		}
1166 	}
1167 
1168 	/**
1169 	 * Create an index for a hash database.
1170 	 *
1171 	 * @param dbHandle A hash database handle.
1172 	 *
1173 	 * @throws TskCoreException if a critical error occurs within TSK core
1174 	 */
createLookupIndexForHashDatabase(int dbHandle)1175 	public static void createLookupIndexForHashDatabase(int dbHandle) throws TskCoreException {
1176 		hashDbCreateIndexNat(dbHandle);
1177 	}
1178 
1179 	/**
1180 	 * Check if an index exists for a hash database.
1181 	 *
1182 	 * @param dbHandle A hash database handle.
1183 	 *
1184 	 * @return true if index exists
1185 	 *
1186 	 * @throws TskCoreException if a critical error occurs within TSK core
1187 	 */
hashDatabaseHasLookupIndex(int dbHandle)1188 	public static boolean hashDatabaseHasLookupIndex(int dbHandle) throws TskCoreException {
1189 		return hashDbIndexExistsNat(dbHandle);
1190 	}
1191 
1192 	/**
1193 	 * hashDatabaseCanBeReindexed
1194 	 *
1195 	 * @param dbHandle previously opened hash db handle
1196 	 *
1197 	 * @return Does this database have a source database that is different than
1198 	 *         the index?
1199 	 *
1200 	 * @throws TskCoreException if a critical error occurs within TSK core
1201 	 */
hashDatabaseCanBeReindexed(int dbHandle)1202 	public static boolean hashDatabaseCanBeReindexed(int dbHandle) throws TskCoreException {
1203 		return hashDbIsReindexableNat(dbHandle);
1204 	}
1205 
1206 	/**
1207 	 * getHashDatabasePath
1208 	 *
1209 	 * @param dbHandle previously opened hash db handle
1210 	 *
1211 	 * @return Hash db file path
1212 	 *
1213 	 * @throws TskCoreException if a critical error occurs within TSK core
1214 	 */
getHashDatabasePath(int dbHandle)1215 	public static String getHashDatabasePath(int dbHandle) throws TskCoreException {
1216 		return hashDbPathNat(dbHandle);
1217 	}
1218 
1219 	/**
1220 	 * getHashDatabaseIndexPath
1221 	 *
1222 	 * @param dbHandle previously opened hash db handle
1223 	 *
1224 	 * @return Index file path
1225 	 *
1226 	 * @throws TskCoreException if a critical error occurs within TSK core
1227 	 */
getHashDatabaseIndexPath(int dbHandle)1228 	public static String getHashDatabaseIndexPath(int dbHandle) throws TskCoreException {
1229 		return hashDbIndexPathNat(dbHandle);
1230 	}
1231 
1232 	/**
1233 	 * Open a hash database for lookups
1234 	 * @param path Path to Hash DB or index file
1235 	 * @return Handle open db
1236 	 * @throws TskCoreException if there is an error opening the DB
1237 	 */
openHashDatabase(String path)1238 	public static int openHashDatabase(String path) throws TskCoreException {
1239 		return hashDbOpenNat(path);
1240 	}
1241 
1242 	/**
1243 	 * Creates a hash database. Will be of the default TSK hash database type.
1244 	 *
1245 	 * @param path The path to the database
1246 	 *
1247 	 * @return a handle for that database
1248 	 *
1249 	 * @throws TskCoreException if a critical error occurs within TSK core
1250 	 */
createHashDatabase(String path)1251 	public static int createHashDatabase(String path) throws TskCoreException {
1252 		return hashDbNewNat(path);
1253 	}
1254 
1255 	/**
1256 	 * Close the currently open lookup databases. Resets the handle counting.
1257 	 *
1258 	 * @throws TskCoreException exception thrown if critical error occurs within
1259 	 *                          TSK
1260 	 */
closeAllHashDatabases()1261 	public static void closeAllHashDatabases() throws TskCoreException {
1262 		hashDbCloseAll();
1263 	}
1264 
1265 	/**
1266 	 * Close a particular open lookup database. Existing handles are not
1267 	 * affected.
1268 	 *
1269 	 * @param dbHandle Handle of database to close.
1270 	 *
1271 	 * @throws TskCoreException exception thrown if critical error occurs within
1272 	 *                          TSK
1273 	 */
closeHashDatabase(int dbHandle)1274 	public static void closeHashDatabase(int dbHandle) throws TskCoreException {
1275 		hashDbClose(dbHandle);
1276 	}
1277 
1278 	/**
1279 	 * Get the name of the database
1280 	 *
1281 	 * @param dbHandle Previously opened hash db handle.
1282 	 *
1283 	 * @return The display name.
1284 	 *
1285 	 * @throws TskCoreException if a critical error occurs within TSK core
1286 	 */
getHashDatabaseDisplayName(int dbHandle)1287 	public static String getHashDatabaseDisplayName(int dbHandle) throws TskCoreException {
1288 		return hashDbGetDisplayName(dbHandle);
1289 	}
1290 
1291 	/**
1292 	 * Lookup the given hash value and get basic answer
1293 	 *
1294 	 * @param hash     Hash value to search for.
1295 	 * @param dbHandle Handle of database to lookup in.
1296 	 *
1297 	 * @return True if hash was found in database.
1298 	 *
1299 	 * @throws TskCoreException
1300 	 */
lookupInHashDatabase(String hash, int dbHandle)1301 	public static boolean lookupInHashDatabase(String hash, int dbHandle) throws TskCoreException {
1302 		return hashDbLookup(hash, dbHandle);
1303 	}
1304 
1305 	/**
1306 	 * Lookup hash value in DB and return details on results (more time
1307 	 * consuming than basic lookup)
1308 	 *
1309 	 * @param hash     Hash value to search for
1310 	 * @param dbHandle Handle of database to lookup in.
1311 	 *
1312 	 * @return Details on hash if it was in DB or null if it was not found.
1313 	 *
1314 	 * @throws TskCoreException
1315 	 */
lookupInHashDatabaseVerbose(String hash, int dbHandle)1316 	public static HashHitInfo lookupInHashDatabaseVerbose(String hash, int dbHandle) throws TskCoreException {
1317 		return hashDbLookupVerbose(hash, dbHandle);
1318 	}
1319 
1320 	/**
1321 	 * Adds a hash value to a hash database.
1322 	 *
1323 	 * @param filename Name of file (can be null)
1324 	 * @param md5      Text of MD5 hash (can be null)
1325 	 * @param sha1     Text of SHA1 hash (can be null)
1326 	 * @param sha256   Text of SHA256 hash (can be null)
1327 	 * @param comment  A comment (can be null)
1328 	 * @param dbHandle Handle to DB
1329 	 *
1330 	 * @throws TskCoreException
1331 	 */
addToHashDatabase(String filename, String md5, String sha1, String sha256, String comment, int dbHandle)1332 	public static void addToHashDatabase(String filename, String md5, String sha1, String sha256, String comment, int dbHandle) throws TskCoreException {
1333 		hashDbAddEntryNat(filename, md5, sha1, sha256, comment, dbHandle);
1334 	}
1335 
addToHashDatabase(List<HashEntry> hashes, int dbHandle)1336 	public static void addToHashDatabase(List<HashEntry> hashes, int dbHandle) throws TskCoreException {
1337 		hashDbBeginTransactionNat(dbHandle);
1338 		try {
1339 			for (HashEntry entry : hashes) {
1340 				hashDbAddEntryNat(entry.getFileName(), entry.getMd5Hash(), entry.getSha1Hash(), entry.getSha256Hash(), entry.getComment(), dbHandle);
1341 			}
1342 			hashDbCommitTransactionNat(dbHandle);
1343 		} catch (TskCoreException ex) {
1344 			try {
1345 				hashDbRollbackTransactionNat(dbHandle);
1346 			} catch (TskCoreException ex2) {
1347 				ex2.initCause(ex);
1348 				throw ex2;
1349 			}
1350 			throw ex;
1351 		}
1352 	}
1353 
isUpdateableHashDatabase(int dbHandle)1354 	public static boolean isUpdateableHashDatabase(int dbHandle) throws TskCoreException {
1355 		return hashDbIsUpdateableNat(dbHandle);
1356 	}
1357 
hashDatabaseIsIndexOnly(int dbHandle)1358 	public static boolean hashDatabaseIsIndexOnly(int dbHandle) throws TskCoreException {
1359 		return hashDbIsIdxOnlyNat(dbHandle);
1360 	}
1361 
1362 	/**
1363 	 * Convert this timezone from long to short form Convert timezoneLongForm
1364 	 * passed in from long to short form
1365 	 *
1366 	 * @param timezoneLongForm the long form (e.g., America/New_York)
1367 	 *
1368 	 * @return the short form (e.g., EST5EDT) string representation, or an empty
1369 	 *         string if empty long form was passed in
1370 	 */
timezoneLongToShort(String timezoneLongForm)1371 	private static String timezoneLongToShort(String timezoneLongForm) {
1372 		if (timezoneLongForm == null || timezoneLongForm.isEmpty()) {
1373 			return "";
1374 		}
1375 
1376 		String timezoneShortForm;
1377 		TimeZone zone = TimeZone.getTimeZone(timezoneLongForm);
1378 		int offset = zone.getRawOffset() / 1000;
1379 		int hour = offset / 3600;
1380 		int min = (offset % 3600) / 60;
1381 		DateFormat dfm = new SimpleDateFormat("z");
1382 		dfm.setTimeZone(zone);
1383 		boolean hasDaylight = zone.useDaylightTime();
1384 		String first = dfm.format(new GregorianCalendar(2010, 1, 1).getTime()).substring(0, 3); // make it only 3 letters code
1385 		String second = dfm.format(new GregorianCalendar(2011, 6, 6).getTime()).substring(0, 3); // make it only 3 letters code
1386 		int mid = hour * -1;
1387 		timezoneShortForm = first + Integer.toString(mid);
1388 		if (min != 0) {
1389 			timezoneShortForm = timezoneShortForm + ":" + (min < 10 ? "0" : "") + Integer.toString(min);
1390 		}
1391 		if (hasDaylight) {
1392 			timezoneShortForm += second;
1393 		}
1394 		return timezoneShortForm;
1395 	}
1396 
1397 	/**
1398 	 * Fills in any gaps in the image created by image writer.
1399 	 *
1400 	 * @param imgHandle The image handle.
1401 	 *
1402 	 * @return 0 if no errors occurred; 1 otherwise.
1403 	 *
1404 	 * @throws TskCoreException exception thrown if critical error occurs within
1405 	 *                          TSK
1406 	 */
finishImageWriter(long imgHandle)1407 	public static int finishImageWriter(long imgHandle) throws TskCoreException {
1408 		getTSKReadLock();
1409 		try {
1410 			if(! imgHandleIsValid(imgHandle)) {
1411 				throw new TskCoreException("Image handle " + imgHandle + " is closed");
1412 			}
1413 			return finishImageWriterNat(imgHandle);
1414 		} finally {
1415 			releaseTSKReadLock();
1416 		}
1417 	}
1418 
1419 	/**
1420 	 * Get the current progress of the finish image process (0-100)
1421 	 *
1422 	 * @param imgHandle
1423 	 *
1424 	 * @return Percentage of blocks completed (0-100)
1425 	 */
getFinishImageProgress(long imgHandle)1426 	public static int getFinishImageProgress(long imgHandle) {
1427 		getTSKReadLock();
1428 		try {
1429 			if (imgHandleIsValid(imgHandle)) {
1430 				return getFinishImageProgressNat(imgHandle);
1431 			} else {
1432 				return 0;
1433 			}
1434 		} finally {
1435 			releaseTSKReadLock();
1436 		}
1437 	}
1438 
1439 	/**
1440 	 * Cancel the finish image process
1441 	 *
1442 	 * @param imgHandle
1443 	 */
cancelFinishImage(long imgHandle)1444 	public static void cancelFinishImage(long imgHandle) {
1445 		getTSKReadLock();
1446 		try {
1447 			if (imgHandleIsValid(imgHandle)) {
1448 				cancelFinishImageNat(imgHandle);
1449 			}
1450 		} finally {
1451 			releaseTSKReadLock();
1452 		}
1453 	}
1454 
1455 	/**
1456 	 * Get size of a device (physical, logical device, image) pointed to by
1457 	 * devPath
1458 	 *
1459 	 * @param devPath device path pointing to the device
1460 	 *
1461 	 * @return size of the device in bytes
1462 	 *
1463 	 * @throws TskCoreException exception thrown if the device size could not be
1464 	 *                          queried
1465 	 */
findDeviceSize(String devPath)1466 	public static long findDeviceSize(String devPath) throws TskCoreException {
1467 		return findDeviceSizeNat(devPath);
1468 	}
1469 
isImageSupported(String imagePath)1470 	public static boolean isImageSupported(String imagePath) {
1471 		return isImageSupportedNat(imagePath);
1472 	}
1473 
1474 	/**
1475 	 * Get a read lock for the C++ layer. Do not get this lock after obtaining
1476 	 * HandleCache.cacheLock.
1477 	 */
getTSKReadLock()1478 	private static void getTSKReadLock() {
1479 		tskLock.readLock().lock();
1480 	}
1481 
1482 	/**
1483 	 * Release the read lock
1484 	 */
releaseTSKReadLock()1485 	private static void releaseTSKReadLock() {
1486 		tskLock.readLock().unlock();
1487 	}
1488 
1489 	//free pointers
1490 	/**
1491 	 * frees the imgHandle pointer currently does not close the image -
1492 	 * imgHandle should only be freed as part of CaseDbHandle.free().
1493 	 *
1494 	 * @param imgHandle to close the image
1495 	 */
1496 	@Deprecated
closeImg(long imgHandle)1497 	public static void closeImg(long imgHandle) {
1498 		//closeImgNat(imgHandle);
1499 	}
1500 
1501 	/**
1502 	 * frees the vsHandle pointer - currently does nothing
1503 	 *
1504 	 * @param vsHandle pointer to volume system structure in sleuthkit
1505 	 */
1506 	@Deprecated
closeVs(long vsHandle)1507 	public static void closeVs(long vsHandle) {
1508 		//		closeVsNat(vsHandle);  TODO JIRA-3829
1509 	}
1510 
1511 	/**
1512 	 * frees the fsHandle pointer Currently does not do anything - fsHandle
1513 	 * should only be freed as part of CaseDbHandle.free().
1514 	 *
1515 	 * @param fsHandle pointer to file system structure in sleuthkit
1516 	 */
1517 	@Deprecated
closeFs(long fsHandle)1518 	public static void closeFs(long fsHandle) {
1519 		//closeFsNat(fsHandle);
1520 	}
1521 
1522 	/**
1523 	 * Open the image and return the image info pointer.
1524 	 *
1525 	 * @param imageFiles the paths to the images
1526 	 *
1527 	 * @return the image info pointer
1528 	 *
1529 	 * @throws TskCoreException exception thrown if critical error occurs within
1530 	 *                          TSK
1531 	 * @deprecated Use the version with the SleuthkitCase argument
1532 	 */
1533 	@Deprecated
openImage(String[] imageFiles)1534 	public static long openImage(String[] imageFiles) throws TskCoreException {
1535 
1536 		return openImage(imageFiles, 0, true, null);
1537 	}
1538 
1539 	/**
1540 	 * Open the image with a specified sector size and return the image info
1541 	 * pointer.
1542 	 *
1543 	 * @param imageFiles the paths to the images
1544 	 * @param sSize      the sector size (use '0' for autodetect)
1545 	 *
1546 	 * @return the image info pointer
1547 	 *
1548 	 * @throws TskCoreException exception thrown if critical error occurs within
1549 	 *                          TSK
1550 	 * @deprecated Use the version with the SleuthkitCase argument
1551 	 */
1552 	@Deprecated
openImage(String[] imageFiles, int sSize)1553 	public static long openImage(String[] imageFiles, int sSize) throws TskCoreException {
1554 		return openImage(imageFiles, sSize, true, null);
1555 	}
1556 
1557 
1558 	/**
1559 	 * Get file system Handle Opened handle is cached (transparently) so it does
1560 	 * not need be reopened next time for the duration of the application
1561 	 *
1562 	 * @param imgHandle pointer to imgHandle in sleuthkit
1563 	 * @param fsOffset  byte offset to the file system
1564 	 *
1565 	 * @return pointer to a fsHandle structure in the sleuthkit
1566 	 *
1567 	 * @throws TskCoreException exception thrown if critical error occurs within
1568 	 *                          TSK
1569 	 * @deprecated Use the version with the SleuthkitCase argument
1570 	 */
1571 	@Deprecated
openFs(long imgHandle, long fsOffset)1572 	public static long openFs(long imgHandle, long fsOffset) throws TskCoreException {
1573 		return openFs(imgHandle, fsOffset, null);
1574 	}
1575 
1576 	/**
1577 	 * Get file Handle
1578 	 *
1579 	 * @param fsHandle fsHandle pointer in the sleuthkit
1580 	 * @param fileId   id of the file
1581 	 * @param attrType file attribute type to open
1582 	 * @param attrId   file attribute id to open
1583 	 *
1584 	 * @return pointer to a file structure in the sleuthkit
1585 	 *
1586 	 * @throws TskCoreException exception thrown if critical error occurs within
1587 	 *                          TSK
1588 	 * @deprecated Use the version with the SleuthkitCase argument
1589 	 */
1590 	@Deprecated
openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId)1591 	public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM attrType, int attrId) throws TskCoreException {
1592 		return openFile(fsHandle, fileId, attrType, attrId, null);
1593 	}
1594 
1595 
getVersionNat()1596 	private static native String getVersionNat();
1597 
startVerboseLoggingNat(String logPath)1598 	private static native void startVerboseLoggingNat(String logPath);
1599 
newCaseDbNat(String dbPath)1600 	private static native long newCaseDbNat(String dbPath) throws TskCoreException;
1601 
newCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName)1602 	private static native long newCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName);
1603 
openCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName)1604 	private static native long openCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName);
1605 
openCaseDbNat(String path)1606 	private static native long openCaseDbNat(String path) throws TskCoreException;
1607 
closeCaseDbNat(long db)1608 	private static native void closeCaseDbNat(long db) throws TskCoreException;
1609 
hashDbOpenNat(String hashDbPath)1610 	private static native int hashDbOpenNat(String hashDbPath) throws TskCoreException;
1611 
hashDbNewNat(String hashDbPath)1612 	private static native int hashDbNewNat(String hashDbPath) throws TskCoreException;
1613 
hashDbBeginTransactionNat(int dbHandle)1614 	private static native int hashDbBeginTransactionNat(int dbHandle) throws TskCoreException;
1615 
hashDbCommitTransactionNat(int dbHandle)1616 	private static native int hashDbCommitTransactionNat(int dbHandle) throws TskCoreException;
1617 
hashDbRollbackTransactionNat(int dbHandle)1618 	private static native int hashDbRollbackTransactionNat(int dbHandle) throws TskCoreException;
1619 
hashDbAddEntryNat(String filename, String hashMd5, String hashSha1, String hashSha256, String comment, int dbHandle)1620 	private static native int hashDbAddEntryNat(String filename, String hashMd5, String hashSha1, String hashSha256, String comment, int dbHandle) throws TskCoreException;
1621 
hashDbIsUpdateableNat(int dbHandle)1622 	private static native boolean hashDbIsUpdateableNat(int dbHandle);
1623 
hashDbIsReindexableNat(int dbHandle)1624 	private static native boolean hashDbIsReindexableNat(int dbHandle);
1625 
hashDbPathNat(int dbHandle)1626 	private static native String hashDbPathNat(int dbHandle);
1627 
hashDbIndexPathNat(int dbHandle)1628 	private static native String hashDbIndexPathNat(int dbHandle);
1629 
hashDbGetDisplayName(int dbHandle)1630 	private static native String hashDbGetDisplayName(int dbHandle) throws TskCoreException;
1631 
hashDbCloseAll()1632 	private static native void hashDbCloseAll() throws TskCoreException;
1633 
hashDbClose(int dbHandle)1634 	private static native void hashDbClose(int dbHandle) throws TskCoreException;
1635 
hashDbCreateIndexNat(int dbHandle)1636 	private static native void hashDbCreateIndexNat(int dbHandle) throws TskCoreException;
1637 
hashDbIndexExistsNat(int dbHandle)1638 	private static native boolean hashDbIndexExistsNat(int dbHandle) throws TskCoreException;
1639 
hashDbIsIdxOnlyNat(int dbHandle)1640 	private static native boolean hashDbIsIdxOnlyNat(int dbHandle) throws TskCoreException;
1641 
hashDbLookup(String hash, int dbHandle)1642 	private static native boolean hashDbLookup(String hash, int dbHandle) throws TskCoreException;
1643 
hashDbLookupVerbose(String hash, int dbHandle)1644 	private static native HashHitInfo hashDbLookupVerbose(String hash, int dbHandle) throws TskCoreException;
1645 
initAddImgNat(long db, String timezone, boolean addUnallocSpace, boolean skipFatFsOrphans)1646 	private static native long initAddImgNat(long db, String timezone, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException;
1647 
initializeAddImgNat(long db, String timezone, boolean addFileSystems, boolean addUnallocSpace, boolean skipFatFsOrphans)1648 	private static native long initializeAddImgNat(long db, String timezone, boolean addFileSystems, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException;
1649 
runOpenAndAddImgNat(long process, String deviceId, String[] imgPath, int splits, String timezone)1650 	private static native void runOpenAndAddImgNat(long process, String deviceId, String[] imgPath, int splits, String timezone) throws TskCoreException, TskDataException;
1651 
runAddImgNat(long process, String deviceId, long a_img_info, String timeZone, String imageWriterPath)1652 	private static native void runAddImgNat(long process, String deviceId, long a_img_info, String timeZone, String imageWriterPath) throws TskCoreException, TskDataException;
1653 
stopAddImgNat(long process)1654 	private static native void stopAddImgNat(long process) throws TskCoreException;
1655 
revertAddImgNat(long process)1656 	private static native void revertAddImgNat(long process) throws TskCoreException;
1657 
commitAddImgNat(long process)1658 	private static native long commitAddImgNat(long process) throws TskCoreException;
1659 
openImgNat(String[] imgPath, int splits, int sSize)1660 	private static native long openImgNat(String[] imgPath, int splits, int sSize) throws TskCoreException;
1661 
openVsNat(long imgHandle, long vsOffset)1662 	private static native long openVsNat(long imgHandle, long vsOffset) throws TskCoreException;
1663 
openVolNat(long vsHandle, long volId)1664 	private static native long openVolNat(long vsHandle, long volId) throws TskCoreException;
1665 
openFsNat(long imgHandle, long fsId)1666 	private static native long openFsNat(long imgHandle, long fsId) throws TskCoreException;
1667 
openFileNat(long fsHandle, long fileId, int attrType, int attrId)1668 	private static native long openFileNat(long fsHandle, long fileId, int attrType, int attrId) throws TskCoreException;
1669 
readImgNat(long imgHandle, byte[] readBuffer, long offset, long len)1670 	private static native int readImgNat(long imgHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1671 
readVsNat(long vsHandle, byte[] readBuffer, long offset, long len)1672 	private static native int readVsNat(long vsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1673 
readVolNat(long volHandle, byte[] readBuffer, long offset, long len)1674 	private static native int readVolNat(long volHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1675 
readFsNat(long fsHandle, byte[] readBuffer, long offset, long len)1676 	private static native int readFsNat(long fsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
1677 
readFileNat(long fileHandle, byte[] readBuffer, long offset, int offset_type, long len)1678 	private static native int readFileNat(long fileHandle, byte[] readBuffer, long offset, int offset_type, long len) throws TskCoreException;
1679 
saveFileMetaDataTextNat(long fileHandle, String fileName)1680 	private static native int saveFileMetaDataTextNat(long fileHandle, String fileName) throws TskCoreException;
1681 
closeImgNat(long imgHandle)1682 	private static native void closeImgNat(long imgHandle);
1683 
closeVsNat(long vsHandle)1684 	private static native void closeVsNat(long vsHandle);
1685 
closeFsNat(long fsHandle)1686 	private static native void closeFsNat(long fsHandle);
1687 
closeFileNat(long fileHandle)1688 	private static native void closeFileNat(long fileHandle);
1689 
findDeviceSizeNat(String devicePath)1690 	private static native long findDeviceSizeNat(String devicePath) throws TskCoreException;
1691 
getCurDirNat(long process)1692 	private static native String getCurDirNat(long process);
1693 
isImageSupportedNat(String imagePath)1694 	private static native boolean isImageSupportedNat(String imagePath);
1695 
finishImageWriterNat(long a_img_info)1696 	private static native int finishImageWriterNat(long a_img_info);
1697 
getFinishImageProgressNat(long a_img_info)1698 	private static native int getFinishImageProgressNat(long a_img_info);
1699 
cancelFinishImageNat(long a_img_info)1700 	private static native void cancelFinishImageNat(long a_img_info);
1701 
1702 }
1703