VirtualBox

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

Last change on this file since 69887 was 69887, checked in by vboxsync, 7 years ago

iprt/dvmmbr.cpp: Don't consider the gap/padding between a partition table and the partition as unused as its traditionally used by boot loaders and managers. Instead of guessing what the gap is based on incorrect sectors per heads and worse, just consider 1MiB starting from a partition table to be in use. Also, take extended partition tables into account when checking whether a range is in use (original code didn't support that).

  • 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 69887 2017-11-30 17:46:06Z 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_MAC_OSX_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 uint32_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