VirtualBox

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

Last change on this file since 69616 was 69616, checked in by vboxsync, 7 years ago

DVM: Got a working pseudo vfs.

It's now possible to do stuff like:

RTLs -la :iprtvfs:file(vd,d:\VMs\DosVM\DOS.vmdk,ro):vfs(dvm)
RTLs -la :iprtvfs:file(vd,d:\VMs\DosVM\DOS.vmdk,ro):vfs(dvm):file(open,vol0):vfs(fat):/

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.5 KB
Line 
1/* $Id: dvm.cpp 69616 2017-11-08 13:58:58Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - generic code.
4 */
5
6/*
7 * Copyright (C) 2011-2017 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*********************************************************************************************************************************/
96extern RTDVMFMTOPS g_rtDvmFmtMbr;
97extern RTDVMFMTOPS g_rtDvmFmtGpt;
98extern RTDVMFMTOPS g_rtDvmFmtBsdLbl;
99
100/**
101 * Supported volume formats.
102 */
103static PCRTDVMFMTOPS const g_aDvmFmts[] =
104{
105 &g_rtDvmFmtMbr,
106 &g_rtDvmFmtGpt,
107 &g_rtDvmFmtBsdLbl
108};
109
110/**
111 * Descriptions of the volume types.
112 *
113 * This is indexed by RTDVMVOLTYPE.
114 */
115static const char * const g_apszDvmVolTypes[] =
116{
117 "Invalid",
118 "Unknown",
119 "NTFS",
120 "FAT16",
121 "FAT32",
122 "Linux swap",
123 "Linux native",
124 "Linux LVM",
125 "Linux SoftRaid",
126 "FreeBSD",
127 "NetBSD",
128 "OpenBSD",
129 "Mac OS X HFS or HFS+",
130 "Solaris"
131};
132AssertCompile(RT_ELEMENTS(g_apszDvmVolTypes) == RTDVMVOLTYPE_END);
133
134
135/**
136 * Creates a new volume.
137 *
138 * @returns IPRT status code.
139 * @param pThis The DVM map instance.
140 * @param hVolFmt The format specific volume handle.
141 * @param phVol Where to store the generic volume handle on success.
142 */
143static int rtDvmVolumeCreate(PRTDVMINTERNAL pThis, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUME phVol)
144{
145 PRTDVMVOLUMEINTERNAL pVol = (PRTDVMVOLUMEINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEINTERNAL));
146 if (pVol)
147 {
148 pVol->u32Magic = RTDVMVOLUME_MAGIC;
149 pVol->cRefs = 0;
150 pVol->pVolMgr = pThis;
151 pVol->hVolFmt = hVolFmt;
152
153 *phVol = pVol;
154 return VINF_SUCCESS;
155 }
156 return VERR_NO_MEMORY;
157}
158
159/**
160 * Destroys a volume handle.
161 *
162 * @param pThis The volume to destroy.
163 */
164static void rtDvmVolumeDestroy(PRTDVMVOLUMEINTERNAL pThis)
165{
166 PRTDVMINTERNAL pVolMgr = pThis->pVolMgr;
167
168 AssertPtr(pVolMgr);
169
170 /* Close the volume. */
171 pVolMgr->pDvmFmtOps->pfnVolumeClose(pThis->hVolFmt);
172
173 pThis->u32Magic = RTDVMVOLUME_MAGIC_DEAD;
174 pThis->pVolMgr = NULL;
175 pThis->hVolFmt = NIL_RTDVMVOLUMEFMT;
176 RTMemFree(pThis);
177
178 /* Release the reference of the volume manager. */
179 RTDvmRelease(pVolMgr);
180}
181
182
183RTDECL(int) RTDvmCreate(PRTDVM phVolMgr, RTVFSFILE hVfsFile, uint32_t cbSector, uint32_t fFlags)
184{
185 AssertMsgReturn(!(fFlags & ~DVM_FLAGS_VALID_MASK), ("Invalid flags given %#x\n", fFlags), VERR_INVALID_FLAGS);
186 uint32_t cRefs = RTVfsFileRetain(hVfsFile);
187 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
188
189 uint64_t cbDisk;
190 int rc = RTVfsFileGetSize(hVfsFile, &cbDisk);
191 if (RT_SUCCESS(rc))
192 {
193 PRTDVMINTERNAL pThis = (PRTDVMINTERNAL)RTMemAllocZ(sizeof(RTDVMINTERNAL));
194 if (pThis)
195 {
196 pThis->u32Magic = RTDVM_MAGIC;
197 pThis->DvmDisk.cbDisk = cbDisk;
198 pThis->DvmDisk.cbSector = cbSector;
199 pThis->DvmDisk.hVfsFile = hVfsFile;
200
201 pThis->pDvmFmtOps = NULL;
202 pThis->hVolMgrFmt = NIL_RTDVMFMT;
203 pThis->fFlags = fFlags;
204 pThis->cRefs = 1;
205 RTListInit(&pThis->VolumeList);
206
207 *phVolMgr = pThis;
208 return VINF_SUCCESS;
209 }
210 rc = VERR_NO_MEMORY;
211 }
212 RTVfsFileRelease(hVfsFile);
213 return rc;
214}
215
216
217RTDECL(uint32_t) RTDvmRetain(RTDVM hVolMgr)
218{
219 PRTDVMINTERNAL pThis = hVolMgr;
220 AssertPtrReturn(pThis, UINT32_MAX);
221 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
222
223 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
224 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
225 return cRefs;
226}
227
228/**
229 * Destroys a volume manager handle.
230 *
231 * @param pThis The volume manager to destroy.
232 */
233static void rtDvmDestroy(PRTDVMINTERNAL pThis)
234{
235 pThis->u32Magic = RTDVM_MAGIC_DEAD;
236
237 if (pThis->hVolMgrFmt != NIL_RTDVMFMT)
238 {
239 AssertPtr(pThis->pDvmFmtOps);
240
241 /* Let the backend do it's own cleanup first. */
242 pThis->pDvmFmtOps->pfnClose(pThis->hVolMgrFmt);
243 pThis->hVolMgrFmt = NIL_RTDVMFMT;
244 pThis->pDvmFmtOps = NULL;
245 }
246
247 pThis->DvmDisk.cbDisk = 0;
248 pThis->DvmDisk.cbSector = 0;
249 if (pThis->DvmDisk.hVfsFile != NIL_RTVFSFILE)
250 {
251 RTVfsFileRelease(pThis->DvmDisk.hVfsFile);
252 pThis->DvmDisk.hVfsFile = NIL_RTVFSFILE;
253 }
254 RTMemFree(pThis);
255}
256
257RTDECL(uint32_t) RTDvmRelease(RTDVM hVolMgr)
258{
259 PRTDVMINTERNAL pThis = hVolMgr;
260 if (pThis == NIL_RTDVM)
261 return 0;
262 AssertPtrReturn(pThis, UINT32_MAX);
263 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
264
265 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
266 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
267 if (cRefs == 0)
268 rtDvmDestroy(pThis);
269 return cRefs;
270}
271
272RTDECL(int) RTDvmMapOpen(RTDVM hVolMgr)
273{
274 PRTDVMINTERNAL pThis = hVolMgr;
275 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
276 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
277 AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_WRONG_ORDER);
278
279 Assert(!pThis->pDvmFmtOps);
280
281 /*
282 * Let each format backend have a go at the disk, pick the one which scores the highest.
283 */
284 int rc = VINF_SUCCESS;
285 uint32_t uScoreMax = RTDVM_MATCH_SCORE_UNSUPPORTED;
286 PCRTDVMFMTOPS pDvmFmtOpsMatch = NULL;
287 for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
288 {
289 uint32_t uScore = 0;
290 PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
291
292 rc = pDvmFmtOps->pfnProbe(&pThis->DvmDisk, &uScore);
293 if (RT_SUCCESS(rc))
294 {
295 if (uScore > uScoreMax)
296 {
297 pDvmFmtOpsMatch = pDvmFmtOps;
298 uScoreMax = uScore;
299 }
300 }
301 else
302 return rc;
303 }
304 if (uScoreMax > RTDVM_MATCH_SCORE_UNSUPPORTED)
305 {
306 AssertPtr(pDvmFmtOpsMatch);
307
308 /*
309 * Open the format.
310 */
311 rc = pDvmFmtOpsMatch->pfnOpen(&pThis->DvmDisk, &pThis->hVolMgrFmt);
312 if (RT_SUCCESS(rc))
313 {
314 pThis->pDvmFmtOps = pDvmFmtOpsMatch;
315
316 /*
317 * Construct volume list (we're done if none).
318 */
319 uint32_t cVols = pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
320 if (cVols == 0)
321 return VINF_SUCCESS;
322
323 /* First volume. */
324 RTDVMVOLUMEFMT hVolFmt = NIL_RTDVMVOLUMEFMT;
325 rc = pThis->pDvmFmtOps->pfnQueryFirstVolume(pThis->hVolMgrFmt, &hVolFmt);
326 if (RT_SUCCESS(rc))
327 {
328 for (;;)
329 {
330 PRTDVMVOLUMEINTERNAL pVol = NULL;
331 rc = rtDvmVolumeCreate(pThis, hVolFmt, &pVol);
332 if (RT_FAILURE(rc))
333 {
334 pThis->pDvmFmtOps->pfnVolumeClose(hVolFmt);
335 break;
336 }
337 RTListAppend(&pThis->VolumeList, &pVol->VolumeNode);
338
339 /* Done?*/
340 cVols--;
341 if (cVols < 1)
342 return VINF_SUCCESS;
343
344 /* Next volume. */
345 rc = pThis->pDvmFmtOps->pfnQueryNextVolume(pThis->hVolMgrFmt, pVol->hVolFmt, &hVolFmt);
346 if (RT_FAILURE(rc))
347 break;
348 }
349
350 /* Bail out. */
351 PRTDVMVOLUMEINTERNAL pItNext, pIt;
352 RTListForEachSafe(&pThis->VolumeList, pIt, pItNext, RTDVMVOLUMEINTERNAL, VolumeNode)
353 {
354 RTListNodeRemove(&pIt->VolumeNode);
355 rtDvmVolumeDestroy(pIt);
356 }
357 }
358
359 /** @todo shouldn't we close the format too here? */
360 }
361 }
362 else
363 rc = VERR_NOT_SUPPORTED;
364 return rc;
365}
366
367RTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt)
368{
369 PRTDVMINTERNAL pThis = hVolMgr;
370 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
371 AssertPtrReturn(pszFmt, VERR_INVALID_POINTER);
372 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
373 AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_WRONG_ORDER);
374
375 for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
376 {
377 PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
378 if (!RTStrCmp(pDvmFmtOps->pszFmt, pszFmt))
379 {
380 int rc = pDvmFmtOps->pfnInitialize(&pThis->DvmDisk, &pThis->hVolMgrFmt);
381 if (RT_SUCCESS(rc))
382 pThis->pDvmFmtOps = pDvmFmtOps;
383 return rc;
384 }
385 }
386 return VERR_NOT_SUPPORTED;
387}
388
389RTDECL(const char *) RTDvmMapGetFormatName(RTDVM hVolMgr)
390{
391 PRTDVMINTERNAL pThis = hVolMgr;
392 AssertPtrReturn(pThis, NULL);
393 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, NULL);
394 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, NULL);
395
396 return pThis->pDvmFmtOps->pszFmt;
397}
398
399RTDECL(RTDVMFORMATTYPE) RTDvmMapGetFormatType(RTDVM hVolMgr)
400{
401 PRTDVMINTERNAL pThis = hVolMgr;
402 AssertPtrReturn(pThis, RTDVMFORMATTYPE_INVALID);
403 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, RTDVMFORMATTYPE_INVALID);
404 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, RTDVMFORMATTYPE_INVALID);
405
406 return pThis->pDvmFmtOps->enmFormat;
407}
408
409RTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr)
410{
411 PRTDVMINTERNAL pThis = hVolMgr;
412 AssertPtrReturn(pThis, UINT32_MAX);
413 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
414 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
415
416 return pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
417}
418
419RTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr)
420{
421 PRTDVMINTERNAL pThis = hVolMgr;
422 AssertPtrReturn(pThis, UINT32_MAX);
423 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
424 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
425
426 return pThis->pDvmFmtOps->pfnGetMaxVolumes(pThis->hVolMgrFmt);
427}
428
429RTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol)
430{
431 PRTDVMINTERNAL pThis = hVolMgr;
432 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
433 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
434 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
435 AssertPtrReturn(phVol, VERR_INVALID_POINTER);
436
437 int rc = VERR_DVM_MAP_EMPTY;
438 PRTDVMVOLUMEINTERNAL pVol = RTListGetFirst(&pThis->VolumeList, RTDVMVOLUMEINTERNAL, VolumeNode);
439 if (pVol)
440 {
441 rc = VINF_SUCCESS;
442 RTDvmVolumeRetain(pVol);
443 *phVol = pVol;
444 }
445
446 return rc;
447}
448
449RTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext)
450{
451 PRTDVMINTERNAL pThis = hVolMgr;
452 PRTDVMVOLUMEINTERNAL pVol = hVol;
453 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
454 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
455 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
456 AssertPtrReturn(pVol, VERR_INVALID_HANDLE);
457 AssertReturn(pVol->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
458 AssertPtrReturn(phVolNext, VERR_INVALID_POINTER);
459
460 int rc = VERR_DVM_MAP_NO_VOLUME;
461 PRTDVMVOLUMEINTERNAL pVolNext = RTListGetNext(&pThis->VolumeList, pVol, RTDVMVOLUMEINTERNAL, VolumeNode);
462 if (pVolNext)
463 {
464 rc = VINF_SUCCESS;
465 RTDvmVolumeRetain(pVolNext);
466 *phVolNext = pVolNext;
467 }
468
469 return rc;
470}
471
472RTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb, bool *pfAllocated)
473{
474 PRTDVMINTERNAL pThis = hVolMgr;
475 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
476 AssertPtrReturn(pfAllocated, VERR_INVALID_POINTER);
477 AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
478 AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_WRONG_ORDER);
479 AssertMsgReturn( off <= pThis->DvmDisk.cbDisk
480 || cb <= pThis->DvmDisk.cbDisk
481 || off + cb <= pThis->DvmDisk.cbDisk,
482 ("off=%#RX64 cb=%#RX64 cbDisk=%#RX64\n", off, cb, pThis->DvmDisk.cbDisk),
483 VERR_OUT_OF_RANGE);
484
485 /* Check whether the range is inuse by the volume manager metadata first. */
486 int rc = pThis->pDvmFmtOps->pfnQueryRangeUse(pThis->hVolMgrFmt, off, cb, pfAllocated);
487 if (RT_FAILURE(rc))
488 return rc;
489
490 if (!*pfAllocated)
491 {
492 bool fAllocated = false;
493
494 while ( cb > 0
495 && !fAllocated)
496 {
497 bool fVolFound = false;
498 uint64_t cbIntersect;
499 uint64_t offVol;
500
501 /*
502 * Search through all volumes. It is not possible to
503 * get all start sectors and sizes of all volumes here
504 * because volumes can be scattered around the disk for certain formats.
505 * Linux LVM is one example, extents of logical volumes don't need to be
506 * contigous on the medium.
507 */
508 PRTDVMVOLUMEINTERNAL pVol;
509 RTListForEach(&pThis->VolumeList, pVol, RTDVMVOLUMEINTERNAL, VolumeNode)
510 {
511 bool fIntersect = pThis->pDvmFmtOps->pfnVolumeIsRangeIntersecting(pVol->hVolFmt, off,
512 cb, &offVol,
513 &cbIntersect);
514 if (fIntersect)
515 {
516 fVolFound = true;
517 if (pVol->pfnQueryBlockStatus)
518 {
519 bool fVolAllocated = true;
520 rc = pVol->pfnQueryBlockStatus(pVol->pvUser, offVol, cbIntersect, &fVolAllocated);
521 if (RT_FAILURE(rc))
522 break;
523 if (fVolAllocated)
524 {
525 fAllocated = true;
526 break;
527 }
528 }
529 else if (!(pThis->fFlags & DVM_FLAGS_NO_STATUS_CALLBACK_MARK_AS_UNUSED))
530 fAllocated = true;
531 /* else, flag is set, continue. */
532
533 cb -= cbIntersect;
534 off += cbIntersect;
535 break;
536 }
537 }
538
539 if (!fVolFound)
540 {
541 if (pThis->fFlags & DVM_FLAGS_UNUSED_SPACE_MARK_AS_USED)
542 fAllocated = true;
543
544 cb -= pThis->DvmDisk.cbSector;
545 off += pThis->DvmDisk.cbSector;
546 }
547 }
548
549 *pfAllocated = fAllocated;
550 }
551
552 return rc;
553}
554
555RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
556{
557 PRTDVMVOLUMEINTERNAL pThis = hVol;
558 AssertPtrReturn(pThis, UINT32_MAX);
559 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
560
561 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
562 AssertMsg(cRefs >= 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
563 if (cRefs == 1)
564 RTDvmRetain(pThis->pVolMgr);
565 return cRefs;
566}
567
568RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol)
569{
570 PRTDVMVOLUMEINTERNAL pThis = hVol;
571 if (pThis == NIL_RTDVMVOLUME)
572 return 0;
573 AssertPtrReturn(pThis, UINT32_MAX);
574 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
575
576 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
577 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
578 if (cRefs == 0)
579 {
580 /* Release the volume manager. */
581 pThis->pfnQueryBlockStatus = NULL;
582 RTDvmRelease(pThis->pVolMgr);
583 }
584 return cRefs;
585}
586
587RTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol,
588 PFNDVMVOLUMEQUERYBLOCKSTATUS pfnQueryBlockStatus,
589 void *pvUser)
590{
591 PRTDVMVOLUMEINTERNAL pThis = hVol;
592 AssertPtrReturnVoid(pThis);
593 AssertReturnVoid(pThis->u32Magic == RTDVMVOLUME_MAGIC);
594
595 pThis->pfnQueryBlockStatus = pfnQueryBlockStatus;
596 pThis->pvUser = pvUser;
597}
598
599RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol)
600{
601 PRTDVMVOLUMEINTERNAL pThis = hVol;
602 AssertPtrReturn(pThis, 0);
603 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, 0);
604
605 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetSize(pThis->hVolFmt);
606}
607
608RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName)
609{
610 PRTDVMVOLUMEINTERNAL pThis = hVol;
611 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
612 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
613 AssertReturn(ppszVolName, VERR_INVALID_POINTER);
614
615 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryName(pThis->hVolFmt, ppszVolName);
616}
617
618RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol)
619{
620 PRTDVMVOLUMEINTERNAL pThis = hVol;
621 AssertPtrReturn(pThis, RTDVMVOLTYPE_INVALID);
622 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, RTDVMVOLTYPE_INVALID);
623
624 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetType(pThis->hVolFmt);
625}
626
627RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol)
628{
629 PRTDVMVOLUMEINTERNAL pThis = hVol;
630 AssertPtrReturn(pThis, UINT64_MAX);
631 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT64_MAX);
632
633 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetFlags(pThis->hVolFmt);
634}
635
636RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
637{
638 PRTDVMVOLUMEINTERNAL pThis = hVol;
639 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
640 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
641 AssertReturn(pvBuf, VERR_INVALID_POINTER);
642 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
643
644 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
645}
646
647RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
648{
649 PRTDVMVOLUMEINTERNAL pThis = hVol;
650 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
651 AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
652 AssertReturn(pvBuf, VERR_INVALID_POINTER);
653 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
654
655 return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
656}
657
658RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)
659{
660 AssertReturn(enmVolType >= RTDVMVOLTYPE_INVALID && enmVolType < RTDVMVOLTYPE_END, NULL);
661
662 return g_apszDvmVolTypes[enmVolType];
663}
664
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