Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.datamodel;
20
21import java.beans.PropertyChangeEvent;
22import java.beans.PropertyChangeListener;
23import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.EnumSet;
26import java.util.List;
27import java.util.Observable;
28import java.util.Observer;
29import java.util.Set;
30import java.util.logging.Level;
31import org.openide.nodes.AbstractNode;
32import org.openide.nodes.ChildFactory;
33import org.openide.nodes.Children;
34import org.openide.nodes.Node;
35import org.openide.nodes.Sheet;
36import org.openide.util.NbBundle;
37import org.openide.util.lookup.Lookups;
38import org.sleuthkit.autopsy.casemodule.Case;
39import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
40import org.sleuthkit.autopsy.coreutils.Logger;
41import org.sleuthkit.autopsy.ingest.IngestManager;
42import org.sleuthkit.datamodel.AbstractFile;
43import org.sleuthkit.datamodel.Content;
44import org.sleuthkit.datamodel.ContentVisitor;
45import org.sleuthkit.datamodel.DerivedFile;
46import org.sleuthkit.datamodel.Directory;
47import org.sleuthkit.datamodel.File;
48import org.sleuthkit.datamodel.FsContent;
49import org.sleuthkit.datamodel.LayoutFile;
50import org.sleuthkit.datamodel.LocalFile;
51import org.sleuthkit.datamodel.SlackFile;
52import org.sleuthkit.datamodel.SleuthkitCase;
53import org.sleuthkit.datamodel.TskCoreException;
54import org.sleuthkit.datamodel.TskData;
55import org.sleuthkit.datamodel.VirtualDirectory;
56
60public 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;
180 }
181
186 private static final class FileSizeRootChildrenObservable extends Observable {
187
191
192 FileSizeRootChildrenObservable() {
196 }
197
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) {
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}
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition Case.java:757
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition Case.java:712
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId)
FileSize(SleuthkitCase skCase, long dsObjId)
static synchronized IngestManager getInstance()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
public< T > T accept(AutopsyItemVisitor< T > visitor)
Definition FileSize.java:94
FileSizeFilter(int id, String name, String displayName)
Definition FileSize.java:74

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.