Autopsy  4.6.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-2018 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 javax.swing.JOptionPane;
32 import javax.swing.SwingUtilities;
33 import org.openide.nodes.AbstractNode;
34 import org.openide.nodes.ChildFactory;
35 import org.openide.nodes.Children;
36 import org.openide.nodes.Node;
37 import org.openide.nodes.Sheet;
38 import org.openide.util.NbBundle;
39 import org.openide.util.lookup.Lookups;
40 import org.openide.windows.WindowManager;
45 import static org.sleuthkit.autopsy.datamodel.Bundle.*;
47 import org.sleuthkit.datamodel.AbstractFile;
48 import org.sleuthkit.datamodel.Content;
49 import org.sleuthkit.datamodel.ContentVisitor;
50 import org.sleuthkit.datamodel.Directory;
51 import org.sleuthkit.datamodel.File;
52 import org.sleuthkit.datamodel.FsContent;
53 import org.sleuthkit.datamodel.LayoutFile;
54 import org.sleuthkit.datamodel.SleuthkitCase;
55 import org.sleuthkit.datamodel.TskCoreException;
56 import org.sleuthkit.datamodel.TskData;
57 
61 public class DeletedContent implements AutopsyVisitableItem {
62 
63  private SleuthkitCase skCase;
64 
65  @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
66  "DeletedContent.allDelFilter.text=All"})
67  public enum DeletedContentFilter implements AutopsyVisitableItem {
68 
69  FS_DELETED_FILTER(0, "FS_DELETED_FILTER", //NON-NLS
70  Bundle.DeletedContent_fsDelFilter_text()),
71  ALL_DELETED_FILTER(1, "ALL_DELETED_FILTER", //NON-NLS
72  Bundle.DeletedContent_allDelFilter_text());
73 
74  private int id;
75  private String name;
76  private String displayName;
77 
78  private DeletedContentFilter(int id, String name, String displayName) {
79  this.id = id;
80  this.name = name;
81  this.displayName = displayName;
82 
83  }
84 
85  public String getName() {
86  return this.name;
87  }
88 
89  public int getId() {
90  return this.id;
91  }
92 
93  public String getDisplayName() {
94  return this.displayName;
95  }
96 
97  @Override
98  public <T> T accept(AutopsyItemVisitor<T> visitor) {
99  return visitor.visit(this);
100  }
101  }
102 
103  public DeletedContent(SleuthkitCase skCase) {
104  this.skCase = skCase;
105  }
106 
107  @Override
108  public <T> T accept(AutopsyItemVisitor<T> visitor) {
109  return visitor.visit(this);
110  }
111 
112  public SleuthkitCase getSleuthkitCase() {
113  return this.skCase;
114  }
115 
116  public static class DeletedContentsNode extends DisplayableItemNode {
117 
118  @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files")
119  private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name();
120 
121  DeletedContentsNode(SleuthkitCase skCase) {
122  super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME));
123  super.setName(NAME);
124  super.setDisplayName(NAME);
125  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
126  }
127 
128  @Override
129  public boolean isLeafTypeNode() {
130  return false;
131  }
132 
133  @Override
134  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
135  return visitor.visit(this);
136  }
137 
138  @Override
139  @NbBundle.Messages({
140  "DeletedContent.createSheet.name.displayName=Name",
141  "DeletedContent.createSheet.name.desc=no description"})
142  protected Sheet createSheet() {
143  Sheet sheet = super.createSheet();
144  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
145  if (sheetSet == null) {
146  sheetSet = Sheet.createPropertiesSet();
147  sheet.put(sheetSet);
148  }
149 
150  sheetSet.put(new NodeProperty<>("Name", //NON-NLS
151  Bundle.DeletedContent_createSheet_name_displayName(),
152  Bundle.DeletedContent_createSheet_name_desc(),
153  NAME));
154  return sheet;
155  }
156 
157  @Override
158  public String getItemType() {
159  return getClass().getName();
160  }
161  }
162 
163  public static class DeletedContentsChildren extends ChildFactory<DeletedContent.DeletedContentFilter> {
164 
165  private SleuthkitCase skCase;
166  private Observable notifier;
167  // true if we have already told user that not all files will be shown
168  private static volatile boolean maxFilesDialogShown = false;
169 
170  public DeletedContentsChildren(SleuthkitCase skCase) {
171  this.skCase = skCase;
172  this.notifier = new DeletedContentsChildrenObservable();
173  }
174 
179  private static final class DeletedContentsChildrenObservable extends Observable {
180  private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
183  );
184 
189  }
190 
191  private void removeListeners() {
192  deleteObservers();
196  }
197 
198  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
199  String eventType = evt.getPropertyName();
200  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
209  try {
210  Case.getOpenCase();
211  // new file was added
212  // @@@ COULD CHECK If the new file is deleted before notifying...
213  update();
214  } catch (NoCurrentCaseException notUsed) {
218  }
219  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
220  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
221  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
228  try {
229  Case.getOpenCase();
230  update();
231  } catch (NoCurrentCaseException notUsed) {
235  }
236  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
237  // case was closed. Remove listeners so that we don't get called with a stale case handle
238  if (evt.getNewValue() == null) {
239  removeListeners();
240  }
241  maxFilesDialogShown = false;
242  }
243  };
244 
245  private void update() {
246  setChanged();
247  notifyObservers();
248  }
249  }
250 
251  @Override
252 
253  protected boolean createKeys(List<DeletedContent.DeletedContentFilter> list) {
254  list.addAll(Arrays.asList(DeletedContent.DeletedContentFilter.values()));
255  return true;
256  }
257 
258  @Override
260  return new DeletedContentNode(skCase, key, notifier);
261  }
262 
264 
266 
267  // Use version that has observer for updates
268  @Deprecated
270  super(Children.create(new DeletedContentChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName()));
271  this.filter = filter;
272  init();
273  }
274 
275  DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o) {
276  super(Children.create(new DeletedContentChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
277  this.filter = filter;
278  init();
279  o.addObserver(new DeletedContentNodeObserver());
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-icon-deleted.png"); //NON-NLS
289  }
290 
291  // update the display name when new events are fired
292  private class DeletedContentNodeObserver implements Observer {
293 
294  @Override
295  public void update(Observable o, Object arg) {
297  }
298  }
299 
300  private void updateDisplayName() {
301  //get count of children without preloading all children nodes
302  final long count = DeletedContentChildren.calculateItems(skCase, filter);
303  //final long count = getChildren().getNodesCount(true);
304  super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
305  }
306 
307  @Override
308  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
309  return visitor.visit(this);
310  }
311 
312  @Override
313  @NbBundle.Messages({
314  "DeletedContent.createSheet.filterType.displayName=Type",
315  "DeletedContent.createSheet.filterType.desc=no description"})
316  protected Sheet createSheet() {
317  Sheet sheet = super.createSheet();
318  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
319  if (sheetSet == null) {
320  sheetSet = Sheet.createPropertiesSet();
321  sheet.put(sheetSet);
322  }
323 
324  sheetSet.put(new NodeProperty<>("Type", //NON_NLS
325  Bundle.DeletedContent_createSheet_filterType_displayName(),
326  Bundle.DeletedContent_createSheet_filterType_desc(),
327  filter.getDisplayName()));
328 
329  return sheet;
330  }
331 
332  @Override
333  public boolean isLeafTypeNode() {
334  return true;
335  }
336 
337  @Override
338  public String getItemType() {
343  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
344  }
345  }
346 
347  static class DeletedContentChildren extends ChildFactory.Detachable<AbstractFile> {
348 
349  private final SleuthkitCase skCase;
350  private final DeletedContent.DeletedContentFilter filter;
351  private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
352  private static final int MAX_OBJECTS = 10001;
353  private final Observable notifier;
354 
355  DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o) {
356  this.skCase = skCase;
357  this.filter = filter;
358  this.notifier = o;
359  }
360 
361  private final Observer observer = new DeletedContentChildrenObserver();
362 
363  // Cause refresh of children if there are changes
364  private class DeletedContentChildrenObserver implements Observer {
365 
366  @Override
367  public void update(Observable o, Object arg) {
368  refresh(true);
369  }
370  }
371 
372  @Override
373  protected void addNotify() {
374  if (notifier != null) {
375  notifier.addObserver(observer);
376  }
377  }
378 
379  @Override
380  protected void removeNotify() {
381  if (notifier != null) {
382  notifier.deleteObserver(observer);
383  }
384  }
385 
386  @Override
387  @NbBundle.Messages({"# {0} - The deleted files threshold",
388  "DeletedContent.createKeys.maxObjects.msg="
389  + "There are more Deleted Files than can be displayed."
390  + " Only the first {0} Deleted Files will be shown."})
391  protected boolean createKeys(List<AbstractFile> list) {
392  List<AbstractFile> queryList = runFsQuery();
393  if (queryList.size() == MAX_OBJECTS) {
394  queryList.remove(queryList.size() - 1);
395  // only show the dialog once - not each time we refresh
396  if (maxFilesDialogShown == false) {
397  maxFilesDialogShown = true;
398  SwingUtilities.invokeLater(()
399  -> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
400  DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1))
401  );
402  }
403  }
404  list.addAll(queryList);
405  return true;
406  }
407 
408  static private String makeQuery(DeletedContent.DeletedContentFilter filter) {
409  String query = "";
410  switch (filter) {
411  case FS_DELETED_FILTER:
412  query = "dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue() //NON-NLS
413  + " AND meta_flags != " + TskData.TSK_FS_META_FLAG_ENUM.ORPHAN.getValue() //NON-NLS
414  + " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType(); //NON-NLS
415 
416  break;
417  case ALL_DELETED_FILTER:
418  query = " ( "
419  + "( "
420  + "(dir_flags = " + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue() //NON-NLS
421  + " OR " //NON-NLS
422  + "meta_flags = " + TskData.TSK_FS_META_FLAG_ENUM.ORPHAN.getValue() //NON-NLS
423  + ")"
424  + " AND type = " + TskData.TSK_DB_FILES_TYPE_ENUM.FS.getFileType() //NON-NLS
425  + " )"
426  + " OR type = " + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType() //NON-NLS
427  + " )";
428  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType()
429  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
430  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS.getFileType()
431  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()
432  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.getFileType()
433  //+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType();
434  break;
435 
436  default:
437  logger.log(Level.SEVERE, "Unsupported filter type to get deleted content: {0}", filter); //NON-NLS
438 
439  }
440 
441  if (UserPreferences.hideKnownFilesInViewsTree()) {
442  query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS
443  + " OR known IS NULL)"; //NON-NLS
444  }
445 
446  query += " LIMIT " + MAX_OBJECTS; //NON-NLS
447  return query;
448  }
449 
450  private List<AbstractFile> runFsQuery() {
451  List<AbstractFile> ret = new ArrayList<>();
452 
453  String query = makeQuery(filter);
454  try {
455  ret = skCase.findAllFilesWhere(query);
456  } catch (TskCoreException e) {
457  logger.log(Level.SEVERE, "Error getting files for the deleted content view using: " + query, e); //NON-NLS
458  }
459 
460  return ret;
461 
462  }
463 
472  static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) {
473  try {
474  return sleuthkitCase.countFilesWhere(makeQuery(filter));
475  } catch (TskCoreException ex) {
476  logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS
477  return 0;
478  }
479  }
480 
481  @Override
482  protected Node createNodeForKey(AbstractFile key) {
483  return key.accept(new ContentVisitor.Default<AbstractNode>() {
484  public FileNode visit(AbstractFile f) {
485  return new FileNode(f, false);
486  }
487 
488  public FileNode visit(FsContent f) {
489  return new FileNode(f, false);
490  }
491 
492  @Override
493  public FileNode visit(LayoutFile f) {
494  return new FileNode(f, false);
495  }
496 
497  @Override
498  public FileNode visit(File f) {
499  return new FileNode(f, false);
500  }
501 
502  @Override
503  public FileNode visit(Directory f) {
504  return new FileNode(f, false);
505  }
506 
507  @Override
508  protected AbstractNode defaultVisit(Content di) {
509  throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString());
510  }
511  });
512  }
513  }
514  }
515 }
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:420
Node createNodeForKey(DeletedContent.DeletedContentFilter key)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:465

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