Autopsy  4.4
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileTypesByMimeType.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2017 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.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Observable;
30 import java.util.Observer;
31 import java.util.logging.Level;
32 import org.apache.commons.lang3.ArrayUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.openide.nodes.AbstractNode;
35 import org.openide.nodes.ChildFactory;
36 import org.openide.nodes.Children;
37 import org.openide.nodes.Node;
38 import org.openide.util.NbBundle;
43 import org.sleuthkit.datamodel.AbstractFile;
44 import org.sleuthkit.datamodel.Content;
45 import org.sleuthkit.datamodel.ContentVisitor;
46 import org.sleuthkit.datamodel.DerivedFile;
47 import org.sleuthkit.datamodel.Directory;
48 import org.sleuthkit.datamodel.File;
49 import org.sleuthkit.datamodel.LayoutFile;
50 import org.sleuthkit.datamodel.LocalFile;
51 import org.sleuthkit.datamodel.SlackFile;
52 import org.sleuthkit.datamodel.SleuthkitCase;
53 import org.sleuthkit.datamodel.TskCoreException;
54 import org.sleuthkit.datamodel.TskData;
55 
63 public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
64 
65  private final SleuthkitCase skCase;
71  private final HashMap<String, List<String>> existingMimeTypes = new HashMap<>();
72  private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName());
73 
74  private void removeListeners() {
75  deleteObservers();
78  }
79 
80  /*
81  * The pcl is in the class because it has the easiest mechanisms to add and
82  * remove itself during its life cycles.
83  */
84  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
85  String eventType = evt.getPropertyName();
86  if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
87  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
88 
95  try {
98  } catch (IllegalStateException notUsed) {
102  }
103  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
104  if (evt.getNewValue() == null) {
105  removeListeners();
106  }
107  }
108  };
109 
116  private List<String> getMediaTypeList() {
117  synchronized (existingMimeTypes) {
118  List<String> mediaTypes = new ArrayList<>(existingMimeTypes.keySet());
119  Collections.sort(mediaTypes);
120  return mediaTypes;
121  }
122  }
123 
128  private void populateHashMap() {
129  StringBuilder allDistinctMimeTypesQuery = new StringBuilder();
130  allDistinctMimeTypesQuery.append("SELECT DISTINCT mime_type from tsk_files where mime_type IS NOT null"); //NON-NLS
131  allDistinctMimeTypesQuery.append(" AND dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()); //NON-NLS
132  allDistinctMimeTypesQuery.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS
133  allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(",");
134  allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(",");
136  allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()).append(",");
137  }
138  allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))");
139  synchronized (existingMimeTypes) {
140  existingMimeTypes.clear();
141 
142  if (skCase == null) {
143 
144  return;
145  }
146  try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) {
147  ResultSet resultSet = dbQuery.getResultSet();
148  while (resultSet.next()) {
149  final String mime_type = resultSet.getString("mime_type"); //NON-NLS
150  if (!mime_type.isEmpty()) {
151  String mimeType[] = mime_type.split("/");
152  //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
153  final String mimeMediaSubType = StringUtils.join(ArrayUtils.subarray(mimeType, 1, mimeType.length), "/");
154  if (mimeType.length > 1 && !mimeType[0].isEmpty() && !mimeMediaSubType.isEmpty()) {
155  if (!existingMimeTypes.containsKey(mimeType[0])) {
156  existingMimeTypes.put(mimeType[0], new ArrayList<>());
157  }
158  existingMimeTypes.get(mimeType[0]).add(mimeMediaSubType);
159  }
160  }
161  }
162  } catch (TskCoreException | SQLException ex) {
163  LOGGER.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
164  }
165  }
166 
167  setChanged();
168 
169  notifyObservers();
170  }
171 
172  FileTypesByMimeType(SleuthkitCase skCase) {
175  this.skCase = skCase;
176  populateHashMap();
177  }
178 
179  @Override
180  public <T> T accept(AutopsyItemVisitor<T> v) {
181  return v.visit(this);
182  }
183 
193  public static boolean isEmptyMimeTypeNode(Node node) {
194  boolean isEmptyMimeNode = false;
195  if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
196  isEmptyMimeNode = true;
197  }
198  return isEmptyMimeNode;
199 
200  }
201 
208  class ByMimeTypeNode extends DisplayableItemNode {
209 
210  @NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type")
211  final String NAME = Bundle.FileTypesByMimeType_name_text();
212 
213  ByMimeTypeNode() {
214  super(Children.create(new ByMimeTypeNodeChildren(), true));
215  super.setName(NAME);
216  super.setDisplayName(NAME);
217  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
218  }
219 
220  @Override
221  public boolean isLeafTypeNode() {
222  return false;
223  }
224 
225  @Override
226  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
227  return v.visit(this);
228  }
229 
230  @Override
231  public String getItemType() {
232  return getClass().getName();
233  }
234 
235  boolean isEmpty() {
236  return existingMimeTypes.isEmpty();
237  }
238 
239  }
240 
245  private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
246 
248  super();
249  addObserver(this);
250  }
251 
252  @Override
253  protected boolean createKeys(List<String> mediaTypeNodes) {
254  if (!existingMimeTypes.isEmpty()) {
255  mediaTypeNodes.addAll(getMediaTypeList());
256  }
257  return true;
258  }
259 
260  @Override
261  protected Node createNodeForKey(String key) {
262  return new MediaTypeNode(key);
263  }
264 
265  @Override
266  public void update(Observable o, Object arg) {
267  refresh(true);
268  }
269 
270  }
271 
276  class MediaTypeNode extends DisplayableItemNode {
277 
278  MediaTypeNode(String name) {
279  super(Children.create(new MediaTypeNodeChildren(name), true));
280  setName(name);
281  setDisplayName(name);
282  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
283  }
284 
285  @Override
286  public boolean isLeafTypeNode() {
287  return false;
288  }
289 
290  @Override
291  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
292  return v.visit(this);
293  }
294 
295  @Override
296  public String getItemType() {
297  return getClass().getName();
298  }
299 
300  }
301 
307  private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
308 
309  String mediaType;
310 
311  MediaTypeNodeChildren(String name) {
312  addObserver(this);
313  this.mediaType = name;
314  }
315 
316  @Override
317  protected boolean createKeys(List<String> mediaTypeNodes) {
318  mediaTypeNodes.addAll(existingMimeTypes.get(mediaType));
319  return true;
320  }
321 
322  @Override
323  protected Node createNodeForKey(String subtype) {
324  String mimeType = mediaType + "/" + subtype;
325  return new MediaSubTypeNode(mimeType);
326  }
327 
328  @Override
329  public void update(Observable o, Object arg) {
330  refresh(true);
331  }
332 
333  }
334 
339  class MediaSubTypeNode extends DisplayableItemNode implements Observer {
340 
341  private MediaSubTypeNode(String mimeType) {
342  super(Children.create(new MediaSubTypeNodeChildren(mimeType), true));
343  addObserver(this);
344  init(mimeType);
345  }
346 
347  private void init(String mimeType) {
348  super.setName(mimeType);
349  updateDisplayName(mimeType);
350  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
351  }
352 
360  private void updateDisplayName(String mimeType) {
361  final long count = new MediaSubTypeNodeChildren(mimeType).calculateItems(skCase, mimeType);
362  String[] mimeTypeParts = mimeType.split("/");
363  //joins up all remaining parts of the mimeType into one sub-type string
364  super.setDisplayName(StringUtils.join(ArrayUtils.subarray(mimeTypeParts, 1, mimeTypeParts.length), "/") + " (" + count + ")");
365  }
366 
373  @Override
374  public boolean isLeafTypeNode() {
375  return true;
376  }
377 
378  @Override
379  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
380  return v.visit(this);
381  }
382 
383  @Override
384  public String getItemType() {
385  return getClass().getName();
386  }
387 
388  @Override
389  public void update(Observable o, Object arg) {
390  updateDisplayName(getName());
391  }
392  }
393 
399  private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<Content> implements Observer {
400 
401  private final String mimeType;
402 
403  private MediaSubTypeNodeChildren(String mimeType) {
404  super();
405  addObserver(this);
406  this.mimeType = mimeType;
407  }
408 
415  private long calculateItems(SleuthkitCase sleuthkitCase, String mime_type) {
416  try {
417  return sleuthkitCase.countFilesWhere(createQuery(mime_type));
418  } catch (TskCoreException ex) {
419  LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS
420  return 0;
421  }
422  }
423 
434  @Override
435  protected boolean createKeys(List<Content> list) {
436  try {
437  List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(mimeType));
438  list.addAll(files);
439  } catch (TskCoreException ex) {
440  LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
441  }
442  return true;
443  }
444 
456  private String createQuery(String mimeType) {
457  StringBuilder query = new StringBuilder();
458  query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
459  query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS
460  query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(",");
461  query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(",");
463  query.append(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()).append(",");
464  }
465  query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))");
467  query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
468  }
469  query.append(" AND mime_type = '").append(mimeType).append("'"); //NON-NLS
470  return query.toString();
471  }
472 
473  @Override
474  public void update(Observable o, Object arg) {
475  refresh(true);
476  }
477 
486  @Override
487  protected Node createNodeForKey(Content key) {
488  return key.accept(new ContentVisitor.Default<AbstractNode>() {
489  @Override
490  public FileNode visit(File f) {
491  return new FileNode(f, false);
492  }
493 
494  @Override
495  public DirectoryNode visit(Directory d) {
496  return new DirectoryNode(d);
497  }
498 
499  @Override
500  public LayoutFileNode visit(LayoutFile lf) {
501  return new LayoutFileNode(lf);
502  }
503 
504  @Override
505  public LocalFileNode visit(DerivedFile df) {
506  return new LocalFileNode(df);
507  }
508 
509  @Override
510  public LocalFileNode visit(LocalFile lf) {
511  return new LocalFileNode(lf);
512  }
513 
514  @Override
515  public SlackFileNode visit(SlackFile sf) {
516  return new SlackFileNode(sf, false);
517  }
518 
519  @Override
520  protected AbstractNode defaultVisit(Content di) {
521  throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), "FileTypeChildren.exception.notSupported.msg", di.toString()));
522  }
523  });
524  }
525  }
526 
527 }
static synchronized IngestManager getInstance()
static void removePropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:369
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
final HashMap< String, List< String > > existingMimeTypes
static void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:357
synchronized static Logger getLogger(String name)
Definition: Logger.java:161

Copyright © 2012-2016 Basis Technology. Generated on: Tue Jun 13 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.