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

Copyright © 2012-2018 Basis Technology. Generated on: Thu Oct 4 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.