VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp@ 76531

Last change on this file since 76531 was 73156, checked in by vboxsync, 6 years ago

IPRT/DVM: Added more GUID and partition types. The VFS directory enum now returns symlink objects with the partition name linking to volXX when a name is present (there can be duplicates).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.9 KB
Line 
1/* $Id: dvmmbr.cpp 73156 2018-07-16 12:37:19Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - MBR format backend.
4 */
5
6/*
7 * Copyright (C) 2011-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_FS
32#include <iprt/types.h>
33#include <iprt/assert.h>
34#include <iprt/mem.h>
35#include <iprt/dvm.h>
36#include <iprt/list.h>
37#include <iprt/log.h>
38#include <iprt/string.h>
39#include "internal/dvm.h"
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45/** Checks if the partition type is an extended partition container. */
46#define RTDVMMBR_IS_EXTENDED(a_bType) ((a_bType) == 0x05 || (a_bType) == 0x0f)
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52/** Pointer to a MBR sector. */
53typedef struct RTDVMMBRSECTOR *PRTDVMMBRSECTOR;
54
55/**
56 * MBR entry.
57 */
58typedef struct RTDVMMBRENTRY
59{
60 /** Our entry in the in-use partition entry list (RTDVMMBRENTRY). */
61 RTLISTNODE ListEntry;
62 /** Pointer to the MBR sector containing this entry. */
63 PRTDVMMBRSECTOR pSector;
64 /** Pointer to the next sector in the extended partition table chain. */
65 PRTDVMMBRSECTOR pChain;
66 /** The byte offset of the start of the partition (relative to disk). */
67 uint64_t offPart;
68 /** Number of bytes for this partition. */
69 uint64_t cbPart;
70 /** The partition/filesystem type. */
71 uint8_t bType;
72 /** The partition flags. */
73 uint8_t fFlags;
74 /** Bad entry. */
75 bool fBad;
76} RTDVMMBRENTRY;
77/** Pointer to an MBR entry. */
78typedef RTDVMMBRENTRY *PRTDVMMBRENTRY;
79
80/**
81 * A MBR sector.
82 */
83typedef struct RTDVMMBRSECTOR
84{
85 /** Internal representation of the entries. */
86 RTDVMMBRENTRY aEntries[4];
87 /** The byte offset of this MBR sector (relative to disk).
88 * We keep this for detecting cycles now, but it will be needed if we start
89 * updating the partition table at some point. */
90 uint64_t offOnDisk;
91 /** Pointer to the previous sector if this isn't a primary one. */
92 PRTDVMMBRENTRY pPrevSector;
93 /** Set if this is the primary MBR, cleared if an extended. */
94 bool fIsPrimary;
95 /** Number of used entries. */
96 uint8_t cUsed;
97 /** Number of extended entries. */
98 uint8_t cExtended;
99 /** The extended entry we're following (we only follow one, except when
100 * fIsPrimary is @c true). UINT8_MAX if none. */
101 uint8_t idxExtended;
102 /** The raw data. */
103 uint8_t abData[512];
104} RTDVMMBRSECTOR;
105
106/**
107 * MBR volume manager data.
108 */
109typedef struct RTDVMFMTINTERNAL
110{
111 /** Pointer to the underlying disk. */
112 PCRTDVMDISK pDisk;
113 /** Head of the list of in-use RTDVMMBRENTRY structures. This excludes
114 * extended partition table entries. */
115 RTLISTANCHOR PartitionHead;
116 /** The total number of partitions, not counting extended ones. */
117 uint32_t cPartitions;
118 /** The actual primary MBR sector. */
119 RTDVMMBRSECTOR Primary;
120} RTDVMFMTINTERNAL;
121/** Pointer to the MBR volume manager. */
122typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
123
124/**
125 * MBR volume data.
126 */
127typedef struct RTDVMVOLUMEFMTINTERNAL
128{
129 /** Pointer to the volume manager. */
130 PRTDVMFMTINTERNAL pVolMgr;
131 /** The MBR entry. */
132 PRTDVMMBRENTRY pEntry;
133} RTDVMVOLUMEFMTINTERNAL;
134/** Pointer to an MBR volume. */
135typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
136
137
138/*********************************************************************************************************************************
139* Global Variables *
140*********************************************************************************************************************************/
141/**
142 * Mapping of FS types to DVM volume types.
143 *
144 * @see https://en.wikipedia.org/wiki/Partition_type
145 * @see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
146 */
147static const struct RTDVMMBRFS2VOLTYPE
148{
149 /** MBR FS Id. */
150 uint8_t bFsId;
151 /** DVM volume type. */
152 RTDVMVOLTYPE enmVolType;
153} g_aFs2DvmVolTypes[] =
154{
155 { 0x01, RTDVMVOLTYPE_FAT12 },
156 { 0x04, RTDVMVOLTYPE_FAT16 },
157 { 0x06, RTDVMVOLTYPE_FAT16 }, /* big FAT16 */
158 { 0x07, RTDVMVOLTYPE_NTFS }, /* Simplification: Used for HPFS, exFAT, ++, too but NTFS is the more common one. */
159 { 0x0b, RTDVMVOLTYPE_FAT32 },
160 { 0x0c, RTDVMVOLTYPE_FAT32 },
161 { 0x0e, RTDVMVOLTYPE_FAT16 },
162
163 /* Hidden variants of the above: */
164 { 0x11, RTDVMVOLTYPE_FAT12 },
165 { 0x14, RTDVMVOLTYPE_FAT16 },
166 { 0x16, RTDVMVOLTYPE_FAT16 },
167 { 0x17, RTDVMVOLTYPE_NTFS },
168 { 0x1b, RTDVMVOLTYPE_FAT32 },
169 { 0x1c, RTDVMVOLTYPE_FAT32 },
170 { 0x1e, RTDVMVOLTYPE_FAT16 },
171
172 { 0x82, RTDVMVOLTYPE_LINUX_SWAP },
173 { 0x83, RTDVMVOLTYPE_LINUX_NATIVE },
174 { 0x8e, RTDVMVOLTYPE_LINUX_LVM },
175 { 0xa5, RTDVMVOLTYPE_FREEBSD },
176 { 0xa9, RTDVMVOLTYPE_NETBSD },
177 { 0xa6, RTDVMVOLTYPE_OPENBSD },
178 { 0xaf, RTDVMVOLTYPE_DARWIN_HFS },
179 { 0xbf, RTDVMVOLTYPE_SOLARIS },
180 { 0xfd, RTDVMVOLTYPE_LINUX_SOFTRAID }
181};
182
183static DECLCALLBACK(int) rtDvmFmtMbrProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
184{
185 int rc = VINF_SUCCESS;
186 *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
187 if (pDisk->cbDisk >= 512)
188 {
189 /* Read from the disk and check for the 0x55aa signature at the end. */
190 uint8_t abMbr[512];
191 rc = rtDvmDiskRead(pDisk, 0, &abMbr[0], sizeof(abMbr));
192 if ( RT_SUCCESS(rc)
193 && abMbr[510] == 0x55
194 && abMbr[511] == 0xaa)
195 *puScore = RTDVM_MATCH_SCORE_SUPPORTED; /* Not perfect because GPTs have a protective MBR. */
196 }
197
198 return rc;
199}
200
201
202static void rtDvmFmtMbrDestroy(PRTDVMFMTINTERNAL pThis)
203{
204 /*
205 * Delete chains of extended partitions.
206 */
207 for (unsigned i = 0; i < 4; i++)
208 {
209 PRTDVMMBRSECTOR pCur = pThis->Primary.aEntries[i].pChain;
210 while (pCur)
211 {
212 PRTDVMMBRSECTOR pNext = pCur->idxExtended != UINT8_MAX ? pCur->aEntries[pCur->idxExtended].pChain : NULL;
213
214 RT_ZERO(pCur->aEntries);
215 pCur->pPrevSector = NULL;
216 RTMemFree(pCur);
217
218 pCur = pNext;
219 }
220 }
221
222 /*
223 * Now kill this.
224 */
225 pThis->pDisk = NULL;
226 RT_ZERO(pThis->Primary.aEntries);
227 RTMemFree(pThis);
228}
229
230
231static int rtDvmFmtMbrReadExtended(PRTDVMFMTINTERNAL pThis, PRTDVMMBRENTRY pPrimaryEntry)
232{
233 uint64_t const cbExt = pPrimaryEntry->cbPart;
234 uint64_t const offExtBegin = pPrimaryEntry->offPart;
235
236 uint64_t offCurBegin = offExtBegin;
237 PRTDVMMBRENTRY pCurEntry = pPrimaryEntry;
238 for (unsigned cTables = 1; ; cTables++)
239 {
240 /*
241 * Do some sanity checking.
242 */
243 /* Check the address of the partition table. */
244 if (offCurBegin - offExtBegin >= cbExt)
245 {
246 LogRel(("rtDvmFmtMbrReadExtended: offCurBegin=%#RX64 is outside the extended partition: %#RX64..%#RX64 (LB %#RX64)\n",
247 offCurBegin, offExtBegin, offExtBegin + cbExt - 1, cbExt));
248 pCurEntry->fBad = true;
249 return -VERR_OUT_OF_RANGE;
250 }
251
252 /* Limit the chain length. */
253 if (cTables > 64)
254 {
255 LogRel(("rtDvmFmtMbrReadExtended: offCurBegin=%#RX64 is the %uth table, we stop here.\n", offCurBegin, cTables));
256 pCurEntry->fBad = true;
257 return -VERR_TOO_MANY_SYMLINKS;
258 }
259
260 /* Check for obvious cycles. */
261 for (PRTDVMMBRENTRY pPrev = pCurEntry->pSector->pPrevSector; pPrev != NULL; pPrev = pPrev->pSector->pPrevSector)
262 if (pPrev->offPart == offCurBegin)
263 {
264 LogRel(("rtDvmFmtMbrReadExtended: Cycle! We've seen offCurBegin=%#RX64 before\n", offCurBegin));
265 pCurEntry->fBad = true;
266 return -VERR_TOO_MANY_SYMLINKS;
267 }
268
269 /*
270 * Allocate a new sector entry and read the sector with the table.
271 */
272 PRTDVMMBRSECTOR pNext = (PRTDVMMBRSECTOR)RTMemAllocZ(sizeof(*pNext));
273 if (!pNext)
274 return VERR_NO_MEMORY;
275 pNext->offOnDisk = offCurBegin;
276 pNext->pPrevSector = pCurEntry;
277 //pNext->fIsPrimary = false;
278 //pNext->cUsed = 0;
279 //pNext->cExtended = 0;
280 pNext->idxExtended = UINT8_MAX;
281
282 int rc = rtDvmDiskRead(pThis->pDisk, pNext->offOnDisk, &pNext->abData[0], sizeof(pNext->abData));
283 if ( RT_FAILURE(rc)
284 || pNext->abData[510] != 0x55
285 || pNext->abData[511] != 0xaa)
286 {
287 if (RT_FAILURE(rc))
288 LogRel(("rtDvmFmtMbrReadExtended: Error reading extended partition table at sector %#RX64: %Rrc\n", offCurBegin, rc));
289 else
290 LogRel(("rtDvmFmtMbrReadExtended: Extended partition table at sector %#RX64 does not have a valid DOS signature: %#x %#x\n",
291 offCurBegin, pNext->abData[510], pNext->abData[511]));
292 RTMemFree(pNext);
293 pCurEntry->fBad = true;
294 return rc;
295 }
296 pCurEntry->pChain = pNext;
297
298 /*
299 * Process the table, taking down the first forward entry.
300 *
301 * As noted in the caller of this function, we only deal with one extended
302 * partition entry at this level since noone really ever put more than one
303 * here anyway.
304 */
305 PRTDVMMBRENTRY pEntry = &pNext->aEntries[0];
306 uint8_t *pbMbrEntry = &pNext->abData[446];
307 for (unsigned i = 0; i < 4; i++, pEntry++, pbMbrEntry += 16)
308 {
309 uint8_t const bType = pbMbrEntry[4];
310 pEntry->pSector = pNext;
311 RTListInit(&pEntry->ListEntry);
312 if (bType != 0)
313 {
314 pEntry->bType = bType;
315 pEntry->fFlags = pbMbrEntry[0];
316 pEntry->offPart = RT_MAKE_U32_FROM_U8(pbMbrEntry[0x08],
317 pbMbrEntry[0x08 + 1],
318 pbMbrEntry[0x08 + 2],
319 pbMbrEntry[0x08 + 3]);
320 pEntry->offPart *= 512;
321 pEntry->cbPart = RT_MAKE_U32_FROM_U8(pbMbrEntry[0x0c],
322 pbMbrEntry[0x0c + 1],
323 pbMbrEntry[0x0c + 2],
324 pbMbrEntry[0x0c + 3]);
325 pEntry->cbPart *= 512;
326 if (!RTDVMMBR_IS_EXTENDED(bType))
327 {
328 pEntry->offPart += offCurBegin;
329 pThis->cPartitions++;
330 RTListAppend(&pThis->PartitionHead, &pEntry->ListEntry);
331 Log2(("rtDvmFmtMbrReadExtended: %#012RX64::%u: vol%u bType=%#04x fFlags=%#04x offPart=%#012RX64 cbPart=%#012RX64\n",
332 offCurBegin, i, pThis->cPartitions - 1, pEntry->bType, pEntry->fFlags, pEntry->offPart, pEntry->cbPart));
333 }
334 else
335 {
336 pEntry->offPart += offExtBegin;
337 pNext->cExtended++;
338 if (pNext->idxExtended == UINT8_MAX)
339 pNext->idxExtended = (uint8_t)i;
340 else
341 {
342 pEntry->fBad = true;
343 LogRel(("rtDvmFmtMbrReadExtended: Warning! Both #%u and #%u are extended partition table entries! Only following the former\n",
344 i, pNext->idxExtended));
345 }
346 Log2(("rtDvmFmtMbrReadExtended: %#012RX64::%u: ext%u bType=%#04x fFlags=%#04x offPart=%#012RX64 cbPart=%#012RX64\n",
347 offCurBegin, i, pNext->cExtended - 1, pEntry->bType, pEntry->fFlags, pEntry->offPart, pEntry->cbPart));
348 }
349 pNext->cUsed++;
350
351 }
352 /* else: unused */
353 }
354
355 /*
356 * We're done if we didn't find any extended partition table entry.
357 * Otherwise, advance to the next one.
358 */
359 if (!pNext->cExtended)
360 return VINF_SUCCESS;
361 pCurEntry = &pNext->aEntries[pNext->idxExtended];
362 offCurBegin = pCurEntry->offPart;
363 }
364}
365
366
367static DECLCALLBACK(int) rtDvmFmtMbrOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
368{
369 int rc;
370 PRTDVMFMTINTERNAL pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
371 if (pThis)
372 {
373 pThis->pDisk = pDisk;
374 //pThis->cPartitions = 0;
375 RTListInit(&pThis->PartitionHead);
376 //pThis->Primary.offOnDisk = 0;
377 //pThis->Primary.pPrevSector = NULL;
378 pThis->Primary.fIsPrimary = true;
379 //pThis->Primary.cUsed = 0;
380 //pThis->Primary.cExtended = 0;
381 pThis->Primary.idxExtended = UINT8_MAX;
382
383 /*
384 * Read the primary MBR.
385 */
386 rc = rtDvmDiskRead(pDisk, 0, &pThis->Primary.abData[0], sizeof(pThis->Primary.abData));
387 if (RT_SUCCESS(rc))
388 {
389 Assert(pThis->Primary.abData[510] == 0x55 && pThis->Primary.abData[511] == 0xaa);
390
391 /*
392 * Setup basic data for the 4 entries.
393 */
394 PRTDVMMBRENTRY pEntry = &pThis->Primary.aEntries[0];
395 uint8_t *pbMbrEntry = &pThis->Primary.abData[446];
396 for (unsigned i = 0; i < 4; i++, pEntry++, pbMbrEntry += 16)
397 {
398 pEntry->pSector = &pThis->Primary;
399 RTListInit(&pEntry->ListEntry);
400
401 uint8_t const bType = pbMbrEntry[4];
402 if (bType != 0)
403 {
404 pEntry->offPart = RT_MAKE_U32_FROM_U8(pbMbrEntry[0x08 + 0],
405 pbMbrEntry[0x08 + 1],
406 pbMbrEntry[0x08 + 2],
407 pbMbrEntry[0x08 + 3]);
408 pEntry->offPart *= 512;
409 pEntry->cbPart = RT_MAKE_U32_FROM_U8(pbMbrEntry[0x0c + 0],
410 pbMbrEntry[0x0c + 1],
411 pbMbrEntry[0x0c + 2],
412 pbMbrEntry[0x0c + 3]);
413 pEntry->cbPart *= 512;
414 pEntry->bType = bType;
415 pEntry->fFlags = pbMbrEntry[0];
416 if (!RTDVMMBR_IS_EXTENDED(bType))
417 {
418 pThis->cPartitions++;
419 RTListAppend(&pThis->PartitionHead, &pEntry->ListEntry);
420 Log2(("rtDvmFmtMbrOpen: %u: vol%u bType=%#04x fFlags=%#04x offPart=%#012RX64 cbPart=%#012RX64\n",
421 i, pThis->cPartitions - 1, pEntry->bType, pEntry->fFlags, pEntry->offPart, pEntry->cbPart));
422 }
423 else
424 {
425 pThis->Primary.cExtended++;
426 Log2(("rtDvmFmtMbrOpen: %u: ext%u bType=%#04x fFlags=%#04x offPart=%#012RX64 cbPart=%#012RX64\n",
427 i, pThis->Primary.cExtended - 1, pEntry->bType, pEntry->fFlags, pEntry->offPart, pEntry->cbPart));
428 }
429 pThis->Primary.cUsed++;
430 }
431 /* else: unused */
432 }
433
434 /*
435 * Now read any extended partitions. Since it's no big deal for us, we allow
436 * the primary partition table to have more than one extended partition. However
437 * in the extended tables we only allow a single forward link to avoid having to
438 * deal with recursion.
439 */
440 if (pThis->Primary.cExtended > 0)
441 for (unsigned i = 0; i < 4; i++)
442 if (RTDVMMBR_IS_EXTENDED(pThis->Primary.aEntries[i].bType))
443 {
444 if (pThis->Primary.idxExtended == UINT8_MAX)
445 pThis->Primary.idxExtended = (uint8_t)i;
446 rc = rtDvmFmtMbrReadExtended(pThis, &pThis->Primary.aEntries[i]);
447 if (RT_FAILURE(rc))
448 break;
449 }
450 if (RT_SUCCESS(rc))
451 {
452 *phVolMgrFmt = pThis;
453 return rc;
454 }
455
456 }
457 }
458 else
459 rc = VERR_NO_MEMORY;
460
461 return rc;
462}
463
464static DECLCALLBACK(int) rtDvmFmtMbrInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
465{
466 int rc;
467 PRTDVMFMTINTERNAL pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
468 if (pThis)
469 {
470 pThis->pDisk = pDisk;
471 //pThis->cPartitions = 0;
472 RTListInit(&pThis->PartitionHead);
473 //pThis->Primary.offOnDisk = 0
474 //pThis->Primary.pPrevSector = NULL;
475 pThis->Primary.fIsPrimary = true;
476 //pThis->Primary.cUsed = 0;
477 //pThis->Primary.cExtended = 0;
478 pThis->Primary.idxExtended = UINT8_MAX;
479
480 /* Setup a new MBR and write it to the disk. */
481 pThis->Primary.abData[510] = 0x55;
482 pThis->Primary.abData[511] = 0xaa;
483 rc = rtDvmDiskWrite(pDisk, 0, &pThis->Primary.abData[0], sizeof(pThis->Primary.abData));
484 if (RT_SUCCESS(rc))
485 {
486 pThis->pDisk = pDisk;
487 *phVolMgrFmt = pThis;
488 }
489 else
490 RTMemFree(pThis);
491 }
492 else
493 rc = VERR_NO_MEMORY;
494
495 return rc;
496}
497
498static DECLCALLBACK(void) rtDvmFmtMbrClose(RTDVMFMT hVolMgrFmt)
499{
500 rtDvmFmtMbrDestroy(hVolMgrFmt);
501}
502
503static DECLCALLBACK(int) rtDvmFmtMbrQueryRangeUse(RTDVMFMT hVolMgrFmt, uint64_t off, uint64_t cbRange, bool *pfUsed)
504{
505 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
506
507 /*
508 * The MBR definitely uses the first 512 bytes, but we consider anything up
509 * to 1MB of alignment padding / cylinder gap to be considered in use too.
510 *
511 * The cylinder gap has been used by several boot managers and boot loaders
512 * to store code and data.
513 */
514 if (off < (uint64_t)_1M)
515 {
516 *pfUsed = true;
517 return VINF_SUCCESS;
518 }
519
520 /* Ditto for any extended partition tables. */
521 for (uint32_t iPrimary = 0; iPrimary < 4; iPrimary++)
522 {
523 PRTDVMMBRSECTOR pCur = pThis->Primary.aEntries[iPrimary].pChain;
524 while (pCur)
525 {
526 if ( off < pCur->offOnDisk + _1M
527 && off + cbRange > pCur->offOnDisk)
528 {
529 *pfUsed = true;
530 return VINF_SUCCESS;
531 }
532
533
534 if (pCur->idxExtended == UINT8_MAX)
535 break;
536 pCur = pCur->aEntries[pCur->idxExtended].pChain;
537 }
538
539 }
540
541 /* Not in use. */
542 *pfUsed = false;
543 return VINF_SUCCESS;
544}
545
546static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetValidVolumes(RTDVMFMT hVolMgrFmt)
547{
548 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
549
550 return pThis->cPartitions;
551}
552
553static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetMaxVolumes(RTDVMFMT hVolMgrFmt)
554{
555 NOREF(hVolMgrFmt);
556 return 4; /** @todo Add support for EBR? */
557}
558
559/**
560 * Creates a new volume.
561 *
562 * @returns IPRT status code.
563 * @param pThis The MBR volume manager data.
564 * @param pEntry The MBR entry to create a volume handle for.
565 * @param phVolFmt Where to store the volume data on success.
566 */
567static int rtDvmFmtMbrVolumeCreate(PRTDVMFMTINTERNAL pThis, PRTDVMMBRENTRY pEntry, PRTDVMVOLUMEFMT phVolFmt)
568{
569 PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
570 if (pVol)
571 {
572 pVol->pVolMgr = pThis;
573 pVol->pEntry = pEntry;
574 *phVolFmt = pVol;
575 return VINF_SUCCESS;
576 }
577 return VERR_NO_MEMORY;
578}
579
580static DECLCALLBACK(int) rtDvmFmtMbrQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
581{
582 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
583 if (pThis->cPartitions != 0)
584 return rtDvmFmtMbrVolumeCreate(pThis, RTListGetFirst(&pThis->PartitionHead, RTDVMMBRENTRY, ListEntry), phVolFmt);
585 return VERR_DVM_MAP_EMPTY;
586}
587
588static DECLCALLBACK(int) rtDvmFmtMbrQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
589{
590 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
591 PRTDVMVOLUMEFMTINTERNAL pCurVol = hVolFmt;
592 if (pCurVol)
593 {
594 PRTDVMMBRENTRY pNextEntry = RTListGetNext(&pThis->PartitionHead, pCurVol->pEntry, RTDVMMBRENTRY, ListEntry);
595 if (pNextEntry)
596 return rtDvmFmtMbrVolumeCreate(pThis, pNextEntry, phVolFmtNext);
597 return VERR_DVM_MAP_NO_VOLUME;
598 }
599 if (pThis->cPartitions != 0)
600 return rtDvmFmtMbrVolumeCreate(pThis, RTListGetFirst(&pThis->PartitionHead, RTDVMMBRENTRY, ListEntry), phVolFmtNext);
601 return VERR_DVM_MAP_EMPTY;
602}
603
604static DECLCALLBACK(void) rtDvmFmtMbrVolumeClose(RTDVMVOLUMEFMT hVolFmt)
605{
606 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
607
608 pVol->pVolMgr = NULL;
609 pVol->pEntry = NULL;
610
611 RTMemFree(pVol);
612}
613
614static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
615{
616 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
617
618 return pVol->pEntry->cbPart;
619}
620
621static DECLCALLBACK(int) rtDvmFmtMbrVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
622{
623 NOREF(hVolFmt); NOREF(ppszVolName);
624 return VERR_NOT_SUPPORTED;
625}
626
627static DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtMbrVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
628{
629 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
630
631 uint8_t const bType = pVol->pEntry->bType;
632 for (unsigned i = 0; i < RT_ELEMENTS(g_aFs2DvmVolTypes); i++)
633 if (g_aFs2DvmVolTypes[i].bFsId == bType)
634 return g_aFs2DvmVolTypes[i].enmVolType;
635
636 return RTDVMVOLTYPE_UNKNOWN;
637}
638
639static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
640{
641 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
642
643 uint64_t fFlags = 0;
644 if (pVol->pEntry->bType & 0x80)
645 fFlags |= DVMVOLUME_FLAGS_BOOTABLE | DVMVOLUME_FLAGS_ACTIVE;
646
647 return fFlags;
648}
649
650static DECLCALLBACK(bool) rtDvmFmtMbrVolumeIsRangeIntersecting(RTDVMVOLUMEFMT hVolFmt, uint64_t offStart, size_t cbRange,
651 uint64_t *poffVol, uint64_t *pcbIntersect)
652{
653 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
654
655 if (RTDVM_RANGE_IS_INTERSECTING(pVol->pEntry->offPart, pVol->pEntry->cbPart, offStart))
656 {
657 *poffVol = offStart - pVol->pEntry->offPart;
658 *pcbIntersect = RT_MIN(cbRange, pVol->pEntry->offPart + pVol->pEntry->cbPart - offStart);
659 return true;
660 }
661 return false;
662}
663
664static DECLCALLBACK(int) rtDvmFmtMbrVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
665{
666 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
667 AssertReturn(off + cbRead <= pVol->pEntry->cbPart, VERR_INVALID_PARAMETER);
668
669 return rtDvmDiskRead(pVol->pVolMgr->pDisk, pVol->pEntry->offPart + off, pvBuf, cbRead);
670}
671
672static DECLCALLBACK(int) rtDvmFmtMbrVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
673{
674 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
675 AssertReturn(off + cbWrite <= pVol->pEntry->cbPart, VERR_INVALID_PARAMETER);
676
677 return rtDvmDiskWrite(pVol->pVolMgr->pDisk, pVol->pEntry->offPart + off, pvBuf, cbWrite);
678}
679
680RTDVMFMTOPS g_rtDvmFmtMbr =
681{
682 /* pszFmt */
683 "MBR",
684 /* enmFormat */
685 RTDVMFORMATTYPE_MBR,
686 /* pfnProbe */
687 rtDvmFmtMbrProbe,
688 /* pfnOpen */
689 rtDvmFmtMbrOpen,
690 /* pfnInitialize */
691 rtDvmFmtMbrInitialize,
692 /* pfnClose */
693 rtDvmFmtMbrClose,
694 /* pfnQueryRangeUse */
695 rtDvmFmtMbrQueryRangeUse,
696 /* pfnGetValidVolumes */
697 rtDvmFmtMbrGetValidVolumes,
698 /* pfnGetMaxVolumes */
699 rtDvmFmtMbrGetMaxVolumes,
700 /* pfnQueryFirstVolume */
701 rtDvmFmtMbrQueryFirstVolume,
702 /* pfnQueryNextVolume */
703 rtDvmFmtMbrQueryNextVolume,
704 /* pfnVolumeClose */
705 rtDvmFmtMbrVolumeClose,
706 /* pfnVolumeGetSize */
707 rtDvmFmtMbrVolumeGetSize,
708 /* pfnVolumeQueryName */
709 rtDvmFmtMbrVolumeQueryName,
710 /* pfnVolumeGetType */
711 rtDvmFmtMbrVolumeGetType,
712 /* pfnVolumeGetFlags */
713 rtDvmFmtMbrVolumeGetFlags,
714 /* pfnVOlumeIsRangeIntersecting */
715 rtDvmFmtMbrVolumeIsRangeIntersecting,
716 /* pfnVolumeRead */
717 rtDvmFmtMbrVolumeRead,
718 /* pfnVolumeWrite */
719 rtDvmFmtMbrVolumeWrite
720};
721
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette