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

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