Autopsy  4.5.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-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.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 
64  public enum FileSizeFilter implements AutopsyVisitableItem {
65 
66  SIZE_50_200(0, "SIZE_50_200", "50 - 200MB"), //NON-NLS
67  SIZE_200_1000(1, "SIZE_200_1GB", "200MB - 1GB"), //NON-NLS
68  SIZE_1000_(2, "SIZE_1000+", "1GB+"); //NON-NLS
69  private int id;
70  private String name;
71  private String displayName;
72 
73  private FileSizeFilter(int id, String name, String displayName) {
74  this.id = id;
75  this.name = name;
76  this.displayName = displayName;
77 
78  }
79 
80  public String getName() {
81  return this.name;
82  }
83 
84  public int getId() {
85  return this.id;
86  }
87 
88  public String getDisplayName() {
89  return this.displayName;
90  }
91 
92  @Override
93  public <T> T accept(AutopsyItemVisitor<T> v) {
94  return v.visit(this);
95  }
96  }
97 
98  public FileSize(SleuthkitCase skCase) {
99  this.skCase = skCase;
100  }
101 
102  @Override
103  public <T> T accept(AutopsyItemVisitor<T> v) {
104  return v.visit(this);
105  }
106 
107  public SleuthkitCase getSleuthkitCase() {
108  return this.skCase;
109  }
110 
111  /*
112  * Root node. Children are nodes for specific sizes.
113  */
114  public static class FileSizeRootNode extends DisplayableItemNode {
115 
116  private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name");
117 
118  FileSizeRootNode(SleuthkitCase skCase) {
119  super(Children.create(new FileSizeRootChildren(skCase), true), Lookups.singleton(NAME));
120  super.setName(NAME);
121  super.setDisplayName(NAME);
122  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
123  }
124 
125  @Override
126  public boolean isLeafTypeNode() {
127  return false;
128  }
129 
130  @Override
131  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
132  return v.visit(this);
133  }
134 
135  @Override
136  protected Sheet createSheet() {
137  Sheet s = super.createSheet();
138  Sheet.Set ss = s.get(Sheet.PROPERTIES);
139  if (ss == null) {
140  ss = Sheet.createPropertiesSet();
141  s.put(ss);
142  }
143 
144  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.name"),
145  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.displayName"),
146  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.desc"),
147  NAME));
148  return s;
149  }
150 
151  @Override
152  public String getItemType() {
153  return getClass().getName();
154  }
155  }
156 
157  /*
158  * Makes the children for specific sizes
159  */
160  public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
161 
162  private SleuthkitCase skCase;
163  private Observable notifier;
164 
165  public FileSizeRootChildren(SleuthkitCase skCase) {
166  this.skCase = skCase;
167  notifier = new FileSizeRootChildrenObservable();
168  }
169 
174  private static final class FileSizeRootChildrenObservable extends Observable {
175 
177 
182  }
183 
184  private void removeListeners() {
185  deleteObservers();
189  }
190 
191  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
192  String eventType = evt.getPropertyName();
193 
194  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
201  try {
202  // new file was added
203  // @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
205  update();
206  } catch (IllegalStateException notUsed) {
210  }
211  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
212  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
213  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
220  try {
222  update();
223  } catch (IllegalStateException notUsed) {
227  }
228  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
229  // case was closed. Remove listeners so that we don't get called with a stale case handle
230  if (evt.getNewValue() == null) {
231  removeListeners();
232  }
233  }
234  };
235 
236  private void update() {
237  setChanged();
238  notifyObservers();
239  }
240  }
241 
242  @Override
243  protected boolean createKeys(List<FileSizeFilter> list) {
244  list.addAll(Arrays.asList(FileSizeFilter.values()));
245  return true;
246  }
247 
248  @Override
249  protected Node createNodeForKey(FileSizeFilter key) {
250  return new FileSizeNode(skCase, key, notifier);
251  }
252 
253  /*
254  * Node for a specific size range. Children are files.
255  */
256  public class FileSizeNode extends DisplayableItemNode {
257 
259 
260  // use version with observer instead so that it updates
261  @Deprecated
262  FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter) {
263  super(Children.create(new FileSizeChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName()));
264  this.filter = filter;
265  init();
266  }
267 
275  FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o) {
276  super(Children.create(new FileSizeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
277  this.filter = filter;
278  init();
279  o.addObserver(new FileSizeNodeObserver());
280  }
281 
282  private void init() {
283  super.setName(filter.getName());
284 
285  String tooltip = filter.getDisplayName();
286  this.setShortDescription(tooltip);
287  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
288 
290  }
291 
292  @Override
293  public String getItemType() {
298  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
299  }
300 
301  // update the display name when new events are fired
302  private class FileSizeNodeObserver implements Observer {
303 
304  @Override
305  public void update(Observable o, Object arg) {
307  }
308  }
309 
310  private void updateDisplayName() {
311  final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter);
312  super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")");
313  }
314 
315  @Override
316  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
317  return v.visit(this);
318  }
319 
320  @Override
321  protected Sheet createSheet() {
322  Sheet s = super.createSheet();
323  Sheet.Set ss = s.get(Sheet.PROPERTIES);
324  if (ss == null) {
325  ss = Sheet.createPropertiesSet();
326  s.put(ss);
327  }
328 
329  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.name"),
330  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.displayName"),
331  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.desc"),
332  filter.getDisplayName()));
333 
334  return s;
335  }
336 
337  @Override
338  public boolean isLeafTypeNode() {
339  return true;
340  }
341  }
342 
343  /*
344  * Makes children, which are nodes for files of a given range
345  */
346  static class FileSizeChildren extends ChildFactory.Detachable<AbstractFile> {
347 
348  private final SleuthkitCase skCase;
349  private final FileSizeFilter filter;
350  private final Observable notifier;
351  private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
352 
360  FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o) {
361  this.skCase = skCase;
362  this.filter = filter;
363  this.notifier = o;
364  }
365 
366  @Override
367  protected void addNotify() {
368  if (notifier != null) {
369  notifier.addObserver(observer);
370  }
371  }
372 
373  @Override
374  protected void removeNotify() {
375  if (notifier != null) {
376  notifier.deleteObserver(observer);
377  }
378  }
379 
380  private final Observer observer = new FileSizeChildrenObserver();
381 
382  // Cause refresh of children if there are changes
383  private class FileSizeChildrenObserver implements Observer {
384 
385  @Override
386  public void update(Observable o, Object arg) {
387  refresh(true);
388  }
389  }
390 
391  @Override
392  protected boolean createKeys(List<AbstractFile> list) {
393  list.addAll(runFsQuery());
394  return true;
395  }
396 
397  private static String makeQuery(FileSizeFilter filter) {
398  String query;
399  switch (filter) {
400  case SIZE_50_200:
401  query = "(size >= 50000000 AND size < 200000000)"; //NON-NLS
402  break;
403  case SIZE_200_1000:
404  query = "(size >= 200000000 AND size < 1000000000)"; //NON-NLS
405  break;
406 
407  case SIZE_1000_:
408  query = "(size >= 1000000000)"; //NON-NLS
409  break;
410 
411  default:
412  throw new IllegalArgumentException("Unsupported filter type to get files by size: " + filter); //NON-NLS
413  }
414 
415  // Ignore unallocated block files.
416  query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
417 
418  // Hide known files if indicated in the user preferences.
420  query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS
421  + " OR known IS NULL)"; //NON-NLS
422  }
423 
424  // Hide slack files if indicated in the user preferences.
425  if(UserPreferences.hideSlackFilesInViewsTree()) {
426  query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
427  }
428 
429  return query;
430  }
431 
432  private List<AbstractFile> runFsQuery() {
433  List<AbstractFile> ret = new ArrayList<>();
434 
435  try {
436  String query = makeQuery(filter);
437 
438  ret = skCase.findAllFilesWhere(query);
439  } catch (Exception e) {
440  logger.log(Level.SEVERE, "Error getting files for the file size view: " + e.getMessage()); //NON-NLS
441  }
442 
443  return ret;
444  }
445 
451  static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter) {
452  try {
453  return sleuthkitCase.countFilesWhere(makeQuery(filter));
454  } catch (TskCoreException ex) {
455  logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS
456  return 0;
457  }
458  }
459 
460  @Override
461  protected Node createNodeForKey(AbstractFile key) {
462  return key.accept(new ContentVisitor.Default<AbstractNode>() {
463  public FileNode visit(AbstractFile f) {
464  return new FileNode(f, false);
465  }
466 
467  public FileNode visit(FsContent f) {
468  return new FileNode(f, false);
469  }
470 
471  @Override
472  public FileNode visit(LayoutFile f) {
473  return new FileNode(f, false);
474  }
475 
476  @Override
477  public FileNode visit(File f) {
478  return new FileNode(f, false);
479  }
480 
481  @Override
482  public FileNode visit(Directory f) {
483  return new FileNode(f, false);
484  }
485 
486  @Override
487  public FileNode visit(LocalFile f) {
488  return new FileNode(f, false);
489  }
490 
491  @Override
492  public FileNode visit(DerivedFile f) {
493  return new FileNode(f, false);
494  }
495 
496  @Override
497  public FileNode visit(VirtualDirectory f) {
498  return new FileNode(f, false);
499  }
500 
501  @Override
502  public FileNode visit(SlackFile f) {
503  return new FileNode(f, false);
504  }
505 
506  @Override
507  protected AbstractNode defaultVisit(Content di) {
508  throw new UnsupportedOperationException(
509  NbBundle.getMessage(this.getClass(),
510  "FileSize.exception.notSupported.msg",
511  di.toString()));
512  }
513  });
514  }
515  }
516  }
517 }
public< T > T accept(AutopsyItemVisitor< T > v)
Definition: FileSize.java:93
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
FileSizeFilter(int id, String name, String displayName)
Definition: FileSize.java:73
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:419
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:464

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