VirtualBox

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

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

IPRT/vfs: Implemented RTVFsFileSetSize, RTVfsFileGetMaxSize and RTvfsFileQueryMaxSize.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1/* $Id: dvmvfs.cpp 69977 2017-12-07 13:02:36Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - 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.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#define LOG_GROUP RTLOGGROUP_FS /** @todo fix log group */
32#include <iprt/types.h>
33#include <iprt/assert.h>
34#include <iprt/mem.h>
35#include <iprt/dvm.h>
36#include <iprt/err.h>
37#include <iprt/asm.h>
38#include <iprt/string.h>
39#include <iprt/file.h>
40#include <iprt/sg.h>
41#include <iprt/vfslowlevel.h>
42#include <iprt/poll.h>
43#include <iprt/log.h>
44#include "internal/dvm.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * A volume manager VFS for use in chains (thing pseudo/devfs).
52 */
53typedef struct RTDVMVFSVOL
54{
55 /** The volume manager. */
56 RTDVM hVolMgr;
57 /** Whether to close it on success. */
58 bool fCloseDvm;
59 /** Whether the access is read-only. */
60 bool fReadOnly;
61 /** Number of volumes. */
62 uint32_t cVolumes;
63 /** Self reference. */
64 RTVFS hVfsSelf;
65} RTDVMVFSVOL;
66/** Poitner to a volume manager VFS. */
67typedef RTDVMVFSVOL *PRTDVMVFSVOL;
68
69/**
70 * The volume manager VFS (root) dir data.
71 */
72typedef struct RTDVMVFSDIR
73{
74 /** Pointer to the VFS volume. */
75 PRTDVMVFSVOL pVfsVol;
76 /** The current directory offset. */
77 uint32_t offDir;
78 /** Set if we need to try return hCurVolume again because of buffer overflow. */
79 bool fReturnCurrent;
80 /** The current DVM volume. */
81 RTDVMVOLUME hCurVolume;
82} RTDVMVFSDIR;
83/** Poitner to a volume manager VFS (root) dir. */
84typedef RTDVMVFSDIR *PRTDVMVFSDIR;
85
86/**
87 * The internal data of a DVM volume I/O stream.
88 */
89typedef struct RTVFSDVMFILE
90{
91 /** The volume the VFS file belongs to. */
92 RTDVMVOLUME hVol;
93 /** Pointer to the VFS volume. Can be NULL. */
94 PRTDVMVFSVOL pVfsVol;
95 /** Current position. */
96 uint64_t offCurPos;
97 /** Set if readable. */
98 bool fCanRead;
99 /** Set if writable. */
100 bool fCanWrite;
101} RTVFSDVMFILE;
102/** Pointer to a the internal data of a DVM volume file. */
103typedef RTVFSDVMFILE *PRTVFSDVMFILE;
104
105
106/*********************************************************************************************************************************
107* Internal Functions *
108*********************************************************************************************************************************/
109static DECLCALLBACK(int) rtDvmVfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir);
110
111
112/**
113 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
114 */
115static DECLCALLBACK(int) rtDvmVfsFile_Close(void *pvThis)
116{
117 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
118
119 RTDvmVolumeRelease(pThis->hVol);
120 return VINF_SUCCESS;
121}
122
123
124/**
125 * Worker for rtDvmVfsFile_QueryInfo, rtDvmVfsDir_QueryEntryInfo, and
126 * rtDvmVfsDir_ReadDir.
127 */
128static int rtDvmVfsFile_QueryInfoWorker(RTDVMVOLUME hVolume, RTDVM hVolMgr, bool fReadOnly,
129 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
130{
131
132 pObjInfo->cbObject = RTDvmVolumeGetSize(hVolume);
133 pObjInfo->cbAllocated = pObjInfo->cbObject;
134 RTTimeSpecSetNano(&pObjInfo->AccessTime, 0);
135 RTTimeSpecSetNano(&pObjInfo->ModificationTime, 0);
136 RTTimeSpecSetNano(&pObjInfo->ChangeTime, 0);
137 RTTimeSpecSetNano(&pObjInfo->BirthTime, 0);
138 pObjInfo->Attr.fMode = RTFS_TYPE_FILE | RTFS_DOS_NT_NORMAL;
139 if (fReadOnly)
140 pObjInfo->Attr.fMode |= RTFS_DOS_READONLY | 0444;
141 else
142 pObjInfo->Attr.fMode |= 0666;
143
144 switch (enmAddAttr)
145 {
146 case RTFSOBJATTRADD_NOTHING:
147 case RTFSOBJATTRADD_UNIX:
148 pObjInfo->Attr.u.Unix.uid = (RTUID)RTDvmVolumeGetType(hVolume);
149 pObjInfo->Attr.u.Unix.gid = hVolMgr != NIL_RTDVM ? (RTGID)RTDvmMapGetFormatType(hVolMgr) : NIL_RTGID;
150 pObjInfo->Attr.u.Unix.cHardlinks = 1;
151 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
152 pObjInfo->Attr.u.Unix.INodeId = 0;
153 pObjInfo->Attr.u.Unix.fFlags = 0;
154 pObjInfo->Attr.u.Unix.GenerationId = 0;
155 pObjInfo->Attr.u.Unix.Device = 0;
156 break;
157
158 case RTFSOBJATTRADD_UNIX_OWNER:
159 {
160 RTDVMVOLTYPE enmType = RTDvmVolumeGetType(hVolume);
161 pObjInfo->Attr.u.UnixOwner.uid = (RTUID)enmType;
162 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName),
163 RTDvmVolumeTypeGetDescr(enmType));
164 break;
165 }
166
167 case RTFSOBJATTRADD_UNIX_GROUP:
168 if (hVolMgr != NIL_RTDVM)
169 {
170 pObjInfo->Attr.u.UnixGroup.gid = (RTGID)RTDvmMapGetFormatType(hVolMgr);
171 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
172 RTDvmMapGetFormatName(hVolMgr));
173 }
174 else
175 {
176 pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID;
177 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
178 }
179 break;
180
181 case RTFSOBJATTRADD_EASIZE:
182 pObjInfo->Attr.u.EASize.cb = 0;
183 break;
184
185 default:
186 return VERR_INVALID_PARAMETER;
187 }
188 return VINF_SUCCESS;
189}
190
191
192/**
193 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
194 */
195static DECLCALLBACK(int) rtDvmVfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
196{
197 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
198 return rtDvmVfsFile_QueryInfoWorker(pThis->hVol,
199 pThis->pVfsVol ? pThis->pVfsVol->hVolMgr : NIL_RTDVM,
200 pThis->pVfsVol ? pThis->pVfsVol->fReadOnly : !pThis->fCanWrite,
201 pObjInfo, enmAddAttr);
202}
203
204
205/**
206 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
207 */
208static DECLCALLBACK(int) rtDvmVfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
209{
210 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
211 int rc = VINF_SUCCESS;
212
213 Assert(pSgBuf->cSegs == 1);
214 NOREF(fBlocking);
215
216 /*
217 * Find the current position and check if it's within the volume.
218 */
219 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
220 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
221 {
222 if (pcbRead)
223 {
224 *pcbRead = 0;
225 pThis->offCurPos = offUnsigned;
226 return VINF_EOF;
227 }
228 return VERR_EOF;
229 }
230
231 size_t cbLeftToRead;
232 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
233 {
234 if (!pcbRead)
235 return VERR_EOF;
236 *pcbRead = cbLeftToRead = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
237 }
238 else
239 {
240 cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
241 if (pcbRead)
242 *pcbRead = cbLeftToRead;
243 }
244
245 /*
246 * Ok, we've got a valid stretch within the file. Do the reading.
247 */
248 if (cbLeftToRead > 0)
249 {
250 rc = RTDvmVolumeRead(pThis->hVol, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToRead);
251 if (RT_SUCCESS(rc))
252 offUnsigned += cbLeftToRead;
253 }
254
255 pThis->offCurPos = offUnsigned;
256 return rc;
257}
258
259
260/**
261 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
262 */
263static DECLCALLBACK(int) rtDvmVfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
264{
265 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
266 int rc = VINF_SUCCESS;
267
268 Assert(pSgBuf->cSegs == 1);
269 NOREF(fBlocking);
270
271 /*
272 * Find the current position and check if it's within the volume.
273 * Writing beyond the end of a volume is not supported.
274 */
275 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
276 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
277 {
278 if (pcbWritten)
279 {
280 *pcbWritten = 0;
281 pThis->offCurPos = offUnsigned;
282 }
283 return VERR_NOT_SUPPORTED;
284 }
285
286 size_t cbLeftToWrite;
287 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
288 {
289 if (!pcbWritten)
290 return VERR_EOF;
291 *pcbWritten = cbLeftToWrite = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
292 }
293 else
294 {
295 cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
296 if (pcbWritten)
297 *pcbWritten = cbLeftToWrite;
298 }
299
300 /*
301 * Ok, we've got a valid stretch within the file. Do the reading.
302 */
303 if (cbLeftToWrite > 0)
304 {
305 rc = RTDvmVolumeWrite(pThis->hVol, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
306 if (RT_SUCCESS(rc))
307 offUnsigned += cbLeftToWrite;
308 }
309
310 pThis->offCurPos = offUnsigned;
311 return rc;
312}
313
314
315/**
316 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
317 */
318static DECLCALLBACK(int) rtDvmVfsFile_Flush(void *pvThis)
319{
320 NOREF(pvThis);
321 return VINF_SUCCESS; /** @todo Implement missing DVM API. */
322}
323
324
325/**
326 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
327 */
328static DECLCALLBACK(int) rtDvmVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
329{
330 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
331 *poffActual = pThis->offCurPos;
332 return VINF_SUCCESS;
333}
334
335
336/**
337 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
338 */
339static DECLCALLBACK(int) rtDvmVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
340{
341 NOREF(pvThis);
342 NOREF(fMode);
343 NOREF(fMask);
344 return VERR_NOT_SUPPORTED;
345}
346
347
348/**
349 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
350 */
351static DECLCALLBACK(int) rtDvmVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
352 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
353{
354 NOREF(pvThis);
355 NOREF(pAccessTime);
356 NOREF(pModificationTime);
357 NOREF(pChangeTime);
358 NOREF(pBirthTime);
359 return VERR_NOT_SUPPORTED;
360}
361
362
363/**
364 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
365 */
366static DECLCALLBACK(int) rtDvmVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
367{
368 NOREF(pvThis);
369 NOREF(uid);
370 NOREF(gid);
371 return VERR_NOT_SUPPORTED;
372}
373
374
375/**
376 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
377 */
378static DECLCALLBACK(int) rtDvmVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
379{
380 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
381
382 /*
383 * Seek relative to which position.
384 */
385 uint64_t offWrt;
386 switch (uMethod)
387 {
388 case RTFILE_SEEK_BEGIN:
389 offWrt = 0;
390 break;
391
392 case RTFILE_SEEK_CURRENT:
393 offWrt = pThis->offCurPos;
394 break;
395
396 case RTFILE_SEEK_END:
397 offWrt = RTDvmVolumeGetSize(pThis->hVol);
398 break;
399
400 default:
401 return VERR_INTERNAL_ERROR_5;
402 }
403
404 /*
405 * Calc new position, take care to stay within bounds.
406 *
407 * @todo: Setting position beyond the end of the volume does not make sense.
408 */
409 uint64_t offNew;
410 if (offSeek == 0)
411 offNew = offWrt;
412 else if (offSeek > 0)
413 {
414 offNew = offWrt + offSeek;
415 if ( offNew < offWrt
416 || offNew > RTFOFF_MAX)
417 offNew = RTFOFF_MAX;
418 }
419 else if ((uint64_t)-offSeek < offWrt)
420 offNew = offWrt + offSeek;
421 else
422 offNew = 0;
423
424 /*
425 * Update the state and set return value.
426 */
427 pThis->offCurPos = offNew;
428
429 *poffActual = offNew;
430 return VINF_SUCCESS;
431}
432
433
434/**
435 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
436 */
437static DECLCALLBACK(int) rtDvmVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
438{
439 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
440 *pcbFile = RTDvmVolumeGetSize(pThis->hVol);
441 return VINF_SUCCESS;
442}
443
444
445/**
446 * Standard file operations.
447 */
448DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtDvmVfsStdFileOps =
449{
450 { /* Stream */
451 { /* Obj */
452 RTVFSOBJOPS_VERSION,
453 RTVFSOBJTYPE_FILE,
454 "DvmFile",
455 rtDvmVfsFile_Close,
456 rtDvmVfsFile_QueryInfo,
457 RTVFSOBJOPS_VERSION
458 },
459 RTVFSIOSTREAMOPS_VERSION,
460 RTVFSIOSTREAMOPS_FEAT_NO_SG,
461 rtDvmVfsFile_Read,
462 rtDvmVfsFile_Write,
463 rtDvmVfsFile_Flush,
464 NULL /*pfnPollOne*/,
465 rtDvmVfsFile_Tell,
466 NULL /*Skip*/,
467 NULL /*ZeroFill*/,
468 RTVFSIOSTREAMOPS_VERSION,
469 },
470 RTVFSFILEOPS_VERSION,
471 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
472 { /* ObjSet */
473 RTVFSOBJSETOPS_VERSION,
474 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
475 rtDvmVfsFile_SetMode,
476 rtDvmVfsFile_SetTimes,
477 rtDvmVfsFile_SetOwner,
478 RTVFSOBJSETOPS_VERSION
479 },
480 rtDvmVfsFile_Seek,
481 rtDvmVfsFile_QuerySize,
482 NULL /*SetSize*/,
483 NULL /*QueryMaxSize*/,
484 RTVFSFILEOPS_VERSION
485};
486
487
488/**
489 * Internal worker for RTDvmVolumeCreateVfsFile and rtDvmVfsDir_OpenFile.
490 *
491 * @returns IPRT status code.
492 * @param pVfsVol The VFS volume, optional.
493 * @param hVol The volume handle. (Reference not consumed.)
494 * @param fOpen RTFILE_O_XXX (valid).
495 * @param phVfsFileOut Where to return the handle to the file.
496 */
497static int rtDvmVfsCreateFileForVolume(PRTDVMVFSVOL pVfsVol, RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut)
498{
499 uint32_t cRefs = RTDvmVolumeRetain(hVol);
500 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
501
502 /*
503 * Create the volume file.
504 */
505 RTVFSFILE hVfsFile;
506 PRTVFSDVMFILE pThis;
507 int rc = RTVfsNewFile(&g_rtDvmVfsStdFileOps, sizeof(*pThis), fOpen, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
508 if (RT_SUCCESS(rc))
509 {
510 pThis->offCurPos = 0;
511 pThis->hVol = hVol;
512 pThis->fCanRead = RT_BOOL(fOpen & RTFILE_O_READ);
513 pThis->fCanWrite = RT_BOOL(fOpen & RTFILE_O_WRITE);
514 pThis->pVfsVol = pVfsVol;
515
516 *phVfsFileOut = hVfsFile;
517 return VINF_SUCCESS;
518 }
519
520 RTDvmVolumeRelease(hVol);
521 return rc;
522}
523
524
525RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut)
526{
527 AssertPtrReturn(hVol, VERR_INVALID_HANDLE);
528 AssertPtrReturn(phVfsFileOut, VERR_INVALID_POINTER);
529 AssertReturn(fOpen & RTFILE_O_ACCESS_MASK, VERR_INVALID_FLAGS);
530 AssertReturn(!(fOpen & ~RTFILE_O_VALID_MASK), VERR_INVALID_FLAGS);
531 return rtDvmVfsCreateFileForVolume(NULL, hVol, fOpen, phVfsFileOut);
532}
533
534
535/**
536 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
537 */
538static DECLCALLBACK(int) rtDvmVfsDir_Close(void *pvThis)
539{
540 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
541
542 if (pThis->hCurVolume != NIL_RTDVMVOLUME)
543 {
544 RTDvmVolumeRelease(pThis->hCurVolume);
545 pThis->hCurVolume = NIL_RTDVMVOLUME;
546 }
547
548 pThis->pVfsVol = NULL;
549
550 return VINF_SUCCESS;
551}
552
553
554/**
555 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
556 */
557static DECLCALLBACK(int) rtDvmVfsDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
558{
559 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
560 pObjInfo->cbObject = pThis->pVfsVol->cVolumes;
561 pObjInfo->cbAllocated = pThis->pVfsVol->cVolumes;
562 RTTimeSpecSetNano(&pObjInfo->AccessTime, 0);
563 RTTimeSpecSetNano(&pObjInfo->ModificationTime, 0);
564 RTTimeSpecSetNano(&pObjInfo->ChangeTime, 0);
565 RTTimeSpecSetNano(&pObjInfo->BirthTime, 0);
566 pObjInfo->Attr.fMode = RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY;
567 if (pThis->pVfsVol->fReadOnly)
568 pObjInfo->Attr.fMode |= RTFS_DOS_READONLY | 0555;
569 else
570 pObjInfo->Attr.fMode |= 0777;
571
572 switch (enmAddAttr)
573 {
574 case RTFSOBJATTRADD_NOTHING:
575 case RTFSOBJATTRADD_UNIX:
576 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
577 pObjInfo->Attr.u.Unix.gid = (RTGID)RTDvmMapGetFormatType(pThis->pVfsVol->hVolMgr);
578 pObjInfo->Attr.u.Unix.cHardlinks = pThis->pVfsVol->cVolumes;
579 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
580 pObjInfo->Attr.u.Unix.INodeId = 0;
581 pObjInfo->Attr.u.Unix.fFlags = 0;
582 pObjInfo->Attr.u.Unix.GenerationId = 0;
583 pObjInfo->Attr.u.Unix.Device = 0;
584 break;
585
586 case RTFSOBJATTRADD_UNIX_OWNER:
587 pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
588 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
589 break;
590
591 case RTFSOBJATTRADD_UNIX_GROUP:
592 pObjInfo->Attr.u.UnixGroup.gid = (RTGID)RTDvmMapGetFormatType(pThis->pVfsVol->hVolMgr);
593 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
594 RTDvmMapGetFormatName(pThis->pVfsVol->hVolMgr));
595 break;
596
597 case RTFSOBJATTRADD_EASIZE:
598 pObjInfo->Attr.u.EASize.cb = 0;
599 break;
600
601 default:
602 return VERR_INVALID_PARAMETER;
603 }
604 return VINF_SUCCESS;
605}
606
607
608/**
609 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
610 */
611static DECLCALLBACK(int) rtDvmVfsDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
612{
613 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
614 return VERR_NOT_SUPPORTED;
615}
616
617
618/**
619 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
620 */
621static DECLCALLBACK(int) rtDvmVfsDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
622 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
623{
624 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
625 return VERR_NOT_SUPPORTED;
626}
627
628
629/**
630 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
631 */
632static DECLCALLBACK(int) rtDvmVfsDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
633{
634 RT_NOREF(pvThis, uid, gid);
635 return VERR_NOT_SUPPORTED;
636}
637
638
639static int rtDvmVfsDir_FindEntry(PRTDVMVFSDIR pThis, const char *pszEntry, PRTDVMVOLUME phVolume)
640{
641 /*
642 * Enumerate the volumes and try match the volume name.
643 */
644 int rc;
645 PRTDVMVFSVOL pVfsVol = pThis->pVfsVol;
646 if (pVfsVol->cVolumes > 0)
647 {
648 /* The first volume. */
649 uint32_t iVol = 0;
650 RTDVMVOLUME hVol;
651 rc = RTDvmMapQueryFirstVolume(pThis->pVfsVol->hVolMgr, &hVol);
652 while (RT_SUCCESS(rc))
653 {
654 /* Match the name. */
655 bool fMatch;
656 char *pszVolName;
657 rc = RTDvmVolumeQueryName(hVol, &pszVolName);
658 if (RT_SUCCESS(rc))
659 {
660 fMatch = RTStrCmp(pszEntry, pszVolName) == 0 && *pszVolName != '\0';
661 RTStrFree(pszVolName);
662 }
663 else if (rc == VERR_NOT_SUPPORTED)
664 fMatch = false;
665 else
666 {
667 RTDvmVolumeRelease(hVol);
668 break;
669 }
670
671 /* Match the sequential volume number. */
672 if (!fMatch)
673 {
674 char szTmp[16];
675 RTStrPrintf(szTmp, sizeof(szTmp), "vol%u", iVol);
676 fMatch = RTStrCmp(pszEntry, szTmp) == 0;
677 }
678
679 if (fMatch)
680 {
681 *phVolume = hVol;
682 return VINF_SUCCESS;
683 }
684
685 /* More volumes? */
686 iVol++;
687 if (iVol >= pVfsVol->cVolumes)
688 {
689 RTDvmVolumeRelease(hVol);
690 rc = VERR_FILE_NOT_FOUND;
691 break;
692 }
693
694 /* Get the next volume. */
695 RTDVMVOLUME hVolNext;
696 rc = RTDvmMapQueryNextVolume(pThis->pVfsVol->hVolMgr, hVol, &hVolNext);
697 RTDvmVolumeRelease(hVol);
698 hVol = hVolNext;
699 }
700 }
701 else
702 rc = VERR_FILE_NOT_FOUND;
703 return rc;
704}
705
706
707/**
708 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
709 */
710static DECLCALLBACK(int) rtDvmVfsDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen, uint32_t fFlags, PRTVFSOBJ phVfsObj)
711{
712 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
713
714 /*
715 * Special case: '.' and '..'
716 */
717 if ( pszEntry[0] == '.'
718 && ( pszEntry[1] == '\0'
719 || ( pszEntry[1] == '.'
720 && pszEntry[2] == '\0')))
721 {
722 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
723 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
724 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
725 {
726 if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
727 {
728 RTVFSDIR hVfsDir;
729 int rc = rtDvmVfsVol_OpenRoot(pThis->pVfsVol, &hVfsDir);
730 if (RT_SUCCESS(rc))
731 {
732 *phVfsObj = RTVfsObjFromDir(hVfsDir);
733 RTVfsDirRelease(hVfsDir);
734 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
735 }
736 return rc;
737 }
738 return VERR_IS_A_DIRECTORY;
739 }
740 return VERR_ACCESS_DENIED;
741 }
742
743 /*
744 * Open volume file.
745 */
746 RTDVMVOLUME hVolume = NIL_RTDVMVOLUME;
747 int rc = rtDvmVfsDir_FindEntry(pThis, pszEntry, &hVolume);
748 if (RT_SUCCESS(rc))
749 {
750 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
751 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
752 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
753 {
754 if (fFlags & (RTVFSOBJ_F_OPEN_FILE | RTVFSOBJ_F_OPEN_DEV_BLOCK))
755 {
756 if ( !(fOpen & RTFILE_O_WRITE)
757 || !pThis->pVfsVol->fReadOnly)
758 {
759 RTVFSFILE hVfsFile;
760 rc = rtDvmVfsCreateFileForVolume(pThis->pVfsVol, hVolume, fOpen, &hVfsFile);
761 if (RT_SUCCESS(rc))
762 {
763 *phVfsObj = RTVfsObjFromFile(hVfsFile);
764 RTVfsFileRelease(hVfsFile);
765 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
766 }
767 }
768 else
769 rc = VERR_WRITE_PROTECT;
770 }
771 else
772 rc = VERR_IS_A_FILE;
773 }
774 else
775 rc = VERR_ALREADY_EXISTS;
776 RTDvmVolumeRelease(hVolume);
777 }
778 return rc;
779}
780
781
782/**
783 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
784 */
785static DECLCALLBACK(int) rtDvmVfsDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
786{
787 RTVFSOBJ hVfsObj;
788 int rc = rtDvmVfsDir_Open(pvThis, pszFilename, fOpen, RTVFSOBJ_F_OPEN_FILE, &hVfsObj);
789 if (RT_SUCCESS(rc))
790 {
791 *phVfsFile = RTVfsObjToFile(hVfsObj);
792 RTVfsObjRelease(hVfsObj);
793 }
794 return rc;
795}
796
797
798/**
799 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
800 */
801static DECLCALLBACK(int) rtDvmVfsDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
802{
803 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
804 return VERR_NOT_SUPPORTED;
805}
806
807
808/**
809 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
810 */
811static DECLCALLBACK(int) rtDvmVfsDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
812{
813 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
814 return VERR_NOT_SUPPORTED;
815}
816
817
818/**
819 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
820 */
821static DECLCALLBACK(int) rtDvmVfsDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
822 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
823{
824 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
825 return VERR_NOT_SUPPORTED;
826}
827
828
829/**
830 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
831 */
832static DECLCALLBACK(int) rtDvmVfsDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
833{
834 RT_NOREF(pvThis, pszEntry, fType);
835 return VERR_NOT_IMPLEMENTED;
836}
837
838
839/**
840 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
841 */
842static DECLCALLBACK(int) rtDvmVfsDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
843{
844 RT_NOREF(pvThis, pszEntry, fType, pszNewName);
845 return VERR_NOT_IMPLEMENTED;
846}
847
848
849/**
850 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
851 */
852static DECLCALLBACK(int) rtDvmVfsDir_RewindDir(void *pvThis)
853{
854 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
855
856 if (pThis->hCurVolume != NIL_RTDVMVOLUME)
857 {
858 RTDvmVolumeRelease(pThis->hCurVolume);
859 pThis->hCurVolume = NIL_RTDVMVOLUME;
860 }
861 pThis->fReturnCurrent = false;
862 pThis->offDir = 0;
863
864 return VINF_SUCCESS;
865}
866
867
868/**
869 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
870 */
871static DECLCALLBACK(int) rtDvmVfsDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
872 RTFSOBJATTRADD enmAddAttr)
873{
874 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
875 PRTDVMVFSVOL pVfsVol = pThis->pVfsVol;
876 int rc;
877
878 /*
879 * Get the volume to return info about.
880 */
881 if (!pThis->fReturnCurrent)
882 {
883 if (pThis->offDir < pVfsVol->cVolumes)
884 {
885 RTDVMVOLUME hNextVolume;
886 if (pThis->offDir == 0)
887 rc = RTDvmMapQueryFirstVolume(pVfsVol->hVolMgr, &hNextVolume);
888 else
889 rc = RTDvmMapQueryNextVolume(pVfsVol->hVolMgr, pThis->hCurVolume, &hNextVolume);
890 if (RT_FAILURE(rc))
891 return rc;
892 RTDvmVolumeRelease(pThis->hCurVolume);
893 pThis->hCurVolume = hNextVolume;
894 }
895 else
896 {
897 RTDvmVolumeRelease(pThis->hCurVolume);
898 pThis->hCurVolume = NIL_RTDVMVOLUME;
899 return VERR_NO_MORE_FILES;
900 }
901 }
902
903 /*
904 * Figure out the name length.
905 */
906 char szVolNo[16];
907 RTStrPrintf(szVolNo, sizeof(szVolNo), "vol%u", pThis->offDir);
908
909 char *pszVolName;
910 rc = RTDvmVolumeQueryName(pThis->hCurVolume, &pszVolName);
911 if ( RT_SUCCESS(rc)
912 || rc == VERR_NOT_SUPPORTED)
913 {
914 if (rc == VERR_NOT_SUPPORTED)
915 pszVolName = szVolNo;
916 else if (*pszVolName == '\0')
917 {
918 RTStrFree(pszVolName);
919 pszVolName = szVolNo;
920 }
921
922 size_t cchVolName = strlen(pszVolName);
923 size_t cbNeeded = RT_OFFSETOF(RTDIRENTRYEX, szName[cchVolName + 1]);
924 if (cbNeeded <= *pcbDirEntry)
925 {
926 *pcbDirEntry = cbNeeded;
927
928 /* Do the names. */
929 pDirEntry->cbName = (uint16_t)cchVolName;
930 memcpy(pDirEntry->szName, pszVolName, cchVolName + 1);
931 if (pszVolName != szVolNo)
932 {
933 RTStrFree(pszVolName);
934
935 PRTUTF16 pwszShortName = pDirEntry->wszShortName;
936 size_t cwcShortName = 0;
937 rc = RTStrToUtf16Ex(szVolNo, RTSTR_MAX, &pwszShortName, RT_ELEMENTS(pDirEntry->wszShortName), &cwcShortName);
938 AssertRC(rc);
939 pDirEntry->cwcShortName = (uint16_t)cwcShortName;
940 }
941 else
942 {
943 pDirEntry->cwcShortName = 0;
944 pDirEntry->wszShortName[0] = '\0';
945 }
946
947 /* Do the rest. */
948 rc = rtDvmVfsFile_QueryInfoWorker(pThis->hCurVolume, pVfsVol->hVolMgr, pVfsVol->fReadOnly,
949 &pDirEntry->Info, enmAddAttr);
950 pThis->fReturnCurrent = !RT_SUCCESS(rc);
951 pThis->offDir += RT_SUCCESS(rc);
952 return rc;
953 }
954
955 *pcbDirEntry = cbNeeded;
956 rc = VERR_BUFFER_OVERFLOW;
957
958 if (pszVolName != szVolNo)
959 RTStrFree(pszVolName);
960 }
961
962 pThis->fReturnCurrent = true;
963 return rc;
964}
965
966
967/**
968 * DVM (root) directory operations.
969 */
970static const RTVFSDIROPS g_rtDvmVfsDirOps =
971{
972 { /* Obj */
973 RTVFSOBJOPS_VERSION,
974 RTVFSOBJTYPE_DIR,
975 "DvmDir",
976 rtDvmVfsDir_Close,
977 rtDvmVfsDir_QueryInfo,
978 RTVFSOBJOPS_VERSION
979 },
980 RTVFSDIROPS_VERSION,
981 0,
982 { /* ObjSet */
983 RTVFSOBJSETOPS_VERSION,
984 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
985 rtDvmVfsDir_SetMode,
986 rtDvmVfsDir_SetTimes,
987 rtDvmVfsDir_SetOwner,
988 RTVFSOBJSETOPS_VERSION
989 },
990 rtDvmVfsDir_Open,
991 NULL /* pfnFollowAbsoluteSymlink */,
992 rtDvmVfsDir_OpenFile,
993 NULL /* pfnOpenDir */,
994 rtDvmVfsDir_CreateDir,
995 rtDvmVfsDir_OpenSymlink,
996 rtDvmVfsDir_CreateSymlink,
997 NULL /* pfnQueryEntryInfo */,
998 rtDvmVfsDir_UnlinkEntry,
999 rtDvmVfsDir_RenameEntry,
1000 rtDvmVfsDir_RewindDir,
1001 rtDvmVfsDir_ReadDir,
1002 RTVFSDIROPS_VERSION,
1003};
1004
1005
1006
1007/**
1008 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
1009 */
1010static DECLCALLBACK(int) rtDvmVfsVol_Close(void *pvThis)
1011{
1012 PRTDVMVFSVOL pThis = (PRTDVMVFSVOL)pvThis;
1013 LogFlow(("rtDvmVfsVol_Close(%p)\n", pThis));
1014
1015 if ( pThis->fCloseDvm
1016 && pThis->hVolMgr != NIL_RTDVM )
1017 RTDvmRelease(pThis->hVolMgr);
1018 pThis->hVolMgr = NIL_RTDVM;
1019
1020 return VINF_SUCCESS;
1021}
1022
1023
1024/**
1025 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
1026 */
1027static DECLCALLBACK(int) rtDvmVfsVol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1028{
1029 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
1030 return VERR_WRONG_TYPE;
1031}
1032
1033
1034/**
1035 * @interface_method_impl{RTVFSOPS,pfnOpenRoot}
1036 */
1037static DECLCALLBACK(int) rtDvmVfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
1038{
1039 PRTDVMVFSVOL pThis = (PRTDVMVFSVOL)pvThis;
1040
1041 PRTDVMVFSDIR pNewDir;
1042 int rc = RTVfsNewDir(&g_rtDvmVfsDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf,
1043 NIL_RTVFSLOCK /*use volume lock*/, phVfsDir, (void **)&pNewDir);
1044 if (RT_SUCCESS(rc))
1045 {
1046 pNewDir->offDir = 0;
1047 pNewDir->pVfsVol = pThis;
1048 pNewDir->fReturnCurrent = false;
1049 pNewDir->hCurVolume = NIL_RTDVMVOLUME;
1050 }
1051 return rc;
1052}
1053
1054
1055/**
1056 * @interface_method_impl{RTVFSOPS,pfnQueryRangeState}
1057 */
1058static DECLCALLBACK(int) rtDvmVfsVol_QueryRangeState(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)
1059{
1060 RT_NOREF(pvThis, off, cb, pfUsed);
1061 return VERR_NOT_IMPLEMENTED;
1062}
1063
1064
1065DECL_HIDDEN_CONST(const RTVFSOPS) g_rtDvmVfsVolOps =
1066{
1067 { /* Obj */
1068 RTVFSOBJOPS_VERSION,
1069 RTVFSOBJTYPE_VFS,
1070 "DvmVol",
1071 rtDvmVfsVol_Close,
1072 rtDvmVfsVol_QueryInfo,
1073 RTVFSOBJOPS_VERSION
1074 },
1075 RTVFSOPS_VERSION,
1076 0 /* fFeatures */,
1077 rtDvmVfsVol_OpenRoot,
1078 rtDvmVfsVol_QueryRangeState,
1079 RTVFSOPS_VERSION
1080};
1081
1082
1083
1084/**
1085 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
1086 */
1087static DECLCALLBACK(int) rtDvmVfsChain_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
1088 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
1089{
1090 RT_NOREF(pProviderReg, pSpec);
1091
1092 /*
1093 * Basic checks.
1094 */
1095 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
1096 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
1097 if (pElement->enmType != RTVFSOBJTYPE_VFS)
1098 return VERR_VFS_CHAIN_ONLY_VFS;
1099
1100 if (pElement->cArgs > 1)
1101 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
1102
1103 /*
1104 * Parse the flag if present, save in pElement->uProvider.
1105 */
1106 /** @todo allow specifying sector size */
1107 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
1108 if (pElement->cArgs > 0)
1109 {
1110 const char *psz = pElement->paArgs[0].psz;
1111 if (*psz)
1112 {
1113 if ( !strcmp(psz, "ro")
1114 || !strcmp(psz, "r"))
1115 fReadOnly = true;
1116 else if (!strcmp(psz, "rw"))
1117 fReadOnly = false;
1118 else
1119 {
1120 *poffError = pElement->paArgs[0].offSpec;
1121 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
1122 }
1123 }
1124 }
1125
1126 pElement->uProvider = fReadOnly;
1127 return VINF_SUCCESS;
1128}
1129
1130
1131/**
1132 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
1133 */
1134static DECLCALLBACK(int) rtDvmVfsChain_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
1135 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
1136 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
1137{
1138 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
1139 AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
1140
1141 /*
1142 * Instantiate the volume manager and open the map stuff.
1143 */
1144 RTVFSFILE hPrevVfsFile = RTVfsObjToFile(hPrevVfsObj);
1145 AssertReturn(hPrevVfsFile != NIL_RTVFSFILE, VERR_VFS_CHAIN_CAST_FAILED);
1146
1147 RTDVM hVolMgr;
1148 int rc = RTDvmCreate(&hVolMgr, hPrevVfsFile, 512, 0 /*fFlags*/);
1149 RTVfsFileRelease(hPrevVfsFile);
1150 if (RT_SUCCESS(rc))
1151 {
1152 rc = RTDvmMapOpen(hVolMgr);
1153 if (RT_SUCCESS(rc))
1154 {
1155 /*
1156 * Create a VFS instance for the volume manager.
1157 */
1158 RTVFS hVfs = NIL_RTVFS;
1159 PRTDVMVFSVOL pThis = NULL;
1160 rc = RTVfsNew(&g_rtDvmVfsVolOps, sizeof(RTDVMVFSVOL), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
1161 if (RT_SUCCESS(rc))
1162 {
1163 pThis->hVolMgr = hVolMgr;
1164 pThis->fCloseDvm = true;
1165 pThis->fReadOnly = pElement->uProvider == (uint64_t)true;
1166 pThis->cVolumes = RTDvmMapGetValidVolumes(hVolMgr);
1167 pThis->hVfsSelf = hVfs;
1168
1169 *phVfsObj = RTVfsObjFromVfs(hVfs);
1170 RTVfsRelease(hVfs);
1171 return *phVfsObj != NIL_RTVFSOBJ ? VINF_SUCCESS : VERR_VFS_CHAIN_CAST_FAILED;
1172 }
1173 }
1174 else
1175 rc = RTErrInfoSetF(pErrInfo, rc, "RTDvmMapOpen failed: %Rrc", rc);
1176 RTDvmRelease(hVolMgr);
1177 }
1178 else
1179 rc = RTErrInfoSetF(pErrInfo, rc, "RTDvmCreate failed: %Rrc", rc);
1180 return rc;
1181}
1182
1183
1184/**
1185 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
1186 */
1187static DECLCALLBACK(bool) rtDvmVfsChain_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
1188 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
1189 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
1190{
1191 RT_NOREF(pProviderReg, pSpec, pElement, pReuseSpec, pReuseElement);
1192 return false;
1193}
1194
1195
1196/** VFS chain element 'file'. */
1197static RTVFSCHAINELEMENTREG g_rtVfsChainIsoFsVolReg =
1198{
1199 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
1200 /* fReserved = */ 0,
1201 /* pszName = */ "dvm",
1202 /* ListEntry = */ { NULL, NULL },
1203 /* pszHelp = */ "Opens a container image using the VD API.\n"
1204 "Optionally takes one parameter 'ro' (read only) or 'rw' (read write).\n",
1205 /* pfnValidate = */ rtDvmVfsChain_Validate,
1206 /* pfnInstantiate = */ rtDvmVfsChain_Instantiate,
1207 /* pfnCanReuseElement = */ rtDvmVfsChain_CanReuseElement,
1208 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
1209};
1210
1211RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainIsoFsVolReg, rtVfsChainIsoFsVolReg);
1212
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