VirtualBox

source: vbox/trunk/src/VBox/Storage/VDVfs.cpp@ 70305

最後變更 在這個檔案從70305是 70305,由 vboxsync 提交於 7 年 前

VDVfs.cpp: Assertions. [grr]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 21.8 KB
 
1/* $Id: VDVfs.cpp 70305 2017-12-22 08:27:01Z vboxsync $ */
2/** @file
3 * Virtual Disk Container implementation. - VFS glue.
4 */
5
6/*
7 * Copyright (C) 2012-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/types.h>
23#include <iprt/assert.h>
24#include <iprt/mem.h>
25#include <iprt/err.h>
26#include <iprt/asm.h>
27#include <iprt/string.h>
28#include <iprt/file.h>
29#include <iprt/sg.h>
30#include <iprt/vfslowlevel.h>
31#include <iprt/poll.h>
32#include <VBox/vd.h>
33
34
35/*********************************************************************************************************************************
36* Structures and Typedefs *
37*********************************************************************************************************************************/
38
39/**
40 * The internal data of a DVM volume I/O stream.
41 */
42typedef struct VDVFSFILE
43{
44 /** The volume the VFS file belongs to. */
45 PVDISK pDisk;
46 /** Current position. */
47 uint64_t offCurPos;
48 /** Flags given during creation. */
49 uint32_t fFlags;
50} VDVFSFILE;
51/** Pointer to a the internal data of a DVM volume file. */
52typedef VDVFSFILE *PVDVFSFILE;
53
54/**
55 * VD read helper taking care of unaligned accesses.
56 *
57 * @return VBox status code.
58 * @param pDisk VD disk container.
59 * @param off Offset to start reading from.
60 * @param pvBuf Pointer to the buffer to read into.
61 * @param cbRead Amount of bytes to read.
62 */
63static int vdReadHelper(PVDISK pDisk, uint64_t off, void *pvBuf, size_t cbRead)
64{
65 int rc;
66
67 /* Take direct route if the request is sector aligned. */
68 uint64_t const offMisalign = off & 511;
69 size_t const cbMisalign = (off + cbRead) & 511;
70 if ( !offMisalign
71 && !cbMisalign)
72 rc = VDRead(pDisk, off, pvBuf, cbRead);
73 else
74 {
75 uint8_t *pbBuf = (uint8_t *)pvBuf;
76 uint8_t abBuf[512];
77 rc = VINF_SUCCESS; /* Make compilers happy. */
78
79 /* Unaligned buffered read of head. Aligns the offset. */
80 if (offMisalign)
81 {
82 rc = VDRead(pDisk, off - offMisalign, abBuf, 512);
83 if (RT_SUCCESS(rc))
84 {
85 size_t const cbPart = RT_MIN(512 - offMisalign, cbRead);
86 memcpy(pbBuf, &abBuf[offMisalign], cbPart);
87 pbBuf += cbPart;
88 off += cbPart;
89 cbRead -= cbPart;
90 }
91 }
92
93 /* Aligned direct read. */
94 if ( RT_SUCCESS(rc)
95 && cbRead >= 512)
96 {
97 Assert(!(off % 512));
98
99 size_t cbPart = cbRead - cbMisalign;
100 Assert(!(cbPart % 512));
101 rc = VDRead(pDisk, off, pbBuf, cbPart);
102 if (RT_SUCCESS(rc))
103 {
104 pbBuf += cbPart;
105 off += cbPart;
106 cbRead -= cbPart;
107 }
108 }
109
110 /* Unaligned buffered read of tail. */
111 if ( RT_SUCCESS(rc)
112 && cbRead)
113 {
114 Assert(cbRead == cbMisalign);
115 Assert(cbRead < 512);
116 Assert(!(off % 512));
117
118 rc = VDRead(pDisk, off, abBuf, 512);
119 if (RT_SUCCESS(rc))
120 memcpy(pbBuf, abBuf, cbRead);
121 }
122 }
123
124 return rc;
125}
126
127
128/**
129 * VD write helper taking care of unaligned accesses.
130 *
131 * @return VBox status code.
132 * @param pDisk VD disk container.
133 * @param off Offset to start writing to.
134 * @param pvBuf Pointer to the buffer to read from.
135 * @param cbWrite Amount of bytes to write.
136 */
137static int vdWriteHelper(PVDISK pDisk, uint64_t off, const void *pvBuf, size_t cbWrite)
138{
139 int rc;
140
141 /* Take direct route if the request is sector aligned. */
142 uint64_t const offMisalign = off & 511;
143 size_t const cbMisalign = (off + cbWrite) & 511;
144 if ( !offMisalign
145 && !cbMisalign)
146 rc = VDWrite(pDisk, off, pvBuf, cbWrite);
147 else
148 {
149 uint8_t *pbBuf = (uint8_t *)pvBuf;
150 uint8_t abBuf[512];
151 rc = VINF_SUCCESS; /* Make compilers happy. */
152
153 /* Unaligned buffered read+write of head. Aligns the offset. */
154 if (offMisalign)
155 {
156 rc = VDRead(pDisk, off - offMisalign, abBuf, 512);
157 if (RT_SUCCESS(rc))
158 {
159 size_t const cbPart = RT_MIN(512 - offMisalign, cbWrite);
160 memcpy(&abBuf[offMisalign], pbBuf, cbPart);
161 rc = VDWrite(pDisk, off - offMisalign, abBuf, 512);
162 if (RT_SUCCESS(rc))
163 {
164 pbBuf += cbPart;
165 off += cbPart;
166 cbWrite -= cbPart;
167 }
168 }
169 }
170
171 /* Aligned direct write. */
172 if ( RT_SUCCESS(rc)
173 && cbWrite >= 512)
174 {
175 Assert(!(off % 512));
176
177 size_t cbPart = cbWrite - cbMisalign;
178 Assert(!(cbPart % 512));
179 rc = VDWrite(pDisk, off, pbBuf, cbPart);
180 if (RT_SUCCESS(rc))
181 {
182 pbBuf += cbPart;
183 off += cbPart;
184 cbWrite -= cbPart;
185 }
186 }
187
188 /* Unaligned buffered read+write of tail. */
189 if ( RT_SUCCESS(rc)
190 && cbWrite > 0)
191 {
192 Assert(cbWrite == cbMisalign);
193 Assert(cbWrite < 512);
194 Assert(!(off % 512));
195
196 rc = VDRead(pDisk, off, abBuf, 512);
197 if (RT_SUCCESS(rc))
198 {
199 memcpy(abBuf, pbBuf, cbWrite);
200 rc = VDWrite(pDisk, off, abBuf, 512);
201 }
202 }
203 }
204
205 return rc;
206}
207
208
209/**
210 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
211 */
212static DECLCALLBACK(int) vdVfsFile_Close(void *pvThis)
213{
214 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
215
216 if (pThis->fFlags & VD_VFSFILE_DESTROY_ON_RELEASE)
217 VDDestroy(pThis->pDisk);
218
219 return VINF_SUCCESS;
220}
221
222
223/**
224 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
225 */
226static DECLCALLBACK(int) vdVfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
227{
228 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
229 unsigned const cOpenImages = VDGetCount(pThis->pDisk);
230
231 pObjInfo->cbObject = VDGetSize(pThis->pDisk, cOpenImages - 1);
232 pObjInfo->cbAllocated = 0;
233 for (unsigned iImage = 0; iImage < cOpenImages; iImage++)
234 pObjInfo->cbAllocated += VDGetFileSize(pThis->pDisk, iImage);
235
236 /** @todo enumerate the disk images directly... */
237 RTTimeNow(&pObjInfo->AccessTime);
238 pObjInfo->BirthTime = pObjInfo->AccessTime;
239 pObjInfo->ChangeTime = pObjInfo->AccessTime;
240 pObjInfo->ModificationTime = pObjInfo->AccessTime;
241
242 pObjInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0644;
243 pObjInfo->Attr.enmAdditional = enmAddAttr;
244 switch (enmAddAttr)
245 {
246 case RTFSOBJATTRADD_UNIX:
247 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
248 pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
249 pObjInfo->Attr.u.Unix.cHardlinks = 1;
250 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
251 pObjInfo->Attr.u.Unix.INodeId = 0;
252 pObjInfo->Attr.u.Unix.fFlags = 0;
253 pObjInfo->Attr.u.Unix.GenerationId = 0;
254 pObjInfo->Attr.u.Unix.Device = 0;
255 break;
256
257 case RTFSOBJATTRADD_UNIX_OWNER:
258 pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
259 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
260 break;
261 case RTFSOBJATTRADD_UNIX_GROUP:
262 pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID;
263 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
264 break;
265 case RTFSOBJATTRADD_EASIZE:
266 pObjInfo->Attr.u.EASize.cb = 0;
267 break;
268
269 default:
270 AssertFailedReturn(VERR_INVALID_PARAMETER);
271 }
272
273 return VINF_SUCCESS;
274}
275
276
277/**
278 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
279 */
280static DECLCALLBACK(int) vdVfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
281{
282 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
283
284 Assert(pSgBuf->cSegs == 1);
285 NOREF(fBlocking);
286
287 /*
288 * Find the current position and check if it's within the volume.
289 */
290 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
291 uint64_t const cbImage = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
292 if (offUnsigned >= cbImage)
293 {
294 if (pcbRead)
295 {
296 *pcbRead = 0;
297 pThis->offCurPos = cbImage;
298 return VINF_EOF;
299 }
300 return VERR_EOF;
301 }
302
303 int rc = VINF_SUCCESS;
304 size_t cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
305 if (offUnsigned + cbLeftToRead <= cbImage)
306 {
307 if (pcbRead)
308 *pcbRead = cbLeftToRead;
309 }
310 else
311 {
312 if (!pcbRead)
313 return VERR_EOF;
314 *pcbRead = cbLeftToRead = (size_t)(cbImage - offUnsigned);
315 rc = VINF_EOF;
316 }
317
318 /*
319 * Ok, we've got a valid stretch within the file. Do the reading.
320 */
321 if (cbLeftToRead > 0)
322 {
323 int rc2 = vdReadHelper(pThis->pDisk, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToRead);
324 if (RT_SUCCESS(rc2))
325 offUnsigned += cbLeftToRead;
326 else
327 rc = rc2;
328 }
329
330 pThis->offCurPos = offUnsigned;
331 return rc;
332}
333
334
335/**
336 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
337 */
338static DECLCALLBACK(int) vdVfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
339{
340 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
341
342 Assert(pSgBuf->cSegs == 1);
343 NOREF(fBlocking);
344
345 /*
346 * Find the current position and check if it's within the volume.
347 * Writing beyond the end of a volume is not supported.
348 */
349 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
350 uint64_t const cbImage = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
351 if (offUnsigned >= cbImage)
352 {
353 if (pcbWritten)
354 {
355 *pcbWritten = 0;
356 pThis->offCurPos = cbImage;
357 }
358 return VERR_EOF;
359 }
360
361 size_t cbLeftToWrite;
362 if (offUnsigned + pSgBuf->paSegs[0].cbSeg < cbImage)
363 {
364 cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
365 if (pcbWritten)
366 *pcbWritten = cbLeftToWrite;
367 }
368 else
369 {
370 if (!pcbWritten)
371 return VERR_EOF;
372 *pcbWritten = cbLeftToWrite = (size_t)(cbImage - offUnsigned);
373 }
374
375 /*
376 * Ok, we've got a valid stretch within the file. Do the reading.
377 */
378 int rc = VINF_SUCCESS;
379 if (cbLeftToWrite > 0)
380 {
381 rc = vdWriteHelper(pThis->pDisk, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
382 if (RT_SUCCESS(rc))
383 offUnsigned += cbLeftToWrite;
384 }
385
386 pThis->offCurPos = offUnsigned;
387 return rc;
388}
389
390
391/**
392 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
393 */
394static DECLCALLBACK(int) vdVfsFile_Flush(void *pvThis)
395{
396 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
397 return VDFlush(pThis->pDisk);
398}
399
400
401/**
402 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
403 */
404static DECLCALLBACK(int) vdVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
405{
406 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
407 *poffActual = pThis->offCurPos;
408 return VINF_SUCCESS;
409}
410
411
412/**
413 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetMode}
414 */
415static DECLCALLBACK(int) vdVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
416{
417 NOREF(pvThis);
418 NOREF(fMode);
419 NOREF(fMask);
420 return VERR_NOT_SUPPORTED;
421}
422
423
424/**
425 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
426 */
427static DECLCALLBACK(int) vdVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
428 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
429{
430 NOREF(pvThis);
431 NOREF(pAccessTime);
432 NOREF(pModificationTime);
433 NOREF(pChangeTime);
434 NOREF(pBirthTime);
435 return VERR_NOT_SUPPORTED;
436}
437
438
439/**
440 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
441 */
442static DECLCALLBACK(int) vdVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
443{
444 NOREF(pvThis);
445 NOREF(uid);
446 NOREF(gid);
447 return VERR_NOT_SUPPORTED;
448}
449
450
451/**
452 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
453 */
454static DECLCALLBACK(int) vdVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
455{
456 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
457
458 /*
459 * Seek relative to which position.
460 */
461 uint64_t offWrt;
462 switch (uMethod)
463 {
464 case RTFILE_SEEK_BEGIN:
465 offWrt = 0;
466 break;
467
468 case RTFILE_SEEK_CURRENT:
469 offWrt = pThis->offCurPos;
470 break;
471
472 case RTFILE_SEEK_END:
473 offWrt = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
474 break;
475
476 default:
477 return VERR_INTERNAL_ERROR_5;
478 }
479
480 /*
481 * Calc new position, take care to stay without bounds.
482 */
483 uint64_t offNew;
484 if (offSeek == 0)
485 offNew = offWrt;
486 else if (offSeek > 0)
487 {
488 offNew = offWrt + offSeek;
489 if ( offNew < offWrt
490 || offNew > RTFOFF_MAX)
491 offNew = RTFOFF_MAX;
492 }
493 else if ((uint64_t)-offSeek < offWrt)
494 offNew = offWrt + offSeek;
495 else
496 offNew = 0;
497
498 /*
499 * Update the state and set return value.
500 */
501 pThis->offCurPos = offNew;
502
503 *poffActual = offNew;
504 return VINF_SUCCESS;
505}
506
507
508/**
509 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
510 */
511static DECLCALLBACK(int) vdVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
512{
513 PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
514 *pcbFile = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
515 return VINF_SUCCESS;
516}
517
518
519/**
520 * Standard file operations.
521 */
522DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_vdVfsStdFileOps =
523{
524 { /* Stream */
525 { /* Obj */
526 RTVFSOBJOPS_VERSION,
527 RTVFSOBJTYPE_FILE,
528 "VDFile",
529 vdVfsFile_Close,
530 vdVfsFile_QueryInfo,
531 RTVFSOBJOPS_VERSION
532 },
533 RTVFSIOSTREAMOPS_VERSION,
534 RTVFSIOSTREAMOPS_FEAT_NO_SG,
535 vdVfsFile_Read,
536 vdVfsFile_Write,
537 vdVfsFile_Flush,
538 NULL /*PollOne*/,
539 vdVfsFile_Tell,
540 NULL /*Skip*/,
541 NULL /*ZeroFill*/,
542 RTVFSIOSTREAMOPS_VERSION,
543 },
544 RTVFSFILEOPS_VERSION,
545 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
546 { /* ObjSet */
547 RTVFSOBJSETOPS_VERSION,
548 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
549 vdVfsFile_SetMode,
550 vdVfsFile_SetTimes,
551 vdVfsFile_SetOwner,
552 RTVFSOBJSETOPS_VERSION
553 },
554 vdVfsFile_Seek,
555 vdVfsFile_QuerySize,
556 NULL /*SetSize*/,
557 NULL /*QueryMaxSize*/,
558 RTVFSFILEOPS_VERSION
559};
560
561
562VBOXDDU_DECL(int) VDCreateVfsFileFromDisk(PVDISK pDisk, uint32_t fFlags,
563 PRTVFSFILE phVfsFile)
564{
565 AssertPtrReturn(pDisk, VERR_INVALID_HANDLE);
566 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
567 AssertReturn((fFlags & ~VD_VFSFILE_FLAGS_MASK) == 0, VERR_INVALID_PARAMETER);
568
569 /*
570 * Create the volume file.
571 */
572 RTVFSFILE hVfsFile;
573 PVDVFSFILE pThis;
574 int rc = RTVfsNewFile(&g_vdVfsStdFileOps, sizeof(*pThis), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE,
575 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
576 if (RT_SUCCESS(rc))
577 {
578 pThis->offCurPos = 0;
579 pThis->pDisk = pDisk;
580 pThis->fFlags = fFlags;
581
582 *phVfsFile = hVfsFile;
583 return VINF_SUCCESS;
584 }
585
586 return rc;
587}
588
589
590/**
591 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
592 */
593static DECLCALLBACK(int) vdVfsChain_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
594 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
595{
596 RT_NOREF(pProviderReg, pSpec);
597
598 /*
599 * Basic checks.
600 */
601 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
602 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
603 if ( pElement->enmType != RTVFSOBJTYPE_FILE
604 && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
605 return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS;
606
607 if (pElement->cArgs < 1)
608 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
609
610 /*
611 * Parse the flag if present, save in pElement->uProvider.
612 */
613 uint32_t fFlags = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ
614 ? VD_OPEN_FLAGS_READONLY : VD_OPEN_FLAGS_NORMAL;
615 if (pElement->cArgs > 1)
616 {
617 pElement->paArgs[pElement->cArgs - 1].uProvider = true; /* indicates flags */
618 const char *psz = pElement->paArgs[pElement->cArgs - 1].psz;
619 if (*psz)
620 {
621 if ( !strcmp(psz, "ro")
622 || !strcmp(psz, "r"))
623 {
624 fFlags &= ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_NORMAL);
625 fFlags |= VD_OPEN_FLAGS_READONLY;
626 }
627 else if (!strcmp(psz, "rw"))
628 {
629 fFlags &= ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_NORMAL);
630 fFlags |= VD_OPEN_FLAGS_NORMAL;
631 }
632 else if (strlen(psz) <= 4)
633 {
634 *poffError = pElement->paArgs[pElement->cArgs - 1].offSpec;
635 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
636 }
637 else
638 pElement->paArgs[pElement->cArgs - 1].uProvider = false; /* indicates no flags */
639 }
640 }
641
642 pElement->uProvider = fFlags;
643 if ( pElement->cArgs > 2
644 || (pElement->cArgs == 2 && !pElement->paArgs[pElement->cArgs - 1].uProvider))
645 pElement->uProvider |= RT_BIT_64(63);
646 return VINF_SUCCESS;
647}
648
649
650/**
651 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
652 */
653static DECLCALLBACK(int) vdVfsChain_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
654 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
655 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
656{
657 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
658 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
659
660 /* Determin the format. */
661 char *pszFormat = NULL;
662 VDTYPE enmType = VDTYPE_INVALID;
663 int rc = VDGetFormat(NULL, NULL, pElement->paArgs[0].psz, &pszFormat, &enmType);
664 if (RT_SUCCESS(rc))
665 {
666 PVDISK pDisk = NULL;
667 rc = VDCreate(NULL, enmType, &pDisk);
668 if (RT_SUCCESS(rc))
669 {
670 if (!(pElement->uProvider & RT_BIT_64(63)))
671 rc = VDOpen(pDisk, pszFormat, pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, NULL);
672 else
673 {
674 uint32_t cChain = pElement->cArgs;
675 if (pElement->cArgs == 2 && pElement->paArgs[pElement->cArgs - 1].uProvider != 0)
676 cChain--;
677 uint32_t const fFinal = (uint32_t)pElement->uProvider;
678 uint32_t const fReadOnly = (fFinal & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_NORMAL)) | VD_OPEN_FLAGS_READONLY;
679 uint32_t iChain;
680 for (iChain = 0; iChain < cChain && RT_SUCCESS(rc); iChain++)
681 rc = VDOpen(pDisk, pszFormat, pElement->paArgs[iChain].psz, iChain + 1 >= cChain ? fFinal : fReadOnly, NULL);
682 }
683 if (RT_SUCCESS(rc))
684 {
685 RTVFSFILE hVfsFile;
686 rc = VDCreateVfsFileFromDisk(pDisk, VD_VFSFILE_DESTROY_ON_RELEASE, &hVfsFile);
687 if (RT_SUCCESS(rc))
688 {
689 RTStrFree(pszFormat);
690
691 *phVfsObj = RTVfsObjFromFile(hVfsFile);
692 RTVfsFileRelease(hVfsFile);
693
694 if (*phVfsObj != NIL_RTVFSOBJ)
695 return VINF_SUCCESS;
696 return VERR_VFS_CHAIN_CAST_FAILED;
697 }
698 }
699 VDDestroy(pDisk);
700 }
701 RTStrFree(pszFormat);
702 }
703 return rc;
704}
705
706
707/**
708 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
709 */
710static DECLCALLBACK(bool) vdVfsChain_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
711 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
712 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
713{
714 RT_NOREF(pProviderReg, pSpec, pElement, pReuseSpec, pReuseElement);
715 return false;
716}
717
718
719/** VFS chain element 'file'. */
720static RTVFSCHAINELEMENTREG g_rtVfsChainIsoFsVolReg =
721{
722 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
723 /* fReserved = */ 0,
724 /* pszName = */ "vd",
725 /* ListEntry = */ { NULL, NULL },
726 /* pszHelp = */ "Opens a container image using the VD API.\n"
727 "To open a snapshot chain, start with the root image and end with the more recent diff image.\n"
728 "The final argument can be a flag 'ro' or 'r' for read-only, 'rw' for read-write.",
729 /* pfnValidate = */ vdVfsChain_Validate,
730 /* pfnInstantiate = */ vdVfsChain_Instantiate,
731 /* pfnCanReuseElement = */ vdVfsChain_CanReuseElement,
732 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
733};
734
735RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainIsoFsVolReg, rtVfsChainIsoFsVolReg);
736
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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