VirtualBox

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

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

Runtime/dvm: don't use VALID_PTR here, that only confuses code scanners

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