mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-28 21:39:52 +00:00
Merge pull request #2553 from APriestman/imageWriterFilename
Completed FinishImage and added path selection
This commit is contained in:
@@ -206,6 +206,9 @@ class AddImageTask implements Runnable {
|
||||
if (!verificationError.isEmpty()) {
|
||||
errorMessages.add(verificationError);
|
||||
}
|
||||
if(! imageWriterPath.isEmpty()){
|
||||
Case.getCurrentCase().scheduleImageWriterFinish(imageId);
|
||||
}
|
||||
newDataSources.add(newImage);
|
||||
} else {
|
||||
String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
|
||||
|
||||
@@ -76,7 +76,10 @@ LocalDiskPanel.timeZoneLabel.text=Please select the input timezone:
|
||||
LocalDiskPanel.noFatOrphansCheckbox.toolTipText=
|
||||
LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
|
||||
LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched)
|
||||
LocalDiskPanel.imageWriterError.text=Error - file already exists
|
||||
LocalDiskPanel.imageWriterDirError.text=Error - directory does not exist
|
||||
LocalDiskPanel.imageWriterEmptyPathError.text=Error - enter path for VHD
|
||||
LocalDiskPanel.imageWriterIsDirError.text=Error - VHD path is a directory
|
||||
LocalDiskPanel.imageWriterFileExistsError.text=Error - VHD path already exists
|
||||
MissingImageDialog.browseButton.text=Browse
|
||||
MissingImageDialog.pathNameTextField.text=
|
||||
AddImageWizardAddingProgressVisual.progressTextArea.border.title=Status
|
||||
@@ -243,6 +246,7 @@ IngestJobInfoPanel.jLabel1.text=Ingest Modules
|
||||
IngestJobInfoPanel.jLabel2.text=Ingest Jobs
|
||||
CaseInformationPanel.closeButton.text=Close
|
||||
LocalDiskPanel.copyImageCheckbox.text=Make a VHD image of the drive while it is being analyzed
|
||||
LocalDiskPanel.imageWriterPathLabel.text=jLabel1
|
||||
LocalDiskPanel.imageWriterPathDescLabel.text=Will be saved in the Module Output/Image Writer directory as :
|
||||
LocalDiskPanel.imageWriterErrorLabel.text=Error Label
|
||||
LocalDiskPanel.jLabel1.text=Note that at least one ingest module must be run to create a complete copy
|
||||
LocalDiskPanel.pathTextField.text=
|
||||
LocalDiskPanel.browseButton.text=Browse
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import org.sleuthkit.autopsy.datasourceprocessors.ImageWriter;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Frame;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -286,6 +287,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
private static final int MIN_SECS_BETWEEN_TSK_ERROR_REPORTS = 60;
|
||||
private static final Logger logger = Logger.getLogger(Case.class.getName());
|
||||
private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher();
|
||||
private final ImageWriter imageWriter = new ImageWriter();
|
||||
private static String appName;
|
||||
private static Case currentCase;
|
||||
private static CoordinationService.Lock currentCaseLock;
|
||||
@@ -1437,6 +1439,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
});
|
||||
IngestManager.getInstance().cancelAllIngestJobs(IngestJob.CancellationReason.CASE_CLOSED);
|
||||
oldCase.closeImageWriter();
|
||||
completeCaseChange(null); //closes windows, etc
|
||||
if (null != oldCase.tskErrorReporter) {
|
||||
oldCase.tskErrorReporter.shutdown(); // stop listening for TSK errors for the old case
|
||||
@@ -1613,6 +1616,22 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
}
|
||||
return currentCaseExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the ID of an image that is being copied using ImageWriter.
|
||||
* This will cause the image to be finished after ingest is complete.
|
||||
* @param imageID The image ID
|
||||
*/
|
||||
void scheduleImageWriterFinish(long imageID){
|
||||
imageWriter.addDataSourceId(imageID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all tasks associated with Image Writer
|
||||
*/
|
||||
void closeImageWriter(){
|
||||
imageWriter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time zone(s) of the image data source(s) in this case.
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 65]"/>
|
||||
<Dimension value="[0, 420]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[485, 65]"/>
|
||||
<Dimension value="[485, 410]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
@@ -26,30 +26,38 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="diskComboBox" min="-2" pref="345" max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="copyImageCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="imageWriterPathDescLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="imageWriterPathLabel" min="-2" pref="261" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="pathTextField" alignment="1" min="-2" pref="362" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="diskComboBox" min="-2" pref="345" max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="copyImageCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="imageWriterErrorLabel" alignment="0" min="-2" pref="444" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabel1" min="-2" pref="423" max="-2" attributes="0"/>
|
||||
<Component id="imageWriterErrorLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="29" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -74,12 +82,14 @@
|
||||
<Component id="copyImageCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="imageWriterPathDescLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="imageWriterPathLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="imageWriterErrorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="124" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="170" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -189,20 +199,9 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.copyImageCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="imageWriterPathLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.imageWriterPathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="imageWriterPathDescLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.imageWriterPathDescLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="copyImageCheckboxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="imageWriterErrorLabel">
|
||||
<Properties>
|
||||
@@ -219,5 +218,33 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="pathTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="pathTextFieldKeyReleased"/>
|
||||
<EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="pathTextFieldKeyTyped"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="browseButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.TimeZone;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
@@ -58,8 +59,8 @@ final class LocalDiskPanel extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private List<LocalDisk> disks;
|
||||
private LocalDiskModel model;
|
||||
private String fullImageWriterPath = "";
|
||||
private boolean enableNext = false;
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
|
||||
/**
|
||||
* Creates new form LocalDiskPanel
|
||||
@@ -91,8 +92,10 @@ final class LocalDiskPanel extends JPanel {
|
||||
errorLabel.setVisible(false);
|
||||
errorLabel.setText("");
|
||||
diskComboBox.setEnabled(false);
|
||||
imageWriterErrorLabel.setOpaque(true);
|
||||
imageWriterErrorLabel.setText("");
|
||||
imageWriterPathLabel.setText("");
|
||||
pathTextField.setEnabled(copyImageCheckbox.isSelected());
|
||||
browseButton.setEnabled(copyImageCheckbox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,12 +115,13 @@ final class LocalDiskPanel extends JPanel {
|
||||
noFatOrphansCheckbox = new javax.swing.JCheckBox();
|
||||
descLabel = new javax.swing.JLabel();
|
||||
copyImageCheckbox = new javax.swing.JCheckBox();
|
||||
imageWriterPathLabel = new javax.swing.JLabel();
|
||||
imageWriterPathDescLabel = new javax.swing.JLabel();
|
||||
imageWriterErrorLabel = new javax.swing.JLabel();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
pathTextField = new javax.swing.JTextField();
|
||||
browseButton = new javax.swing.JButton();
|
||||
|
||||
setMinimumSize(new java.awt.Dimension(0, 65));
|
||||
setPreferredSize(new java.awt.Dimension(485, 65));
|
||||
setMinimumSize(new java.awt.Dimension(0, 420));
|
||||
setPreferredSize(new java.awt.Dimension(485, 410));
|
||||
|
||||
diskLabel.setFont(diskLabel.getFont().deriveFont(diskLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(diskLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.diskLabel.text")); // NOI18N
|
||||
@@ -142,40 +146,65 @@ final class LocalDiskPanel extends JPanel {
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.descLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(copyImageCheckbox, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.copyImageCheckbox.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(imageWriterPathLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.imageWriterPathLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(imageWriterPathDescLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.imageWriterPathDescLabel.text")); // NOI18N
|
||||
copyImageCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
copyImageCheckboxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
imageWriterErrorLabel.setFont(imageWriterErrorLabel.getFont().deriveFont(imageWriterErrorLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||
imageWriterErrorLabel.setForeground(new java.awt.Color(255, 0, 0));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(imageWriterErrorLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.imageWriterErrorLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.jLabel1.text")); // NOI18N
|
||||
|
||||
pathTextField.setText(org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.pathTextField.text")); // NOI18N
|
||||
pathTextField.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||
public void keyReleased(java.awt.event.KeyEvent evt) {
|
||||
pathTextFieldKeyReleased(evt);
|
||||
}
|
||||
public void keyTyped(java.awt.event.KeyEvent evt) {
|
||||
pathTextFieldKeyTyped(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.browseButton.text")); // NOI18N
|
||||
browseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
browseButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(diskLabel)
|
||||
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(errorLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addComponent(copyImageCheckbox)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(diskLabel)
|
||||
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(errorLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addComponent(copyImageCheckbox)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(21, 21, 21)
|
||||
.addComponent(descLabel))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(browseButton))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(21, 21, 21)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(descLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(imageWriterPathDescLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(imageWriterPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(imageWriterErrorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 444, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 423, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(imageWriterErrorLabel))))
|
||||
.addGap(0, 29, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -197,27 +226,72 @@ final class LocalDiskPanel extends JPanel {
|
||||
.addComponent(copyImageCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(imageWriterPathDescLabel)
|
||||
.addComponent(imageWriterPathLabel))
|
||||
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(browseButton))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(imageWriterErrorLabel)
|
||||
.addContainerGap(124, Short.MAX_VALUE))
|
||||
.addContainerGap(170, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
String oldText = pathTextField.getText();
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentFile = new File(oldText);
|
||||
if ((currentFile.getParentFile() != null) && (currentFile.getParentFile().exists())) {
|
||||
fc.setCurrentDirectory(currentFile.getParentFile());
|
||||
}
|
||||
|
||||
int retval = fc.showOpenDialog(this);
|
||||
if (retval == JFileChooser.APPROVE_OPTION) {
|
||||
String path = fc.getSelectedFile().getPath();
|
||||
pathTextField.setText(path);
|
||||
}
|
||||
fireUpdateEvent();
|
||||
}//GEN-LAST:event_browseButtonActionPerformed
|
||||
|
||||
private void copyImageCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_copyImageCheckboxActionPerformed
|
||||
pathTextField.setEnabled(copyImageCheckbox.isSelected());
|
||||
browseButton.setEnabled(copyImageCheckbox.isSelected());
|
||||
fireUpdateEvent();
|
||||
}//GEN-LAST:event_copyImageCheckboxActionPerformed
|
||||
|
||||
private void pathTextFieldKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_pathTextFieldKeyTyped
|
||||
|
||||
}//GEN-LAST:event_pathTextFieldKeyTyped
|
||||
|
||||
private void pathTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_pathTextFieldKeyReleased
|
||||
fireUpdateEvent();
|
||||
}//GEN-LAST:event_pathTextFieldKeyReleased
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton browseButton;
|
||||
private javax.swing.JCheckBox copyImageCheckbox;
|
||||
private javax.swing.JLabel descLabel;
|
||||
private javax.swing.JComboBox<LocalDisk> diskComboBox;
|
||||
private javax.swing.JLabel diskLabel;
|
||||
private javax.swing.JLabel errorLabel;
|
||||
private javax.swing.JLabel imageWriterErrorLabel;
|
||||
private javax.swing.JLabel imageWriterPathDescLabel;
|
||||
private javax.swing.JLabel imageWriterPathLabel;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JCheckBox noFatOrphansCheckbox;
|
||||
private javax.swing.JTextField pathTextField;
|
||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||
private javax.swing.JLabel timeZoneLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
private void fireUpdateEvent(){
|
||||
try {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "LocalDiskPanel listener threw exception", e); //NON-NLS
|
||||
MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr"),
|
||||
NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr.msg"),
|
||||
MessageNotifyUtil.MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently selected disk path.
|
||||
*
|
||||
@@ -267,17 +341,30 @@ final class LocalDiskPanel extends JPanel {
|
||||
String path = disk.getName().replaceAll("[:]", "");
|
||||
path += " " + System.currentTimeMillis();
|
||||
path += ".vhd";
|
||||
imageWriterPathLabel.setText(path);
|
||||
fullImageWriterPath = Paths.get(getDefaultImageWriterFolder(), path).toString();
|
||||
pathTextField.setText(Paths.get(getDefaultImageWriterFolder(), path).toString());
|
||||
}
|
||||
|
||||
private boolean imageWriterPathIsValid(){
|
||||
|
||||
File f = new File(fullImageWriterPath);
|
||||
if(f.exists()) {
|
||||
imageWriterErrorLabel.setText(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.imageWriterError.text"));
|
||||
if(pathTextField.getText().isEmpty()){
|
||||
imageWriterErrorLabel.setText(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.imageWriterEmptyPathError.text"));
|
||||
return false;
|
||||
}
|
||||
|
||||
File f = new File(pathTextField.getText());
|
||||
if(((f.getParentFile() != null) && (! f.getParentFile().exists())) ||
|
||||
(f.getParentFile() == null)) {
|
||||
imageWriterErrorLabel.setText(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.imageWriterDirError.text"));
|
||||
return false;
|
||||
}
|
||||
if(f.isDirectory()){
|
||||
imageWriterErrorLabel.setText(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.imageWriterIsDirError.text"));
|
||||
return false;
|
||||
}
|
||||
if(f.exists()){
|
||||
imageWriterErrorLabel.setText(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.imageWriterFileExistsError.text"));
|
||||
return false;
|
||||
}
|
||||
|
||||
imageWriterErrorLabel.setText("");
|
||||
return true;
|
||||
}
|
||||
@@ -287,14 +374,14 @@ final class LocalDiskPanel extends JPanel {
|
||||
}
|
||||
|
||||
String getImageWriterPath(){
|
||||
return fullImageWriterPath;
|
||||
return pathTextField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we enable the wizard's next button? Always return true because we
|
||||
* control the possible selections.
|
||||
* Should we enable the wizard's next button? We control all the possible
|
||||
* selections except for Image Writer.
|
||||
*
|
||||
* @return true
|
||||
* @return true if panel is valid
|
||||
*/
|
||||
public boolean validatePanel() {
|
||||
if(copyImageCheckbox.isSelected() &&
|
||||
@@ -399,15 +486,7 @@ final class LocalDiskPanel extends JPanel {
|
||||
selected = (LocalDisk) anItem;
|
||||
enableNext = true;
|
||||
setPotentialImageWriterPath((LocalDisk) selected);
|
||||
|
||||
try {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "LocalDiskPanel listener threw exception", e); //NON-NLS
|
||||
MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr"),
|
||||
NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr.msg"),
|
||||
MessageNotifyUtil.MessageType.ERROR);
|
||||
}
|
||||
fireUpdateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourceprocessors;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
|
||||
import org.sleuthkit.datamodel.SleuthkitJNI;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* The ImageWriter class is used to complete VHD copies created from local disks
|
||||
* after the ingest process completes.
|
||||
*/
|
||||
public class ImageWriter {
|
||||
|
||||
private final Logger logger = Logger.getLogger(ImageWriter.class.getName());
|
||||
|
||||
private final HashSet<Long> dataSourceIds = new HashSet<>();
|
||||
private final Object dataSourceIdsLock; // Get this lock before accessing dataSourceIds
|
||||
|
||||
private final HashSet<ScheduledFuture<?>> progressUpdaters = new HashSet<>();
|
||||
private final HashSet<Long> imagesBeingFinished = new HashSet<>();
|
||||
private final HashSet<ProgressHandle> progressBars = new HashSet<>();
|
||||
private final HashSet<Future<?>> finishTasksInProgress = new HashSet<>();
|
||||
private boolean isCancelled;
|
||||
private final Object currentTasksLock; // Get this lock before accessing imagesBeingFinished, progressBars, progressUpdaters, finishTasksInProgress or isCancelled
|
||||
|
||||
private boolean listenerStarted;
|
||||
private ScheduledThreadPoolExecutor periodicTasksExecutor = null;
|
||||
private final boolean doUI;
|
||||
|
||||
public ImageWriter(){
|
||||
dataSourceIdsLock = new Object();
|
||||
currentTasksLock = new Object();
|
||||
listenerStarted = false;
|
||||
isCancelled = false;
|
||||
|
||||
doUI = RuntimeProperties.coreComponentsAreActive();
|
||||
if(doUI){
|
||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(5, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listener on IngestJobEvents if it hasn't already been started.
|
||||
* When a DataSourceAnalysisCompletedEvent arrives, if it matches
|
||||
* the data source ID of an image that is using Image Writer, then finish the image
|
||||
* (fill in any gaps). The AddImageTask for this data source must have included
|
||||
* a non-empty imageWriterPath parameter to enable Image Writer.
|
||||
*/
|
||||
private synchronized void startListener(){
|
||||
if(! listenerStarted){
|
||||
IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if(evt.getPropertyName().equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED.toString())){
|
||||
DataSourceAnalysisCompletedEvent event = (DataSourceAnalysisCompletedEvent)evt;
|
||||
|
||||
if(event.getDataSource() != null){
|
||||
long imageId = event.getDataSource().getId();
|
||||
String name = event.getDataSource().getName();
|
||||
|
||||
// Check whether we need to run finishImage for this data source
|
||||
synchronized(dataSourceIdsLock){
|
||||
if( ! ImageWriter.this.dataSourceIds.contains(imageId)){
|
||||
// Image writer was not used on this data source or we've already finished it
|
||||
return;
|
||||
} else {
|
||||
// Remove the imageId from the list here so we can't get past this point twice
|
||||
// for the same image. Multiple DataSourceAnalysisCompletedEvent events can come from
|
||||
// the same image if more ingest modules are run later, but the imageId is only added
|
||||
// to the list during the intial task to add the image to the database.
|
||||
ImageWriter.this.dataSourceIds.remove(imageId);
|
||||
}
|
||||
}
|
||||
logger.log(Level.INFO, String.format("Finishing VHD image for %s",
|
||||
event.getDataSource().getName())); //NON-NLS
|
||||
|
||||
new Thread(() -> {
|
||||
try{
|
||||
Image image = Case.getCurrentCase().getSleuthkitCase().getImageById(imageId);
|
||||
ProgressHandle progressHandle = null;
|
||||
ScheduledFuture<?> progressUpdateTask = null;
|
||||
|
||||
if(doUI){
|
||||
progressHandle = ProgressHandle.createHandle("Image writer - " + name);
|
||||
progressHandle.start(100);
|
||||
progressUpdateTask = periodicTasksExecutor.scheduleAtFixedRate(
|
||||
new ProgressUpdateTask(progressHandle, image.getImageHandle()), 0, 250, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
synchronized(currentTasksLock){
|
||||
ImageWriter.this.imagesBeingFinished.add(image.getImageHandle());
|
||||
|
||||
if(doUI){
|
||||
if(isCancelled){
|
||||
progressUpdateTask.cancel(true);
|
||||
return;
|
||||
}
|
||||
ImageWriter.this.progressUpdaters.add(progressUpdateTask);
|
||||
ImageWriter.this.progressBars.add(progressHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// The added complexity here with the Future is because we absolutely need to make sure
|
||||
// the call to finishImageWriter returns before allowing the TSK data structures to be freed
|
||||
// during case close.
|
||||
Future<?> finishTask = Executors.newSingleThreadExecutor().submit(() -> {
|
||||
try{
|
||||
SleuthkitJNI.finishImageWriter(image.getImageHandle());
|
||||
} catch (TskCoreException ex){
|
||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
synchronized(currentTasksLock){
|
||||
ImageWriter.this.finishTasksInProgress.add(finishTask);
|
||||
}
|
||||
|
||||
// Wait for finishImageWriter to complete
|
||||
try{
|
||||
// The call to get() will happen twice if the user closes the case, which is ok
|
||||
finishTask.get();
|
||||
} catch (InterruptedException | ExecutionException ex){
|
||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||
}
|
||||
|
||||
synchronized(currentTasksLock){
|
||||
ImageWriter.this.finishTasksInProgress.remove(finishTask);
|
||||
ImageWriter.this.imagesBeingFinished.remove(image.getImageHandle());
|
||||
|
||||
if(doUI){
|
||||
progressUpdateTask.cancel(true);
|
||||
ImageWriter.this.progressUpdaters.remove(progressUpdateTask);
|
||||
progressHandle.finish();
|
||||
ImageWriter.this.progressBars.remove(progressHandle);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, String.format("Finished writing VHD image for %s", event.getDataSource().getName())); //NON-NLS
|
||||
} catch (TskCoreException ex){
|
||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "DataSourceAnalysisCompletedEvent did not contain a dataSource object"); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
listenerStarted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a data source ID to the list of images to run finishImage on.
|
||||
* Also starts the listener if needed.
|
||||
* @param id The dataSource/Image ID
|
||||
*/
|
||||
public void addDataSourceId(Long id){
|
||||
startListener();
|
||||
synchronized(dataSourceIdsLock){
|
||||
dataSourceIds.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop any open progress update task, finish the progress bars, and tell
|
||||
* the finishImage process to stop
|
||||
*/
|
||||
public void close(){
|
||||
synchronized(currentTasksLock){
|
||||
isCancelled = true;
|
||||
|
||||
for(ScheduledFuture<?> task:ImageWriter.this.progressUpdaters){
|
||||
task.cancel(true);
|
||||
}
|
||||
|
||||
for(Long handle:imagesBeingFinished){
|
||||
SleuthkitJNI.cancelFinishImage(handle);
|
||||
logger.log(Level.SEVERE, "Case closed before VHD image could be finished"); //NON-NLS
|
||||
}
|
||||
|
||||
// Wait for all the finish tasks to end
|
||||
for(Future<?> task:ImageWriter.this.finishTasksInProgress){
|
||||
try{
|
||||
task.get();
|
||||
} catch (InterruptedException | ExecutionException ex){
|
||||
logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
for(ProgressHandle progressHandle:ImageWriter.this.progressBars){
|
||||
progressHandle.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to query the Sleuthkit processing to get the percentage done.
|
||||
*/
|
||||
private final class ProgressUpdateTask implements Runnable {
|
||||
long imageHandle;
|
||||
ProgressHandle progressHandle;
|
||||
|
||||
ProgressUpdateTask(ProgressHandle progressHandle, long imageHandle){
|
||||
this.imageHandle = imageHandle;
|
||||
this.progressHandle = progressHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int progress = SleuthkitJNI.getFinishImageProgress(imageHandle);
|
||||
progressHandle.progress(progress);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception in ProgressUpdateTask", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user