[37270] | 1 | /* $Id: dvmbsdlabel.cpp 99989 2023-05-26 12:06:12Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * IPRT Disk Volume Management API (DVM) - BSD disklabel format backend.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2011-2023 Oracle and/or its affiliates.
|
---|
[37270] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[37270] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[37270] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[37270] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[37270] | 35 | */
|
---|
| 36 |
|
---|
| 37 | #include <iprt/types.h>
|
---|
| 38 | #include <iprt/assert.h>
|
---|
| 39 | #include <iprt/mem.h>
|
---|
| 40 | #include <iprt/dvm.h>
|
---|
| 41 | #include <iprt/string.h>
|
---|
[40949] | 42 | #include <iprt/asm.h>
|
---|
[37270] | 43 | #include "internal/dvm.h"
|
---|
| 44 |
|
---|
| 45 |
|
---|
[57358] | 46 | /*********************************************************************************************************************************
|
---|
| 47 | * Structures and Typedefs *
|
---|
| 48 | *********************************************************************************************************************************/
|
---|
| 49 |
|
---|
[37270] | 50 | /*
|
---|
| 51 | * Below are the on disk structures of a bsd disklabel as found in
|
---|
| 52 | * /usr/include/sys/disklabel.h from a FreeBSD system.
|
---|
| 53 | *
|
---|
| 54 | * Everything is stored in little endian on the disk.
|
---|
| 55 | */
|
---|
| 56 |
|
---|
| 57 | /** BSD disklabel magic. */
|
---|
| 58 | #define RTDVM_BSDLBL_MAGIC UINT32_C(0x82564557)
|
---|
| 59 | /** Maximum number of partitions in the label. */
|
---|
| 60 | #define RTDVM_BSDLBL_MAX_PARTITIONS 8
|
---|
| 61 |
|
---|
| 62 | /**
|
---|
| 63 | * A BSD disk label partition.
|
---|
| 64 | */
|
---|
| 65 | typedef struct BsdLabelPartition
|
---|
| 66 | {
|
---|
| 67 | /** Number of sectors in the partition. */
|
---|
| 68 | uint32_t cSectors;
|
---|
| 69 | /** Start sector. */
|
---|
| 70 | uint32_t offSectorStart;
|
---|
| 71 | /** Filesystem fragment size. */
|
---|
| 72 | uint32_t cbFsFragment;
|
---|
| 73 | /** Filesystem type. */
|
---|
| 74 | uint8_t bFsType;
|
---|
| 75 | /** Filesystem fragments per block. */
|
---|
| 76 | uint8_t cFsFragmentsPerBlock;
|
---|
| 77 | /** Filesystem cylinders per group. */
|
---|
| 78 | uint16_t cFsCylPerGroup;
|
---|
| 79 | } BsdLabelPartition;
|
---|
| 80 | AssertCompileSize(BsdLabelPartition, 16);
|
---|
| 81 | /** Pointer to a BSD disklabel partition structure. */
|
---|
| 82 | typedef BsdLabelPartition *PBsdLabelPartition;
|
---|
| 83 |
|
---|
| 84 | /**
|
---|
| 85 | * On disk BSD label structure.
|
---|
| 86 | */
|
---|
| 87 | typedef struct BsdLabel
|
---|
| 88 | {
|
---|
| 89 | /** Magic identifying the BSD disk label. */
|
---|
| 90 | uint32_t u32Magic;
|
---|
| 91 | /** Drive type */
|
---|
| 92 | uint16_t u16DriveType;
|
---|
| 93 | /** Subtype depending on the drive type above. */
|
---|
| 94 | uint16_t u16SubType;
|
---|
| 95 | /** Type name. */
|
---|
| 96 | uint8_t abTypeName[16];
|
---|
| 97 | /** Pack identifier. */
|
---|
| 98 | uint8_t abPackName[16];
|
---|
| 99 | /** Number of bytes per sector. */
|
---|
| 100 | uint32_t cbSector;
|
---|
| 101 | /** Number of sectors per track. */
|
---|
| 102 | uint32_t cSectorsPerTrack;
|
---|
| 103 | /** Number of tracks per cylinder. */
|
---|
| 104 | uint32_t cTracksPerCylinder;
|
---|
| 105 | /** Number of data cylinders pre unit. */
|
---|
| 106 | uint32_t cDataCylindersPerUnit;
|
---|
| 107 | /** Number of data sectors per cylinder. */
|
---|
| 108 | uint32_t cDataSectorsPerCylinder;
|
---|
| 109 | /** Number of data sectors per unit (unit as in disk drive?). */
|
---|
| 110 | uint32_t cSectorsPerUnit;
|
---|
| 111 | /** Number of spare sectors per track. */
|
---|
| 112 | uint16_t cSpareSectorsPerTrack;
|
---|
| 113 | /** Number of spare sectors per cylinder. */
|
---|
| 114 | uint16_t cSpareSectorsPerCylinder;
|
---|
| 115 | /** Number of alternate cylinders per unit. */
|
---|
| 116 | uint32_t cSpareCylindersPerUnit;
|
---|
| 117 | /** Rotational speed of the disk drive in rotations per minute. */
|
---|
| 118 | uint16_t cRotationsPerMinute;
|
---|
| 119 | /** Sector interleave. */
|
---|
| 120 | uint16_t uSectorInterleave;
|
---|
| 121 | /** Sector 0 skew, per track. */
|
---|
| 122 | uint16_t uSectorSkewPerTrack;
|
---|
| 123 | /** Sector 0 skew, per cylinder. */
|
---|
| 124 | uint16_t uSectorSkewPerCylinder;
|
---|
| 125 | /** Head switch time in us. */
|
---|
| 126 | uint32_t usHeadSwitch;
|
---|
| 127 | /** Time of a track-to-track seek in us. */
|
---|
| 128 | uint32_t usTrackSeek;
|
---|
| 129 | /** Flags. */
|
---|
| 130 | uint32_t fFlags;
|
---|
| 131 | /** Drive type sepcific information. */
|
---|
| 132 | uint32_t au32DriveData[5];
|
---|
| 133 | /** Reserved. */
|
---|
| 134 | uint32_t au32Reserved[5];
|
---|
| 135 | /** The magic number again. */
|
---|
| 136 | uint32_t u32Magic2;
|
---|
| 137 | /** Checksum (xor of the whole structure). */
|
---|
| 138 | uint16_t u16ChkSum;
|
---|
| 139 | /** Number of partitions in the array. */
|
---|
| 140 | uint16_t cPartitions;
|
---|
| 141 | /** Boot area size in bytes. */
|
---|
| 142 | uint32_t cbBootArea;
|
---|
| 143 | /** Maximum size of the filesystem super block. */
|
---|
| 144 | uint32_t cbFsSuperBlock;
|
---|
| 145 | /** The partition array. */
|
---|
| 146 | BsdLabelPartition aPartitions[RTDVM_BSDLBL_MAX_PARTITIONS];
|
---|
| 147 | } BsdLabel;
|
---|
| 148 | AssertCompileSize(BsdLabel, 148 + RTDVM_BSDLBL_MAX_PARTITIONS * 16);
|
---|
| 149 | /** Pointer to a BSD disklabel structure. */
|
---|
| 150 | typedef BsdLabel *PBsdLabel;
|
---|
| 151 |
|
---|
| 152 | /**
|
---|
| 153 | * BSD disk label volume manager data.
|
---|
| 154 | */
|
---|
| 155 | typedef struct RTDVMFMTINTERNAL
|
---|
| 156 | {
|
---|
| 157 | /** Pointer to the underlying disk. */
|
---|
| 158 | PCRTDVMDISK pDisk;
|
---|
| 159 | /** Number of used partitions. */
|
---|
| 160 | uint32_t cPartitions;
|
---|
| 161 | /** Saved BSD disklabel structure. */
|
---|
| 162 | BsdLabel DiskLabel;
|
---|
| 163 | } RTDVMFMTINTERNAL;
|
---|
| 164 | /** Pointer to the MBR volume manager. */
|
---|
| 165 | typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
|
---|
| 166 |
|
---|
| 167 | /**
|
---|
| 168 | * MBR volume data.
|
---|
| 169 | */
|
---|
| 170 | typedef struct RTDVMVOLUMEFMTINTERNAL
|
---|
| 171 | {
|
---|
| 172 | /** Pointer to the volume manager. */
|
---|
| 173 | PRTDVMFMTINTERNAL pVolMgr;
|
---|
| 174 | /** Partition table entry index. */
|
---|
| 175 | uint32_t idxEntry;
|
---|
| 176 | /** Start offset of the volume. */
|
---|
| 177 | uint64_t offStart;
|
---|
| 178 | /** Size of the volume. */
|
---|
| 179 | uint64_t cbVolume;
|
---|
| 180 | /** Pointer to the raw partition table entry. */
|
---|
| 181 | PBsdLabelPartition pBsdPartitionEntry;
|
---|
| 182 | } RTDVMVOLUMEFMTINTERNAL;
|
---|
| 183 | /** Pointer to an MBR volume. */
|
---|
| 184 | typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
|
---|
| 185 |
|
---|
| 186 | /** Converts a LBA number to the byte offset. */
|
---|
| 187 | #define RTDVM_BSDLBL_LBA2BYTE(lba, disk) ((lba) * (disk)->cbSector)
|
---|
| 188 | /** Converts a Byte offset to the LBA number. */
|
---|
| 189 | #define RTDVM_BSDLBL_BYTE2LBA(lba, disk) ((lba) / (disk)->cbSector)
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
| 192 | * Calculates the checksum of the entire bsd disklabel structure.
|
---|
| 193 | *
|
---|
| 194 | * @returns The checksum.
|
---|
[41785] | 195 | * @param pBsdLabel BSD disklabel to get the checksum for.
|
---|
[37270] | 196 | */
|
---|
| 197 | static uint16_t rtDvmFmtBsdLblDiskLabelChkSum(PBsdLabel pBsdLabel)
|
---|
| 198 | {
|
---|
| 199 | uint16_t uChkSum = 0;
|
---|
| 200 | uint16_t *pCurr = (uint16_t *)pBsdLabel;
|
---|
| 201 | uint16_t *pEnd = (uint16_t *)&pBsdLabel->aPartitions[pBsdLabel->cPartitions];
|
---|
| 202 |
|
---|
| 203 | while (pCurr < pEnd)
|
---|
| 204 | uChkSum ^= *pCurr++;
|
---|
| 205 |
|
---|
| 206 | return uChkSum;
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | /**
|
---|
| 210 | * Converts a partition entry to the host endianness.
|
---|
| 211 | *
|
---|
| 212 | * @param pPartition The partition to decode.
|
---|
| 213 | */
|
---|
| 214 | static void rtDvmFmtBsdLblDiskLabelDecodePartition(PBsdLabelPartition pPartition)
|
---|
| 215 | {
|
---|
| 216 | pPartition->cSectors = RT_LE2H_U32(pPartition->cSectors);
|
---|
| 217 | pPartition->offSectorStart = RT_LE2H_U32(pPartition->offSectorStart);
|
---|
| 218 | pPartition->cbFsFragment = RT_LE2H_U32(pPartition->cbFsFragment);
|
---|
| 219 | pPartition->cFsCylPerGroup = RT_LE2H_U16(pPartition->cFsCylPerGroup);
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | /**
|
---|
| 223 | * Converts the on disk BSD label to the host endianness.
|
---|
| 224 | *
|
---|
| 225 | * @returns Whether the given label structure is a valid BSD disklabel.
|
---|
| 226 | * @param pBsdLabel Pointer to the BSD disklabel to decode.
|
---|
| 227 | */
|
---|
| 228 | static bool rtDvmFmtBsdLblDiskLabelDecode(PBsdLabel pBsdLabel)
|
---|
| 229 | {
|
---|
| 230 | pBsdLabel->u32Magic = RT_LE2H_U32(pBsdLabel->u32Magic);
|
---|
| 231 | pBsdLabel->u16DriveType = RT_LE2H_U16(pBsdLabel->u16DriveType);
|
---|
| 232 | pBsdLabel->u16SubType = RT_LE2H_U16(pBsdLabel->u16SubType);
|
---|
| 233 | pBsdLabel->cbSector = RT_LE2H_U32(pBsdLabel->cbSector);
|
---|
| 234 | pBsdLabel->cSectorsPerTrack = RT_LE2H_U32(pBsdLabel->cSectorsPerTrack);
|
---|
| 235 | pBsdLabel->cTracksPerCylinder = RT_LE2H_U32(pBsdLabel->cTracksPerCylinder);
|
---|
| 236 | pBsdLabel->cDataCylindersPerUnit = RT_LE2H_U32(pBsdLabel->cDataCylindersPerUnit);
|
---|
| 237 | pBsdLabel->cDataSectorsPerCylinder = RT_LE2H_U32(pBsdLabel->cDataSectorsPerCylinder);
|
---|
| 238 | pBsdLabel->cSectorsPerUnit = RT_LE2H_U32(pBsdLabel->cSectorsPerUnit);
|
---|
| 239 | pBsdLabel->cSpareSectorsPerTrack = RT_LE2H_U16(pBsdLabel->cSpareSectorsPerTrack);
|
---|
| 240 | pBsdLabel->cSpareSectorsPerCylinder = RT_LE2H_U16(pBsdLabel->cSpareSectorsPerCylinder);
|
---|
| 241 | pBsdLabel->cSpareCylindersPerUnit = RT_LE2H_U32(pBsdLabel->cSpareCylindersPerUnit);
|
---|
| 242 | pBsdLabel->cRotationsPerMinute = RT_LE2H_U16(pBsdLabel->cRotationsPerMinute);
|
---|
| 243 | pBsdLabel->uSectorInterleave = RT_LE2H_U16(pBsdLabel->uSectorInterleave);
|
---|
| 244 | pBsdLabel->uSectorSkewPerTrack = RT_LE2H_U16(pBsdLabel->uSectorSkewPerTrack);
|
---|
| 245 | pBsdLabel->uSectorSkewPerCylinder = RT_LE2H_U16(pBsdLabel->uSectorSkewPerCylinder);
|
---|
| 246 | pBsdLabel->usHeadSwitch = RT_LE2H_U16(pBsdLabel->usHeadSwitch);
|
---|
| 247 | pBsdLabel->usTrackSeek = RT_LE2H_U16(pBsdLabel->usTrackSeek);
|
---|
| 248 | pBsdLabel->fFlags = RT_LE2H_U32(pBsdLabel->fFlags);
|
---|
| 249 |
|
---|
| 250 | for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->au32DriveData); i++)
|
---|
| 251 | pBsdLabel->au32DriveData[i] = RT_LE2H_U32(pBsdLabel->au32DriveData[i]);
|
---|
| 252 | for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->au32Reserved); i++)
|
---|
| 253 | pBsdLabel->au32Reserved[i] = RT_LE2H_U32(pBsdLabel->au32Reserved[i]);
|
---|
| 254 |
|
---|
| 255 | pBsdLabel->u32Magic2 = RT_LE2H_U32(pBsdLabel->u32Magic2);
|
---|
| 256 | pBsdLabel->u16ChkSum = RT_LE2H_U16(pBsdLabel->u16ChkSum);
|
---|
| 257 | pBsdLabel->cPartitions = RT_LE2H_U16(pBsdLabel->cPartitions);
|
---|
| 258 | pBsdLabel->cbBootArea = RT_LE2H_U32(pBsdLabel->cbBootArea);
|
---|
| 259 | pBsdLabel->cbFsSuperBlock = RT_LE2H_U32(pBsdLabel->cbFsSuperBlock);
|
---|
| 260 |
|
---|
| 261 | /* Check the magics now. */
|
---|
| 262 | if ( pBsdLabel->u32Magic != RTDVM_BSDLBL_MAGIC
|
---|
| 263 | || pBsdLabel->u32Magic2 != RTDVM_BSDLBL_MAGIC
|
---|
| 264 | || pBsdLabel->cPartitions != RTDVM_BSDLBL_MAX_PARTITIONS)
|
---|
| 265 | return false;
|
---|
| 266 |
|
---|
| 267 | /* Convert the partitions array. */
|
---|
| 268 | for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->aPartitions); i++)
|
---|
| 269 | rtDvmFmtBsdLblDiskLabelDecodePartition(&pBsdLabel->aPartitions[i]);
|
---|
| 270 |
|
---|
| 271 | /* Check the checksum now. */
|
---|
| 272 | uint16_t u16ChkSumSaved = pBsdLabel->u16ChkSum;
|
---|
| 273 |
|
---|
| 274 | pBsdLabel->u16ChkSum = 0;
|
---|
| 275 | if (u16ChkSumSaved != rtDvmFmtBsdLblDiskLabelChkSum(pBsdLabel))
|
---|
| 276 | return false;
|
---|
| 277 |
|
---|
| 278 | pBsdLabel->u16ChkSum = u16ChkSumSaved;
|
---|
| 279 | return true;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
[57444] | 282 | static DECLCALLBACK(int) rtDvmFmtBsdLblProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
|
---|
[37270] | 283 | {
|
---|
| 284 | BsdLabel DiskLabel;
|
---|
| 285 | int rc = VINF_SUCCESS;
|
---|
| 286 |
|
---|
| 287 | *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
|
---|
| 288 |
|
---|
| 289 | if (pDisk->cbDisk >= sizeof(BsdLabel))
|
---|
| 290 | {
|
---|
| 291 | /* Read from the disk and check for the disk label structure. */
|
---|
[85877] | 292 | rc = rtDvmDiskReadUnaligned(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &DiskLabel, sizeof(BsdLabel));
|
---|
[37270] | 293 | if ( RT_SUCCESS(rc)
|
---|
| 294 | && rtDvmFmtBsdLblDiskLabelDecode(&DiskLabel))
|
---|
| 295 | *puScore = RTDVM_MATCH_SCORE_PERFECT;
|
---|
| 296 | }
|
---|
| 297 | return rc;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
[57444] | 300 | static DECLCALLBACK(int) rtDvmFmtBsdLblOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
|
---|
[37270] | 301 | {
|
---|
| 302 | int rc = VINF_SUCCESS;
|
---|
| 303 | PRTDVMFMTINTERNAL pThis = NULL;
|
---|
| 304 |
|
---|
| 305 | pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
|
---|
[40298] | 306 | if (pThis)
|
---|
[37270] | 307 | {
|
---|
| 308 | pThis->pDisk = pDisk;
|
---|
| 309 | pThis->cPartitions = 0;
|
---|
| 310 |
|
---|
| 311 | /* Read from the disk and check for the disk label structure. */
|
---|
[85877] | 312 | rc = rtDvmDiskReadUnaligned(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &pThis->DiskLabel, sizeof(BsdLabel));
|
---|
[37270] | 313 | if ( RT_SUCCESS(rc)
|
---|
| 314 | && rtDvmFmtBsdLblDiskLabelDecode(&pThis->DiskLabel))
|
---|
| 315 | {
|
---|
| 316 | /* Count number of used entries. */
|
---|
| 317 | for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
|
---|
| 318 | if (pThis->DiskLabel.aPartitions[i].cSectors)
|
---|
| 319 | pThis->cPartitions++;
|
---|
| 320 |
|
---|
| 321 | *phVolMgrFmt = pThis;
|
---|
| 322 | }
|
---|
| 323 | else
|
---|
| 324 | {
|
---|
| 325 | RTMemFree(pThis);
|
---|
| 326 | rc = VERR_INVALID_MAGIC;
|
---|
| 327 | }
|
---|
| 328 | }
|
---|
| 329 | else
|
---|
| 330 | rc = VERR_NO_MEMORY;
|
---|
| 331 |
|
---|
| 332 | return rc;
|
---|
| 333 | }
|
---|
| 334 |
|
---|
[57444] | 335 | static DECLCALLBACK(int) rtDvmFmtBsdLblInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
|
---|
[37270] | 336 | {
|
---|
[39083] | 337 | NOREF(pDisk); NOREF(phVolMgrFmt);
|
---|
[37270] | 338 | return VERR_NOT_IMPLEMENTED;
|
---|
| 339 | }
|
---|
| 340 |
|
---|
[57444] | 341 | static DECLCALLBACK(void) rtDvmFmtBsdLblClose(RTDVMFMT hVolMgrFmt)
|
---|
[37270] | 342 | {
|
---|
| 343 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 344 |
|
---|
| 345 | pThis->pDisk = NULL;
|
---|
| 346 | pThis->cPartitions = 0;
|
---|
[85877] | 347 | RT_ZERO(pThis->DiskLabel);
|
---|
[37270] | 348 | RTMemFree(pThis);
|
---|
| 349 | }
|
---|
| 350 |
|
---|
[41549] | 351 | static DECLCALLBACK(int) rtDvmFmtBsdLblQueryRangeUse(RTDVMFMT hVolMgrFmt,
|
---|
| 352 | uint64_t off, uint64_t cbRange,
|
---|
| 353 | bool *pfUsed)
|
---|
| 354 | {
|
---|
| 355 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 356 |
|
---|
[42387] | 357 | NOREF(cbRange);
|
---|
| 358 |
|
---|
[41549] | 359 | if (off <= RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk))
|
---|
| 360 | *pfUsed = true;
|
---|
| 361 | else
|
---|
| 362 | *pfUsed = false;
|
---|
| 363 |
|
---|
| 364 | return VINF_SUCCESS;
|
---|
| 365 | }
|
---|
| 366 |
|
---|
[57444] | 367 | static DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetValidVolumes(RTDVMFMT hVolMgrFmt)
|
---|
[37270] | 368 | {
|
---|
| 369 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 370 | return pThis->cPartitions;
|
---|
| 371 | }
|
---|
| 372 |
|
---|
[57444] | 373 | static DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetMaxVolumes(RTDVMFMT hVolMgrFmt)
|
---|
[37270] | 374 | {
|
---|
| 375 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 376 | return pThis->DiskLabel.cPartitions;
|
---|
| 377 | }
|
---|
| 378 |
|
---|
| 379 | /**
|
---|
| 380 | * Creates a new volume.
|
---|
| 381 | *
|
---|
| 382 | * @returns IPRT status code.
|
---|
| 383 | * @param pThis The MBR volume manager data.
|
---|
| 384 | * @param pbBsdLblEntry The raw MBR entry data.
|
---|
| 385 | * @param idx The index in the partition table.
|
---|
| 386 | * @param phVolFmt Where to store the volume data on success.
|
---|
| 387 | */
|
---|
| 388 | static int rtDvmFmtBsdLblVolumeCreate(PRTDVMFMTINTERNAL pThis, PBsdLabelPartition pBsdPartitionEntry,
|
---|
| 389 | uint32_t idx, PRTDVMVOLUMEFMT phVolFmt)
|
---|
| 390 | {
|
---|
| 391 | int rc = VINF_SUCCESS;
|
---|
| 392 | PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
|
---|
| 393 |
|
---|
[40298] | 394 | if (pVol)
|
---|
[37270] | 395 | {
|
---|
| 396 | pVol->pVolMgr = pThis;
|
---|
| 397 | pVol->idxEntry = idx;
|
---|
| 398 | pVol->pBsdPartitionEntry = pBsdPartitionEntry;
|
---|
[40085] | 399 | pVol->offStart = (uint64_t)pBsdPartitionEntry->offSectorStart * pThis->DiskLabel.cbSector;
|
---|
[40137] | 400 | pVol->cbVolume = (uint64_t)pBsdPartitionEntry->cSectors * pThis->DiskLabel.cbSector;
|
---|
[37270] | 401 |
|
---|
| 402 | *phVolFmt = pVol;
|
---|
| 403 | }
|
---|
| 404 | else
|
---|
| 405 | rc = VERR_NO_MEMORY;
|
---|
| 406 |
|
---|
| 407 | return rc;
|
---|
| 408 | }
|
---|
| 409 |
|
---|
[57444] | 410 | static DECLCALLBACK(int) rtDvmFmtBsdLblQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
|
---|
[37270] | 411 | {
|
---|
| 412 | int rc = VINF_SUCCESS;
|
---|
| 413 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 414 |
|
---|
| 415 | if (pThis->cPartitions != 0)
|
---|
| 416 | {
|
---|
| 417 | /* Search for the first non empty entry. */
|
---|
| 418 | for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
|
---|
| 419 | {
|
---|
| 420 | if (pThis->DiskLabel.aPartitions[i].cSectors)
|
---|
| 421 | {
|
---|
[69609] | 422 | rc = rtDvmFmtBsdLblVolumeCreate(pThis, &pThis->DiskLabel.aPartitions[i], i, phVolFmt);
|
---|
[37270] | 423 | break;
|
---|
| 424 | }
|
---|
| 425 | }
|
---|
| 426 | }
|
---|
| 427 | else
|
---|
| 428 | rc = VERR_DVM_MAP_EMPTY;
|
---|
| 429 |
|
---|
| 430 | return rc;
|
---|
| 431 | }
|
---|
| 432 |
|
---|
[57444] | 433 | static DECLCALLBACK(int) rtDvmFmtBsdLblQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
|
---|
[37270] | 434 | {
|
---|
| 435 | int rc = VERR_DVM_MAP_NO_VOLUME;
|
---|
| 436 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 437 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 438 | PBsdLabelPartition pBsdPartitionEntry = pVol->pBsdPartitionEntry + 1;
|
---|
| 439 |
|
---|
| 440 | for (unsigned i = pVol->idxEntry + 1; i < pThis->DiskLabel.cPartitions; i++)
|
---|
| 441 | {
|
---|
| 442 | if (pBsdPartitionEntry->cSectors)
|
---|
| 443 | {
|
---|
| 444 | rc = rtDvmFmtBsdLblVolumeCreate(pThis, pBsdPartitionEntry, i, phVolFmtNext);
|
---|
| 445 | break;
|
---|
| 446 | }
|
---|
| 447 | pBsdPartitionEntry++;
|
---|
| 448 | }
|
---|
| 449 |
|
---|
| 450 | return rc;
|
---|
| 451 | }
|
---|
| 452 |
|
---|
[85894] | 453 | /** @copydoc RTDVMFMTOPS::pfnQueryTableLocations */
|
---|
| 454 | static DECLCALLBACK(int) rtDvmFmtBsdLblQueryTableLocations(RTDVMFMT hVolMgrFmt, uint32_t fFlags, PRTDVMTABLELOCATION paLocations,
|
---|
| 455 | size_t cLocations, size_t *pcActual)
|
---|
| 456 | {
|
---|
| 457 | PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
|
---|
| 458 |
|
---|
| 459 | /*
|
---|
| 460 | * The MBR if requested.
|
---|
| 461 | */
|
---|
| 462 | int rc = VINF_SUCCESS;
|
---|
| 463 | size_t iLoc = 0;
|
---|
| 464 | if (fFlags & RTDVMMAPQTABLOC_F_INCLUDE_LEGACY)
|
---|
| 465 | {
|
---|
| 466 | if (cLocations > 0)
|
---|
| 467 | {
|
---|
| 468 | paLocations[iLoc].off = 0;
|
---|
| 469 | paLocations[iLoc].cb = RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk);
|
---|
| 470 | paLocations[iLoc].cbPadding = 0;
|
---|
| 471 | }
|
---|
| 472 | else
|
---|
| 473 | rc = VERR_BUFFER_OVERFLOW;
|
---|
| 474 | iLoc++;
|
---|
| 475 | }
|
---|
| 476 |
|
---|
| 477 | /*
|
---|
| 478 | * The BSD lable.
|
---|
| 479 | */
|
---|
| 480 | if (cLocations > iLoc)
|
---|
| 481 | {
|
---|
| 482 | paLocations[iLoc].off = RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk);
|
---|
| 483 | paLocations[iLoc].cb = (sizeof(BsdLabel) + pThis->pDisk->cbSector - 1) / pThis->pDisk->cbSector * pThis->pDisk->cbSector;
|
---|
| 484 |
|
---|
| 485 | uint32_t offFirstSector = pThis->pDisk->cbDisk / pThis->pDisk->cbSector;
|
---|
| 486 | for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
|
---|
| 487 | if ( pThis->DiskLabel.aPartitions[i].cSectors
|
---|
| 488 | && pThis->DiskLabel.aPartitions[i].offSectorStart < offFirstSector)
|
---|
| 489 | offFirstSector = pThis->DiskLabel.aPartitions[i].offSectorStart;
|
---|
| 490 |
|
---|
| 491 | uint64_t offEnd = paLocations[iLoc].off + paLocations[iLoc].cb;
|
---|
| 492 | paLocations[iLoc].cbPadding = (uint64_t)offFirstSector * pThis->DiskLabel.cbSector;
|
---|
| 493 | if (paLocations[iLoc].cbPadding > offEnd)
|
---|
| 494 | paLocations[iLoc].cbPadding -= offEnd;
|
---|
| 495 | else
|
---|
| 496 | AssertFailedStmt(paLocations[iLoc].cbPadding = 0);
|
---|
| 497 | }
|
---|
| 498 | else
|
---|
| 499 | rc = VERR_BUFFER_OVERFLOW;
|
---|
| 500 | iLoc++;
|
---|
| 501 |
|
---|
| 502 | /*
|
---|
| 503 | * Return values.
|
---|
| 504 | */
|
---|
| 505 | if (pcActual)
|
---|
| 506 | *pcActual = iLoc;
|
---|
| 507 | else if (cLocations != iLoc && RT_SUCCESS(rc))
|
---|
| 508 | {
|
---|
| 509 | RT_BZERO(&paLocations[iLoc], (cLocations - iLoc) * sizeof(paLocations[0]));
|
---|
| 510 | rc = VERR_BUFFER_UNDERFLOW;
|
---|
| 511 | }
|
---|
| 512 | return rc;
|
---|
| 513 | }
|
---|
| 514 |
|
---|
[57444] | 515 | static DECLCALLBACK(void) rtDvmFmtBsdLblVolumeClose(RTDVMVOLUMEFMT hVolFmt)
|
---|
[37270] | 516 | {
|
---|
| 517 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 518 |
|
---|
| 519 | pVol->pVolMgr = NULL;
|
---|
| 520 | pVol->offStart = 0;
|
---|
| 521 | pVol->cbVolume = 0;
|
---|
| 522 | pVol->pBsdPartitionEntry = NULL;
|
---|
| 523 |
|
---|
| 524 | RTMemFree(pVol);
|
---|
| 525 | }
|
---|
| 526 |
|
---|
[57444] | 527 | static DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
|
---|
[37270] | 528 | {
|
---|
| 529 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 530 |
|
---|
| 531 | return pVol->cbVolume;
|
---|
| 532 | }
|
---|
| 533 |
|
---|
[57444] | 534 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
|
---|
[37270] | 535 | {
|
---|
[39083] | 536 | NOREF(hVolFmt); NOREF(ppszVolName);
|
---|
[37270] | 537 | return VERR_NOT_SUPPORTED;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
[57444] | 540 | static DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtBsdLblVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
|
---|
[37270] | 541 | {
|
---|
[39083] | 542 | NOREF(hVolFmt);
|
---|
[37270] | 543 | return RTDVMVOLTYPE_UNKNOWN;
|
---|
| 544 | }
|
---|
| 545 |
|
---|
[57444] | 546 | static DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
|
---|
[37270] | 547 | {
|
---|
| 548 | NOREF(hVolFmt);
|
---|
[77256] | 549 | return DVMVOLUME_F_CONTIGUOUS;
|
---|
[37270] | 550 | }
|
---|
| 551 |
|
---|
[77970] | 552 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryRange(RTDVMVOLUMEFMT hVolFmt, uint64_t *poffStart, uint64_t *poffLast)
|
---|
[77256] | 553 | {
|
---|
| 554 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 555 | *poffStart = pVol->offStart;
|
---|
[77970] | 556 | *poffLast = pVol->offStart + pVol->cbVolume - 1;
|
---|
[77256] | 557 | return VINF_SUCCESS;
|
---|
| 558 | }
|
---|
| 559 |
|
---|
[57444] | 560 | static DECLCALLBACK(bool) rtDvmFmtBsdLblVolumeIsRangeIntersecting(RTDVMVOLUMEFMT hVolFmt,
|
---|
| 561 | uint64_t offStart, size_t cbRange,
|
---|
| 562 | uint64_t *poffVol,
|
---|
| 563 | uint64_t *pcbIntersect)
|
---|
[40027] | 564 | {
|
---|
| 565 | bool fIntersect = false;
|
---|
| 566 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 567 |
|
---|
| 568 | if (RTDVM_RANGE_IS_INTERSECTING(pVol->offStart, pVol->cbVolume, offStart))
|
---|
| 569 | {
|
---|
| 570 | fIntersect = true;
|
---|
| 571 | *poffVol = offStart - pVol->offStart;
|
---|
| 572 | *pcbIntersect = RT_MIN(cbRange, pVol->offStart + pVol->cbVolume - offStart);
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 | return fIntersect;
|
---|
| 576 | }
|
---|
| 577 |
|
---|
[85877] | 578 | /** @copydoc RTDVMFMTOPS::pfnVolumeQueryTableLocation */
|
---|
| 579 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryTableLocation(RTDVMVOLUMEFMT hVolFmt, uint64_t *poffTable, uint64_t *pcbTable)
|
---|
| 580 | {
|
---|
| 581 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 582 | *poffTable = RTDVM_BSDLBL_LBA2BYTE(1, pVol->pVolMgr->pDisk);
|
---|
| 583 | *pcbTable = RT_ALIGN_Z(sizeof(BsdLabel), pVol->pVolMgr->pDisk->cbSector);
|
---|
| 584 | return VINF_SUCCESS;
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | /** @copydoc RTDVMFMTOPS::pfnVolumeGetIndex */
|
---|
| 588 | static DECLCALLBACK(uint32_t) rtDvmFmtBsdLblVolumeGetIndex(RTDVMVOLUMEFMT hVolFmt, RTDVMVOLIDX enmIndex)
|
---|
| 589 | {
|
---|
| 590 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 591 | switch (enmIndex)
|
---|
| 592 | {
|
---|
| 593 | case RTDVMVOLIDX_USER_VISIBLE:
|
---|
| 594 | case RTDVMVOLIDX_ALL:
|
---|
| 595 | case RTDVMVOLIDX_LINUX:
|
---|
| 596 | return pVol->idxEntry + 1;
|
---|
| 597 | case RTDVMVOLIDX_IN_TABLE:
|
---|
| 598 | return pVol->idxEntry;
|
---|
| 599 |
|
---|
| 600 | case RTDVMVOLIDX_INVALID:
|
---|
[85887] | 601 | case RTDVMVOLIDX_HOST:
|
---|
[85877] | 602 | case RTDVMVOLIDX_END:
|
---|
| 603 | case RTDVMVOLIDX_32BIT_HACK:
|
---|
| 604 | break;
|
---|
| 605 | /* no default! */
|
---|
| 606 | }
|
---|
| 607 | AssertFailed();
|
---|
| 608 | return UINT32_MAX;
|
---|
| 609 | }
|
---|
| 610 |
|
---|
| 611 | /** @copydoc RTDVMFMTOPS::pfnVolumeQueryProp */
|
---|
| 612 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryProp(RTDVMVOLUMEFMT hVolFmt, RTDVMVOLPROP enmProperty,
|
---|
| 613 | void *pvBuf, size_t cbBuf, size_t *pcbBuf)
|
---|
| 614 | {
|
---|
| 615 | switch (enmProperty)
|
---|
| 616 | {
|
---|
| 617 | case RTDVMVOLPROP_MBR_FIRST_CYLINDER:
|
---|
| 618 | case RTDVMVOLPROP_MBR_FIRST_HEAD:
|
---|
| 619 | case RTDVMVOLPROP_MBR_FIRST_SECTOR:
|
---|
| 620 | case RTDVMVOLPROP_MBR_LAST_CYLINDER:
|
---|
| 621 | case RTDVMVOLPROP_MBR_LAST_HEAD:
|
---|
| 622 | case RTDVMVOLPROP_MBR_LAST_SECTOR:
|
---|
| 623 | case RTDVMVOLPROP_MBR_TYPE:
|
---|
| 624 | case RTDVMVOLPROP_GPT_TYPE:
|
---|
| 625 | case RTDVMVOLPROP_GPT_UUID:
|
---|
| 626 | return VERR_NOT_SUPPORTED;
|
---|
| 627 |
|
---|
| 628 | case RTDVMVOLPROP_INVALID:
|
---|
| 629 | case RTDVMVOLPROP_END:
|
---|
| 630 | case RTDVMVOLPROP_32BIT_HACK:
|
---|
| 631 | break;
|
---|
| 632 | /* no default! */
|
---|
| 633 | }
|
---|
| 634 | RT_NOREF(hVolFmt, pvBuf, cbBuf, pcbBuf);
|
---|
| 635 | return VERR_NOT_SUPPORTED;
|
---|
| 636 | }
|
---|
| 637 |
|
---|
[57444] | 638 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
|
---|
[37270] | 639 | {
|
---|
| 640 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 641 | AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
|
---|
| 642 |
|
---|
[99989] | 643 | return rtDvmDiskReadUnaligned(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
|
---|
[37270] | 644 | }
|
---|
| 645 |
|
---|
[57444] | 646 | static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
|
---|
[37270] | 647 | {
|
---|
| 648 | PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
|
---|
| 649 | AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
|
---|
| 650 |
|
---|
| 651 | return rtDvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
|
---|
| 652 | }
|
---|
| 653 |
|
---|
[85124] | 654 | DECL_HIDDEN_CONST(const RTDVMFMTOPS) g_rtDvmFmtBsdLbl =
|
---|
[37270] | 655 | {
|
---|
| 656 | /* pcszFmt */
|
---|
| 657 | "BsdLabel",
|
---|
[69616] | 658 | /* enmFormat, */
|
---|
[77256] | 659 | RTDVMFORMATTYPE_BSD_LABEL,
|
---|
[37270] | 660 | /* pfnProbe */
|
---|
| 661 | rtDvmFmtBsdLblProbe,
|
---|
| 662 | /* pfnOpen */
|
---|
| 663 | rtDvmFmtBsdLblOpen,
|
---|
| 664 | /* pfnInitialize */
|
---|
| 665 | rtDvmFmtBsdLblInitialize,
|
---|
| 666 | /* pfnClose */
|
---|
| 667 | rtDvmFmtBsdLblClose,
|
---|
[41549] | 668 | /* pfnQueryRangeUse */
|
---|
| 669 | rtDvmFmtBsdLblQueryRangeUse,
|
---|
[85877] | 670 | /* pfnQueryDiskUuid */
|
---|
| 671 | NULL,
|
---|
[37270] | 672 | /* pfnGetValidVolumes */
|
---|
| 673 | rtDvmFmtBsdLblGetValidVolumes,
|
---|
| 674 | /* pfnGetMaxVolumes */
|
---|
| 675 | rtDvmFmtBsdLblGetMaxVolumes,
|
---|
| 676 | /* pfnQueryFirstVolume */
|
---|
| 677 | rtDvmFmtBsdLblQueryFirstVolume,
|
---|
| 678 | /* pfnQueryNextVolume */
|
---|
| 679 | rtDvmFmtBsdLblQueryNextVolume,
|
---|
[85894] | 680 | /* pfnQueryTableLocations */
|
---|
| 681 | rtDvmFmtBsdLblQueryTableLocations,
|
---|
[37270] | 682 | /* pfnVolumeClose */
|
---|
| 683 | rtDvmFmtBsdLblVolumeClose,
|
---|
| 684 | /* pfnVolumeGetSize */
|
---|
| 685 | rtDvmFmtBsdLblVolumeGetSize,
|
---|
| 686 | /* pfnVolumeQueryName */
|
---|
| 687 | rtDvmFmtBsdLblVolumeQueryName,
|
---|
| 688 | /* pfnVolumeGetType */
|
---|
| 689 | rtDvmFmtBsdLblVolumeGetType,
|
---|
| 690 | /* pfnVolumeGetFlags */
|
---|
| 691 | rtDvmFmtBsdLblVolumeGetFlags,
|
---|
[77256] | 692 | /* pfnVolumeQueryRange */
|
---|
| 693 | rtDvmFmtBsdLblVolumeQueryRange,
|
---|
[40027] | 694 | /* pfnVolumeIsRangeIntersecting */
|
---|
| 695 | rtDvmFmtBsdLblVolumeIsRangeIntersecting,
|
---|
[85877] | 696 | /* pfnVolumeQueryTableLocation */
|
---|
| 697 | rtDvmFmtBsdLblVolumeQueryTableLocation,
|
---|
| 698 | /* pfnVolumeGetIndex */
|
---|
| 699 | rtDvmFmtBsdLblVolumeGetIndex,
|
---|
| 700 | /* pfnVolumeQueryProp */
|
---|
| 701 | rtDvmFmtBsdLblVolumeQueryProp,
|
---|
[37270] | 702 | /* pfnVolumeRead */
|
---|
| 703 | rtDvmFmtBsdLblVolumeRead,
|
---|
| 704 | /* pfnVolumeWrite */
|
---|
| 705 | rtDvmFmtBsdLblVolumeWrite
|
---|
| 706 | };
|
---|
| 707 |
|
---|