VirtualBox

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

Last change on this file since 62477 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: dvmmbr.cpp 62477 2016-07-22 18:27:37Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - MBR format backend.
4 */
5
6/*
7 * Copyright (C) 2011-2016 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#include <iprt/types.h>
32#include <iprt/assert.h>
33#include <iprt/mem.h>
34#include <iprt/dvm.h>
35#include <iprt/string.h>
36#include "internal/dvm.h"
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42
43/**
44 * MBR volume manager data.
45 */
46typedef struct RTDVMFMTINTERNAL
47{
48 /** Pointer to the underlying disk. */
49 PCRTDVMDISK pDisk;
50 /** Number of initialized partitions. */
51 uint32_t cPartitions;
52 /** The raw MBR data. */
53 uint8_t abMbr[512];
54} RTDVMFMTINTERNAL;
55/** Pointer to the MBR volume manager. */
56typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
57
58/**
59 * MBR volume data.
60 */
61typedef struct RTDVMVOLUMEFMTINTERNAL
62{
63 /** Pointer to the volume manager. */
64 PRTDVMFMTINTERNAL pVolMgr;
65 /** Partition table entry index. */
66 uint32_t idxEntry;
67 /** Start offset of the volume. */
68 uint64_t offStart;
69 /** Size of the volume. */
70 uint64_t cbVolume;
71 /** Pointer to the raw partition table entry. */
72 uint8_t *pbMbrEntry;
73} RTDVMVOLUMEFMTINTERNAL;
74/** Pointer to an MBR volume. */
75typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
76
77/**
78 * MBR FS type to DVM volume type mapping entry.
79 */
80
81typedef struct RTDVMMBRFS2VOLTYPE
82{
83 /** MBR FS Id. */
84 uint8_t bFsId;
85 /** DVM volume type. */
86 RTDVMVOLTYPE enmVolType;
87} RTDVMMBRFS2VOLTYPE;
88/** Pointer to a MBR FS Type to volume type mapping entry. */
89typedef RTDVMMBRFS2VOLTYPE *PRTDVMMBRFS2VOLTYPE;
90
91
92/*********************************************************************************************************************************
93* Global Variables *
94*********************************************************************************************************************************/
95/**
96 * Mapping of FS types to DVM volume types.
97 *
98 * From http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
99 */
100static const RTDVMMBRFS2VOLTYPE g_aFs2DvmVolTypes[] =
101{
102 { 0x06, RTDVMVOLTYPE_FAT16 },
103 { 0x07, RTDVMVOLTYPE_NTFS }, /* Simplification: Used for HPFS, exFAT, ++, too but NTFS is the more common one. */
104 { 0x0b, RTDVMVOLTYPE_FAT32 },
105 { 0x0c, RTDVMVOLTYPE_FAT32 },
106 { 0x82, RTDVMVOLTYPE_LINUX_SWAP },
107 { 0x83, RTDVMVOLTYPE_LINUX_NATIVE },
108 { 0x8e, RTDVMVOLTYPE_LINUX_LVM },
109 { 0xa5, RTDVMVOLTYPE_FREEBSD },
110 { 0xa9, RTDVMVOLTYPE_NETBSD },
111 { 0xa6, RTDVMVOLTYPE_OPENBSD },
112 { 0xaf, RTDVMVOLTYPE_MAC_OSX_HFS },
113 { 0xbf, RTDVMVOLTYPE_SOLARIS },
114 { 0xfd, RTDVMVOLTYPE_LINUX_SOFTRAID }
115};
116
117static DECLCALLBACK(int) rtDvmFmtMbrProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
118{
119 int rc = VINF_SUCCESS;
120 uint8_t abMbr[512];
121
122 *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
123
124 if (pDisk->cbDisk >= 512)
125 {
126 /* Read from the disk and check for the 0x55aa signature at the end. */
127 rc = rtDvmDiskRead(pDisk, 0, &abMbr[0], sizeof(abMbr));
128 if ( RT_SUCCESS(rc)
129 && abMbr[510] == 0x55
130 && abMbr[511] == 0xaa)
131 *puScore = RTDVM_MATCH_SCORE_SUPPORTED; /* Not perfect because GPTs have a protective MBR. */
132 }
133
134 return rc;
135}
136
137static DECLCALLBACK(int) rtDvmFmtMbrOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
138{
139 int rc = VINF_SUCCESS;
140 PRTDVMFMTINTERNAL pThis = NULL;
141
142 pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
143 if (pThis)
144 {
145 pThis->pDisk = pDisk;
146 pThis->cPartitions = 0;
147
148 /* Read the MBR and count the valid partition entries. */
149 rc = rtDvmDiskRead(pDisk, 0, &pThis->abMbr[0], sizeof(pThis->abMbr));
150 if (RT_SUCCESS(rc))
151 {
152 uint8_t *pbMbrEntry = &pThis->abMbr[446];
153
154 Assert(pThis->abMbr[510] == 0x55 && pThis->abMbr[511] == 0xaa);
155
156 for (unsigned i = 0; i < 4; i++)
157 {
158 /* The entry is unused if the type contains 0x00. */
159 if (pbMbrEntry[4] != 0x00)
160 pThis->cPartitions++;
161
162 pbMbrEntry += 16;
163 }
164
165 *phVolMgrFmt = pThis;
166 }
167 }
168 else
169 rc = VERR_NO_MEMORY;
170
171 return rc;
172}
173
174static DECLCALLBACK(int) rtDvmFmtMbrInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
175{
176 int rc = VINF_SUCCESS;
177 PRTDVMFMTINTERNAL pThis = NULL;
178
179 pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
180 if (pThis)
181 {
182 /* Setup a new MBR and write it to the disk. */
183 memset(&pThis->abMbr[0], 0, sizeof(pThis->abMbr));
184 pThis->abMbr[510] = 0x55;
185 pThis->abMbr[511] = 0xaa;
186
187 rc = rtDvmDiskWrite(pDisk, 0, &pThis->abMbr[0], sizeof(pThis->abMbr));
188
189 if (RT_SUCCESS(rc))
190 {
191 pThis->pDisk = pDisk;
192 pThis->cPartitions = 0;
193 *phVolMgrFmt = pThis;
194 }
195 else
196 RTMemFree(pThis);
197 }
198 else
199 rc = VERR_NO_MEMORY;
200
201 return rc;
202}
203
204static DECLCALLBACK(void) rtDvmFmtMbrClose(RTDVMFMT hVolMgrFmt)
205{
206 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
207
208 pThis->pDisk = NULL;
209 pThis->cPartitions = 0;
210 memset(&pThis->abMbr[0], 0, sizeof(pThis->abMbr));
211 RTMemFree(pThis);
212}
213
214static DECLCALLBACK(int) rtDvmFmtMbrQueryRangeUse(RTDVMFMT hVolMgrFmt,
215 uint64_t off, uint64_t cbRange,
216 bool *pfUsed)
217{
218 NOREF(hVolMgrFmt);
219 NOREF(cbRange);
220
221 /* MBR uses the first sector only. */
222 *pfUsed = off < 512;
223 return VINF_SUCCESS;
224}
225
226static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetValidVolumes(RTDVMFMT hVolMgrFmt)
227{
228 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
229
230 return pThis->cPartitions;
231}
232
233static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetMaxVolumes(RTDVMFMT hVolMgrFmt)
234{
235 NOREF(hVolMgrFmt);
236 return 4; /** @todo: Add support for EBR? */
237}
238
239/**
240 * Creates a new volume.
241 *
242 * @returns IPRT status code.
243 * @param pThis The MBR volume manager data.
244 * @param pbMbrEntry The raw MBR entry data.
245 * @param idx The index in the partition table.
246 * @param phVolFmt Where to store the volume data on success.
247 */
248static int rtDvmFmtMbrVolumeCreate(PRTDVMFMTINTERNAL pThis, uint8_t *pbMbrEntry,
249 uint32_t idx, PRTDVMVOLUMEFMT phVolFmt)
250{
251 int rc = VINF_SUCCESS;
252 PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
253
254 if (pVol)
255 {
256 pVol->pVolMgr = pThis;
257 pVol->idxEntry = idx;
258 pVol->pbMbrEntry = pbMbrEntry;
259 pVol->offStart = *(uint32_t *)&pbMbrEntry[0x08] * pThis->pDisk->cbSector;
260 pVol->cbVolume = *(uint32_t *)&pbMbrEntry[0x0c] * pThis->pDisk->cbSector;
261
262 *phVolFmt = pVol;
263 }
264 else
265 rc = VERR_NO_MEMORY;
266
267 return rc;
268}
269
270static DECLCALLBACK(int) rtDvmFmtMbrQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
271{
272 int rc = VINF_SUCCESS;
273 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
274
275 if (pThis->cPartitions != 0)
276 {
277 uint8_t *pbMbrEntry = &pThis->abMbr[446];
278
279 /* Search for the first non empty entry. */
280 for (unsigned i = 0; i < 4; i++)
281 {
282 if (pbMbrEntry[0x04] != 0x00)
283 {
284 rc = rtDvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmt);
285 break;
286 }
287 pbMbrEntry += 16;
288 }
289 }
290 else
291 rc = VERR_DVM_MAP_EMPTY;
292
293 return rc;
294}
295
296static DECLCALLBACK(int) rtDvmFmtMbrQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
297{
298 int rc = VERR_DVM_MAP_NO_VOLUME;
299 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
300 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
301 uint8_t *pbMbrEntry = pVol->pbMbrEntry + 16;
302
303 for (unsigned i = pVol->idxEntry + 1; i < 4; i++)
304 {
305 if (pbMbrEntry[0x04] != 0x00)
306 {
307 rc = rtDvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmtNext);
308 break;
309 }
310 pbMbrEntry += 16;
311 }
312
313 return rc;
314}
315
316static DECLCALLBACK(void) rtDvmFmtMbrVolumeClose(RTDVMVOLUMEFMT hVolFmt)
317{
318 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
319
320 pVol->pVolMgr = NULL;
321 pVol->offStart = 0;
322 pVol->cbVolume = 0;
323 pVol->pbMbrEntry = NULL;
324
325 RTMemFree(pVol);
326}
327
328static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
329{
330 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
331
332 return pVol->cbVolume;
333}
334
335static DECLCALLBACK(int) rtDvmFmtMbrVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
336{
337 NOREF(hVolFmt); NOREF(ppszVolName);
338 return VERR_NOT_SUPPORTED;
339}
340
341static DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtMbrVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
342{
343 RTDVMVOLTYPE enmVolType = RTDVMVOLTYPE_UNKNOWN;
344 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
345
346 for (unsigned i = 0; i < RT_ELEMENTS(g_aFs2DvmVolTypes); i++)
347 if (pVol->pbMbrEntry[0x04] == g_aFs2DvmVolTypes[i].bFsId)
348 {
349 enmVolType = g_aFs2DvmVolTypes[i].enmVolType;
350 break;
351 }
352
353 return enmVolType;
354}
355
356static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
357{
358 uint64_t fFlags = 0;
359 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
360
361 if (pVol->pbMbrEntry[0x00] & 0x80)
362 fFlags |= DVMVOLUME_FLAGS_BOOTABLE | DVMVOLUME_FLAGS_ACTIVE;
363
364 return fFlags;
365}
366
367static DECLCALLBACK(bool) rtDvmFmtMbrVolumeIsRangeIntersecting(RTDVMVOLUMEFMT hVolFmt,
368 uint64_t offStart, size_t cbRange,
369 uint64_t *poffVol,
370 uint64_t *pcbIntersect)
371{
372 bool fIntersect = false;
373 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
374
375 if (RTDVM_RANGE_IS_INTERSECTING(pVol->offStart, pVol->cbVolume, offStart))
376 {
377 fIntersect = true;
378 *poffVol = offStart - pVol->offStart;
379 *pcbIntersect = RT_MIN(cbRange, pVol->offStart + pVol->cbVolume - offStart);
380 }
381
382 return fIntersect;
383}
384
385static DECLCALLBACK(int) rtDvmFmtMbrVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
386{
387 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
388 AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
389
390 return rtDvmDiskRead(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
391}
392
393static DECLCALLBACK(int) rtDvmFmtMbrVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
394{
395 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
396 AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
397
398 return rtDvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
399}
400
401RTDVMFMTOPS g_rtDvmFmtMbr =
402{
403 /* pcszFmt */
404 "MBR",
405 /* pfnProbe */
406 rtDvmFmtMbrProbe,
407 /* pfnOpen */
408 rtDvmFmtMbrOpen,
409 /* pfnInitialize */
410 rtDvmFmtMbrInitialize,
411 /* pfnClose */
412 rtDvmFmtMbrClose,
413 /* pfnQueryRangeUse */
414 rtDvmFmtMbrQueryRangeUse,
415 /* pfnGetValidVolumes */
416 rtDvmFmtMbrGetValidVolumes,
417 /* pfnGetMaxVolumes */
418 rtDvmFmtMbrGetMaxVolumes,
419 /* pfnQueryFirstVolume */
420 rtDvmFmtMbrQueryFirstVolume,
421 /* pfnQueryNextVolume */
422 rtDvmFmtMbrQueryNextVolume,
423 /* pfnVolumeClose */
424 rtDvmFmtMbrVolumeClose,
425 /* pfnVolumeGetSize */
426 rtDvmFmtMbrVolumeGetSize,
427 /* pfnVolumeQueryName */
428 rtDvmFmtMbrVolumeQueryName,
429 /* pfnVolumeGetType */
430 rtDvmFmtMbrVolumeGetType,
431 /* pfnVolumeGetFlags */
432 rtDvmFmtMbrVolumeGetFlags,
433 /* pfnVOlumeIsRangeIntersecting */
434 rtDvmFmtMbrVolumeIsRangeIntersecting,
435 /* pfnVolumeRead */
436 rtDvmFmtMbrVolumeRead,
437 /* pfnVolumeWrite */
438 rtDvmFmtMbrVolumeWrite
439};
440
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