VirtualBox

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

Last change on this file since 85938 was 85894, checked in by vboxsync, 4 years ago

IPRT/Dvm: Added RTDvmMapQueryTableLocations (for VMDK). Completely untested. bugref:9224

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.3 KB
Line 
1/* $Id: dvm.cpp 85894 2020-08-26 20:50:52Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - generic code.
4 */
5
6/*
7 * Copyright (C) 2011-2020 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/err.h>
36#include <iprt/asm.h>
37#include <iprt/string.h>
38#include <iprt/list.h>
39#include "internal/dvm.h"
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45
46/**
47 * The internal volume manager structure.
48 */
49typedef struct RTDVMINTERNAL
50{
51 /** The DVM magic (RTDVM_MAGIC). */
52 uint32_t u32Magic;
53 /** The disk descriptor. */
54 RTDVMDISK DvmDisk;
55 /** Pointer to the backend operations table after a successful probe. */
56 PCRTDVMFMTOPS pDvmFmtOps;
57 /** The format specific volume manager data. */
58 RTDVMFMT hVolMgrFmt;
59 /** Flags passed on manager creation. */
60 uint32_t fFlags;
61 /** Reference counter. */
62 uint32_t volatile cRefs;
63 /** List of recognised volumes (RTDVMVOLUMEINTERNAL). */
64 RTLISTANCHOR VolumeList;
65} RTDVMINTERNAL;
66/** Pointer to an internal volume manager. */
67typedef RTDVMINTERNAL *PRTDVMINTERNAL;
68
69/**
70 * The internal volume structure.
71 */
72typedef struct RTDVMVOLUMEINTERNAL
73{
74 /** The DVM volume magic (RTDVMVOLUME_MAGIC). */
75 uint32_t u32Magic;
76 /** Node for the volume list. */
77 RTLISTNODE VolumeNode;
78 /** Pointer to the owning volume manager. */
79 PRTDVMINTERNAL pVolMgr;
80 /** Format specific volume data. */
81 RTDVMVOLUMEFMT hVolFmt;
82 /** Set block status.callback */
83 PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus;
84 /** Opaque user data. */
85 void *pvUser;
86 /** Reference counter. */
87 uint32_t volatile cRefs;
88} RTDVMVOLUMEINTERNAL;
89/** Pointer to an internal volume. */
90typedef RTDVMVOLUMEINTERNAL *PRTDVMVOLUMEINTERNAL;
91
92
93/*********************************************************************************************************************************
94* Global variables *
95*********************************************************************************************************************************/
96/**
97 * Supported volume formats.
98 */
99static PCRTDVMFMTOPS const g_aDvmFmts[] =
100{
101 &g_rtDvmFmtMbr,
102 &g_rtDvmFmtGpt,
103 &g_rtDvmFmtBsdLbl
104};
105
106/**
107 * Descriptions of the volume types.
108 *
109 * This is indexed by RTDVMVOLTYPE.
110 */
111static const char * const g_apszDvmVolTypes[] =
112{
113 "Invalid",
114 "Unknown",
115 "NTFS",
116 "FAT12",
117 "FAT16",
118 "FAT32",
119
120 "EFI system partition",
121
122 "Mac OS X HFS or HFS+",
123 "Mac OS X APFS",
124
125 "Linux swap",
126 "Linux native",
127 "Linux LVM",
128 "Linux SoftRaid",
129
130 "FreeBSD",
131 "NetBSD",
132 "OpenBSD",
133 "Solaris",
134
135 "Basic data partition",
136 "Microsoft reserved partition",
137 "Windows LDM metadata",
138 "Windows LDM data",
139 "Windows recovery partition",
140 "Windows storage spaces",
141
142 "IBM GPFS",
143};
144AssertCompile(RT_ELEMENTS(g_apszDvmVolTypes) == RTDVMVOLTYPE_END);
145
146
147/**
148 * Read from the disk at the given offset, neither the offset nor the size is
149 * necessary sector aligned.
150 *
151 * @returns IPRT status code.
152 * @param pDisk The disk descriptor to read from.
153 * @param off Start offset.
154 * @param pvBuf Destination buffer.
155 * @param cbRead How much to read.
156 */
157DECLHIDDEN(int) rtDvmDiskReadUnaligned(PCRTDVMDISK pDisk, uint64_t off, void *pvBuf, size_t cbRead)
158{
159 size_t const cbSector = (size_t)pDisk->cbSector;
160 size_t const offDelta = off % cbSector;
161 size_t const cbDelta = cbRead % cbSector;
162 if (!cbDelta && !offDelta)
163 return rtDvmDiskRead(pDisk, off, pvBuf, cbRead);
164
165 int rc;
166 size_t cbExtra = offDelta + (cbDelta ? cbSector - cbDelta: 0);
167 uint8_t *pbTmpBuf = (uint8_t *)RTMemTmpAlloc(cbRead + cbExtra);
168 if (pbTmpBuf)
169 {
170 rc = rtDvmDiskRead(pDisk, off - offDelta, pbTmpBuf, cbRead + cbExtra);
171 if (RT_SUCCESS(rc))
172 memcpy(pvBuf, &pbTmpBuf[offDelta], cbRead);
173 else
174 RT_BZERO(pvBuf, cbRead);
175 RTMemTmpFree(pbTmpBuf);
176 }
177 else
178 rc = VERR_NO_TMP_MEMORY;
179 return rc;
180}
181
182
183/**
184 * Creates a new volume.
185 *
186 * @returns IPRT status code.
187 * @param pThis The DVM map instance.
188 * @param hVolFmt The format specific volume handle.
189 * @param phVol Where to store the generic volume handle on success.
190 */
191static int rtDvmVolumeCreate(PRTDVMINTERNAL pThis, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUME phVol)
192{
193 PRTDVMVOLUMEINTERNAL pVol = (PRTDVMVOLUMEINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEINTERNAL));
194 if (pVol)
195 {
196 pVol->u32Magic = RTDVMVOLUME_MAGIC;
197 pVol->cRefs = 0;
198 pVol->pVolMgr = pThis;
199 pVol->hVolFmt = hVolFmt;
200
201 *phVol = pVol;
202 return VINF_SUCCESS;
203 }
204 return VERR_NO_MEMORY;
205}
206
207/**
208 * Destroys a volume handle.
209 *
210 * @param pThis The volume manager instance.
211 * @param pVol The volume to destroy.
212 */
213static void rtDvmVolumeDestroy(PRTDVMINTERNAL pThis, PRTDVMVOLUMEINTERNAL pVol)
214{
215 AssertPtr(pThis);
216 AssertPtr(pThis->pDvmFmtOps);
217 Assert(pVol->pVolMgr == pThis);
218
219 /* Close the volume. */
220 pThis->pDvmFmtOps->pfnVolumeClose(pVol->hVolFmt);
221
222 pVol->u32Magic = RTDVMVOLUME_MAGIC_DEAD;
223 pVol->pVolMgr = NULL;
224 pVol->hVolFmt = NIL_RTDVMVOLUMEFMT;
225 RTMemFree(pVol);
226}
227
228
229RTDECL(int) RTDvmCreate(PRTDVM phVolMgr, RTVFSFILE hVfsFile, uint32_t cbSector, uint32_t fFlags)
230{
231 AssertMsgReturn(!(fFlags & ~DVM_FLAGS_VALID_MASK), ("Invalid flags given %#x\n", fFlags), VERR_INVALID_FLAGS);
232 uint32_t cRefs = RTVfsFileRetain(hVfsFile);
233 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
234
235 uint64_t cbDisk;
236 int rc = RTVfsFileQuerySize(hVfsFile, &cbDisk);
237 if (RT_SUCCESS(rc))
238 {
239 PRTDVMINTERNAL pThis = (PRTDVMINTERNAL)RTMemAllocZ(sizeof(RTDVMINTERNAL));
240 if (pThis)
241 {
242 pThis->u32Magic = RTDVM_MAGIC;
243 pThis->DvmDisk.cbDisk = cbDisk;
244 pThis->DvmDisk.cbSector = cbSector;
245 pThis->DvmDisk.hVfsFile = hVfsFile;
246
247 pThis->pDvmFmtOps = NULL;
248 pThis->hVolMgrFmt = NIL_RTDVMFMT;
249 pThis->fFlags = fFlags;
250 pThis->cRefs = 1;
251 RTListInit(&pThis->VolumeList);
252
253 *phVolMgr = pThis;
254 return VINF_SUCCESS;
255 }
256 rc = VERR_NO_MEMORY;
257 }
258 RTVfsFileRelease(hVfsFile);
259 return rc;
260}
261
262
263RTDECL(uint32_t) RTDvmRetain(RTDVM hVolMgr)
264{
265 PRTDVMINTERNAL pThis = hVolMgr;
266 AssertPtrReturn(pThis, UINT32_MAX);
267 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
268
269 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
270 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
271 return cRefs;
272}
273
274/**
275 * Destroys a volume manager handle.
276 *
277 * @param pThis The volume manager to destroy.
278 */
279static void rtDvmDestroy(PRTDVMINTERNAL pThis)
280{
281 pThis->u32Magic = RTDVM_MAGIC_DEAD;
282
283 if (pThis->hVolMgrFmt != NIL_RTDVMFMT)
284 {
285 AssertPtr(pThis->pDvmFmtOps);
286
287 /* */
288 PRTDVMVOLUMEINTERNAL pItNext, pIt;
289 RTListForEachSafe(&pThis->VolumeList, pIt, pItNext, RTDVMVOLUMEINTERNAL, VolumeNode)
290 {
291 RTListNodeRemove(&pIt->VolumeNode);
292 rtDvmVolumeDestroy(pThis, pIt);
293 }
294
295 /* Let the backend do it's own cleanup first. */
296 pThis->pDvmFmtOps->pfnClose(pThis->hVolMgrFmt);
297 pThis->hVolMgrFmt = NIL_RTDVMFMT;
298 pThis->pDvmFmtOps = NULL;
299 }
300
301 pThis->DvmDisk.cbDisk = 0;
302 pThis->DvmDisk.cbSector = 0;
303 if (pThis->DvmDisk.hVfsFile != NIL_RTVFSFILE)
304 {
305 RTVfsFileRelease(pThis->DvmDisk.hVfsFile);
306 pThis->DvmDisk.hVfsFile = NIL_RTVFSFILE;
307 }
308
309 RTMemFree(pThis);
310}
311
312RTDECL(uint32_t) RTDvmRelease(RTDVM hVolMgr)
313{
314 PRTDVMINTERNAL pThis = hVolMgr;
315 if (pThis == NIL_RTDVM)
316 return 0;
317 AssertPtrReturn(pThis, UINT32_MAX);
318 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
319
320 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
321 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
322 if (cRefs == 0)
323 rtDvmDestroy(pThis);
324 return cRefs;
325}
326
327RTDECL(int) RTDvmMapOpen(RTDVM hVolMgr)
328{
329 PRTDVMINTERNAL pThis = hVolMgr;
330 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
331 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
332 AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_WRONG_ORDER);
333
334 Assert(!pThis->pDvmFmtOps);
335
336 /*
337 * Let each format backend have a go at the disk, pick the one which scores the highest.
338 */
339 int rc = VINF_SUCCESS;
340 uint32_t uScoreMax = RTDVM_MATCH_SCORE_UNSUPPORTED;
341 PCRTDVMFMTOPS pDvmFmtOpsMatch = NULL;
342 for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
343 {
344 uint32_t uScore = 0;
345 PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
346
347 rc = pDvmFmtOps->pfnProbe(&pThis->DvmDisk, &uScore);
348 if (RT_SUCCESS(rc))
349 {
350 if (uScore > uScoreMax)
351 {
352 pDvmFmtOpsMatch = pDvmFmtOps;
353 uScoreMax = uScore;
354 }
355 }
356 else
357 return rc;
358 }
359 if (uScoreMax > RTDVM_MATCH_SCORE_UNSUPPORTED)
360 {
361 AssertPtr(pDvmFmtOpsMatch);
362
363 /*
364 * Open the format.
365 */
366 rc = pDvmFmtOpsMatch->pfnOpen(&pThis->DvmDisk, &pThis->hVolMgrFmt);
367 if (RT_SUCCESS(rc))
368 {
369 pThis->pDvmFmtOps = pDvmFmtOpsMatch;
370
371 /*
372 * Construct volume list (we're done if none).
373 */
374 uint32_t cVols = pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
375 if (cVols == 0)
376 return VINF_SUCCESS;
377
378 /* First volume. */
379 RTDVMVOLUMEFMT hVolFmt = NIL_RTDVMVOLUMEFMT;
380 rc = pThis->pDvmFmtOps->pfnQueryFirstVolume(pThis->hVolMgrFmt, &hVolFmt);
381 if (RT_SUCCESS(rc))
382 {
383 for (;;)
384 {
385 PRTDVMVOLUMEINTERNAL pVol = NULL;
386 rc = rtDvmVolumeCreate(pThis, hVolFmt, &pVol);
387 if (RT_FAILURE(rc))
388 {
389 pThis->pDvmFmtOps->pfnVolumeClose(hVolFmt);
390 break;
391 }
392 RTListAppend(&pThis->VolumeList, &pVol->VolumeNode);
393
394 /* Done?*/
395 cVols--;
396 if (cVols < 1)
397 return VINF_SUCCESS;
398
399 /* Next volume. */
400 rc = pThis->pDvmFmtOps->pfnQueryNextVolume(pThis->hVolMgrFmt, pVol->hVolFmt, &hVolFmt);
401 if (RT_FAILURE(rc))
402 break;
403 }
404
405 /* Bail out. */
406 PRTDVMVOLUMEINTERNAL pItNext, pIt;
407 RTListForEachSafe(&pThis->VolumeList, pIt, pItNext, RTDVMVOLUMEINTERNAL, VolumeNode)
408 {
409 RTListNodeRemove(&pIt->VolumeNode);
410 rtDvmVolumeDestroy(pThis, pIt);
411 }
412 }
413
414 pDvmFmtOpsMatch->pfnClose(pThis->hVolMgrFmt);
415 }
416 }
417 else
418 rc = VERR_NOT_SUPPORTED;
419 return rc;
420}
421
422RTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt)
423{
424 PRTDVMINTERNAL pThis = hVolMgr;
425 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
426 AssertPtrReturn(pszFmt, VERR_INVALID_POINTER);
427 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
428 AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_WRONG_ORDER);
429
430 for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
431 {
432 PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
433 if (!RTStrCmp(pDvmFmtOps->pszFmt, pszFmt))
434 {
435 int rc = pDvmFmtOps->pfnInitialize(&pThis->DvmDisk, &pThis->hVolMgrFmt);
436 if (RT_SUCCESS(rc))
437 pThis->pDvmFmtOps = pDvmFmtOps;
438 return rc;
439 }
440 }
441 return VERR_NOT_SUPPORTED;
442}
443
444RTDECL(const char *) RTDvmMapGetFormatName(RTDVM hVolMgr)
445{
446 PRTDVMINTERNAL pThis = hVolMgr;
447 AssertPtrReturn(pThis, NULL);
448 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, NULL);
449 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, NULL);
450
451 return pThis->pDvmFmtOps->pszFmt;
452}
453
454RTDECL(RTDVMFORMATTYPE) RTDvmMapGetFormatType(RTDVM hVolMgr)
455{
456 PRTDVMINTERNAL pThis = hVolMgr;
457 AssertPtrReturn(pThis, RTDVMFORMATTYPE_INVALID);
458 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, RTDVMFORMATTYPE_INVALID);
459 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, RTDVMFORMATTYPE_INVALID);
460
461 return pThis->pDvmFmtOps->enmFormat;
462}
463
464RTDECL(int) RTDvmMapQueryDiskUuid(RTDVM hVolMgr, PRTUUID pUuid)
465{
466 PRTDVMINTERNAL pThis = hVolMgr;
467 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
468 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
469 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
470 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
471
472 if (pThis->pDvmFmtOps->pfnQueryDiskUuid)
473 return pThis->pDvmFmtOps->pfnQueryDiskUuid(pThis->hVolMgrFmt, pUuid);
474 return VERR_NOT_SUPPORTED;
475}
476
477RTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr)
478{
479 PRTDVMINTERNAL pThis = hVolMgr;
480 AssertPtrReturn(pThis, UINT32_MAX);
481 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
482 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
483
484 return pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
485}
486
487RTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr)
488{
489 PRTDVMINTERNAL pThis = hVolMgr;
490 AssertPtrReturn(pThis, UINT32_MAX);
491 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
492 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
493
494 return pThis->pDvmFmtOps->pfnGetMaxVolumes(pThis->hVolMgrFmt);
495}
496
497RTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol)
498{
499 PRTDVMINTERNAL pThis = hVolMgr;
500 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
501 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
502 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
503 AssertPtrReturn(phVol, VERR_INVALID_POINTER);
504
505 int rc = VERR_DVM_MAP_EMPTY;
506 PRTDVMVOLUMEINTERNAL pVol = RTListGetFirst(&pThis->VolumeList, RTDVMVOLUMEINTERNAL, VolumeNode);
507 if (pVol)
508 {
509 rc = VINF_SUCCESS;
510 RTDvmVolumeRetain(pVol);
511 *phVol = pVol;
512 }
513
514 return rc;
515}
516
517RTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext)
518{
519 PRTDVMINTERNAL pThis = hVolMgr;
520 PRTDVMVOLUMEINTERNAL pVol = hVol;
521 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
522 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
523 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
524 AssertPtrReturn(pVol, VERR_INVALID_HANDLE);
525 AssertReturn(pVol->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
526 AssertPtrReturn(phVolNext, VERR_INVALID_POINTER);
527
528 int rc = VERR_DVM_MAP_NO_VOLUME;
529 PRTDVMVOLUMEINTERNAL pVolNext = RTListGetNext(&pThis->VolumeList, pVol, RTDVMVOLUMEINTERNAL, VolumeNode);
530 if (pVolNext)
531 {
532 rc = VINF_SUCCESS;
533 RTDvmVolumeRetain(pVolNext);
534 *phVolNext = pVolNext;
535 }
536
537 return rc;
538}
539
540RTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb, bool *pfAllocated)
541{
542 PRTDVMINTERNAL pThis = hVolMgr;
543
544 /*
545 * Input validation.
546 */
547 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
548 AssertPtrReturn(pfAllocated, VERR_INVALID_POINTER);
549 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
550 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_WRONG_ORDER);
551 AssertMsgReturn( off <= pThis->DvmDisk.cbDisk
552 || cb <= pThis->DvmDisk.cbDisk
553 || off + cb <= pThis->DvmDisk.cbDisk,
554 ("off=%#RX64 cb=%#RX64 cbDisk=%#RX64\n", off, cb, pThis->DvmDisk.cbDisk),
555 VERR_OUT_OF_RANGE);
556
557 /*
558 * Check whether the range is inuse by the volume manager metadata first.
559 */
560 int rc = pThis->pDvmFmtOps->pfnQueryRangeUse(pThis->hVolMgrFmt, off, cb, pfAllocated);
561 if (RT_FAILURE(rc) || *pfAllocated)
562 return rc;
563
564 /*
565 * Not used by volume manager metadata, so work thru the specified range one
566 * volume / void (free space) at a time. All must be unallocated for us to
567 * reach the end, we return immediately if any portion is allocated.
568 */
569 while (cb > 0)
570 {
571 /*
572 * Search through all volumes.
573 *
574 * It is not possible to get all start sectors and sizes of all volumes
575 * here because volumes can be scattered around the disk for certain formats.
576 * Linux LVM is one example, it extents of logical volumes don't need to be
577 * contiguous on the medium.
578 */
579 bool fVolFound = false;
580 PRTDVMVOLUMEINTERNAL pVol;
581 RTListForEach(&pThis->VolumeList, pVol, RTDVMVOLUMEINTERNAL, VolumeNode)
582 {
583 uint64_t cbIntersect;
584 uint64_t offVol;
585 bool fIntersect = pThis->pDvmFmtOps->pfnVolumeIsRangeIntersecting(pVol->hVolFmt, off, cb, &offVol, &cbIntersect);
586 if (fIntersect)
587 {
588 fVolFound = true;
589 if (pVol->pfnQueryBlockStatus)
590 {
591 bool fVolAllocated = true;
592 rc = pVol->pfnQueryBlockStatus(pVol->pvUser, offVol, cbIntersect, &fVolAllocated);
593 if (RT_FAILURE(rc) || fVolAllocated)
594 {
595 *pfAllocated = true;
596 return rc;
597 }
598 }
599 else if (!(pThis->fFlags & DVM_FLAGS_NO_STATUS_CALLBACK_MARK_AS_UNUSED))
600 {
601 *pfAllocated = true;
602 return VINF_SUCCESS;
603 }
604 /* else, flag is set, continue. */
605
606 cb -= cbIntersect;
607 off += cbIntersect;
608 break;
609 }
610 }
611
612 if (!fVolFound)
613 {
614 if (pThis->fFlags & DVM_FLAGS_UNUSED_SPACE_MARK_AS_USED)
615 {
616 *pfAllocated = true;
617 return VINF_SUCCESS;
618 }
619
620 cb -= pThis->DvmDisk.cbSector;
621 off += pThis->DvmDisk.cbSector;
622 }
623 }
624
625 *pfAllocated = false;
626 return rc;
627}
628
629RTDECL(int) RTDvmMapQueryTableLocations(RTDVM hVolMgr, uint32_t fFlags,
630 PRTDVMTABLELOCATION paLocations, size_t cLocations, size_t *pcActual)
631{
632 PRTDVMINTERNAL pThis = hVolMgr;
633
634 /*
635 * Input validation.
636 */
637 if (cLocations)
638 {
639 AssertPtrReturn(paLocations, VERR_INVALID_POINTER);
640 if (pcActual)
641 {
642 AssertPtrReturn(pcActual, VERR_INVALID_POINTER);
643 *pcActual = 0;
644 }
645 }
646 else
647 {
648 AssertPtrReturn(pcActual, VERR_INVALID_POINTER);
649 *pcActual = 0;
650 }
651 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
652 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
653 AssertReturn(!(fFlags & ~RTDVMMAPQTABLOC_F_VALID_MASK), VERR_INVALID_FLAGS);
654
655 /*
656 * Pass it down to the format backend.
657 */
658 return pThis->pDvmFmtOps->pfnQueryTableLocations(pThis->hVolMgrFmt, fFlags, paLocations, cLocations, pcActual);
659}
660
661RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
662{
663 PRTDVMVOLUMEINTERNAL pThis = hVol;
664 AssertPtrReturn(pThis, UINT32_MAX);
665 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
666
667 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
668 AssertMsg(cRefs >= 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
669 if (cRefs == 1)
670 RTDvmRetain(pThis->pVolMgr);
671 return cRefs;
672}
673
674RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol)
675{
676 PRTDVMVOLUMEINTERNAL pThis = hVol;
677 if (pThis == NIL_RTDVMVOLUME)
678 return 0;
679 AssertPtrReturn(pThis, UINT32_MAX);
680 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
681
682 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
683 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
684 if (cRefs == 0)
685 {
686 /* Release the volume manager. */
687 pThis->pfnQueryBlockStatus = NULL;
688 RTDvmRelease(pThis->pVolMgr);
689 }
690 return cRefs;
691}
692
693RTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol,
694 PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus,
695 void *pvUser)
696{
697 PRTDVMVOLUMEINTERNAL pThis = hVol;
698 AssertPtrReturnVoid(pThis);
699 AssertReturnVoid(pThis->u32Magic == RTDVMVOLUME_MAGIC);
700
701 pThis->pfnQueryBlockStatus = pfnQueryBlockStatus;
702 pThis->pvUser = pvUser;
703}
704
705RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol)
706{
707 PRTDVMVOLUMEINTERNAL pThis = hVol;
708 AssertPtrReturn(pThis, 0);
709 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, 0);
710
711 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetSize(pThis->hVolFmt);
712}
713
714RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName)
715{
716 PRTDVMVOLUMEINTERNAL pThis = hVol;
717 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
718 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
719 AssertReturn(ppszVolName, VERR_INVALID_POINTER);
720
721 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryName(pThis->hVolFmt, ppszVolName);
722}
723
724RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol)
725{
726 PRTDVMVOLUMEINTERNAL pThis = hVol;
727 AssertPtrReturn(pThis, RTDVMVOLTYPE_INVALID);
728 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, RTDVMVOLTYPE_INVALID);
729
730 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetType(pThis->hVolFmt);
731}
732
733RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol)
734{
735 PRTDVMVOLUMEINTERNAL pThis = hVol;
736 AssertPtrReturn(pThis, UINT64_MAX);
737 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT64_MAX);
738
739 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetFlags(pThis->hVolFmt);
740}
741
742RTDECL(int) RTDvmVolumeQueryRange(RTDVMVOLUME hVol, uint64_t *poffStart, uint64_t *poffLast)
743{
744 PRTDVMVOLUMEINTERNAL pThis = hVol;
745 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
746 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
747 AssertPtrReturn(poffStart, VERR_INVALID_POINTER);
748 AssertPtrReturn(poffLast, VERR_INVALID_POINTER);
749
750 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryRange(pThis->hVolFmt, poffStart, poffLast);
751}
752
753RTDECL(int) RTDvmVolumeQueryTableLocation(RTDVMVOLUME hVol, uint64_t *poffTable, uint64_t *pcbTable)
754{
755 PRTDVMVOLUMEINTERNAL pThis = hVol;
756 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
757 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
758 AssertPtrReturn(poffTable, VERR_INVALID_POINTER);
759 AssertPtrReturn(pcbTable, VERR_INVALID_POINTER);
760
761 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryTableLocation(pThis->hVolFmt, poffTable, pcbTable);
762}
763
764RTDECL(uint32_t) RTDvmVolumeGetIndex(RTDVMVOLUME hVol, RTDVMVOLIDX enmIndex)
765{
766 PRTDVMVOLUMEINTERNAL pThis = hVol;
767 AssertPtrReturn(pThis, UINT32_MAX);
768 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
769 AssertReturn(enmIndex > RTDVMVOLIDX_INVALID && enmIndex < RTDVMVOLIDX_END, UINT32_MAX);
770
771 if (enmIndex == RTDVMVOLIDX_HOST)
772 {
773#ifdef RT_OS_WINDOWS
774 enmIndex = RTDVMVOLIDX_USER_VISIBLE;
775#elif defined(RT_OS_LINUX) \
776 || defined(RT_OS_FREEBSD) \
777 || defined(RT_OS_SOLARIS) \
778 || defined(RT_OS_DARWIN) \
779 || defined(RT_OS_OS2) /*whatever*/
780/** @todo verify darwin, solaris and freebsd matches the linux algo. Check the linux index matching actual linux. */
781 enmIndex = RTDVMVOLIDX_LINUX;
782#else
783# error "PORTME"
784#endif
785 }
786
787 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetIndex(pThis->hVolFmt, enmIndex);
788}
789
790/**
791 * Helper for RTDvmVolumeQueryProp.
792 */
793static void rtDvmReturnInteger(void *pvDst, size_t cbDst, PRTUINT64U pSrc, size_t cbSrc)
794{
795 /* Read the source: */
796 uint64_t uSrc;
797 switch (cbSrc)
798 {
799 case sizeof(uint8_t): uSrc = (uint8_t)pSrc->Words.w0; break;
800 case sizeof(uint16_t): uSrc = pSrc->Words.w0; break;
801 case sizeof(uint32_t): uSrc = pSrc->s.Lo; break;
802 default: AssertFailed(); RT_FALL_THROUGH();
803 case sizeof(uint64_t): uSrc = pSrc->u; break;
804 }
805
806 /* Write the destination: */
807 switch (cbDst)
808 {
809 default: AssertFailed(); RT_FALL_THROUGH();
810 case sizeof(uint8_t): *(uint8_t *)pvDst = (uint8_t)uSrc; break;
811 case sizeof(uint16_t): *(uint16_t *)pvDst = (uint16_t)uSrc; break;
812 case sizeof(uint32_t): *(uint32_t *)pvDst = (uint32_t)uSrc; break;
813 case sizeof(uint64_t): *(uint64_t *)pvDst = uSrc; break;
814 }
815}
816
817RTDECL(int) RTDvmVolumeQueryProp(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
818{
819 PRTDVMVOLUMEINTERNAL pThis = hVol;
820 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
821 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
822 size_t cbBufFallback = 0;
823 if (pcbBuf == NULL)
824 pcbBuf = &cbBufFallback;
825 AssertReturnStmt(enmProperty > RTDVMVOLPROP_INVALID && enmProperty < RTDVMVOLPROP_END, *pcbBuf = 0, VERR_INVALID_FUNCTION);
826
827 switch (enmProperty)
828 {
829 /* 8, 16, 32 or 64 bit sized integers: */
830 case RTDVMVOLPROP_MBR_FIRST_HEAD:
831 case RTDVMVOLPROP_MBR_FIRST_SECTOR:
832 case RTDVMVOLPROP_MBR_LAST_HEAD:
833 case RTDVMVOLPROP_MBR_LAST_SECTOR:
834 case RTDVMVOLPROP_MBR_TYPE:
835 {
836 *pcbBuf = sizeof(uint8_t);
837 AssertReturn( cbBuf == sizeof(uint8_t)
838 || cbBuf == sizeof(uint16_t)
839 || cbBuf == sizeof(uint32_t)
840 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
841 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
842
843 RTUINT64U Union64 = {0};
844 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
845 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
846 return rc;
847 }
848
849 /* 16, 32 or 64 bit sized integers: */
850 case RTDVMVOLPROP_MBR_FIRST_CYLINDER:
851 case RTDVMVOLPROP_MBR_LAST_CYLINDER:
852 {
853 *pcbBuf = sizeof(uint16_t);
854 AssertReturn( cbBuf == sizeof(uint16_t)
855 || cbBuf == sizeof(uint32_t)
856 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
857 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
858
859 RTUINT64U Union64 = {0};
860 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
861 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
862 return rc;
863 }
864
865 /* RTUUIDs: */
866 case RTDVMVOLPROP_GPT_TYPE:
867 case RTDVMVOLPROP_GPT_UUID:
868 {
869 *pcbBuf = sizeof(RTUUID);
870 AssertReturn(cbBuf == sizeof(RTUUID), VERR_INVALID_PARAMETER);
871 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
872
873 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
874 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Uuid, sizeof(RTUUID), pcbBuf);
875 memcpy(pvBuf, &Uuid, sizeof(Uuid));
876 return rc;
877 }
878
879 case RTDVMVOLPROP_INVALID:
880 case RTDVMVOLPROP_END:
881 case RTDVMVOLPROP_32BIT_HACK:
882 break;
883 /* No default case! */
884 }
885 AssertFailed();
886 return VERR_NOT_SUPPORTED;
887}
888
889RTDECL(uint64_t) RTDvmVolumeGetPropU64(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, uint64_t uDefault)
890{
891 uint64_t uValue = uDefault;
892 int rc = RTDvmVolumeQueryProp(hVol, enmProperty, &uValue, sizeof(uValue), NULL);
893 if (RT_SUCCESS(rc))
894 return uValue;
895 AssertMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_FOUND, ("%Rrc enmProperty=%d\n", rc, enmProperty));
896 return uDefault;
897}
898
899RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
900{
901 PRTDVMVOLUMEINTERNAL pThis = hVol;
902 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
903 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
904 AssertReturn(pvBuf, VERR_INVALID_POINTER);
905 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
906
907 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
908}
909
910RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
911{
912 PRTDVMVOLUMEINTERNAL pThis = hVol;
913 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
914 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
915 AssertReturn(pvBuf, VERR_INVALID_POINTER);
916 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
917
918 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
919}
920
921RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)
922{
923 AssertReturn(enmVolType >= RTDVMVOLTYPE_INVALID && enmVolType < RTDVMVOLTYPE_END, NULL);
924
925 return g_apszDvmVolTypes[enmVolType];
926}
927
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