diff options
Diffstat (limited to 'src/VBox/Main/src-server/HostDriveImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-server/HostDriveImpl.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/HostDriveImpl.cpp b/src/VBox/Main/src-server/HostDriveImpl.cpp new file mode 100644 index 00000000..10b06d3f --- /dev/null +++ b/src/VBox/Main/src-server/HostDriveImpl.cpp @@ -0,0 +1,273 @@ +/* $Id: HostDriveImpl.cpp $ */ +/** @file + * VirtualBox Main - IHostDrive implementation, VBoxSVC. + */ + +/* + * Copyright (C) 2013-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_MAIN_HOSTDRIVE +#include "Global.h" +#include "HostDriveImpl.h" +#include "HostDrivePartitionImpl.h" +#include "LoggingNew.h" +#include "VirtualBoxImpl.h" + +#include <iprt/dvm.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/path.h> +#include <iprt/vfs.h> +#include <VBox/com/Guid.h> + + +/* + * HostDrive implementation. + */ +DEFINE_EMPTY_CTOR_DTOR(HostDrive) + +HRESULT HostDrive::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void HostDrive::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + +/** + * Initializes the instance. + */ +HRESULT HostDrive::initFromPathAndModel(const com::Utf8Str &drivePath, const com::Utf8Str &driveModel) +{ + LogFlowThisFunc(("\n")); + + AssertReturn(!drivePath.isEmpty(), E_INVALIDARG); + + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + m.partitioningType = PartitioningType_MBR; + m.drivePath = drivePath; + m.model = driveModel; + m.partitions.clear(); + + /* + * Try open the drive so we can extract futher details, + * like the size, sector size and partitions. + */ + HRESULT hrc = E_FAIL; + RTFILE hRawFile = NIL_RTFILE; + int vrc = RTFileOpen(&hRawFile, drivePath.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); + if (RT_SUCCESS(vrc)) + { + vrc = RTFileQuerySize(hRawFile, &m.cbDisk); + int vrc2 = RTFileQuerySectorSize(hRawFile, &m.cbSector); + if (RT_FAILURE(vrc2)) + vrc = vrc2; + if (RT_SUCCESS(vrc)) + { + /* + * Hand it to DVM. + */ + RTVFSFILE hVfsFile = NIL_RTVFSFILE; + vrc = RTVfsFileFromRTFile(hRawFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE /*fOpen*/, + true /*fLeaveOpen*/, &hVfsFile); + if (RT_SUCCESS(vrc)) + { + RTDVM hVolMgr = NIL_RTDVM; + vrc = RTDvmCreate(&hVolMgr, hVfsFile, m.cbSector, 0 /*fFlags*/); + if (RT_SUCCESS(vrc)) + { + vrc = RTDvmMapOpen(hVolMgr); + if (RT_SUCCESS(vrc)) + { + hrc = S_OK; + + /* + * Get details. + */ + switch (RTDvmMapGetFormatType(hVolMgr)) + { + case RTDVMFORMATTYPE_GPT: + m.partitioningType = PartitioningType_GPT; + break; + case RTDVMFORMATTYPE_MBR: + m.partitioningType = PartitioningType_MBR; + break; + case RTDVMFORMATTYPE_BSD_LABEL: + AssertMsgFailed(("TODO\n")); + break; + default: + AssertFailed(); + } + + RTUUID Uuid = RTUUID_INITIALIZE_NULL; + if (RT_SUCCESS(RTDvmMapQueryDiskUuid(hVolMgr, &Uuid))) + m.uuid = Uuid; + + /* + * Enumerate volumes and tuck them into the partitions list.. + */ + uint32_t const cVolumes = RTDvmMapGetValidVolumes(hVolMgr); + RTDVMVOLUME hVol = NIL_RTDVMVOLUME; + for (uint32_t i = 0; i < cVolumes; i++) + { + /* Enumeration cruft: */ + RTDVMVOLUME hVolNext = NIL_RTDVMVOLUME; + if (i == 0) + vrc = RTDvmMapQueryFirstVolume(hVolMgr, &hVolNext); + else + vrc = RTDvmMapQueryNextVolume(hVolMgr, hVol, &hVolNext); + AssertRCBreakStmt(vrc, hrc = Global::vboxStatusCodeToCOM(vrc)); + + uint32_t cRefs = RTDvmVolumeRelease(hVol); + Assert(cRefs != UINT32_MAX); RT_NOREF(cRefs); + hVol = hVolNext; + + /* Instantiate a new partition object and add it to the list: */ + ComObjPtr<HostDrivePartition> ptrHostPartition; + hrc = ptrHostPartition.createObject(); + if (SUCCEEDED(hrc)) + hrc = ptrHostPartition->initFromDvmVol(hVol); + if (SUCCEEDED(hrc)) + try + { + m.partitions.push_back(ptrHostPartition); + } + catch (std::bad_alloc &) + { + AssertFailedBreakStmt(hrc = E_OUTOFMEMORY); + } + } + RTDvmVolumeRelease(hVol); + } + else + hrc = Global::vboxStatusCodeToCOM(vrc); + RTDvmRelease(hVolMgr); + } + else + hrc = Global::vboxStatusCodeToCOM(vrc); + RTVfsFileRelease(hVfsFile); + } + else + hrc = Global::vboxStatusCodeToCOM(vrc); + } + else /* VERR_IO_NOT_READ / STATUS_NO_MEDIA_IN_DEVICE is likely for card readers on windows. */ + hrc = Global::vboxStatusCodeToCOM(vrc); + RTFileClose(hRawFile); + } + else + { + /* + * We don't use the Global::vboxStatusCodeToCOM(vrc) here + * because RTFileOpen can return some error which causes + * the assertion and breaks original idea of returning + * the object in the limited state. + */ + if ( vrc == VERR_RESOURCE_BUSY + || vrc == VERR_ACCESS_DENIED) + hrc = E_ACCESSDENIED; + else + hrc = VBOX_E_IPRT_ERROR; + } + + /* Confirm a successful initialization */ + if (SUCCEEDED(hrc)) + autoInitSpan.setSucceeded(); + else + autoInitSpan.setLimited(hrc); + return S_OK; +} + +/** + * Uninitializes the instance. + * Called either from FinalRelease() or by the parent when it gets destroyed. + */ +void HostDrive::uninit() +{ + LogFlowThisFunc(("\n")); + + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + + m.drivePath.setNull(); + m.partitions.clear(); +} + + +/********************************************************************************************************************************* +* IHostDrive properties * +*********************************************************************************************************************************/ + +HRESULT HostDrive::getPartitioningType(PartitioningType_T *aPartitioningType) +{ + *aPartitioningType = m.partitioningType; + return S_OK; +} + +HRESULT HostDrive::getDrivePath(com::Utf8Str &aDrivePath) +{ + aDrivePath = m.drivePath; + return S_OK; +} + +HRESULT HostDrive::getUuid(com::Guid &aUuid) +{ + aUuid = m.uuid; + return S_OK; +} + +HRESULT HostDrive::getSectorSize(ULONG *aSectorSize) +{ + *aSectorSize = m.cbSector; + return S_OK; +} + +HRESULT HostDrive::getSize(LONG64 *aSize) +{ + *aSize = (LONG64)m.cbDisk; + if (*aSize < 0) + *aSize = INT64_MAX; + return S_OK; +} + +HRESULT HostDrive::getModel(com::Utf8Str &aModel) +{ + return aModel.assignEx(m.model); +} + +HRESULT HostDrive::getPartitions(std::vector<ComPtr<IHostDrivePartition> > &aPartitions) +{ + aPartitions = m.partitions; + return S_OK; +} + + + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ |