Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileSize.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-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.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.EnumSet;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.Observable;
29 import java.util.Observer;
30 import java.util.Set;
31 import java.util.logging.Level;
32 import org.openide.nodes.AbstractNode;
33 import org.openide.nodes.ChildFactory;
34 import org.openide.nodes.Children;
35 import org.openide.nodes.Node;
36 import org.openide.nodes.Sheet;
37 import org.openide.util.NbBundle;
38 import org.openide.util.lookup.Lookups;
45 import org.sleuthkit.datamodel.AbstractFile;
46 import org.sleuthkit.datamodel.Content;
47 import org.sleuthkit.datamodel.ContentVisitor;
48 import org.sleuthkit.datamodel.DerivedFile;
49 import org.sleuthkit.datamodel.Directory;
50 import org.sleuthkit.datamodel.File;
51 import org.sleuthkit.datamodel.FsContent;
52 import org.sleuthkit.datamodel.LayoutFile;
53 import org.sleuthkit.datamodel.LocalFile;
54 import org.sleuthkit.datamodel.SlackFile;
55 import org.sleuthkit.datamodel.SleuthkitCase;
56 import org.sleuthkit.datamodel.TskCoreException;
57 import org.sleuthkit.datamodel.TskData;
58 import org.sleuthkit.datamodel.VirtualDirectory;
59 
63 public class FileSize implements AutopsyVisitableItem {
64 
65  private SleuthkitCase skCase;
66  private final long datasourceObjId;
67 
68  public enum FileSizeFilter implements AutopsyVisitableItem {
69 
70  SIZE_50_200(0, "SIZE_50_200", "50 - 200MB"), //NON-NLS
71  SIZE_200_1000(1, "SIZE_200_1GB", "200MB - 1GB"), //NON-NLS
72  SIZE_1000_(2, "SIZE_1000+", "1GB+"); //NON-NLS
73  private int id;
74  private String name;
75  private String displayName;
76 
77  private FileSizeFilter(int id, String name, String displayName) {
78  this.id = id;
79  this.name = name;
80  this.displayName = displayName;
81 
82  }
83 
84  public String getName() {
85  return this.name;
86  }
87 
88  public int getId() {
89  return this.id;
90  }
91 
92  public String getDisplayName() {
93  return this.displayName;
94  }
95 
96  @Override
97  public <T> T accept(AutopsyItemVisitor<T> visitor) {
98  return visitor.visit(this);
99  }
100  }
101 
102  public FileSize(SleuthkitCase skCase) {
103  this(skCase, 0);
104  }
105 
106  public FileSize(SleuthkitCase skCase, long dsObjId) {
107  this.skCase = skCase;
108  this.datasourceObjId = dsObjId;
109  }
110 
111  @Override
112  public <T> T accept(AutopsyItemVisitor<T> visitor) {
113  return visitor.visit(this);
114  }
115 
116  public SleuthkitCase getSleuthkitCase() {
117  return this.skCase;
118  }
119 
120  long filteringDataSourceObjId() {
121  return this.datasourceObjId;
122  }
123  /*
124  * Root node. Children are nodes for specific sizes.
125  */
126  public static class FileSizeRootNode extends DisplayableItemNode {
127 
128  private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name");
129 
130  FileSizeRootNode(SleuthkitCase skCase, long datasourceObjId) {
131  super(Children.create(new FileSizeRootChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
132  super.setName(NAME);
133  super.setDisplayName(NAME);
134  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
135  }
136 
137  @Override
138  public boolean isLeafTypeNode() {
139  return false;
140  }
141 
142  @Override
143  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
144  return visitor.visit(this);
145  }
146 
147  @Override
148  protected Sheet createSheet() {
149  Sheet sheet = super.createSheet();
150  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
151  if (sheetSet == null) {
152  sheetSet = Sheet.createPropertiesSet();
153  sheet.put(sheetSet);
154  }
155 
156  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.name"),
157  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.displayName"),
158  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.desc"),
159  NAME));
160  return sheet;
161  }
162 
163  @Override
164  public String getItemType() {
165  return getClass().getName();
166  }
167  }
168 
169  /*
170  * Makes the children for specific sizes
171  */
172  public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
173 
174  private SleuthkitCase skCase;
175  private final long datasourceObjId;
176  private Observable notifier;
177 
178  public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) {
179  this.skCase = skCase;
180  this.datasourceObjId = datasourceObjId;
181  notifier = new FileSizeRootChildrenObservable();
182  }
183 
188  private static final class FileSizeRootChildrenObservable extends Observable {
189 
191 
196  }
197 
198  private void removeListeners() {
199  deleteObservers();
203  }
204 
205  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
206  String eventType = evt.getPropertyName();
207 
208  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
215  try {
216  // new file was added
217  // @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
219  update();
220  } catch (NoCurrentCaseException notUsed) {
224  }
225  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
226  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
227  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
234  try {
236  update();
237  } catch (NoCurrentCaseException notUsed) {
241  }
242  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
243  // case was closed. Remove listeners so that we don't get called with a stale case handle
244  if (evt.getNewValue() == null) {
245  removeListeners();
246  }
247  }
248  };
249 
250  private void update() {
251  setChanged();
252  notifyObservers();
253  }
254  }
255 
256  @Override
257  protected boolean createKeys(List<FileSizeFilter> list) {
258  list.addAll(Arrays.asList(FileSizeFilter.values()));
259  return true;
260  }
261 
262  @Override
263  protected Node createNodeForKey(FileSizeFilter key) {
264  return new FileSizeNode(skCase, key, notifier, datasourceObjId);
265  }
266 
267  /*
268  * Node for a specific size range. Children are files.
269  */
270  public class FileSizeNode extends DisplayableItemNode {
271 
273  private final long datasourceObjId;
274 
275  // use version with observer instead so that it updates
276  @Deprecated
277  FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, long datasourceObjId) {
278  super(Children.create(new FileSizeChildren(filter, skCase, null, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
279  this.filter = filter;
280  this.datasourceObjId = datasourceObjId;
281  init();
282  }
283 
292  FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
293  super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
294  this.filter = filter;
295  this.datasourceObjId = datasourceObjId;
296  init();
297  o.addObserver(new FileSizeNodeObserver());
298  }
299 
300  private void init() {
301  super.setName(filter.getName());
302 
303  String tooltip = filter.getDisplayName();
304  this.setShortDescription(tooltip);
305  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
306 
308  }
309 
310  @Override
311  public String getItemType() {
316  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
317  }
318 
319  // update the display name when new events are fired
320  private class FileSizeNodeObserver implements Observer {
321 
322  @Override
323  public void update(Observable o, Object arg) {
325  }
326  }
327 
328  private void updateDisplayName() {
329  final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter, datasourceObjId);
330  super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")");
331  }
332 
333  @Override
334  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
335  return visitor.visit(this);
336  }
337 
338  @Override
339  protected Sheet createSheet() {
340  Sheet sheet = super.createSheet();
341  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
342  if (sheetSet == null) {
343  sheetSet = Sheet.createPropertiesSet();
344  sheet.put(sheetSet);
345  }
346 
347  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.name"),
348  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.displayName"),
349  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.desc"),
350  filter.getDisplayName()));
351 
352  return sheet;
353  }
354 
355  @Override
356  public boolean isLeafTypeNode() {
357  return true;
358  }
359  }
360 
361  /*
362  * Makes children, which are nodes for files of a given range
363  */
364  static class FileSizeChildren extends ChildFactory.Detachable<AbstractFile> {
365 
366  private final SleuthkitCase skCase;
367  private final FileSizeFilter filter;
368  private final Observable notifier;
369  private final long datasourceObjId;
370  private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
371 
379  FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
380  this.skCase = skCase;
381  this.filter = filter;
382  this.notifier = o;
383  this.datasourceObjId = dsObjId;
384 
385  }
386 
387  @Override
388  protected void addNotify() {
389  if (notifier != null) {
390  notifier.addObserver(observer);
391  }
392  }
393 
394  @Override
395  protected void removeNotify() {
396  if (notifier != null) {
397  notifier.deleteObserver(observer);
398  }
399  }
400 
401  private final Observer observer = new FileSizeChildrenObserver();
402 
403  // Cause refresh of children if there are changes
404  private class FileSizeChildrenObserver implements Observer {
405 
406  @Override
407  public void update(Observable o, Object arg) {
408  refresh(true);
409  }
410  }
411 
412  @Override
413  protected boolean createKeys(List<AbstractFile> list) {
414  list.addAll(runFsQuery());
415  return true;
416  }
417 
418  private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
419  String query;
420  switch (filter) {
421  case SIZE_50_200:
422  query = "(size >= 50000000 AND size < 200000000)"; //NON-NLS
423  break;
424  case SIZE_200_1000:
425  query = "(size >= 200000000 AND size < 1000000000)"; //NON-NLS
426  break;
427 
428  case SIZE_1000_:
429  query = "(size >= 1000000000)"; //NON-NLS
430  break;
431 
432  default:
433  throw new IllegalArgumentException("Unsupported filter type to get files by size: " + filter); //NON-NLS
434  }
435 
436  // Ignore unallocated block files.
437  query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
438 
439  // Hide known files if indicated in the user preferences.
441  query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS
442  + " OR known IS NULL)"; //NON-NLS
443  }
444 
445  // Hide slack files if indicated in the user preferences.
446  if(UserPreferences.hideSlackFilesInViewsTree()) {
447  query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
448  }
449 
450  // filter by datasource if indicated in case preferences
451  if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
452  query += " AND data_source_obj_id = " + filteringDSObjId;
453  }
454 
455  return query;
456  }
457 
458  private List<AbstractFile> runFsQuery() {
459  List<AbstractFile> ret = new ArrayList<>();
460 
461  try {
462  String query = makeQuery(filter, datasourceObjId);
463 
464  ret = skCase.findAllFilesWhere(query);
465  } catch (Exception e) {
466  logger.log(Level.SEVERE, "Error getting files for the file size view: " + e.getMessage()); //NON-NLS
467  }
468 
469  return ret;
470  }
471 
477  static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter, long datasourceObjId) {
478  try {
479  return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
480  } catch (TskCoreException ex) {
481  logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS
482  return 0;
483  }
484  }
485 
486  @Override
487  protected Node createNodeForKey(AbstractFile key) {
488  return key.accept(new ContentVisitor.Default<AbstractNode>() {
489  public FileNode visit(AbstractFile f) {
490  return new FileNode(f, false);
491  }
492 
493  public FileNode visit(FsContent f) {
494  return new FileNode(f, false);
495  }
496 
497  @Override
498  public FileNode visit(LayoutFile f) {
499  return new FileNode(f, false);
500  }
501 
502  @Override
503  public FileNode visit(File f) {
504  return new FileNode(f, false);
505  }
506 
507  @Override
508  public FileNode visit(Directory f) {
509  return new FileNode(f, false);
510  }
511 
512  @Override
513  public FileNode visit(LocalFile f) {
514  return new FileNode(f, false);
515  }
516 
517  @Override
518  public FileNode visit(DerivedFile f) {
519  return new FileNode(f, false);
520  }
521 
522  @Override
523  public FileNode visit(VirtualDirectory f) {
524  return new FileNode(f, false);
525  }
526 
527  @Override
528  public FileNode visit(SlackFile f) {
529  return new FileNode(f, false);
530  }
531 
532  @Override
533  protected AbstractNode defaultVisit(Content di) {
534  throw new UnsupportedOperationException(
535  NbBundle.getMessage(this.getClass(),
536  "FileSize.exception.notSupported.msg",
537  di.toString()));
538  }
539  });
540  }
541  }
542  }
543 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId)
Definition: FileSize.java:178
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
FileSize(SleuthkitCase skCase, long dsObjId)
Definition: FileSize.java:106
FileSizeFilter(int id, String name, String displayName)
Definition: FileSize.java:77
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:437
public< T > T accept(AutopsyItemVisitor< T > visitor)
Definition: FileSize.java:97
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:482

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.