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