VirtualBox

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

Last change on this file since 45234 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: dvmmbr.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - MBR format backend.
4 */
5
6/*
7 * Copyright (C) 2011-2012 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 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
219
220 NOREF(cbRange);
221
222 /* MBR uses the first sector only. */
223 if (off < 512)
224 *pfUsed = true;
225 else
226 *pfUsed = false;
227
228 return VINF_SUCCESS;
229}
230
231static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetValidVolumes(RTDVMFMT hVolMgrFmt)
232{
233 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
234
235 return pThis->cPartitions;
236}
237
238static DECLCALLBACK(uint32_t) rtDvmFmtMbrGetMaxVolumes(RTDVMFMT hVolMgrFmt)
239{
240 NOREF(hVolMgrFmt);
241 return 4; /** @todo: Add support for EBR? */
242}
243
244/**
245 * Creates a new volume.
246 *
247 * @returns IPRT status code.
248 * @param pThis The MBR volume manager data.
249 * @param pbMbrEntry The raw MBR entry data.
250 * @param idx The index in the partition table.
251 * @param phVolFmt Where to store the volume data on success.
252 */
253static int rtDvmFmtMbrVolumeCreate(PRTDVMFMTINTERNAL pThis, uint8_t *pbMbrEntry,
254 uint32_t idx, PRTDVMVOLUMEFMT phVolFmt)
255{
256 int rc = VINF_SUCCESS;
257 PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
258
259 if (pVol)
260 {
261 pVol->pVolMgr = pThis;
262 pVol->idxEntry = idx;
263 pVol->pbMbrEntry = pbMbrEntry;
264 pVol->offStart = *(uint32_t *)&pbMbrEntry[0x08] * pThis->pDisk->cbSector;
265 pVol->cbVolume = *(uint32_t *)&pbMbrEntry[0x0c] * pThis->pDisk->cbSector;
266
267 *phVolFmt = pVol;
268 }
269 else
270 rc = VERR_NO_MEMORY;
271
272 return rc;
273}
274
275static DECLCALLBACK(int) rtDvmFmtMbrQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
276{
277 int rc = VINF_SUCCESS;
278 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
279
280 if (pThis->cPartitions != 0)
281 {
282 uint8_t *pbMbrEntry = &pThis->abMbr[446];
283
284 /* Search for the first non empty entry. */
285 for (unsigned i = 0; i < 4; i++)
286 {
287 if (pbMbrEntry[0x04] != 0x00)
288 {
289 rc = rtDvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmt);
290 break;
291 }
292 pbMbrEntry += 16;
293 }
294 }
295 else
296 rc = VERR_DVM_MAP_EMPTY;
297
298 return rc;
299}
300
301static DECLCALLBACK(int) rtDvmFmtMbrQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
302{
303 int rc = VERR_DVM_MAP_NO_VOLUME;
304 PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
305 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
306 uint8_t *pbMbrEntry = pVol->pbMbrEntry + 16;
307
308 for (unsigned i = pVol->idxEntry + 1; i < 4; i++)
309 {
310 if (pbMbrEntry[0x04] != 0x00)
311 {
312 rc = rtDvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmtNext);
313 break;
314 }
315 pbMbrEntry += 16;
316 }
317
318 return rc;
319}
320
321static DECLCALLBACK(void) rtDvmFmtMbrVolumeClose(RTDVMVOLUMEFMT hVolFmt)
322{
323 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
324
325 pVol->pVolMgr = NULL;
326 pVol->offStart = 0;
327 pVol->cbVolume = 0;
328 pVol->pbMbrEntry = NULL;
329
330 RTMemFree(pVol);
331}
332
333static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
334{
335 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
336
337 return pVol->cbVolume;
338}
339
340static DECLCALLBACK(int) rtDvmFmtMbrVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
341{
342 NOREF(hVolFmt); NOREF(ppszVolName);
343 return VERR_NOT_SUPPORTED;
344}
345
346static DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtMbrVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
347{
348 RTDVMVOLTYPE enmVolType = RTDVMVOLTYPE_UNKNOWN;
349 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
350
351 for (unsigned i = 0; i < RT_ELEMENTS(g_aFs2DvmVolTypes); i++)
352 if (pVol->pbMbrEntry[0x04] == g_aFs2DvmVolTypes[i].bFsId)
353 {
354 enmVolType = g_aFs2DvmVolTypes[i].enmVolType;
355 break;
356 }
357
358 return enmVolType;
359}
360
361static DECLCALLBACK(uint64_t) rtDvmFmtMbrVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
362{
363 uint64_t fFlags = 0;
364 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
365
366 if (pVol->pbMbrEntry[0x00] & 0x80)
367 fFlags |= DVMVOLUME_FLAGS_BOOTABLE | DVMVOLUME_FLAGS_ACTIVE;
368
369 return fFlags;
370}
371
372DECLCALLBACK(bool) rtDvmFmtMbrVolumeIsRangeIntersecting(RTDVMVOLUMEFMT hVolFmt,
373 uint64_t offStart, size_t cbRange,
374 uint64_t *poffVol,
375 uint64_t *pcbIntersect)
376{
377 bool fIntersect = false;
378 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
379
380 if (RTDVM_RANGE_IS_INTERSECTING(pVol->offStart, pVol->cbVolume, offStart))
381 {
382 fIntersect = true;
383 *poffVol = offStart - pVol->offStart;
384 *pcbIntersect = RT_MIN(cbRange, pVol->offStart + pVol->cbVolume - offStart);
385 }
386
387 return fIntersect;
388}
389
390static DECLCALLBACK(int) rtDvmFmtMbrVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
391{
392 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
393 AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
394
395 return rtDvmDiskRead(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
396}
397
398static DECLCALLBACK(int) rtDvmFmtMbrVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
399{
400 PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
401 AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
402
403 return rtDvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
404}
405
406RTDVMFMTOPS g_rtDvmFmtMbr =
407{
408 /* pcszFmt */
409 "MBR",
410 /* pfnProbe */
411 rtDvmFmtMbrProbe,
412 /* pfnOpen */
413 rtDvmFmtMbrOpen,
414 /* pfnInitialize */
415 rtDvmFmtMbrInitialize,
416 /* pfnClose */
417 rtDvmFmtMbrClose,
418 /* pfnQueryRangeUse */
419 rtDvmFmtMbrQueryRangeUse,
420 /* pfnGetValidVolumes */
421 rtDvmFmtMbrGetValidVolumes,
422 /* pfnGetMaxVolumes */
423 rtDvmFmtMbrGetMaxVolumes,
424 /* pfnQueryFirstVolume */
425 rtDvmFmtMbrQueryFirstVolume,
426 /* pfnQueryNextVolume */
427 rtDvmFmtMbrQueryNextVolume,
428 /* pfnVolumeClose */
429 rtDvmFmtMbrVolumeClose,
430 /* pfnVolumeGetSize */
431 rtDvmFmtMbrVolumeGetSize,
432 /* pfnVolumeQueryName */
433 rtDvmFmtMbrVolumeQueryName,
434 /* pfnVolumeGetType */
435 rtDvmFmtMbrVolumeGetType,
436 /* pfnVolumeGetFlags */
437 rtDvmFmtMbrVolumeGetFlags,
438 /* pfnVOlumeIsRangeIntersecting */
439 rtDvmFmtMbrVolumeIsRangeIntersecting,
440 /* pfnVolumeRead */
441 rtDvmFmtMbrVolumeRead,
442 /* pfnVolumeWrite */
443 rtDvmFmtMbrVolumeWrite
444};
445
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