Autopsy  4.11.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DeletedContent.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-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.Directory;
46 import org.sleuthkit.datamodel.File;
47 import org.sleuthkit.datamodel.FsContent;
48 import org.sleuthkit.datamodel.LayoutFile;
49 import org.sleuthkit.datamodel.SleuthkitCase;
50 import org.sleuthkit.datamodel.TskCoreException;
51 import org.sleuthkit.datamodel.TskData;
52 import org.sleuthkit.datamodel.VirtualDirectory;
53 
57 public class DeletedContent implements AutopsyVisitableItem {
58 
59  private SleuthkitCase skCase;
60  private final long filteringDSObjId; // 0 if not filtering/grouping by data source
61 
62  @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
63  "DeletedContent.allDelFilter.text=All"})
64  public enum DeletedContentFilter implements AutopsyVisitableItem {
65 
66  FS_DELETED_FILTER(0, "FS_DELETED_FILTER", //NON-NLS
67  Bundle.DeletedContent_fsDelFilter_text()),
68  ALL_DELETED_FILTER(1, "ALL_DELETED_FILTER", //NON-NLS
69  Bundle.DeletedContent_allDelFilter_text());
70 
71  private int id;
72  private String name;
73  private String displayName;
74 
75  private DeletedContentFilter(int id, String name, String displayName) {
76  this.id = id;
77  this.name = name;
78  this.displayName = displayName;
79 
80  }
81 
82  public String getName() {
83  return this.name;
84  }
85 
86  public int getId() {
87  return this.id;
88  }
89 
90  public String getDisplayName() {
91  return this.displayName;
92  }
93 
94  @Override
95  public <T> T accept(AutopsyItemVisitor<T> visitor) {
96  return visitor.visit(this);
97  }
98  }
99 
100  public DeletedContent(SleuthkitCase skCase) {
101  this(skCase, 0);
102  }
103 
104  public DeletedContent(SleuthkitCase skCase, long dsObjId) {
105  this.skCase = skCase;
106  this.filteringDSObjId = dsObjId;
107  }
108 
109  long filteringDataSourceObjId() {
110  return this.filteringDSObjId;
111  }
112 
113  @Override
114  public <T> T accept(AutopsyItemVisitor<T> visitor) {
115  return visitor.visit(this);
116  }
117 
118  public SleuthkitCase getSleuthkitCase() {
119  return this.skCase;
120  }
121 
122  public static class DeletedContentsNode extends DisplayableItemNode {
123 
124  @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files")
125  private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name();
126 
127  DeletedContentsNode(SleuthkitCase skCase, long datasourceObjId) {
128  super(Children.create(new DeletedContentsChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
129  super.setName(NAME);
130  super.setDisplayName(NAME);
131  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.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  @NbBundle.Messages({
146  "DeletedContent.createSheet.name.displayName=Name",
147  "DeletedContent.createSheet.name.desc=no description"})
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<>("Name", //NON-NLS
157  Bundle.DeletedContent_createSheet_name_displayName(),
158  Bundle.DeletedContent_createSheet_name_desc(),
159  NAME));
160  return sheet;
161  }
162 
163  @Override
164  public String getItemType() {
165  return getClass().getName();
166  }
167  }
168 
169  public static class DeletedContentsChildren extends ChildFactory<DeletedContent.DeletedContentFilter> {
170 
171  private SleuthkitCase skCase;
172  private Observable notifier;
173  private final long datasourceObjId;
174  // true if we have already told user that not all files will be shown
175  private static volatile boolean maxFilesDialogShown = false;
176 
177  public DeletedContentsChildren(SleuthkitCase skCase, long dsObjId) {
178  this.skCase = skCase;
179  this.datasourceObjId = dsObjId;
180  this.notifier = new DeletedContentsChildrenObservable();
181  }
182 
187  private static final class DeletedContentsChildrenObservable extends Observable {
188 
189  private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
192  );
193 
198  }
199 
200  private void removeListeners() {
201  deleteObservers();
205  }
206 
207  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
208  String eventType = evt.getPropertyName();
209  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
217  try {
219  // new file was added
220  // @@@ COULD CHECK If the new file is deleted before notifying...
221  update();
222  } catch (NoCurrentCaseException notUsed) {
226  }
227  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
228  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
229  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
236  try {
238  update();
239  } catch (NoCurrentCaseException notUsed) {
243  }
244  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
245  // case was closed. Remove listeners so that we don't get called with a stale case handle
246  if (evt.getNewValue() == null) {
247  removeListeners();
248  }
249  maxFilesDialogShown = false;
250  }
251  };
252 
253  private void update() {
254  setChanged();
255  notifyObservers();
256  }
257  }
258 
259  @Override
260 
261  protected boolean createKeys(List<DeletedContent.DeletedContentFilter> list) {
262  list.addAll(Arrays.asList(DeletedContent.DeletedContentFilter.values()));
263  return true;
264  }
265 
266  @Override
268  return new DeletedContentNode(skCase, key, notifier, datasourceObjId);
269  }
270 
272 
274  private final long datasourceObjId;
275 
276  // Use version that has observer for updates
277  @Deprecated
278  DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) {
279  super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId), true), Lookups.singleton(filter.getDisplayName()));
280  this.filter = filter;
281  this.datasourceObjId = dsObjId;
282  init();
283  }
284 
285  DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o, long dsObjId) {
286  super(Children.create(new DeletedContentChildren(filter, skCase, o, dsObjId), true), Lookups.singleton(filter.getDisplayName()));
287  this.filter = filter;
288  this.datasourceObjId = dsObjId;
289  init();
290  o.addObserver(new DeletedContentNodeObserver());
291  }
292 
293  private void init() {
294  super.setName(filter.getName());
295 
296  String tooltip = filter.getDisplayName();
297  this.setShortDescription(tooltip);
298  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
300  }
301 
302  // update the display name when new events are fired
303  private class DeletedContentNodeObserver implements Observer {
304 
305  @Override
306  public void update(Observable o, Object arg) {
308  }
309  }
310 
311  private void updateDisplayName() {
312  //get count of children without preloading all children nodes
313  final long count = DeletedContentChildren.calculateItems(skCase, filter, datasourceObjId);
314  //final long count = getChildren().getNodesCount(true);
315  super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
316  }
317 
318  @Override
319  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
320  return visitor.visit(this);
321  }
322 
323  @Override
324  @NbBundle.Messages({
325  "DeletedContent.createSheet.filterType.displayName=Type",
326  "DeletedContent.createSheet.filterType.desc=no description"})
327  protected Sheet createSheet() {
328  Sheet sheet = super.createSheet();
329  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
330  if (sheetSet == null) {
331  sheetSet = Sheet.createPropertiesSet();
332  sheet.put(sheetSet);
333  }
334 
335  sheetSet.put(new NodeProperty<>("Type", //NON_NLS
336  Bundle.DeletedContent_createSheet_filterType_displayName(),
337  Bundle.DeletedContent_createSheet_filterType_desc(),
338  filter.getDisplayName()));
339 
340  return sheet;
341  }
342 
343  @Override
344  public boolean isLeafTypeNode() {
345  return true;
346  }
347 
348  @Override
349  public String getItemType() {
354  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
355  }
356  }
357 
358  static class DeletedContentChildren extends BaseChildFactory<AbstractFile> {
359 
360  private final SleuthkitCase skCase;
361  private final DeletedContent.DeletedContentFilter filter;
362  private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
363 
364  private final Observable notifier;
365  private final long datasourceObjId;
366 
367  DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
368  super(filter.getName(), new ViewsKnownAndSlackFilter<>());
369  this.skCase = skCase;
370  this.filter = filter;
371  this.notifier = o;
372  this.datasourceObjId = datasourceObjId;
373  }
374 
375  private final Observer observer = new DeletedContentChildrenObserver();
376 
377  @Override
378  protected List<AbstractFile> makeKeys() {
379  return runFsQuery();
380  }
381 
382  // Cause refresh of children if there are changes
383  private class DeletedContentChildrenObserver implements Observer {
384 
385  @Override
386  public void update(Observable o, Object arg) {
387  refresh(true);
388  }
389  }
390 
391  @Override
392  protected void onAdd() {
393  if (notifier != null) {
394  notifier.addObserver(observer);
395  }
396  }
397 
398  @Override
399  protected void onRemove() {
400  if (notifier != null) {
401  notifier.deleteObserver(observer);
402  }
403  }
404 
405  static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
406  String query = "";
407  switch (filter) {
408  case FS_DELETED_FILTER:
409  query = "dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue() //NON-NLS
410  + " AND meta_flags != " + TskData.TSK_FS_META_FLAG_ENUM.ORPHAN.getValue() //NON-NLS
411  + " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType(); //NON-NLS
412 
413  break;
414  case ALL_DELETED_FILTER:
415  query = " ( "
416  + "( "
417  + "(dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue() //NON-NLS
418  + " OR " //NON-NLS
419  + "meta_flags = " + TskData.TSK_FS_META_FLAG_ENUM.ORPHAN.getValue() //NON-NLS
420  + ")"
421  + " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType() //NON-NLS
422  + " )"
423  + " OR type = " + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType() //NON-NLS
424  + " OR (dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()
425  + " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.getFileType() + " )"
426  + " )";
427  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
428  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
429  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
430  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()
431  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()
432  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType();
433  break;
434 
435  default:
436  logger.log(Level.SEVERE, "Unsupported filter type to get deleted content: {0}", filter); //NON-NLS
437 
438  }
439 
440  if (filteringDSObjId > 0) {
441  query += " AND data_source_obj_id = " + filteringDSObjId;
442  }
443  return query;
444  }
445 
446  private List<AbstractFile> runFsQuery() {
447  List<AbstractFile> ret = new ArrayList<>();
448 
449  String query = makeQuery(filter, datasourceObjId);
450  try {
451  ret = skCase.findAllFilesWhere(query);
452  } catch (TskCoreException e) {
453  logger.log(Level.SEVERE, "Error getting files for the deleted content view using: " + query, e); //NON-NLS
454  }
455 
456  return ret;
457 
458  }
459 
468  static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter, long datasourceObjId) {
469  try {
470  return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
471  } catch (TskCoreException ex) {
472  logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS
473  return 0;
474  }
475  }
476 
477  @Override
478  protected Node createNodeForKey(AbstractFile key) {
479  return key.accept(new ContentVisitor.Default<AbstractNode>() {
480  public FileNode visit(AbstractFile f) {
481  return new FileNode(f, false);
482  }
483 
484  public FileNode visit(FsContent f) {
485  return new FileNode(f, false);
486  }
487 
488  @Override
489  public FileNode visit(LayoutFile f) {
490  return new FileNode(f, false);
491  }
492 
493  @Override
494  public FileNode visit(File f) {
495  return new FileNode(f, false);
496  }
497 
498  @Override
499  public FileNode visit(Directory f) {
500  return new FileNode(f, false);
501  }
502 
503  @Override
504  public FileNode visit(VirtualDirectory f) {
505  return new FileNode(f, false);
506  }
507 
508  @Override
509  protected AbstractNode defaultVisit(Content di) {
510  throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString());
511  }
512  });
513  }
514  }
515  }
516 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
public< T > T accept(AutopsyItemVisitor< T > visitor)
void removeIngestJobEventListener(final PropertyChangeListener listener)
boolean createKeys(List< DeletedContent.DeletedContentFilter > list)
void addIngestJobEventListener(final PropertyChangeListener listener)
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
Node createNodeForKey(DeletedContent.DeletedContentFilter key)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:486
DeletedContent(SleuthkitCase skCase, long dsObjId)

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.