Autopsy  4.7.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("GMT");
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 
300  public static boolean isDotDirectory(AbstractFile dir) {
301  String name = dir.getName();
302  return name.equals(".") || name.equals("..");
303  }
304 
310  public static class ExtractFscContentVisitor<T, V> extends ContentVisitor.Default<Void> {
311 
312  java.io.File dest;
313  ProgressHandle progress;
314  SwingWorker<T, V> worker;
315  boolean source = false;
316 
329  public ExtractFscContentVisitor(java.io.File dest,
330  ProgressHandle progress, SwingWorker<T, V> worker, boolean source) {
331  this.dest = dest;
332  this.progress = progress;
333  this.worker = worker;
334  this.source = source;
335  }
336 
337  public ExtractFscContentVisitor(java.io.File dest) {
338  this.dest = dest;
339  }
340 
345  public static <T, V> void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker<T, V> worker) {
346  cntnt.accept(new ExtractFscContentVisitor<>(dest, progress, worker, true));
347  }
348 
349  @Override
350  public Void visit(File file) {
351  try {
352  ContentUtils.writeToFile(file, dest, progress, worker, source);
353  } catch (ReadContentInputStreamException ex) {
354  logger.log(Level.WARNING,
355  String.format("Error reading file '%s' (id=%d).",
356  file.getName(), file.getId()), ex); //NON-NLS
357  } catch (IOException ex) {
358  logger.log(Level.SEVERE,
359  String.format("Error extracting file '%s' (id=%d) to '%s'.",
360  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
361  }
362  return null;
363  }
364 
365  @Override
366  public Void visit(LayoutFile file) {
367  try {
368  ContentUtils.writeToFile(file, dest, progress, worker, source);
369  } catch (ReadContentInputStreamException ex) {
370  logger.log(Level.WARNING,
371  String.format("Error reading file '%s' (id=%d).",
372  file.getName(), file.getId()), ex); //NON-NLS
373  } catch (IOException ex) {
374  logger.log(Level.SEVERE,
375  String.format("Error extracting unallocated content file '%s' (id=%d) to '%s'.",
376  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
377  }
378  return null;
379  }
380 
381  @Override
382  public Void visit(DerivedFile file) {
383  try {
384  ContentUtils.writeToFile(file, dest, progress, worker, source);
385  } catch (ReadContentInputStreamException ex) {
386  logger.log(Level.WARNING,
387  String.format("Error reading file '%s' (id=%d).",
388  file.getName(), file.getId()), ex); //NON-NLS
389  } catch (IOException ex) {
390  logger.log(Level.SEVERE,
391  String.format("Error extracting derived file '%s' (id=%d) to '%s'.",
392  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
393  }
394  return null;
395  }
396 
397  @Override
398  public Void visit(LocalFile file) {
399  try {
400  ContentUtils.writeToFile(file, dest, progress, worker, source);
401  } catch (ReadContentInputStreamException ex) {
402  logger.log(Level.WARNING,
403  String.format("Error reading file '%s' (id=%d).",
404  file.getName(), file.getId()), ex); //NON-NLS
405  } catch (IOException ex) {
406  logger.log(Level.SEVERE,
407  String.format("Error extracting local file '%s' (id=%d) to '%s'.",
408  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
409  }
410  return null;
411  }
412 
413  @Override
414  public Void visit(SlackFile file) {
415  try {
416  ContentUtils.writeToFile(file, dest, progress, worker, source);
417  } catch (ReadContentInputStreamException ex) {
418  logger.log(Level.WARNING,
419  String.format("Error reading file '%s' (id=%d).",
420  file.getName(), file.getId()), ex); //NON-NLS
421  } catch (IOException ex) {
422  logger.log(Level.SEVERE,
423  String.format("Error extracting slack file '%s' (id=%d) to '%s'.",
424  file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
425  }
426  return null;
427  }
428 
429  @Override
430  public Void visit(Directory dir) {
431  return visitDir(dir);
432  }
433 
434  @Override
435  public Void visit(VirtualDirectory dir) {
436  return visitDir(dir);
437  }
438 
439  @Override
440  public Void visit(LocalDirectory dir) {
441  return visitDir(dir);
442  }
443 
444  private java.io.File getFsContentDest(Content content) {
445  String path = dest.getAbsolutePath() + java.io.File.separator
446  + content.getName();
447  return new java.io.File(path);
448  }
449 
450  public Void visitDir(AbstractFile dir) {
451 
452  // don't extract . and .. directories
453  if (isDotDirectory(dir)) {
454  return null;
455  }
456 
457  dest.mkdir();
458 
459  try {
460  int numProcessed = 0;
461  // recurse on children
462  for (Content child : dir.getChildren()) {
463  if (child instanceof AbstractFile) { //ensure the directory's artifact children are ignored
464  java.io.File childFile = getFsContentDest(child);
465  ExtractFscContentVisitor<T, V> childVisitor
466  = new ExtractFscContentVisitor<>(childFile, progress, worker, false);
467  // If this is the source directory of an extract it
468  // will have a progress and worker, and will keep track
469  // of the progress bar's progress
470  if (worker != null && worker.isCancelled()) {
471  break;
472  }
473  if (progress != null && source) {
474  progress.progress(child.getName(), numProcessed);
475  }
476  child.accept(childVisitor);
477  numProcessed++;
478  }
479  }
480  } catch (TskCoreException ex) {
481  logger.log(Level.SEVERE,
482  "Trouble fetching children to extract.", ex); //NON-NLS
483  }
484 
485  return null;
486  }
487 
488  @Override
489  protected Void defaultVisit(Content content) {
490  throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(),
491  "ContentUtils.exception.msg",
492  content.getClass().getSimpleName()));
493  }
494  }
495 
501  public static boolean shouldDisplayTimesInLocalTime() {
503  }
504 
505 }
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 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-2016 Basis Technology. Generated on: Mon Jun 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.