Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ContentUtils.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
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.autopsy.datamodel;
20 
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.text.SimpleDateFormat;
25 import java.util.TimeZone;
26 import java.util.concurrent.Future;
27 import java.util.function.Supplier;
28 import java.util.logging.Level;
29 import java.util.prefs.PreferenceChangeEvent;
30 import java.util.prefs.PreferenceChangeListener;
31 import javax.swing.SwingWorker;
32 import org.netbeans.api.progress.ProgressHandle;
33 import org.openide.util.NbBundle;
36 import org.sleuthkit.datamodel.AbstractFile;
37 import org.sleuthkit.datamodel.Content;
38 import org.sleuthkit.datamodel.ContentVisitor;
39 import org.sleuthkit.datamodel.DerivedFile;
40 import org.sleuthkit.datamodel.Directory;
41 import org.sleuthkit.datamodel.File;
42 import org.sleuthkit.datamodel.Image;
43 import org.sleuthkit.datamodel.LayoutFile;
44 import org.sleuthkit.datamodel.LocalFile;
45 import org.sleuthkit.datamodel.LocalDirectory;
46 import org.sleuthkit.datamodel.ReadContentInputStream;
47 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
48 import org.sleuthkit.datamodel.SlackFile;
49 import org.sleuthkit.datamodel.TskCoreException;
50 import org.sleuthkit.datamodel.VirtualDirectory;
51 
55 public final class ContentUtils {
56 
57  private final static Logger logger = Logger.getLogger(ContentUtils.class.getName());
59  private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
60  private static final SimpleDateFormat dateFormatterISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
61 
62  static {
63  UserPreferences.addChangeListener(new PreferenceChangeListener() {
64  @Override
65  public void preferenceChange(PreferenceChangeEvent evt) {
66  if (evt.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
67  displayTimesInLocalTime = UserPreferences.displayTimesInLocalTime();
68  }
69  }
70  });
71  }
72 
76  private ContentUtils() {
77  throw new AssertionError();
78  }
79 
88  public static String getStringTime(long epochSeconds, TimeZone tzone) {
89  String time = "0000-00-00 00:00:00";
90  if (epochSeconds != 0) {
91  synchronized (dateFormatter) {
92  dateFormatter.setTimeZone(tzone);
93  time = dateFormatter.format(new java.util.Date(epochSeconds * 1000));
94  }
95  }
96  return time;
97  }
98 
107  public static String getStringTimeISO8601(long epochSeconds, TimeZone tzone) {
108  String time = "0000-00-00T00:00:00Z"; //NON-NLS
109  if (epochSeconds != 0) {
110  synchronized (dateFormatterISO8601) {
111  dateFormatterISO8601.setTimeZone(tzone);
112  time = dateFormatterISO8601.format(new java.util.Date(epochSeconds * 1000));
113  }
114  }
115 
116  return time;
117  }
118 
127  public static String getStringTime(long epochSeconds, Content content) {
128  return getStringTime(epochSeconds, getTimeZone(content));
129  }
130 
140  public static String getStringTimeISO8601(long epochSeconds, Content c) {
141  return getStringTimeISO8601(epochSeconds, getTimeZone(c));
142  }
143 
144  public static TimeZone getTimeZone(Content content) {
145 
146  try {
148  return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
149  } else {
150  final Content dataSource = content.getDataSource();
151  if ((dataSource != null) && (dataSource instanceof Image)) {
152  Image image = (Image) dataSource;
153  return TimeZone.getTimeZone(image.getTimeZone());
154  } else {
155  //case such as top level VirtualDirectory
156  return TimeZone.getDefault();
157  }
158  }
159  } catch (TskCoreException ex) {
160  return TimeZone.getDefault();
161  }
162  }
163  private static final SystemNameVisitor systemName = new SystemNameVisitor();
164 
172  public static String getSystemName(Content content) {
173  return content.accept(systemName);
174  }
175 
180  private static class SystemNameVisitor extends ContentVisitor.Default<String> {
181 
183  }
184 
185  @Override
186  protected String defaultVisit(Content cntnt) {
187  return cntnt.getName() + ":" + Long.toString(cntnt.getId());
188  }
189  }
190  private static final int TO_FILE_BUFFER_SIZE = 8192;
191 
210  public static <T> long writeToFile(Content content, java.io.File outputFile,
211  ProgressHandle progress, Future<T> worker, boolean source) throws IOException {
212  InputStream in = new ReadContentInputStream(content);
213 
214  // Get the unit size for a progress bar
215  int unit = (int) (content.getSize() / 100);
216  long totalRead = 0;
217 
218  try (FileOutputStream out = new FileOutputStream(outputFile, false)) {
219  byte[] buffer = new byte[TO_FILE_BUFFER_SIZE];
220  int len = in.read(buffer);
221  while (len != -1) {
222  // If there is a worker, check for a cancelation
223  if (worker != null && worker.isCancelled()) {
224  break;
225  }
226  out.write(buffer, 0, len);
227  len = in.read(buffer);
228  totalRead += len;
229  // If there is a progress bar and this is the source file,
230  // report any progress
231  if (progress != null && source && totalRead >= TO_FILE_BUFFER_SIZE) {
232  int totalProgress = (int) (totalRead / unit);
233  progress.progress(content.getName(), totalProgress);
234  // If it's not the source, just update the file being processed
235  } else if (progress != null && !source) {
236  progress.progress(content.getName());
237  }
238  }
239  } finally {
240  in.close();
241  }
242  return totalRead;
243  }
244 
253  public static void writeToFile(Content content, java.io.File outputFile) throws IOException {
254  writeToFile(content, outputFile, null, null, false);
255  }
256 
271  public static long writeToFile(Content content, java.io.File outputFile,
272  Supplier<Boolean> cancelCheck) throws IOException {
273  InputStream in = new ReadContentInputStream(content);
274  long totalRead = 0;
275 
276  try (FileOutputStream out = new FileOutputStream(outputFile, false)) {
277  byte[] buffer = new byte[TO_FILE_BUFFER_SIZE];
278  int len = in.read(buffer);
279  while (len != -1) {
280  out.write(buffer, 0, len);
281  totalRead += len;
282  if (cancelCheck.get()) {
283  break;
284  }
285  len = in.read(buffer);
286  }
287  } finally {
288  in.close();
289  }
290  return totalRead;
291  }
292 
309  public static long writeToFile(Content content, java.io.File outputFile,
310  Supplier<Boolean> cancelCheck, long startingOffset, long endingOffset) throws IOException {
311 
312  InputStream in = new ReadContentInputStream(content);
313  long totalRead = 0;
314  try (FileOutputStream out = new FileOutputStream(outputFile, false)) {
315  long offsetSkipped = in.skip(startingOffset);
316  if (offsetSkipped != startingOffset) {
317  in.close();
318  throw new IOException(String.format("Skipping file to starting offset {0} was not successful only skipped to offset {1}.", startingOffset, offsetSkipped));
319  }
320  byte[] buffer = new byte[TO_FILE_BUFFER_SIZE];
321  int len = in.read(buffer);
322  long writeFileLength = endingOffset - startingOffset;
323  writeFileLength = writeFileLength - TO_FILE_BUFFER_SIZE;
324  while (len != -1 && writeFileLength != 0) {
325  out.write(buffer, 0, len);
326  totalRead += len;
327  if (cancelCheck.get()) {
328  break;
329  }
330  if (writeFileLength > TO_FILE_BUFFER_SIZE) {
331  len = in.read(buffer);
332  writeFileLength = writeFileLength - TO_FILE_BUFFER_SIZE;
333  } else {
334  int writeLength = (int)writeFileLength;
335  byte[] lastBuffer = new byte[writeLength];
336  len = in.read(lastBuffer);
337  out.write(lastBuffer, 0, len);
338  totalRead += len;
339  writeFileLength = 0;
340  }
341  }
342 
343  } finally {
344  in.close();
345  }
346  return totalRead;
347  }
348 
356  public static boolean isDotDirectory(AbstractFile dir) {
357  String name = dir.getName();
358  return name.equals(".") || name.equals("..");
359  }
360 
366  public static class ExtractFscContentVisitor<T, V> extends ContentVisitor.Default<Void> {
367 
368  java.io.File dest;
369  ProgressHandle progress;
370  SwingWorker<T, V> worker;
371  boolean source = false;
372 
385  public ExtractFscContentVisitor(java.io.File dest,
386  ProgressHandle progress, SwingWorker<T, V> worker, boolean source) {
387  this.dest = dest;
388  this.progress = progress;
389  this.worker = worker;
390  this.source = source;
391  }
392 
393  public ExtractFscContentVisitor(java.io.File dest) {
394  this.dest = dest;
395  }
396 
401  public static <T, V> void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker<T, V> worker) {
402  cntnt.accept(new ExtractFscContentVisitor<>(dest, progress, worker, true));
403  }
404 
405  @Override
406  public Void visit(File file) {
407  try {
408  ContentUtils.writeToFile(file, dest, progress, worker, source);
409  } catch (ReadContentInputStreamException ex) {
410  logger.log(Level.WARNING,
411  String.format("Error reading file '%s' (id=%d).",
412  file.getName(), file.getId()), ex); //NON-NLS
413  } catch (IOException ex) {
414  logger.log(Level.SEVERE,
415  String.format("Error extracting file '%s' (id=%d) to '%s'.",
416  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
417  }
418  return null;
419  }
420 
421  @Override
422  public Void visit(LayoutFile file) {
423  try {
424  ContentUtils.writeToFile(file, dest, progress, worker, source);
425  } catch (ReadContentInputStreamException ex) {
426  logger.log(Level.WARNING,
427  String.format("Error reading file '%s' (id=%d).",
428  file.getName(), file.getId()), ex); //NON-NLS
429  } catch (IOException ex) {
430  logger.log(Level.SEVERE,
431  String.format("Error extracting unallocated content file '%s' (id=%d) to '%s'.",
432  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
433  }
434  return null;
435  }
436 
437  @Override
438  public Void visit(DerivedFile file) {
439  try {
440  ContentUtils.writeToFile(file, dest, progress, worker, source);
441  } catch (ReadContentInputStreamException ex) {
442  logger.log(Level.WARNING,
443  String.format("Error reading file '%s' (id=%d).",
444  file.getName(), file.getId()), ex); //NON-NLS
445  } catch (IOException ex) {
446  logger.log(Level.SEVERE,
447  String.format("Error extracting derived file '%s' (id=%d) to '%s'.",
448  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
449  }
450  return null;
451  }
452 
453  @Override
454  public Void visit(LocalFile file) {
455  try {
456  ContentUtils.writeToFile(file, dest, progress, worker, source);
457  } catch (ReadContentInputStreamException ex) {
458  logger.log(Level.WARNING,
459  String.format("Error reading file '%s' (id=%d).",
460  file.getName(), file.getId()), ex); //NON-NLS
461  } catch (IOException ex) {
462  logger.log(Level.SEVERE,
463  String.format("Error extracting local file '%s' (id=%d) to '%s'.",
464  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
465  }
466  return null;
467  }
468 
469  @Override
470  public Void visit(SlackFile file) {
471  try {
472  ContentUtils.writeToFile(file, dest, progress, worker, source);
473  } catch (ReadContentInputStreamException ex) {
474  logger.log(Level.WARNING,
475  String.format("Error reading file '%s' (id=%d).",
476  file.getName(), file.getId()), ex); //NON-NLS
477  } catch (IOException ex) {
478  logger.log(Level.SEVERE,
479  String.format("Error extracting slack file '%s' (id=%d) to '%s'.",
480  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
481  }
482  return null;
483  }
484 
485  @Override
486  public Void visit(Directory dir) {
487  return visitDir(dir);
488  }
489 
490  @Override
491  public Void visit(VirtualDirectory dir) {
492  return visitDir(dir);
493  }
494 
495  @Override
496  public Void visit(LocalDirectory dir) {
497  return visitDir(dir);
498  }
499 
500  private java.io.File getFsContentDest(Content content) {
501  String path = dest.getAbsolutePath() + java.io.File.separator
502  + content.getName();
503  return new java.io.File(path);
504  }
505 
506  public Void visitDir(AbstractFile dir) {
507 
508  // don't extract . and .. directories
509  if (isDotDirectory(dir)) {
510  return null;
511  }
512 
513  dest.mkdir();
514 
515  try {
516  int numProcessed = 0;
517  // recurse on children
518  for (Content child : dir.getChildren()) {
519  if (child instanceof AbstractFile) { //ensure the directory's artifact children are ignored
520  java.io.File childFile = getFsContentDest(child);
521  ExtractFscContentVisitor<T, V> childVisitor
522  = new ExtractFscContentVisitor<>(childFile, progress, worker, false);
523  // If this is the source directory of an extract it
524  // will have a progress and worker, and will keep track
525  // of the progress bar's progress
526  if (worker != null && worker.isCancelled()) {
527  break;
528  }
529  if (progress != null && source) {
530  progress.progress(child.getName(), numProcessed);
531  }
532  child.accept(childVisitor);
533  numProcessed++;
534  }
535  }
536  } catch (TskCoreException ex) {
537  logger.log(Level.SEVERE,
538  "Trouble fetching children to extract.", ex); //NON-NLS
539  }
540 
541  return null;
542  }
543 
544  @Override
545  protected Void defaultVisit(Content content) {
546  throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(),
547  "ContentUtils.exception.msg",
548  content.getClass().getSimpleName()));
549  }
550  }
551 
557  public static boolean shouldDisplayTimesInLocalTime() {
559  }
560 
561 }
static String getStringTime(long epochSeconds, TimeZone tzone)
static final SimpleDateFormat dateFormatter
ExtractFscContentVisitor(java.io.File dest, ProgressHandle progress, SwingWorker< T, V > worker, boolean source)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
static long writeToFile(Content content, java.io.File outputFile, Supplier< Boolean > cancelCheck, long startingOffset, long endingOffset)
static String getSystemName(Content content)
static String getStringTime(long epochSeconds, Content content)
static< T, V > void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker< T, V > worker)
static TimeZone getTimeZone(Content content)
static String getStringTimeISO8601(long epochSeconds, TimeZone tzone)
static final SimpleDateFormat dateFormatterISO8601
static final SystemNameVisitor systemName
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static String getStringTimeISO8601(long epochSeconds, Content c)
static void addChangeListener(PreferenceChangeListener listener)
static void writeToFile(Content content, java.io.File outputFile)
static long writeToFile(Content content, java.io.File outputFile, Supplier< Boolean > cancelCheck)
static boolean isDotDirectory(AbstractFile dir)

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.