VirtualBox

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

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

IPRT/RTDvm: Added RTDVMVOLIDX_HOST index. bugref:9224

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.3 KB
Line 
1/* $Id: dvm.cpp 85887 2020-08-25 21:05:37Z 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 if (enmIndex == RTDVMVOLIDX_HOST)
740 {
741#ifdef RT_OS_WINDOWS
742 enmIndex = RTDVMVOLIDX_USER_VISIBLE;
743#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
744/** @todo verify darwin, solaris and freebsd matches the linux algo. Check the linux index matching actual linux. */
745 enmIndex = RTDVMVOLIDX_LINUX;
746#else
747# error "PORTME"
748#endif
749 }
750
751 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetIndex(pThis->hVolFmt, enmIndex);
752}
753
754/**
755 * Helper for RTDvmVolumeQueryProp.
756 */
757static void rtDvmReturnInteger(void *pvDst, size_t cbDst, PRTUINT64U pSrc, size_t cbSrc)
758{
759 /* Read the source: */
760 uint64_t uSrc;
761 switch (cbSrc)
762 {
763 case sizeof(uint8_t): uSrc = (uint8_t)pSrc->Words.w0; break;
764 case sizeof(uint16_t): uSrc = pSrc->Words.w0; break;
765 case sizeof(uint32_t): uSrc = pSrc->s.Lo; break;
766 default: AssertFailed(); RT_FALL_THROUGH();
767 case sizeof(uint64_t): uSrc = pSrc->u; break;
768 }
769
770 /* Write the destination: */
771 switch (cbDst)
772 {
773 default: AssertFailed(); RT_FALL_THROUGH();
774 case sizeof(uint8_t): *(uint8_t *)pvDst = (uint8_t)uSrc; break;
775 case sizeof(uint16_t): *(uint16_t *)pvDst = (uint16_t)uSrc; break;
776 case sizeof(uint32_t): *(uint32_t *)pvDst = (uint32_t)uSrc; break;
777 case sizeof(uint64_t): *(uint64_t *)pvDst = uSrc; break;
778 }
779}
780
781RTDECL(int) RTDvmVolumeQueryProp(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
782{
783 PRTDVMVOLUMEINTERNAL pThis = hVol;
784 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
785 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
786 size_t cbBufFallback = 0;
787 if (pcbBuf == NULL)
788 pcbBuf = &cbBufFallback;
789 AssertReturnStmt(enmProperty > RTDVMVOLPROP_INVALID && enmProperty < RTDVMVOLPROP_END, *pcbBuf = 0, VERR_INVALID_FUNCTION);
790
791 switch (enmProperty)
792 {
793 /* 8, 16, 32 or 64 bit sized integers: */
794 case RTDVMVOLPROP_MBR_FIRST_HEAD:
795 case RTDVMVOLPROP_MBR_FIRST_SECTOR:
796 case RTDVMVOLPROP_MBR_LAST_HEAD:
797 case RTDVMVOLPROP_MBR_LAST_SECTOR:
798 case RTDVMVOLPROP_MBR_TYPE:
799 {
800 *pcbBuf = sizeof(uint8_t);
801 AssertReturn( cbBuf == sizeof(uint8_t)
802 || cbBuf == sizeof(uint16_t)
803 || cbBuf == sizeof(uint32_t)
804 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
805 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
806
807 RTUINT64U Union64 = {0};
808 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
809 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
810 return rc;
811 }
812
813 /* 16, 32 or 64 bit sized integers: */
814 case RTDVMVOLPROP_MBR_FIRST_CYLINDER:
815 case RTDVMVOLPROP_MBR_LAST_CYLINDER:
816 {
817 *pcbBuf = sizeof(uint16_t);
818 AssertReturn( cbBuf == sizeof(uint16_t)
819 || cbBuf == sizeof(uint32_t)
820 || cbBuf == sizeof(uint64_t), VERR_INVALID_PARAMETER);
821 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
822
823 RTUINT64U Union64 = {0};
824 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Union64, cbBuf, pcbBuf);
825 rtDvmReturnInteger(pvBuf, cbBuf, &Union64, *pcbBuf);
826 return rc;
827 }
828
829 /* RTUUIDs: */
830 case RTDVMVOLPROP_GPT_TYPE:
831 case RTDVMVOLPROP_GPT_UUID:
832 {
833 *pcbBuf = sizeof(RTUUID);
834 AssertReturn(cbBuf == sizeof(RTUUID), VERR_INVALID_PARAMETER);
835 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
836
837 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
838 int rc = pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryProp(pThis->hVolFmt, enmProperty, &Uuid, sizeof(RTUUID), pcbBuf);
839 memcpy(pvBuf, &Uuid, sizeof(Uuid));
840 return rc;
841 }
842
843 case RTDVMVOLPROP_INVALID:
844 case RTDVMVOLPROP_END:
845 case RTDVMVOLPROP_32BIT_HACK:
846 break;
847 /* No default case! */
848 }
849 AssertFailed();
850 return VERR_NOT_SUPPORTED;
851}
852
853RTDECL(uint64_t) RTDvmVolumeGetPropU64(RTDVMVOLUME hVol, RTDVMVOLPROP enmProperty, uint64_t uDefault)
854{
855 uint64_t uValue = uDefault;
856 int rc = RTDvmVolumeQueryProp(hVol, enmProperty, &uValue, sizeof(uValue), NULL);
857 if (RT_SUCCESS(rc))
858 return uValue;
859 AssertMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_FOUND, ("%Rrc enmProperty=%d\n", rc, enmProperty));
860 return uDefault;
861}
862
863RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
864{
865 PRTDVMVOLUMEINTERNAL pThis = hVol;
866 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
867 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
868 AssertReturn(pvBuf, VERR_INVALID_POINTER);
869 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
870
871 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
872}
873
874RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
875{
876 PRTDVMVOLUMEINTERNAL pThis = hVol;
877 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
878 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
879 AssertReturn(pvBuf, VERR_INVALID_POINTER);
880 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
881
882 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
883}
884
885RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)
886{
887 AssertReturn(enmVolType >= RTDVMVOLTYPE_INVALID && enmVolType < RTDVMVOLTYPE_END, NULL);
888
889 return g_apszDvmVolTypes[enmVolType];
890}
891
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