VirtualBox

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

Last change on this file since 42072 was 41549, checked in by vboxsync, 13 years ago

VFS/Filesystem: Convert the filesystem specific code to the VFS framework and make it work

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