Autopsy  4.4.1
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.EnumSet;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Observable;
32 import java.util.Observer;
33 import java.util.Set;
34 import java.util.logging.Level;
35 import java.util.stream.Collectors;
36 import org.apache.commons.lang3.StringUtils;
37 import org.openide.nodes.ChildFactory;
38 import org.openide.nodes.Children;
39 import org.openide.nodes.Node;
40 import org.openide.nodes.Sheet;
41 import org.openide.util.NbBundle;
42 import org.openide.util.lookup.Lookups;
49 import org.sleuthkit.datamodel.SleuthkitCase;
50 import org.sleuthkit.datamodel.TskCoreException;
51 import org.sleuthkit.datamodel.TskData;
52 
60 public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
61 
62  private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
63 
64  private final SleuthkitCase skCase;
70  private final HashMap<String, Map<String, Long>> existingMimeTypeCounts = new HashMap<>();
75  private final FileTypes typesRoot;
76 
81  private final PropertyChangeListener pcl;
82 
84 
93  static private String createBaseWhereExpr() {
94  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
95  + " AND (type IN ("
96  + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
97  + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
98  + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
99  + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
100  + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
101  + "))"
102  + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
103  }
104 
105  private void removeListeners() {
106  deleteObservers();
109  }
110 
115  private void populateHashMap() {
116  String query = "SELECT mime_type, count(*) AS count FROM tsk_files "
117  + " WHERE mime_type IS NOT null "
118  + " AND " + createBaseWhereExpr()
119  + " GROUP BY mime_type";
120  synchronized (existingMimeTypeCounts) {
121  existingMimeTypeCounts.clear();
122 
123  if (skCase == null) {
124  return;
125  }
126  try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
127  ResultSet resultSet = dbQuery.getResultSet();
128  while (resultSet.next()) {
129  final String mime_type = resultSet.getString("mime_type"); //NON-NLS
130  if (!mime_type.isEmpty()) {
131  //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
132  final String mediaType = StringUtils.substringBefore(mime_type, "/");
133  final String subType = StringUtils.removeStart(mime_type, mediaType + "/");
134  if (!mediaType.isEmpty() && !subType.isEmpty()) {
135  final long count = resultSet.getLong("count");
136  existingMimeTypeCounts.computeIfAbsent(mediaType, t -> new HashMap<>())
137  .put(subType, count);
138  }
139  }
140  }
141  } catch (TskCoreException | SQLException ex) {
142  logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
143  }
144  }
145 
146  setChanged();
147  notifyObservers();
148  }
149 
150  FileTypesByMimeType(FileTypes typesRoot) {
151  this.skCase = typesRoot.getSleuthkitCase();
152  this.typesRoot = typesRoot;
153  this.pcl = (PropertyChangeEvent evt) -> {
154  String eventType = evt.getPropertyName();
155  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
156  || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
157  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
158  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
165  try {
167  typesRoot.updateShowCounts();
168  populateHashMap();
169  } catch (IllegalStateException notUsed) {
173  }
174  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
175  if (evt.getNewValue() == null) {
176  removeListeners();
177  }
178  }
179  };
180  IngestManager.getInstance().addIngestJobEventListener(pcl);
181  Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
182  populateHashMap();
183  }
184 
185  @Override
186  public <T> T accept(AutopsyItemVisitor<T> v) {
187  return v.visit(this);
188  }
189 
199  public static boolean isEmptyMimeTypeNode(Node node) {
200  boolean isEmptyMimeNode = false;
201  if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
202  isEmptyMimeNode = true;
203  }
204  return isEmptyMimeNode;
205 
206  }
207 
214  class ByMimeTypeNode extends DisplayableItemNode {
215 
216  @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
217 
218  final String NAME = Bundle.FileTypesByMimeType_name_text();
219 
220  ByMimeTypeNode() {
221  super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
222  super.setName(NAME);
223  super.setDisplayName(NAME);
224  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
225  }
226 
227  @Override
228  public boolean isLeafTypeNode() {
229  return false;
230  }
231 
232  @Override
233  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
234  return v.visit(this);
235  }
236 
237  @Override
238  public String getItemType() {
239  return getClass().getName();
240  }
241 
242  boolean isEmpty() {
243  synchronized (existingMimeTypeCounts) {
244  return existingMimeTypeCounts.isEmpty();
245  }
246  }
247  }
248 
253  private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
254 
256  super();
257  addObserver(this);
258  }
259 
260  @Override
261  protected boolean createKeys(List<String> mediaTypeNodes) {
262  final List<String> keylist;
263  synchronized (existingMimeTypeCounts) {
264  keylist = new ArrayList<>(existingMimeTypeCounts.keySet());
265  }
266  Collections.sort(keylist);
267  mediaTypeNodes.addAll(keylist);
268 
269  return true;
270  }
271 
272  @Override
273  protected Node createNodeForKey(String key) {
274  return new MediaTypeNode(key);
275  }
276 
277  @Override
278  public void update(Observable o, Object arg) {
279  refresh(true);
280  }
281  }
282 
287  class MediaTypeNode extends DisplayableItemNode {
288 
289  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type",
290  "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type",
291  "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"})
292 
293  MediaTypeNode(String name) {
294  super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
295  setName(name);
296  setDisplayName(name);
297  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
298  }
299 
300  @Override
301  public boolean isLeafTypeNode() {
302  return false;
303  }
304 
305  @Override
306  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
307  return v.visit(this);
308  }
309 
310  @Override
311  protected Sheet createSheet() {
312  Sheet s = super.createSheet();
313  Sheet.Set ss = s.get(Sheet.PROPERTIES);
314  if (ss == null) {
315  ss = Sheet.createPropertiesSet();
316  s.put(ss);
317  }
318  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.desc"), getDisplayName()));
319  return s;
320  }
321 
322  @Override
323  public String getItemType() {
324  return getClass().getName();
325  }
326 
327  }
328 
334  private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
335 
336  String mediaType;
337 
338  MediaTypeNodeChildren(String name) {
339  addObserver(this);
340  this.mediaType = name;
341  }
342 
343  @Override
344  protected boolean createKeys(List<String> mediaTypeNodes) {
345  mediaTypeNodes.addAll(existingMimeTypeCounts.get(mediaType).keySet());
346  return true;
347  }
348 
349  @Override
350  protected Node createNodeForKey(String subtype) {
351  String mimeType = mediaType + "/" + subtype;
352  return new MediaSubTypeNode(mimeType);
353  }
354 
355  @Override
356  public void update(Observable o, Object arg) {
357  refresh(true);
358  }
359 
360  }
361 
366  class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
367 
368  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
369  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
370  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"})
371  private final String mimeType;
372  private final String subType;
373 
374  private MediaSubTypeNode(String mimeType) {
375  super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true), Lookups.singleton(mimeType));
376  this.mimeType = mimeType;
377  this.subType = StringUtils.substringAfter(mimeType, "/");
378  super.setName(mimeType);
379  super.setDisplayName(subType);
380  updateDisplayName();
381  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
382  addObserver(this);
383  }
384 
391  @Override
392  public boolean isLeafTypeNode() {
393  return true;
394  }
395 
396  @Override
397  public <T> T accept(DisplayableItemNodeVisitor< T> v) {
398  return v.visit(this);
399  }
400 
401  @Override
402  protected Sheet createSheet() {
403  Sheet s = super.createSheet();
404  Sheet.Set ss = s.get(Sheet.PROPERTIES);
405  if (ss == null) {
406  ss = Sheet.createPropertiesSet();
407  s.put(ss);
408  }
409  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc"), getDisplayName()));
410  return s;
411  }
412 
413  @Override
414  public String getItemType() {
415  return getClass().getName();
416  }
417 
418  @Override
419  public void update(Observable o, Object arg) {
420  updateDisplayName();
421  }
422 
423  @Override
424  String getDisplayNameBase() {
425  return subType;
426  }
427 
428  @Override
429  long calculateChildCount() {
430  return existingMimeTypeCounts.get(StringUtils.substringBefore(mimeType, "/")).get(subType);
431  }
432  }
433 
439  private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
440 
441  private final String mimeType;
442 
443  private MediaSubTypeNodeChildren(String mimeType) {
444  super();
445  addObserver(this);
446  this.mimeType = mimeType;
447  }
448 
449  @Override
450  protected boolean createKeys(List<FileTypesKey> list) {
451  try {
452  list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
453  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS
454  } catch (TskCoreException ex) {
455  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
456  }
457  return true;
458  }
459 
460  @Override
461  public void update(Observable o, Object arg) {
462  refresh(true);
463  }
464 
465  @Override
466  protected Node createNodeForKey(FileTypesKey key) {
467  return key.accept(new FileTypes.FileNodeCreationVisitor());
468  }
469  }
470 }
static synchronized IngestManager getInstance()
void removeIngestJobEventListener(final PropertyChangeListener listener)
final HashMap< String, Map< String, Long > > existingMimeTypeCounts
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:440

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