VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp

Last change on this file was 99989, checked in by vboxsync, 11 months ago

IPRT/dvm: Use rtDvmDiskReadUnaligned rather than rtDvmDiskRead in the RTDVMFMTOPS::pfnVolumeRead implementations to avoid triggering assertion when RTCp and others reads files via the FAT file system driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
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/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
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>
42#include <iprt/asm.h>
43#include "internal/dvm.h"
44
45
46/*********************************************************************************************************************************
47* Structures and Typedefs *
48*********************************************************************************************************************************/
49
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 */
65typedef 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;
80AssertCompileSize(BsdLabelPartition, 16);
81/** Pointer to a BSD disklabel partition structure. */
82typedef BsdLabelPartition *PBsdLabelPartition;
83
84/**
85 * On disk BSD label structure.
86 */
87typedef 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;
148AssertCompileSize(BsdLabel, 148 + RTDVM_BSDLBL_MAX_PARTITIONS * 16);
149/** Pointer to a BSD disklabel structure. */
150typedef BsdLabel *PBsdLabel;
151
152/**
153 * BSD disk label volume manager data.
154 */
155typedef 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. */
165typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
166
167/**
168 * MBR volume data.
169 */
170typedef 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. */
184typedef 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.
195 * @param pBsdLabel BSD disklabel to get the checksum for.
196 */
197static 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 */
214static 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 */
228static 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
282static DECLCALLBACK(int) rtDvmFmtBsdLblProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
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. */
292 rc = rtDvmDiskReadUnaligned(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &DiskLabel, sizeof(BsdLabel));
293 if ( RT_SUCCESS(rc)
294 && rtDvmFmtBsdLblDiskLabelDecode(&DiskLabel))
295 *puScore = RTDVM_MATCH_SCORE_PERFECT;
296 }
297 return rc;
298}
299
300static DECLCALLBACK(int) rtDvmFmtBsdLblOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
301{
302 int rc = VINF_SUCCESS;
303 PRTDVMFMTINTERNAL pThis = NULL;
304
305 pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
306 if (pThis)
307 {
308 pThis->pDisk = pDisk;
309 pThis->cPartitions = 0;
310
311 /* Read from the disk and check for the disk label structure. */
312 rc = rtDvmDiskReadUnaligned(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &pThis->DiskLabel, sizeof(BsdLabel));
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
335static DECLCALLBACK(int) rtDvmFmtBsdLblInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
336{
337 NOREF(pDisk); NOREF(phVolMgrFmt);
338 return VERR_NOT_IMPLEMENTED;
339}
340
341static DECLCALLBACK(void) rtDvmFmtBsdLblClose(RTDVMFMT hVolMgrFmt)
342{
343 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
344
345 pThis->pDisk = NULL;
346 pThis->cPartitions = 0;
347 RT_ZERO(pThis->DiskLabel);
348 RTMemFree(pThis);
349}
350
351static DECLCALLBACK(int) rtDvmFmtBsdLblQueryRangeUse(RTDVMFMT hVolMgrFmt,
352 uint64_t off, uint64_t cbRange,
353 bool *pfUsed)
354{
355 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
356
357 NOREF(cbRange);
358
359 if (off <= RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk))
360 *pfUsed = true;
361 else
362 *pfUsed = false;
363
364 return VINF_SUCCESS;
365}
366
367static DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetValidVolumes(RTDVMFMT hVolMgrFmt)
368{
369 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
370 return pThis->cPartitions;
371}
372
373static DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetMaxVolumes(RTDVMFMT hVolMgrFmt)
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 */
388static 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
394 if (pVol)
395 {
396 pVol->pVolMgr = pThis;
397 pVol->idxEntry = idx;
398 pVol->pBsdPartitionEntry = pBsdPartitionEntry;
399 pVol->offStart = (uint64_t)pBsdPartitionEntry->offSectorStart * pThis->DiskLabel.cbSector;
400 pVol->cbVolume = (uint64_t)pBsdPartitionEntry->cSectors * pThis->DiskLabel.cbSector;
401
402 *phVolFmt = pVol;
403 }
404 else
405 rc = VERR_NO_MEMORY;
406
407 return rc;
408}
409
410static DECLCALLBACK(int) rtDvmFmtBsdLblQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
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 {
422 rc = rtDvmFmtBsdLblVolumeCreate(pThis, &pThis->DiskLabel.aPartitions[i], i, phVolFmt);
423 break;
424 }
425 }
426 }
427 else
428 rc = VERR_DVM_MAP_EMPTY;
429
430 return rc;
431}
432
433static DECLCALLBACK(int) rtDvmFmtBsdLblQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
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
453/** @copydoc RTDVMFMTOPS::pfnQueryTableLocations */
454static 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
515static DECLCALLBACK(void) rtDvmFmtBsdLblVolumeClose(RTDVMVOLUMEFMT hVolFmt)
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
527static DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
528{
529 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
530
531 return pVol->cbVolume;
532}
533
534static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
535{
536 NOREF(hVolFmt); NOREF(ppszVolName);
537 return VERR_NOT_SUPPORTED;
538}
539
540static DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtBsdLblVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
541{
542 NOREF(hVolFmt);
543 return RTDVMVOLTYPE_UNKNOWN;
544}
545
546static DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
547{
548 NOREF(hVolFmt);
549 return DVMVOLUME_F_CONTIGUOUS;
550}
551
552static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryRange(RTDVMVOLUMEFMT hVolFmt, uint64_t *poffStart, uint64_t *poffLast)
553{
554 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
555 *poffStart = pVol->offStart;
556 *poffLast = pVol->offStart + pVol->cbVolume - 1;
557 return VINF_SUCCESS;
558}
559
560static DECLCALLBACK(bool) rtDvmFmtBsdLblVolumeIsRangeIntersecting(RTDVMVOLUMEFMT hVolFmt,
561 uint64_t offStart, size_t cbRange,
562 uint64_t *poffVol,
563 uint64_t *pcbIntersect)
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
578/** @copydoc RTDVMFMTOPS::pfnVolumeQueryTableLocation */
579static 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 */
588static 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:
601 case RTDVMVOLIDX_HOST:
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 */
612static 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
638static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
639{
640 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
641 AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
642
643 return rtDvmDiskReadUnaligned(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
644}
645
646static DECLCALLBACK(int) rtDvmFmtBsdLblVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
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
654DECL_HIDDEN_CONST(const RTDVMFMTOPS) g_rtDvmFmtBsdLbl =
655{
656 /* pcszFmt */
657 "BsdLabel",
658 /* enmFormat, */
659 RTDVMFORMATTYPE_BSD_LABEL,
660 /* pfnProbe */
661 rtDvmFmtBsdLblProbe,
662 /* pfnOpen */
663 rtDvmFmtBsdLblOpen,
664 /* pfnInitialize */
665 rtDvmFmtBsdLblInitialize,
666 /* pfnClose */
667 rtDvmFmtBsdLblClose,
668 /* pfnQueryRangeUse */
669 rtDvmFmtBsdLblQueryRangeUse,
670 /* pfnQueryDiskUuid */
671 NULL,
672 /* pfnGetValidVolumes */
673 rtDvmFmtBsdLblGetValidVolumes,
674 /* pfnGetMaxVolumes */
675 rtDvmFmtBsdLblGetMaxVolumes,
676 /* pfnQueryFirstVolume */
677 rtDvmFmtBsdLblQueryFirstVolume,
678 /* pfnQueryNextVolume */
679 rtDvmFmtBsdLblQueryNextVolume,
680 /* pfnQueryTableLocations */
681 rtDvmFmtBsdLblQueryTableLocations,
682 /* pfnVolumeClose */
683 rtDvmFmtBsdLblVolumeClose,
684 /* pfnVolumeGetSize */
685 rtDvmFmtBsdLblVolumeGetSize,
686 /* pfnVolumeQueryName */
687 rtDvmFmtBsdLblVolumeQueryName,
688 /* pfnVolumeGetType */
689 rtDvmFmtBsdLblVolumeGetType,
690 /* pfnVolumeGetFlags */
691 rtDvmFmtBsdLblVolumeGetFlags,
692 /* pfnVolumeQueryRange */
693 rtDvmFmtBsdLblVolumeQueryRange,
694 /* pfnVolumeIsRangeIntersecting */
695 rtDvmFmtBsdLblVolumeIsRangeIntersecting,
696 /* pfnVolumeQueryTableLocation */
697 rtDvmFmtBsdLblVolumeQueryTableLocation,
698 /* pfnVolumeGetIndex */
699 rtDvmFmtBsdLblVolumeGetIndex,
700 /* pfnVolumeQueryProp */
701 rtDvmFmtBsdLblVolumeQueryProp,
702 /* pfnVolumeRead */
703 rtDvmFmtBsdLblVolumeRead,
704 /* pfnVolumeWrite */
705 rtDvmFmtBsdLblVolumeWrite
706};
707
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use