mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-09 14:49:32 +00:00
updates and fixes
This commit is contained in:
parent
7b66af30a5
commit
8ae984831b
@ -110,6 +110,14 @@ Case_caseType_singleUser=Single-user case
|
|||||||
Case_checkImagePaths_exceptionOccurred=An exception occurred while checking if image paths are present
|
Case_checkImagePaths_exceptionOccurred=An exception occurred while checking if image paths are present
|
||||||
# {0} - paths
|
# {0} - paths
|
||||||
Case_checkImagePaths_noPaths=The following images had no associated paths: {0}
|
Case_checkImagePaths_noPaths=The following images had no associated paths: {0}
|
||||||
|
# {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
|
||||||
|
Case_createCaseDatabase_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
|
||||||
|
Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.
|
||||||
CaseDetailsPanel.casePanel.border.title=Case
|
CaseDetailsPanel.casePanel.border.title=Case
|
||||||
CaseDetailsPanel.examinerLabel.text=Name:
|
CaseDetailsPanel.examinerLabel.text=Name:
|
||||||
CaseDetailsPanel.examinerPanel.border.title=Examiner
|
CaseDetailsPanel.examinerPanel.border.title=Examiner
|
||||||
|
@ -32,8 +32,8 @@ 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.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.nio.channels.OverlappingFileLockException;
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@ -78,6 +78,7 @@ import org.sleuthkit.autopsy.actions.OpenOutputFolderAction;
|
|||||||
import org.sleuthkit.autopsy.appservices.AutopsyService;
|
import org.sleuthkit.autopsy.appservices.AutopsyService;
|
||||||
import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext;
|
import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException;
|
import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.TskLockResources.ConcurrentDbAccessException;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.ui.DataSourceSummaryAction;
|
import org.sleuthkit.autopsy.datasourcesummary.ui.DataSourceSummaryAction;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
|
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
|
||||||
@ -183,7 +184,6 @@ 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();
|
||||||
@ -200,10 +200,7 @@ public class Case {
|
|||||||
private CollaborationMonitor collaborationMonitor;
|
private CollaborationMonitor collaborationMonitor;
|
||||||
private Services caseServices;
|
private Services caseServices;
|
||||||
|
|
||||||
private RansomAccessFile lockFileRaf = null;
|
private TskLockResources tskLockResources = 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;
|
||||||
|
|
||||||
@ -218,6 +215,7 @@ public class Case {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enumeration of case types.
|
* An enumeration of case types.
|
||||||
*/
|
*/
|
||||||
@ -778,59 +776,6 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lockFileRaf.setLength(0);
|
|
||||||
lockFileRaf.writeChars(APP_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
@ -2802,13 +2747,13 @@ public class Case {
|
|||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
tryAcquireFileLock(metadata.getCaseDirectory());
|
this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName());
|
||||||
} catch (IOException ex) {
|
} catch (IOException | OverlappingFileLockException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_ioException(), ex);
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex);
|
||||||
} catch (ConcurrentDbAccessException ex) {
|
} catch (ConcurrentDbAccessException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException(
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException(
|
||||||
StringUtils.defaultIfBlank(ex.getConflictingApplicationName(),
|
StringUtils.defaultIfBlank(ex.getConflictingApplicationName(),
|
||||||
Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp())
|
Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp())
|
||||||
), ex);
|
), 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());
|
||||||
@ -2868,8 +2813,8 @@ public class Case {
|
|||||||
|
|
||||||
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
||||||
try {
|
try {
|
||||||
tryAcquireFileLock(metadata.getCaseDirectory());
|
this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName());
|
||||||
} catch (IOException ex) {
|
} catch (IOException | OverlappingFileLockException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex);
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex);
|
||||||
} catch (ConcurrentDbAccessException ex) {
|
} catch (ConcurrentDbAccessException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException(
|
throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException(
|
||||||
@ -3189,31 +3134,12 @@ public class Case {
|
|||||||
eventPublisher.closeRemoteEventChannel();
|
eventPublisher.closeRemoteEventChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.lockFileLock != null) {
|
if (this.tskLockResources != null) {
|
||||||
try {
|
try {
|
||||||
this.lockFileLock.close();
|
this.tskLockResources.close();
|
||||||
this.lockFileLock = null;
|
this.tskLockResources = null;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.log(Level.WARNING, "There was an error closing the lock file lock", ex);
|
logger.log(Level.WARNING, "There was an error closing the TSK case lock resources", 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
162
Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java
Normal file
162
Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2024 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.casemodule;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.nio.channels.OverlappingFileLockException;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resources associated with the file lock for the TSK database.
|
||||||
|
*/
|
||||||
|
class TskLockResources implements AutoCloseable {
|
||||||
|
|
||||||
|
private static final String LOCK_FILE_NAME = "lock";
|
||||||
|
|
||||||
|
private File lockFile = null;
|
||||||
|
private RandomAccessFile lockFileRaf = null;
|
||||||
|
private FileChannel lockFileChannel = null;
|
||||||
|
private FileLock lockFileLock = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param lockFile The lock file File reference.
|
||||||
|
* @param lockFileRef The lock file random access file reference.
|
||||||
|
* @param lockFileChannel The lock file file channel.
|
||||||
|
* @param lockFileLock The lock file file lock.
|
||||||
|
*/
|
||||||
|
TskLockResources(File lockFile, RandomAccessFile lockFileRaf, FileChannel lockFileChannel, FileLock lockFileLock) {
|
||||||
|
this.lockFile = lockFile;
|
||||||
|
this.lockFileRaf = lockFileRaf;
|
||||||
|
this.lockFileChannel = lockFileChannel;
|
||||||
|
this.lockFileLock = lockFileLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to acquire a lock to the lock file in the case directory.
|
||||||
|
*
|
||||||
|
* @param caseDir The case directory that the autopsy.db is in.
|
||||||
|
* @return The lock file resources to be closed.
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static TskLockResources tryAcquireFileLock(String caseDir, String applicationName) throws ConcurrentDbAccessException, IOException, OverlappingFileLockException {
|
||||||
|
// get the lock file path
|
||||||
|
File lockFile = new File(caseDir, LOCK_FILE_NAME);
|
||||||
|
// make directories leading up to that
|
||||||
|
lockFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
// if the lock file exists
|
||||||
|
if (lockFile.isFile() && !lockFile.canWrite()) {
|
||||||
|
// get the random access file as read only
|
||||||
|
RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "r");
|
||||||
|
throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf);
|
||||||
|
} else {
|
||||||
|
RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "rw");
|
||||||
|
FileChannel lockFileChannel = lockFileRaf.getChannel();
|
||||||
|
FileLock lockFileLock = lockFileChannel == null
|
||||||
|
? null
|
||||||
|
: lockFileChannel.tryLock(1024L, 1L, false);
|
||||||
|
|
||||||
|
if (lockFileLock != null) {
|
||||||
|
lockFileRaf.setLength(0);
|
||||||
|
lockFileRaf.writeChars(applicationName);
|
||||||
|
return new TskLockResources(lockFile, lockFileRaf, lockFileChannel, lockFileLock);
|
||||||
|
} else {
|
||||||
|
throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
// close lock file resources in reverse acquisition order
|
||||||
|
if (this.lockFileLock != null) {
|
||||||
|
this.lockFileLock.close();
|
||||||
|
this.lockFileLock = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockFileChannel != null) {
|
||||||
|
this.lockFileChannel.close();
|
||||||
|
this.lockFileChannel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockFileRaf != null) {
|
||||||
|
this.lockFileRaf.close();
|
||||||
|
this.lockFileRaf = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockFile != null) {
|
||||||
|
this.lockFile.delete();
|
||||||
|
this.lockFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception thrown if the database is currently in use.
|
||||||
|
*/
|
||||||
|
static class ConcurrentDbAccessException extends Exception {
|
||||||
|
|
||||||
|
private final String conflictingApplicationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ConcurrentDbAccessException from the lock file path and the
|
||||||
|
* random access file of that path whose contents are the application
|
||||||
|
* name.
|
||||||
|
*
|
||||||
|
* @param lockFilePath The lock file path.
|
||||||
|
* @param lockFileRaf The lock file random access file.
|
||||||
|
* @return The exception
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static ConcurrentDbAccessException createForFile(String lockFilePath, RandomAccessFile lockFileRaf) throws IOException {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
while (lockFileRaf.getFilePointer() < lockFileRaf.length()) {
|
||||||
|
buffer.append(lockFileRaf.readLine() + System.lineSeparator());
|
||||||
|
}
|
||||||
|
String conflictingApplication = buffer.toString().trim();
|
||||||
|
String message = "Unable to acquire lock on " + lockFilePath + "." + (StringUtils.isNotBlank(conflictingApplication) ? (" Database is already open in " + conflictingApplication + ".") : "");
|
||||||
|
return new ConcurrentDbAccessException(message, conflictingApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param message The exception message.
|
||||||
|
* @param conflictingApplicationName The conflicting application name
|
||||||
|
* (or null if unknown).
|
||||||
|
*/
|
||||||
|
ConcurrentDbAccessException(String message, String conflictingApplicationName) {
|
||||||
|
super(message);
|
||||||
|
this.conflictingApplicationName = conflictingApplicationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The conflicting application name (or null if unknown).
|
||||||
|
*/
|
||||||
|
public String getConflictingApplicationName() {
|
||||||
|
return conflictingApplicationName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user