mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-06-19 02:56:07 -05:00
Linux: add emergency cleanup for stale unmounts
When normal filesystem unmount fails, the Linux path could stop before cleaning VeraCrypt mapper, loop and FUSE objects. Add an explicit emergency dismount request that is only reached after interactive confirmation. The recovery path lazy-detaches mounted filesystems, uses deferred dmsetup removal for VeraCrypt mapper devices, detaches loop devices, and keeps normal force/ignoreOpenFiles behavior unchanged.
This commit is contained in:
@@ -40,6 +40,9 @@ namespace VeraCrypt
|
||||
virtual void CreateKeyfile (const FilePath &keyfilePath) const;
|
||||
virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const = 0;
|
||||
virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false) = 0;
|
||||
#if defined(TC_LINUX)
|
||||
virtual shared_ptr <VolumeInfo> EmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume) { throw NotApplicable (SRC_POS); }
|
||||
#endif
|
||||
virtual bool FilesystemSupportsLargeFiles (const FilePath &filePath) const = 0;
|
||||
virtual DirectoryPath GetDeviceMountPoint (const DevicePath &devicePath) const = 0;
|
||||
virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const = 0;
|
||||
|
||||
@@ -25,6 +25,16 @@ namespace VeraCrypt
|
||||
ExecutedProcessFailed::Serialize (stream);
|
||||
}
|
||||
|
||||
void FilesystemDismountFailed::Deserialize (shared_ptr <Stream> stream)
|
||||
{
|
||||
ExecutedProcessFailed::Deserialize (stream);
|
||||
}
|
||||
|
||||
void FilesystemDismountFailed::Serialize (shared_ptr <Stream> stream) const
|
||||
{
|
||||
ExecutedProcessFailed::Serialize (stream);
|
||||
}
|
||||
|
||||
#define TC_EXCEPTION(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)
|
||||
#undef TC_EXCEPTION_NODECL
|
||||
#define TC_EXCEPTION_NODECL(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)
|
||||
|
||||
@@ -25,6 +25,16 @@ namespace VeraCrypt
|
||||
TC_SERIALIZABLE_EXCEPTION (ElevationFailed);
|
||||
};
|
||||
|
||||
struct FilesystemDismountFailed : public ExecutedProcessFailed
|
||||
{
|
||||
FilesystemDismountFailed () { }
|
||||
FilesystemDismountFailed (const string &message, const string &command, int exitCode, const string &errorOutput)
|
||||
: ExecutedProcessFailed (message, command, exitCode, errorOutput) { }
|
||||
FilesystemDismountFailed (const ExecutedProcessFailed &ex)
|
||||
: ExecutedProcessFailed (ex.what(), ex.GetCommand(), static_cast <int> (ex.GetExitCode()), ex.GetErrorOutput()) { }
|
||||
TC_SERIALIZABLE_EXCEPTION (FilesystemDismountFailed);
|
||||
};
|
||||
|
||||
TC_EXCEPTION_DECL (RootDeviceUnavailable, SystemException);
|
||||
|
||||
#define TC_EXCEPTION(NAME) TC_EXCEPTION_DECL(NAME,Exception)
|
||||
@@ -32,6 +42,7 @@ namespace VeraCrypt
|
||||
#undef TC_EXCEPTION_SET
|
||||
#define TC_EXCEPTION_SET \
|
||||
TC_EXCEPTION_NODECL (ElevationFailed); \
|
||||
TC_EXCEPTION_NODECL (FilesystemDismountFailed); \
|
||||
TC_EXCEPTION_NODECL (RootDeviceUnavailable); \
|
||||
TC_EXCEPTION (DriveLetterUnavailable); \
|
||||
TC_EXCEPTION (DriverError); \
|
||||
|
||||
@@ -159,6 +159,18 @@ namespace VeraCrypt
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
// EmergencyDismountVolumeRequest
|
||||
EmergencyDismountVolumeRequest *emergencyDismountRequest = dynamic_cast <EmergencyDismountVolumeRequest*> (request.get());
|
||||
if (emergencyDismountRequest)
|
||||
{
|
||||
DismountVolumeResponse response;
|
||||
response.DismountedVolumeInfo = Core->EmergencyDismountVolume (emergencyDismountRequest->MountedVolumeInfo);
|
||||
response.Serialize (outputStream);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// GetDeviceSectorSizeRequest
|
||||
GetDeviceSectorSizeRequest *getDeviceSectorSizeRequest = dynamic_cast <GetDeviceSectorSizeRequest*> (request.get());
|
||||
if (getDeviceSectorSizeRequest)
|
||||
@@ -252,6 +264,14 @@ namespace VeraCrypt
|
||||
return SendRequest <DismountVolumeResponse> (request)->DismountedVolumeInfo;
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
shared_ptr <VolumeInfo> CoreService::RequestEmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume)
|
||||
{
|
||||
EmergencyDismountVolumeRequest request (mountedVolume);
|
||||
return SendRequest <DismountVolumeResponse> (request)->DismountedVolumeInfo;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32 CoreService::RequestGetDeviceSectorSize (const DevicePath &devicePath)
|
||||
{
|
||||
GetDeviceSectorSizeRequest request (devicePath);
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace VeraCrypt
|
||||
static void RequestCheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair);
|
||||
static void RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force);
|
||||
static shared_ptr <VolumeInfo> RequestDismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false);
|
||||
#ifdef TC_LINUX
|
||||
static shared_ptr <VolumeInfo> RequestEmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume);
|
||||
#endif
|
||||
static uint32 RequestGetDeviceSectorSize (const DevicePath &devicePath);
|
||||
static uint64 RequestGetDeviceSize (const DevicePath &devicePath);
|
||||
static HostDeviceList RequestGetHostDevices (bool pathListOnly);
|
||||
|
||||
@@ -45,6 +45,18 @@ namespace VeraCrypt
|
||||
return dismountedVolumeInfo;
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
virtual shared_ptr <VolumeInfo> EmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume)
|
||||
{
|
||||
shared_ptr <VolumeInfo> dismountedVolumeInfo = CoreService::RequestEmergencyDismountVolume (mountedVolume);
|
||||
|
||||
VolumeEventArgs eventArgs (dismountedVolumeInfo);
|
||||
T::VolumeDismountedEvent.Raise (eventArgs);
|
||||
|
||||
return dismountedVolumeInfo;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const
|
||||
{
|
||||
return CoreService::RequestGetDeviceSectorSize (devicePath);
|
||||
|
||||
@@ -128,6 +128,26 @@ namespace VeraCrypt
|
||||
MountedVolumeInfo->Serialize (stream);
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
// EmergencyDismountVolumeRequest
|
||||
void EmergencyDismountVolumeRequest::Deserialize (shared_ptr <Stream> stream)
|
||||
{
|
||||
CoreServiceRequest::Deserialize (stream);
|
||||
MountedVolumeInfo = Serializable::DeserializeNew <VolumeInfo> (stream);
|
||||
}
|
||||
|
||||
bool EmergencyDismountVolumeRequest::RequiresElevation () const
|
||||
{
|
||||
return !Core->HasAdminPrivileges();
|
||||
}
|
||||
|
||||
void EmergencyDismountVolumeRequest::Serialize (shared_ptr <Stream> stream) const
|
||||
{
|
||||
CoreServiceRequest::Serialize (stream);
|
||||
MountedVolumeInfo->Serialize (stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
// GetDeviceSectorSizeRequest
|
||||
void GetDeviceSectorSizeRequest::Deserialize (shared_ptr <Stream> stream)
|
||||
{
|
||||
@@ -270,6 +290,9 @@ namespace VeraCrypt
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (CheckFilesystemRequest);
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (DismountFilesystemRequest);
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (DismountVolumeRequest);
|
||||
#ifdef TC_LINUX
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (EmergencyDismountVolumeRequest);
|
||||
#endif
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (ExitRequest);
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeRequest);
|
||||
TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeRequest);
|
||||
|
||||
@@ -74,6 +74,20 @@ namespace VeraCrypt
|
||||
bool SyncVolumeInfo;
|
||||
};
|
||||
|
||||
#ifdef TC_LINUX
|
||||
struct EmergencyDismountVolumeRequest : CoreServiceRequest
|
||||
{
|
||||
EmergencyDismountVolumeRequest () { }
|
||||
EmergencyDismountVolumeRequest (shared_ptr <VolumeInfo> volumeInfo)
|
||||
: MountedVolumeInfo (volumeInfo) { }
|
||||
TC_SERIALIZABLE (EmergencyDismountVolumeRequest);
|
||||
|
||||
virtual bool RequiresElevation () const;
|
||||
|
||||
shared_ptr <VolumeInfo> MountedVolumeInfo;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct GetDeviceSectorSizeRequest : CoreServiceRequest
|
||||
{
|
||||
GetDeviceSectorSizeRequest () { }
|
||||
|
||||
+178
-1
@@ -163,11 +163,34 @@ namespace VeraCrypt
|
||||
Process::Execute ("umount", args);
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
void CoreUnix::DismountFilesystemLazy (const DirectoryPath &mountPoint) const
|
||||
{
|
||||
list <string> args;
|
||||
args.push_back ("-l");
|
||||
args.push_back ("--");
|
||||
args.push_back (mountPoint);
|
||||
|
||||
Process::Execute ("umount", args);
|
||||
}
|
||||
#endif
|
||||
|
||||
shared_ptr <VolumeInfo> CoreUnix::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo)
|
||||
{
|
||||
if (!mountedVolume->MountPoint.IsEmpty())
|
||||
{
|
||||
#ifdef TC_LINUX
|
||||
try
|
||||
{
|
||||
DismountFilesystem (mountedVolume->MountPoint, ignoreOpenFiles);
|
||||
}
|
||||
catch (ExecutedProcessFailed &e)
|
||||
{
|
||||
throw FilesystemDismountFailed (e);
|
||||
}
|
||||
#else
|
||||
DismountFilesystem (mountedVolume->MountPoint, ignoreOpenFiles);
|
||||
#endif
|
||||
|
||||
// Delete mount directory if a default path has been used
|
||||
if (string (mountedVolume->MountPoint).find (GetDefaultMountPointPrefix()) == 0)
|
||||
@@ -178,6 +201,12 @@ namespace VeraCrypt
|
||||
{
|
||||
DismountNativeVolume (mountedVolume);
|
||||
}
|
||||
#ifdef TC_LINUX
|
||||
catch (ExecutedProcessFailed &e)
|
||||
{
|
||||
throw FilesystemDismountFailed (e);
|
||||
}
|
||||
#endif
|
||||
catch (NotApplicable &) { }
|
||||
|
||||
if (!mountedVolume->LoopDevice.IsEmpty())
|
||||
@@ -209,10 +238,14 @@ namespace VeraCrypt
|
||||
Process::Execute ("umount", args);
|
||||
break;
|
||||
}
|
||||
catch (ExecutedProcessFailed&)
|
||||
catch (ExecutedProcessFailed &e)
|
||||
{
|
||||
if (t > 10)
|
||||
#ifdef TC_LINUX
|
||||
throw FilesystemDismountFailed (e);
|
||||
#else
|
||||
throw;
|
||||
#endif
|
||||
Thread::Sleep (200);
|
||||
}
|
||||
}
|
||||
@@ -229,6 +262,150 @@ namespace VeraCrypt
|
||||
return mountedVolume;
|
||||
}
|
||||
|
||||
#ifdef TC_LINUX
|
||||
shared_ptr <VolumeInfo> CoreUnix::EmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume)
|
||||
{
|
||||
unique_ptr <Exception> firstException;
|
||||
|
||||
if (!mountedVolume->MountPoint.IsEmpty())
|
||||
{
|
||||
bool mountPointMounted = true;
|
||||
bool mountPointDetached = false;
|
||||
|
||||
try
|
||||
{
|
||||
mountPointMounted = !GetMountedFilesystems (DevicePath(), mountedVolume->MountPoint).empty();
|
||||
}
|
||||
catch (...) { }
|
||||
|
||||
if (mountPointMounted)
|
||||
{
|
||||
try
|
||||
{
|
||||
DismountFilesystemLazy (mountedVolume->MountPoint);
|
||||
mountPointDetached = true;
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
if (!firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
}
|
||||
|
||||
if ((!mountPointMounted || mountPointDetached) && string (mountedVolume->MountPoint).find (GetDefaultMountPointPrefix()) == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
mountedVolume->MountPoint.Delete();
|
||||
}
|
||||
catch (...) { }
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DismountNativeVolumeDeferred (mountedVolume);
|
||||
}
|
||||
catch (NotApplicable&) { }
|
||||
catch (Exception &e)
|
||||
{
|
||||
if (!firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
|
||||
if (!mountedVolume->LoopDevice.IsEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
DetachLoopDevice (mountedVolume->LoopDevice);
|
||||
}
|
||||
catch (ExecutedProcessFailed &e)
|
||||
{
|
||||
if (IsLoopDeviceAttached (mountedVolume->LoopDevice) && !firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
if (!firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
}
|
||||
|
||||
if (!mountedVolume->AuxMountPoint.IsEmpty())
|
||||
{
|
||||
bool auxMountPointMounted = true;
|
||||
bool auxMountPointDetached = false;
|
||||
|
||||
try
|
||||
{
|
||||
auxMountPointMounted = !GetMountedFilesystems (DevicePath(), mountedVolume->AuxMountPoint).empty();
|
||||
}
|
||||
catch (...) { }
|
||||
|
||||
if (auxMountPointMounted)
|
||||
{
|
||||
list <string> args;
|
||||
args.push_back ("--");
|
||||
args.push_back (mountedVolume->AuxMountPoint);
|
||||
|
||||
try
|
||||
{
|
||||
for (int t = 0; true; t++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process::Execute ("umount", args);
|
||||
auxMountPointDetached = true;
|
||||
break;
|
||||
}
|
||||
catch (ExecutedProcessFailed&)
|
||||
{
|
||||
if (t > 10)
|
||||
throw;
|
||||
Thread::Sleep (200);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ExecutedProcessFailed&)
|
||||
{
|
||||
try
|
||||
{
|
||||
DismountFilesystemLazy (mountedVolume->AuxMountPoint);
|
||||
auxMountPointDetached = true;
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
if (!firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
if (!firstException.get())
|
||||
firstException.reset (e.CloneNew());
|
||||
}
|
||||
}
|
||||
|
||||
if (!auxMountPointMounted || auxMountPointDetached)
|
||||
{
|
||||
try
|
||||
{
|
||||
mountedVolume->AuxMountPoint.Delete();
|
||||
}
|
||||
catch (...) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (firstException.get())
|
||||
firstException->Throw();
|
||||
|
||||
VolumeEventArgs eventArgs (mountedVolume);
|
||||
VolumeDismountedEvent.Raise (eventArgs);
|
||||
|
||||
return mountedVolume;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CoreUnix::FilesystemSupportsLargeFiles (const FilePath &filePath) const
|
||||
{
|
||||
string path = filePath;
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace VeraCrypt
|
||||
virtual void CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair = false) const;
|
||||
virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const;
|
||||
virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false);
|
||||
#ifdef TC_LINUX
|
||||
virtual shared_ptr <VolumeInfo> EmergencyDismountVolume (shared_ptr <VolumeInfo> mountedVolume);
|
||||
#endif
|
||||
virtual bool FilesystemSupportsLargeFiles (const FilePath &filePath) const;
|
||||
virtual DirectoryPath GetDeviceMountPoint (const DevicePath &devicePath) const;
|
||||
virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const;
|
||||
@@ -55,6 +58,11 @@ namespace VeraCrypt
|
||||
virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const { throw NotApplicable (SRC_POS); }
|
||||
virtual void DetachLoopDevice (const DevicePath &devicePath) const { throw NotApplicable (SRC_POS); }
|
||||
virtual void DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const { throw NotApplicable (SRC_POS); }
|
||||
#ifdef TC_LINUX
|
||||
virtual void DismountFilesystemLazy (const DirectoryPath &mountPoint) const;
|
||||
virtual void DismountNativeVolumeDeferred (shared_ptr <VolumeInfo> mountedVolume) const { DismountNativeVolume (mountedVolume); }
|
||||
virtual bool IsLoopDeviceAttached (const DevicePath &devicePath) const { return devicePath.IsBlockDevice(); }
|
||||
#endif
|
||||
virtual bool FilesystemSupportsUnixPermissions (const DevicePath &devicePath) const;
|
||||
virtual string GetDefaultMountPointPrefix () const;
|
||||
virtual string GetFuseMountDirPrefix () const { return ".veracrypt_aux_mnt"; }
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
code distribution packages.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <mntent.h>
|
||||
@@ -17,6 +18,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
#include "CoreLinux.h"
|
||||
#include "Platform/SystemInfo.h"
|
||||
@@ -126,45 +129,215 @@ namespace VeraCrypt
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreLinux::IsLoopDeviceAttached (const DevicePath &devicePath) const
|
||||
{
|
||||
struct stat statData;
|
||||
if (stat (string (devicePath).c_str(), &statData) != 0 || !S_ISBLK (statData.st_mode))
|
||||
return false;
|
||||
|
||||
stringstream sysDevicePath;
|
||||
sysDevicePath << "/sys/dev/block/" << major (statData.st_rdev) << ":" << minor (statData.st_rdev);
|
||||
|
||||
if (FilesystemPath (sysDevicePath.str() + "/loop").IsDirectory())
|
||||
return true;
|
||||
|
||||
list <string> args;
|
||||
args.push_back (devicePath);
|
||||
|
||||
try
|
||||
{
|
||||
Process::Execute ("losetup", args);
|
||||
return true;
|
||||
}
|
||||
catch (ExecutedProcessFailed&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...) { }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreLinux::DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const
|
||||
{
|
||||
DismountNativeVolumeInternal (mountedVolume, false);
|
||||
}
|
||||
|
||||
void CoreLinux::DismountNativeVolumeDeferred (shared_ptr <VolumeInfo> mountedVolume) const
|
||||
{
|
||||
DismountNativeVolumeInternal (mountedVolume, true);
|
||||
}
|
||||
|
||||
void CoreLinux::DismountNativeVolumeInternal (shared_ptr <VolumeInfo> mountedVolume, bool deferred) const
|
||||
{
|
||||
string devPath = mountedVolume->VirtualDevice;
|
||||
const string virtualDevice = devPath;
|
||||
|
||||
if (devPath.find ("/dev/mapper/veracrypt") != 0)
|
||||
throw NotApplicable (SRC_POS);
|
||||
|
||||
size_t devCount = 0;
|
||||
while (FilesystemPath (devPath).IsBlockDevice())
|
||||
// Deferred cleanup can follow a partial normal cleanup that removed an earlier mapper.
|
||||
// Keep probing the suffixes VeraCrypt creates for cascade layers.
|
||||
size_t maxDeviceMapperDeviceCount = 1;
|
||||
if (deferred)
|
||||
{
|
||||
foreach (shared_ptr <EncryptionAlgorithm> ea, EncryptionAlgorithm::GetAvailableAlgorithms())
|
||||
{
|
||||
size_t cipherCount = ea->GetCiphers().size();
|
||||
if (cipherCount > maxDeviceMapperDeviceCount)
|
||||
maxDeviceMapperDeviceCount = cipherCount;
|
||||
}
|
||||
}
|
||||
|
||||
size_t devCount = 0;
|
||||
while (true)
|
||||
{
|
||||
string deviceMapperName = StringConverter::Split (devPath, "/").back();
|
||||
bool devicePresent = deferred ? IsDeviceMapperDevicePresent (deviceMapperName) : FilesystemPath (devPath).IsBlockDevice();
|
||||
|
||||
if (!devicePresent)
|
||||
{
|
||||
if (deferred && devCount < maxDeviceMapperDeviceCount - 1)
|
||||
{
|
||||
devPath = virtualDevice + "_" + StringConverter::ToSingle (devCount++);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
list <string> dmsetupArgs;
|
||||
dmsetupArgs.push_back ("remove");
|
||||
dmsetupArgs.push_back (StringConverter::Split (devPath, "/").back());
|
||||
if (deferred)
|
||||
{
|
||||
dmsetupArgs.push_back ("--retry");
|
||||
dmsetupArgs.push_back ("--deferred");
|
||||
}
|
||||
dmsetupArgs.push_back (deviceMapperName);
|
||||
|
||||
for (int t = 0; true; t++)
|
||||
if (deferred)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process::Execute ("dmsetup", dmsetupArgs);
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
catch (ExecutedProcessFailed&)
|
||||
{
|
||||
if (t > 20)
|
||||
throw;
|
||||
if (IsDeviceMapperDevicePresent (deviceMapperName))
|
||||
{
|
||||
list <string> deferredFallbackArgs;
|
||||
deferredFallbackArgs.push_back ("remove");
|
||||
deferredFallbackArgs.push_back ("--deferred");
|
||||
deferredFallbackArgs.push_back (deviceMapperName);
|
||||
|
||||
Thread::Sleep (100);
|
||||
try
|
||||
{
|
||||
Process::Execute ("dmsetup", deferredFallbackArgs);
|
||||
}
|
||||
catch (ExecutedProcessFailed&)
|
||||
{
|
||||
if (IsDeviceMapperDevicePresent (deviceMapperName))
|
||||
{
|
||||
list <string> fallbackArgs;
|
||||
fallbackArgs.push_back ("remove");
|
||||
fallbackArgs.push_back (deviceMapperName);
|
||||
|
||||
for (int t = 0; true; t++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process::Execute ("dmsetup", fallbackArgs);
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (!IsDeviceMapperDevicePresent (deviceMapperName))
|
||||
break;
|
||||
|
||||
if (t > 20)
|
||||
throw;
|
||||
|
||||
Thread::Sleep (100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int t = 0; true; t++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process::Execute ("dmsetup", dmsetupArgs);
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (t > 20)
|
||||
throw;
|
||||
|
||||
Thread::Sleep (100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int t = 0; FilesystemPath (devPath).IsBlockDevice() && t < 20; t++)
|
||||
for (int t = 0; t < 20; t++)
|
||||
{
|
||||
if (deferred)
|
||||
{
|
||||
if (!IsDeviceMapperDevicePresent (deviceMapperName))
|
||||
break;
|
||||
}
|
||||
else if (!FilesystemPath (devPath).IsBlockDevice())
|
||||
break;
|
||||
|
||||
Thread::Sleep (100);
|
||||
}
|
||||
|
||||
devPath = string (mountedVolume->VirtualDevice) + "_" + StringConverter::ToSingle (devCount++);
|
||||
if (deferred && devCount >= maxDeviceMapperDeviceCount - 1)
|
||||
break;
|
||||
|
||||
devPath = virtualDevice + "_" + StringConverter::ToSingle (devCount++);
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreLinux::IsDeviceMapperDevicePresent (const string &deviceMapperName) const
|
||||
{
|
||||
if (deviceMapperName.empty())
|
||||
return false;
|
||||
|
||||
DIR *sysBlockDir = opendir ("/sys/block");
|
||||
if (!sysBlockDir)
|
||||
return FilesystemPath ("/dev/mapper/" + deviceMapperName).IsBlockDevice();
|
||||
|
||||
bool present = false;
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir (sysBlockDir)) != nullptr)
|
||||
{
|
||||
string blockDeviceName = entry->d_name;
|
||||
if (blockDeviceName.find ("dm-") != 0)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
TextReader tr ("/sys/block/" + blockDeviceName + "/dm/name");
|
||||
string name;
|
||||
if (tr.ReadLine (name) && name == deviceMapperName)
|
||||
{
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...) { }
|
||||
}
|
||||
|
||||
closedir (sysBlockDir);
|
||||
return present;
|
||||
}
|
||||
|
||||
HostDeviceList CoreLinux::GetHostDevices (bool pathListOnly) const
|
||||
{
|
||||
HostDeviceList devices;
|
||||
|
||||
@@ -30,11 +30,16 @@ namespace VeraCrypt
|
||||
virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const;
|
||||
virtual void DetachLoopDevice (const DevicePath &devicePath) const;
|
||||
virtual void DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const;
|
||||
virtual void DismountNativeVolumeDeferred (shared_ptr <VolumeInfo> mountedVolume) const;
|
||||
virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const;
|
||||
virtual bool IsLoopDeviceAttached (const DevicePath &devicePath) const;
|
||||
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
|
||||
virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const;
|
||||
|
||||
private:
|
||||
void DismountNativeVolumeInternal (shared_ptr <VolumeInfo> mountedVolume, bool deferred) const;
|
||||
bool IsDeviceMapperDevicePresent (const string &deviceMapperName) const;
|
||||
|
||||
CoreLinux (const CoreLinux &);
|
||||
CoreLinux &operator= (const CoreLinux &);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user