1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2026-06-09 22:36:59 -05:00

macOS: recover mounted volume mount points

Prefer hdiutil plist entities that carry a mount-point when recording the virtual device. This fixes APFS images where the first dev-entry is not the mounted volume.

Add a macOS mounted-volume refresh hook that recovers VirtualDevice and MountPoint from hdiutil info when FUSE-T SMB auxiliary metadata is missing or stale.
This commit is contained in:
Mounir IDRASSI
2026-05-15 09:36:29 +02:00
parent d4a237fbaf
commit cd101433c5
4 changed files with 113 additions and 23 deletions
+4 -1
View File
@@ -594,7 +594,7 @@ namespace VeraCrypt
mountedVol->AuxMountPoint = mf.MountPoint; mountedVol->AuxMountPoint = mf.MountPoint;
if (!mountedVol->VirtualDevice.IsEmpty()) if (mountedVol->MountPoint.IsEmpty() && !mountedVol->VirtualDevice.IsEmpty())
{ {
MountedFilesystemList mpl = GetMountedFilesystems (mountedVol->VirtualDevice); MountedFilesystemList mpl = GetMountedFilesystems (mountedVol->VirtualDevice);
@@ -602,6 +602,9 @@ namespace VeraCrypt
mountedVol->MountPoint = mpl.front()->MountPoint; mountedVol->MountPoint = mpl.front()->MountPoint;
} }
if (mountedVol->MountPoint.IsEmpty() || mountedVol->VirtualDevice.IsEmpty())
UpdateMountedVolumeInfo (mountedVol);
volumes.push_back (mountedVol); volumes.push_back (mountedVol);
if (!volumePath.IsEmpty()) if (!volumePath.IsEmpty())
+1
View File
@@ -73,6 +73,7 @@ namespace VeraCrypt
virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const; virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const;
virtual DevicePath MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const; virtual DevicePath MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const;
virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const { throw NotApplicable (SRC_POS); } virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const { throw NotApplicable (SRC_POS); }
virtual void UpdateMountedVolumeInfo (shared_ptr <VolumeInfo> mountedVolume) const { (void) mountedVolume; }
#ifdef TC_LINUX #ifdef TC_LINUX
string DetectFilesystemType (const DevicePath &devicePath) const; string DetectFilesystemType (const DevicePath &devicePath) const;
#endif #endif
+107 -22
View File
@@ -77,6 +77,7 @@ namespace VeraCrypt
static bool ExtractPlistString (const string &xml, const string &key, size_t start, size_t limit, string &value, size_t *endPos = nullptr) static bool ExtractPlistString (const string &xml, const string &key, size_t start, size_t limit, string &value, size_t *endPos = nullptr)
{ {
// hdiutil currently emits simple <key>name</key><string>value</string> pairs. // hdiutil currently emits simple <key>name</key><string>value</string> pairs.
// This lightweight parser assumes the value follows the requested key.
string keyTag = "<key>" + key + "</key>"; string keyTag = "<key>" + key + "</key>";
size_t p = xml.find (keyTag, start); size_t p = xml.find (keyTag, start);
if (p == string::npos || p >= limit) if (p == string::npos || p >= limit)
@@ -124,7 +125,64 @@ namespace VeraCrypt
return normalized; return normalized;
} }
static DevicePath FindVirtualDeviceByImagePath (const string &imagePath) static bool ExtractDiskImageDeviceAndMountPoint (const string &xml, size_t start, size_t limit, DevicePath &device, DirectoryPath &mountPoint)
{
string firstDevice;
string mountedDevice;
string mountedPath;
for (size_t p = start; ; )
{
size_t devKeyPos = xml.find ("<key>dev-entry</key>", p);
if (devKeyPos == string::npos || devKeyPos >= limit)
break;
string devEntry;
size_t devValueEnd = 0;
if (!ExtractPlistString (xml, "dev-entry", devKeyPos, limit, devEntry, &devValueEnd))
{
p = devKeyPos + 1;
continue;
}
devEntry = StringConverter::Trim (devEntry);
if (firstDevice.empty())
firstDevice = devEntry;
size_t nextDevKeyPos = xml.find ("<key>dev-entry</key>", devValueEnd);
if (nextDevKeyPos == string::npos || nextDevKeyPos > limit)
nextDevKeyPos = limit;
string currentMountPoint;
// hdiutil currently emits dev-entry before mount-point inside each entity.
if (ExtractPlistString (xml, "mount-point", devValueEnd, nextDevKeyPos, currentMountPoint)
&& !currentMountPoint.empty())
{
mountedDevice = devEntry;
mountedPath = currentMountPoint;
break;
}
p = devValueEnd;
}
if (!mountedDevice.empty())
{
device = mountedDevice;
mountPoint = mountedPath;
return true;
}
if (!firstDevice.empty())
{
device = firstDevice;
return true;
}
return false;
}
static bool FindDiskImageInfoByImagePath (const string &imagePath, DevicePath &device, DirectoryPath &mountPoint)
{ {
list <string> args; list <string> args;
args.push_back ("info"); args.push_back ("info");
@@ -150,15 +208,13 @@ namespace VeraCrypt
size_t nextImageKeyPos = xml.find ("<key>image-path</key>", imageValueEnd); size_t nextImageKeyPos = xml.find ("<key>image-path</key>", imageValueEnd);
if (NormalizeDiskImagePath (currentImagePath) == normalizedImagePath) if (NormalizeDiskImagePath (currentImagePath) == normalizedImagePath)
{ {
string devEntry; return ExtractDiskImageDeviceAndMountPoint (xml, imageValueEnd, nextImageKeyPos, device, mountPoint);
if (ExtractPlistString (xml, "dev-entry", imageValueEnd, nextImageKeyPos, devEntry))
return StringConverter::Trim (devEntry);
} }
p = imageValueEnd; p = imageValueEnd;
} }
return DevicePath(); return false;
} }
static bool AuxiliaryControlFileHasVirtualDevice (const DirectoryPath &auxMountPoint, const DevicePath &virtualDev, int retryCount = 50) static bool AuxiliaryControlFileHasVirtualDevice (const DirectoryPath &auxMountPoint, const DevicePath &virtualDev, int retryCount = 50)
@@ -198,13 +254,11 @@ namespace VeraCrypt
shared_ptr <VolumeInfo> CoreMacOSX::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) shared_ptr <VolumeInfo> CoreMacOSX::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo)
{ {
if (mountedVolume->VirtualDevice.IsEmpty() && !mountedVolume->AuxMountPoint.IsEmpty()) if (!mountedVolume->AuxMountPoint.IsEmpty())
{ {
try try
{ {
DevicePath recoveredVirtualDevice = FindVirtualDeviceByImagePath (string (mountedVolume->AuxMountPoint) + FuseService::GetVolumeImagePath()); UpdateMountedVolumeInfo (mountedVolume);
if (!recoveredVirtualDevice.IsEmpty())
mountedVolume->VirtualDevice = recoveredVirtualDevice;
} }
catch (...) { } catch (...) { }
} }
@@ -277,6 +331,45 @@ namespace VeraCrypt
return mountedVolume; return mountedVolume;
} }
void CoreMacOSX::UpdateMountedVolumeInfo (shared_ptr <VolumeInfo> mountedVolume) const
{
if (!mountedVolume || mountedVolume->AuxMountPoint.IsEmpty())
return;
try
{
DevicePath recoveredVirtualDevice;
DirectoryPath recoveredMountPoint;
if (FindDiskImageInfoByImagePath (string (mountedVolume->AuxMountPoint) + FuseService::GetVolumeImagePath(), recoveredVirtualDevice, recoveredMountPoint))
{
if (!recoveredVirtualDevice.IsEmpty())
{
if (mountedVolume->VirtualDevice != recoveredVirtualDevice && recoveredMountPoint.IsEmpty())
mountedVolume->MountPoint = DirectoryPath();
mountedVolume->VirtualDevice = recoveredVirtualDevice;
}
if (!recoveredMountPoint.IsEmpty())
mountedVolume->MountPoint = recoveredMountPoint;
}
}
catch (...) { }
if (mountedVolume->MountPoint.IsEmpty() && !mountedVolume->VirtualDevice.IsEmpty())
{
try
{
MountedFilesystemList mountedFilesystems = GetMountedFilesystems (mountedVolume->VirtualDevice);
if (mountedFilesystems.size() > 0)
mountedVolume->MountPoint = mountedFilesystems.front()->MountPoint;
}
catch (...) { }
}
}
void CoreMacOSX::CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const void CoreMacOSX::CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const
{ {
list <string> args; list <string> args;
@@ -378,20 +471,12 @@ namespace VeraCrypt
} }
} }
size_t p = xml.find ("<key>dev-entry</key>"); DevicePath virtualDev;
if (p == string::npos) DirectoryPath mountPoint;
if (!ExtractDiskImageDeviceAndMountPoint (xml, 0, string::npos, virtualDev, mountPoint)
|| virtualDev.IsEmpty())
throw ParameterIncorrect (SRC_POS); throw ParameterIncorrect (SRC_POS);
(void) mountPoint;
p = xml.find ("<string>", p);
if (p == string::npos)
throw ParameterIncorrect (SRC_POS);
p += 8;
size_t e = xml.find ("</string>", p);
if (e == string::npos)
throw ParameterIncorrect (SRC_POS);
DevicePath virtualDev = StringConverter::Trim (xml.substr (p, e - p));
try try
{ {
+1
View File
@@ -30,6 +30,7 @@ namespace VeraCrypt
protected: protected:
virtual DevicePath MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const; virtual DevicePath MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const;
virtual void UpdateMountedVolumeInfo (shared_ptr <VolumeInfo> mountedVolume) const;
private: private:
CoreMacOSX (const CoreMacOSX &); CoreMacOSX (const CoreMacOSX &);