mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
first draft of locking resources in autopsy
This commit is contained in:
parent
b2c674e6b3
commit
e188f4644e
@ -31,6 +31,8 @@ import java.awt.event.ActionListener;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -181,6 +183,7 @@ public class Case {
|
|||||||
private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources";
|
private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources";
|
||||||
private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode";
|
private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode";
|
||||||
private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_";
|
private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_";
|
||||||
|
private static final String LOCK_FILE_NAME = "lock";
|
||||||
private static final Logger logger = Logger.getLogger(Case.class.getName());
|
private static final Logger logger = Logger.getLogger(Case.class.getName());
|
||||||
private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher();
|
private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher();
|
||||||
private static final Object caseActionSerializationLock = new Object();
|
private static final Object caseActionSerializationLock = new Object();
|
||||||
@ -197,6 +200,10 @@ public class Case {
|
|||||||
private CollaborationMonitor collaborationMonitor;
|
private CollaborationMonitor collaborationMonitor;
|
||||||
private Services caseServices;
|
private Services caseServices;
|
||||||
|
|
||||||
|
private RansomAccessFile lockFileRaf = null;
|
||||||
|
private FileChannel lockFileChannel = null;
|
||||||
|
private FileLock lockFileLock = null;
|
||||||
|
|
||||||
private volatile boolean hasDataSource = false;
|
private volatile boolean hasDataSource = false;
|
||||||
private volatile boolean hasData = false;
|
private volatile boolean hasData = false;
|
||||||
|
|
||||||
@ -769,6 +776,57 @@ public class Case {
|
|||||||
|| caseName.contains("*") || caseName.contains("?") || caseName.contains("\"")
|
|| caseName.contains("*") || caseName.contains("?") || caseName.contains("\"")
|
||||||
|| caseName.contains("<") || caseName.contains(">") || caseName.contains("|"));
|
|| caseName.contains("<") || caseName.contains(">") || caseName.contains("|"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to acquire a lock to the lock file in the case directory.
|
||||||
|
* @param caseDir The case directory that the autopsy.db is in.
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void tryAcquireFileLock(String caseDir) throws ConcurrentDbAccessException, IOException {
|
||||||
|
File lockFile = new File(caseDir, LOCK_FILE_NAME);
|
||||||
|
lockFile.getParentFile().mkdirs();
|
||||||
|
lockFileRaf = new RandomAccessFile(lockFile, "rw");
|
||||||
|
lockFileChannel = lockFileRaf.getChannel();
|
||||||
|
lockFileLock = lockFileChannel.tryLock();
|
||||||
|
if (lockFileLock == null) {
|
||||||
|
String conflictingApplication = null;
|
||||||
|
try {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
while (lockFileRaf.getFilePointer() < lockFileRaf.length()) {
|
||||||
|
buffer.append(lockFileRaf.readLine() + System.lineSeparator());
|
||||||
|
}
|
||||||
|
conflictingApplication = buffer.toString();
|
||||||
|
} finally {
|
||||||
|
throw new ConcurrentDbAccessException("Unable to acquire lock on " + lockFile, conflictingApplication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception thrown if the database is currently in use.
|
||||||
|
*/
|
||||||
|
private static class ConcurrentDbAccessException extends Exception {
|
||||||
|
private final String conflictingApplicationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param message The exception message.
|
||||||
|
* @param conflictingApplicationName The conflicting application name (or null if unknown).
|
||||||
|
*/
|
||||||
|
public ConcurrentDbAccessException(String message, String conflictingApplicationName) {
|
||||||
|
super(message);
|
||||||
|
this.conflictingApplicationName = conflictingApplicationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The conflicting application name (or null if unknown).
|
||||||
|
*/
|
||||||
|
public String getConflictingApplicationName() {
|
||||||
|
return conflictingApplicationName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new case and makes it the current case.
|
* Creates a new case and makes it the current case.
|
||||||
@ -2725,7 +2783,11 @@ public class Case {
|
|||||||
"Case.progressMessage.creatingCaseDatabase=Creating case database...",
|
"Case.progressMessage.creatingCaseDatabase=Creating case database...",
|
||||||
"# {0} - exception message", "Case.exceptionMessage.couldNotGetDbServerConnectionInfo=Failed to get case database server conneciton info:\n{0}.",
|
"# {0} - exception message", "Case.exceptionMessage.couldNotGetDbServerConnectionInfo=Failed to get case database server conneciton info:\n{0}.",
|
||||||
"# {0} - exception message", "Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}.",
|
"# {0} - exception message", "Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}.",
|
||||||
"# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}."
|
"# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}.",
|
||||||
|
"Case_createCaseDatabase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.",
|
||||||
|
"# {0} - appplicationName",
|
||||||
|
"Case_createCaseDatabase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.",
|
||||||
|
"Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp=another application"
|
||||||
})
|
})
|
||||||
private void createCaseDatabase(ProgressIndicator progressIndicator) throws CaseActionException {
|
private void createCaseDatabase(ProgressIndicator progressIndicator) throws CaseActionException {
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase());
|
progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase());
|
||||||
@ -2736,6 +2798,16 @@ public class Case {
|
|||||||
* with a standard name, physically located in the case
|
* with a standard name, physically located in the case
|
||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
|
try {
|
||||||
|
tryAcquireFileLock(metadata.getCaseDirectory());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_ioException(), ex);
|
||||||
|
} catch (ConcurrentDbAccessException ex) {
|
||||||
|
throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException(
|
||||||
|
StringUtils.defaultIfBlank(ex.getConflictingApplicationName(),
|
||||||
|
Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp())
|
||||||
|
), ex);
|
||||||
|
}
|
||||||
caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME).toString());
|
caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME).toString());
|
||||||
metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
|
metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
|
||||||
} else {
|
} else {
|
||||||
@ -2772,7 +2844,11 @@ public class Case {
|
|||||||
"# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.",
|
"# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.",
|
||||||
"# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.",
|
"# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.",
|
||||||
"Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.",
|
"Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.",
|
||||||
"Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User."
|
"Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User.",
|
||||||
|
"Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.",
|
||||||
|
"# {0} - appplicationName",
|
||||||
|
"Case_openCaseDataBase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.",
|
||||||
|
"Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp=another application"
|
||||||
})
|
})
|
||||||
private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException {
|
private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException {
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_openingCaseDatabase());
|
progressIndicator.progress(Bundle.Case_progressMessage_openingCaseDatabase());
|
||||||
@ -2788,6 +2864,16 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
||||||
|
try {
|
||||||
|
tryAcquireFileLock(metadata.getCaseDirectory());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex);
|
||||||
|
} catch (ConcurrentDbAccessException ex) {
|
||||||
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException(
|
||||||
|
StringUtils.defaultIfBlank(ex.getConflictingApplicationName(),
|
||||||
|
Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp())
|
||||||
|
), ex);
|
||||||
|
}
|
||||||
caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider);
|
caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider);
|
||||||
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
|
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
|
||||||
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
|
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
|
||||||
@ -3098,6 +3184,34 @@ public class Case {
|
|||||||
collaborationMonitor.shutdown();
|
collaborationMonitor.shutdown();
|
||||||
}
|
}
|
||||||
eventPublisher.closeRemoteEventChannel();
|
eventPublisher.closeRemoteEventChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockFileLock != null) {
|
||||||
|
try {
|
||||||
|
this.lockFileLock.close();
|
||||||
|
this.lockFileLock = null;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error closing the lock file lock", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockFileChannel != null) {
|
||||||
|
try {
|
||||||
|
this.lockFileChannel.close();
|
||||||
|
this.lockFileChannel = null;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error closing the lock file channel", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.lockFileRaf != null) {
|
||||||
|
try {
|
||||||
|
this.lockFileRaf.close();
|
||||||
|
this.lockFileRaf = null;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error closing the lock file random access file", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user