VirtualBox

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

Last change on this file since 85877 was 85877, checked in by vboxsync, 5 years ago

Main: bugref:9224: DVM API changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/* $Id: dvm.cpp 85877 2020-08-24 17:03:23Z 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(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
630{
631 PRTDVMVOLUMEINTERNAL pThis = hVol;
632 AssertPtrReturn(pThis, UINT32_MAX);
633 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
634
635 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
636 AssertMsg(cRefs >= 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
637 if (cRefs == 1)
638 RTDvmRetain(pThis->pVolMgr);
639 return cRefs;
640}
641
642RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol)
643{
644 PRTDVMVOLUMEINTERNAL pThis = hVol;
645 if (pThis == NIL_RTDVMVOLUME)
646 return 0;
647 AssertPtrReturn(pThis, UINT32_MAX);
648 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
649
650 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
651 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
652 if (cRefs == 0)
653 {
654 /* Release the volume manager. */
655 pThis->pfnQueryBlockStatus = NULL;
656 RTDvmRelease(pThis->pVolMgr);
657 }
658 return cRefs;
659}
660
661RTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol,
662 PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus,
663 void *pvUser)
664{
665 PRTDVMVOLUMEINTERNAL pThis = hVol;
666 AssertPtrReturnVoid(pThis);
667 AssertReturnVoid(pThis->u32Magic == RTDVMVOLUME_MAGIC);
668
669 pThis->pfnQueryBlockStatus = pfnQueryBlockStatus;
670 pThis->pvUser = pvUser;
671}
672
673RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol)
674{
675 PRTDVMVOLUMEINTERNAL pThis = hVol;
676 AssertPtrReturn(pThis, 0);
677 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, 0);
678
679 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetSize(pThis->hVolFmt);
680}
681
682RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName)
683{
684 PRTDVMVOLUMEINTERNAL pThis = hVol;
685 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
686 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
687 AssertReturn(ppszVolName, VERR_INVALID_POINTER);
688
689 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryName(pThis->hVolFmt, ppszVolName);
690}
691
692RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol)
693{
694 PRTDVMVOLUMEINTERNAL pThis = hVol;
695 AssertPtrReturn(pThis, RTDVMVOLTYPE_INVALID);
696 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, RTDVMVOLTYPE_INVALID);
697
698 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetType(pThis->hVolFmt);
699}
700
701RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol)
702{
703 PRTDVMVOLUMEINTERNAL pThis = hVol;
704 AssertPtrReturn(pThis, UINT64_MAX);
705 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT64_MAX);
706
707 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetFlags(pThis->hVolFmt);
708}
709
710RTDECL(int) RTDvmVolumeQueryRange(RTDVMVOLUME hVol, uint64_t *poffStart, uint64_t *poffLast)
711{
712 PRTDVMVOLUMEINTERNAL pThis = hVol;
713 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
714 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
715 AssertPtrReturn(poffStart, VERR_INVALID_POINTER);
716 AssertPtrReturn(poffLast, VERR_INVALID_POINTER);
717
718 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryRange(pThis->hVolFmt, poffStart, poffLast);
719}
720
721RTDECL(int) RTDvmVolumeQueryTableLocation(RTDVMVOLUME hVol, uint64_t *poffTable, uint64_t *pcbTable)
722{
723 PRTDVMVOLUMEINTERNAL pThis = hVol;
724 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
725 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
726 AssertPtrReturn(poffTable, VERR_INVALID_POINTER);
727 AssertPtrReturn(pcbTable, VERR_INVALID_POINTER);
728
729 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryTableLocation(pThis->hVolFmt, poffTable, pcbTable);
730}
731
732RTDECL(uint32_t) RTDvmVolumeGetIndex(RTDVMVOLUME hVol, RTDVMVOLIDX enmIndex)
733{
734 PRTDVMVOLUMEINTERNAL pThis = hVol;
735 AssertPtrReturn(pThis, UINT32_MAX);
736 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
737 AssertReturn(enmIndex > RTDVMVOLIDX_INVALID && enmIndex < RTDVMVOLIDX_END, UINT32_MAX);
738
739 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetIndex(pThis->hVolFmt, enmIndex);
740}
741
742/**
743 * Helper for RTDvmVolumeQueryProp.
744 */
745static void rtDvmReturnInteger(void *pvDst, size_t cbDst, PRTUINT64U pSrc, size_t cbSrc)
746{
747 /* Read the source: */
748 uint64_t uSrc;
749 switch (cbSrc)
750 {
751 case sizeof(uint8_t): uSrc = (uint8_t)pSrc->Words.w0; break;
752 case sizeof(uint16_t): uSrc = pSrc->Words.w0; break;
753 case sizeof(uint32_t): uSrc = pSrc->s.Lo; break;
754 default: AssertFailed(); RT_FALL_THROUGH();
755 case sizeof(uint64_t): uSrc = pSrc->u; break;
756 }
757
758 /* Write the destination: */
759 switch (cbDst)
760 {
761 default: AssertFailed(); RT_FALL_THROUGH();
762 case sizeof(uint8_t): *(uint8_t *)pvDst = (uint8_t)uSrc; break;
763 case sizeof(uint16_t): *(uint16_t *)pvDst = (uint16_t)uSrc; break;
764 case sizeof(uint32_t): *(uint32_t *)pvDst = (uint32_t)uSrc; break;
765 case sizeof(uint64_t): *(uint64_t *)pvDst = uSrc; break;
766 }
767}
768
769RTDECL(int) RTDvmVolumeQueryProp(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
770{
771 PRTDVMVOLUMEINTERNAL pThis = hVol;
772 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
773 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
774 size_t cbBufFallback = 0;
775 if (pcbBuf == NULL)
776 pcbBuf = &cbBufFallback;
777 AssertReturnStmt(enmProperty > RTDVMVOLPROP_INVALID && enmProperty < RTDVMVOLPROP_END, *pcbBuf = 0, VERR_INVALID_FUNCTION);
778
779 switch (enmProperty)
780 {
781 /* 8, 16, 32 or 64 bit sized integers: */
782 case RTDVMVOLPROP_MBR_FIRST_HEAD:
783 case RTDVMVOLPROP_MBR_FIRST_SECTOR:
784 case RTDVMVOLPROP_MBR_LAST_HEAD:
785 case RTDVMVOLPROP_MBR_LAST_SECTOR:
786 case RTDVMVOLPROP_MBR_TYPE:
787 {
788 *pcbBuf = sizeof(uint8_t);
789 AssertReturn( cbBuf == sizeof(uint8_t)
790 || cbBuf == sizeof(uint16_t)
791 || cbBuf == sizeof(uint32_t)
792 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
793 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
794
795 RTUINT64U Union64 = {0};
796 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
797 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
798 return rc;
799 }
800
801 /* 16, 32 or 64 bit sized integers: */
802 case RTDVMVOLPROP_MBR_FIRST_CYLINDER:
803 case RTDVMVOLPROP_MBR_LAST_CYLINDER:
804 {
805 *pcbBuf = sizeof(uint16_t);
806 AssertReturn( cbBuf == sizeof(uint16_t)
807 || cbBuf == sizeof(uint32_t)
808 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
809 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
810
811 RTUINT64U Union64 = {0};
812 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
813 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
814 return rc;
815 }
816
817 /* RTUUIDs: */
818 case RTDVMVOLPROP_GPT_TYPE:
819 case RTDVMVOLPROP_GPT_UUID:
820 {
821 *pcbBuf = sizeof(RTUUID);
822 AssertReturn(cbBuf == sizeof(RTUUID), VERR_INVALID_PARAMETER);
823 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
824
825 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
826 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Uuid, sizeof(RTUUID), pcbBuf);
827 memcpy(pvBuf, &Uuid, sizeof(Uuid));
828 return rc;
829 }
830
831 case RTDVMVOLPROP_INVALID:
832 case RTDVMVOLPROP_END:
833 case RTDVMVOLPROP_32BIT_HACK:
834 break;
835 /* No default case! */
836 }
837 AssertFailed();
838 return VERR_NOT_SUPPORTED;
839}
840
841RTDECL(uint64_t) RTDvmVolumeGetPropU64(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, uint64_t uDefault)
842{
843 uint64_t uValue = uDefault;
844 int rc = RTDvmVolumeQueryProp(hVol, enmProperty, &uValue, sizeof(uValue), NULL);
845 if (RT_SUCCESS(rc))
846 return uValue;
847 AssertMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_FOUND, ("%Rrc enmProperty=%d\n", rc, enmProperty));
848 return uDefault;
849}
850
851RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
852{
853 PRTDVMVOLUMEINTERNAL pThis = hVol;
854 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
855 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
856 AssertReturn(pvBuf, VERR_INVALID_POINTER);
857 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
858
859 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
860}
861
862RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
863{
864 PRTDVMVOLUMEINTERNAL pThis = hVol;
865 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
866 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
867 AssertReturn(pvBuf, VERR_INVALID_POINTER);
868 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
869
870 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
871}
872
873RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)
874{
875 AssertReturn(enmVolType >= RTDVMVOLTYPE_INVALID && enmVolType < RTDVMVOLTYPE_END, NULL);
876
877 return g_apszDvmVolTypes[enmVolType];
878}
879
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette