Autopsy  4.20.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  /*
122  * Root node. Children are nodes for specific sizes.
123  */
124  public static class FileSizeRootNode extends DisplayableItemNode {
125 
126  private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name");
127 
128  FileSizeRootNode(SleuthkitCase skCase, long datasourceObjId) {
129  super(Children.create(new FileSizeRootChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
130  super.setName(NAME);
131  super.setDisplayName(NAME);
132  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
133  }
134 
135  @Override
136  public boolean isLeafTypeNode() {
137  return false;
138  }
139 
140  @Override
141  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
142  return visitor.visit(this);
143  }
144 
145  @Override
146  protected Sheet createSheet() {
147  Sheet sheet = super.createSheet();
148  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
149  if (sheetSet == null) {
150  sheetSet = Sheet.createPropertiesSet();
151  sheet.put(sheetSet);
152  }
153 
154  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.name"),
155  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.displayName"),
156  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.name.desc"),
157  NAME));
158  return sheet;
159  }
160 
161  @Override
162  public String getItemType() {
163  return getClass().getName();
164  }
165  }
166 
167  /*
168  * Makes the children for specific sizes
169  */
170  public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
171 
172  private SleuthkitCase skCase;
173  private final long datasourceObjId;
174  private Observable notifier;
175 
176  public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) {
177  this.skCase = skCase;
178  this.datasourceObjId = datasourceObjId;
179  notifier = new FileSizeRootChildrenObservable();
180  }
181 
186  private static final class FileSizeRootChildrenObservable extends Observable {
187 
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 
272  private final FileSizeFilter filter;
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 
293  FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
294  super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
295  this.filter = filter;
296  this.datasourceObjId = datasourceObjId;
297  init();
298  o.addObserver(new FileSizeNodeObserver());
299  }
300 
301  private void init() {
302  super.setName(filter.getName());
303 
304  String tooltip = filter.getDisplayName();
305  this.setShortDescription(tooltip);
306  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
307 
309  }
310 
311  @Override
312  public String getItemType() {
317  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
318  }
319 
320  // update the display name when new events are fired
321  private class FileSizeNodeObserver implements Observer {
322 
323  @Override
324  public void update(Observable o, Object arg) {
326  }
327  }
328 
329  private void updateDisplayName() {
330  final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter, datasourceObjId);
331  super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")");
332  }
333 
334  @Override
335  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
336  return visitor.visit(this);
337  }
338 
339  @Override
340  protected Sheet createSheet() {
341  Sheet sheet = super.createSheet();
342  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
343  if (sheetSet == null) {
344  sheetSet = Sheet.createPropertiesSet();
345  sheet.put(sheetSet);
346  }
347 
348  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.name"),
349  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.displayName"),
350  NbBundle.getMessage(this.getClass(), "FileSize.createSheet.filterType.desc"),
351  filter.getDisplayName()));
352 
353  return sheet;
354  }
355 
356  @Override
357  public boolean isLeafTypeNode() {
358  return true;
359  }
360  }
361 
362  /*
363  * Makes children, which are nodes for files of a given range
364  */
365  static class FileSizeChildren extends BaseChildFactory<AbstractFile> {
366 
367  private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
368  private final SleuthkitCase skCase;
369  private final FileSizeFilter filter;
370  private final Observable notifier;
371  private final long datasourceObjId;
372 
380  FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
381  super(filter.getName(), new ViewsKnownAndSlackFilter<>());
382  this.skCase = skCase;
383  this.filter = filter;
384  this.notifier = o;
385  this.datasourceObjId = dsObjId;
386 
387  }
388 
389  @Override
390  protected void onAdd() {
391  if (notifier != null) {
392  notifier.addObserver(observer);
393  }
394  }
395 
396  @Override
397  protected void onRemove() {
398  if (notifier != null) {
399  notifier.deleteObserver(observer);
400  }
401  }
402 
403  private final Observer observer = new FileSizeChildrenObserver();
404 
405  @Override
406  protected List<AbstractFile> makeKeys() {
407  return runFsQuery();
408  }
409 
410  // Cause refresh of children if there are changes
411  private class FileSizeChildrenObserver implements Observer {
412 
413  @Override
414  public void update(Observable o, Object arg) {
415  refresh(true);
416  }
417  }
418 
419  private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
420  String query;
421  switch (filter) {
422  case SIZE_50_200:
423  query = "(size >= 50000000 AND size < 200000000)"; //NON-NLS
424  break;
425  case SIZE_200_1000:
426  query = "(size >= 200000000 AND size < 1000000000)"; //NON-NLS
427  break;
428 
429  case SIZE_1000_:
430  query = "(size >= 1000000000)"; //NON-NLS
431  break;
432 
433  default:
434  throw new IllegalArgumentException("Unsupported filter type to get files by size: " + filter); //NON-NLS
435  }
436 
437  // Ignore unallocated block files.
438  query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
439 
440  // filter by datasource if indicated in case preferences
441  if (filteringDSObjId > 0) {
442  query += " AND data_source_obj_id = " + filteringDSObjId;
443  }
444 
445  return query;
446  }
447 
448  private List<AbstractFile> runFsQuery() {
449  List<AbstractFile> ret = new ArrayList<>();
450 
451  try {
452  String query = makeQuery(filter, datasourceObjId);
453 
454  ret = skCase.findAllFilesWhere(query);
455  } catch (Exception e) {
456  logger.log(Level.SEVERE, "Error getting files for the file size view: " + e.getMessage()); //NON-NLS
457  }
458 
459  return ret;
460  }
461 
467  static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter, long datasourceObjId) {
468  try {
469  return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
470  } catch (TskCoreException ex) {
471  logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS
472  return 0;
473  }
474  }
475 
476  @Override
477  protected Node createNodeForKey(AbstractFile key) {
478  return key.accept(new ContentVisitor.Default<AbstractNode>() {
479  public FileNode visit(AbstractFile f) {
480  return new FileNode(f, false);
481  }
482 
483  public FileNode visit(FsContent f) {
484  return new FileNode(f, false);
485  }
486 
487  @Override
488  public FileNode visit(LayoutFile f) {
489  return new FileNode(f, false);
490  }
491 
492  @Override
493  public FileNode visit(File f) {
494  return new FileNode(f, false);
495  }
496 
497  @Override
498  public FileNode visit(Directory f) {
499  return new FileNode(f, false);
500  }
501 
502  @Override
503  public FileNode visit(LocalFile f) {
504  return new FileNode(f, false);
505  }
506 
507  @Override
508  public FileNode visit(DerivedFile f) {
509  return new FileNode(f, false);
510  }
511 
512  @Override
513  public FileNode visit(VirtualDirectory f) {
514  return new FileNode(f, false);
515  }
516 
517  @Override
518  public FileNode visit(SlackFile f) {
519  return new FileNode(f, false);
520  }
521 
522  @Override
523  protected AbstractNode defaultVisit(Content di) {
524  throw new UnsupportedOperationException(
525  NbBundle.getMessage(this.getClass(),
526  "FileSize.exception.notSupported.msg",
527  di.toString()));
528  }
529  });
530  }
531  }
532  }
533 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId)
Definition: FileSize.java:176
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
Definition: FileSize.java:190
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:704
public< T > T accept(AutopsyItemVisitor< T > visitor)
Definition: FileSize.java:94
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:749

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.