VirtualBox

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

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

IPRT/VFS: Reimplemented RTVfsDirOpen and RTVfsDirOpenDir to use pfnOpen, making pfnOpenDir optional. Fixed a couple of problems related to '.' and '..' handling in pfnQueryEntryInfo and pfnOpen implementations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: dvmvfs.cpp 69828 2017-11-24 17:32:23Z 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, (uint64_t)off, 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, (uint64_t)off, 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,pfnPollOne}
327 */
328static DECLCALLBACK(int) rtDvmVfsFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
329 uint32_t *pfRetEvents)
330{
331 NOREF(pvThis);
332 int rc;
333 if (fEvents != RTPOLL_EVT_ERROR)
334 {
335 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
336 rc = VINF_SUCCESS;
337 }
338 else
339 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
340 return rc;
341}
342
343
344/**
345 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
346 */
347static DECLCALLBACK(int) rtDvmVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
348{
349 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
350 *poffActual = pThis->offCurPos;
351 return VINF_SUCCESS;
352}
353
354
355/**
356 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
357 */
358static DECLCALLBACK(int) rtDvmVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
359{
360 NOREF(pvThis);
361 NOREF(fMode);
362 NOREF(fMask);
363 return VERR_NOT_SUPPORTED;
364}
365
366
367/**
368 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
369 */
370static DECLCALLBACK(int) rtDvmVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
371 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
372{
373 NOREF(pvThis);
374 NOREF(pAccessTime);
375 NOREF(pModificationTime);
376 NOREF(pChangeTime);
377 NOREF(pBirthTime);
378 return VERR_NOT_SUPPORTED;
379}
380
381
382/**
383 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
384 */
385static DECLCALLBACK(int) rtDvmVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
386{
387 NOREF(pvThis);
388 NOREF(uid);
389 NOREF(gid);
390 return VERR_NOT_SUPPORTED;
391}
392
393
394/**
395 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
396 */
397static DECLCALLBACK(int) rtDvmVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
398{
399 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
400
401 /*
402 * Seek relative to which position.
403 */
404 uint64_t offWrt;
405 switch (uMethod)
406 {
407 case RTFILE_SEEK_BEGIN:
408 offWrt = 0;
409 break;
410
411 case RTFILE_SEEK_CURRENT:
412 offWrt = pThis->offCurPos;
413 break;
414
415 case RTFILE_SEEK_END:
416 offWrt = RTDvmVolumeGetSize(pThis->hVol);
417 break;
418
419 default:
420 return VERR_INTERNAL_ERROR_5;
421 }
422
423 /*
424 * Calc new position, take care to stay within bounds.
425 *
426 * @todo: Setting position beyond the end of the volume does not make sense.
427 */
428 uint64_t offNew;
429 if (offSeek == 0)
430 offNew = offWrt;
431 else if (offSeek > 0)
432 {
433 offNew = offWrt + offSeek;
434 if ( offNew < offWrt
435 || offNew > RTFOFF_MAX)
436 offNew = RTFOFF_MAX;
437 }
438 else if ((uint64_t)-offSeek < offWrt)
439 offNew = offWrt + offSeek;
440 else
441 offNew = 0;
442
443 /*
444 * Update the state and set return value.
445 */
446 pThis->offCurPos = offNew;
447
448 *poffActual = offNew;
449 return VINF_SUCCESS;
450}
451
452
453/**
454 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
455 */
456static DECLCALLBACK(int) rtDvmVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
457{
458 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
459 *pcbFile = RTDvmVolumeGetSize(pThis->hVol);
460 return VINF_SUCCESS;
461}
462
463
464/**
465 * Standard file operations.
466 */
467DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtDvmVfsStdFileOps =
468{
469 { /* Stream */
470 { /* Obj */
471 RTVFSOBJOPS_VERSION,
472 RTVFSOBJTYPE_FILE,
473 "DvmFile",
474 rtDvmVfsFile_Close,
475 rtDvmVfsFile_QueryInfo,
476 RTVFSOBJOPS_VERSION
477 },
478 RTVFSIOSTREAMOPS_VERSION,
479 RTVFSIOSTREAMOPS_FEAT_NO_SG,
480 rtDvmVfsFile_Read,
481 rtDvmVfsFile_Write,
482 rtDvmVfsFile_Flush,
483 rtDvmVfsFile_PollOne,
484 rtDvmVfsFile_Tell,
485 NULL /*Skip*/,
486 NULL /*ZeroFill*/,
487 RTVFSIOSTREAMOPS_VERSION,
488 },
489 RTVFSFILEOPS_VERSION,
490 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
491 { /* ObjSet */
492 RTVFSOBJSETOPS_VERSION,
493 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
494 rtDvmVfsFile_SetMode,
495 rtDvmVfsFile_SetTimes,
496 rtDvmVfsFile_SetOwner,
497 RTVFSOBJSETOPS_VERSION
498 },
499 rtDvmVfsFile_Seek,
500 rtDvmVfsFile_QuerySize,
501 RTVFSFILEOPS_VERSION
502};
503
504
505/**
506 * Internal worker for RTDvmVolumeCreateVfsFile and rtDvmVfsDir_OpenFile.
507 *
508 * @returns IPRT status code.
509 * @param pVfsVol The VFS volume, optional.
510 * @param hVol The volume handle. (Reference not consumed.)
511 * @param fOpen RTFILE_O_XXX (valid).
512 * @param phVfsFileOut Where to return the handle to the file.
513 */
514static int rtDvmVfsCreateFileForVolume(PRTDVMVFSVOL pVfsVol, RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut)
515{
516 uint32_t cRefs = RTDvmVolumeRetain(hVol);
517 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
518
519 /*
520 * Create the volume file.
521 */
522 RTVFSFILE hVfsFile;
523 PRTVFSDVMFILE pThis;
524 int rc = RTVfsNewFile(&g_rtDvmVfsStdFileOps, sizeof(*pThis), fOpen, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
525 if (RT_SUCCESS(rc))
526 {
527 pThis->offCurPos = 0;
528 pThis->hVol = hVol;
529 pThis->fCanRead = RT_BOOL(fOpen & RTFILE_O_READ);
530 pThis->fCanWrite = RT_BOOL(fOpen & RTFILE_O_WRITE);
531 pThis->pVfsVol = pVfsVol;
532
533 *phVfsFileOut = hVfsFile;
534 return VINF_SUCCESS;
535 }
536
537 RTDvmVolumeRelease(hVol);
538 return rc;
539}
540
541
542RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, uint64_t fOpen, PRTVFSFILE phVfsFileOut)
543{
544 AssertPtrReturn(hVol, VERR_INVALID_HANDLE);
545 AssertPtrReturn(phVfsFileOut, VERR_INVALID_POINTER);
546 AssertReturn(fOpen & RTFILE_O_ACCESS_MASK, VERR_INVALID_FLAGS);
547 AssertReturn(!(fOpen & ~RTFILE_O_VALID_MASK), VERR_INVALID_FLAGS);
548 return rtDvmVfsCreateFileForVolume(NULL, hVol, fOpen, phVfsFileOut);
549}
550
551
552/**
553 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
554 */
555static DECLCALLBACK(int) rtDvmVfsDir_Close(void *pvThis)
556{
557 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
558
559 if (pThis->hCurVolume != NIL_RTDVMVOLUME)
560 {
561 RTDvmVolumeRelease(pThis->hCurVolume);
562 pThis->hCurVolume = NIL_RTDVMVOLUME;
563 }
564
565 pThis->pVfsVol = NULL;
566
567 return VINF_SUCCESS;
568}
569
570
571/**
572 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
573 */
574static DECLCALLBACK(int) rtDvmVfsDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
575{
576 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
577 pObjInfo->cbObject = pThis->pVfsVol->cVolumes;
578 pObjInfo->cbAllocated = pThis->pVfsVol->cVolumes;
579 RTTimeSpecSetNano(&pObjInfo->AccessTime, 0);
580 RTTimeSpecSetNano(&pObjInfo->ModificationTime, 0);
581 RTTimeSpecSetNano(&pObjInfo->ChangeTime, 0);
582 RTTimeSpecSetNano(&pObjInfo->BirthTime, 0);
583 pObjInfo->Attr.fMode = RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY;
584 if (pThis->pVfsVol->fReadOnly)
585 pObjInfo->Attr.fMode |= RTFS_DOS_READONLY | 0555;
586 else
587 pObjInfo->Attr.fMode |= 0777;
588
589 switch (enmAddAttr)
590 {
591 case RTFSOBJATTRADD_NOTHING:
592 case RTFSOBJATTRADD_UNIX:
593 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
594 pObjInfo->Attr.u.Unix.gid = (RTGID)RTDvmMapGetFormatType(pThis->pVfsVol->hVolMgr);
595 pObjInfo->Attr.u.Unix.cHardlinks = pThis->pVfsVol->cVolumes;
596 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
597 pObjInfo->Attr.u.Unix.INodeId = 0;
598 pObjInfo->Attr.u.Unix.fFlags = 0;
599 pObjInfo->Attr.u.Unix.GenerationId = 0;
600 pObjInfo->Attr.u.Unix.Device = 0;
601 break;
602
603 case RTFSOBJATTRADD_UNIX_OWNER:
604 pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
605 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
606 break;
607
608 case RTFSOBJATTRADD_UNIX_GROUP:
609 pObjInfo->Attr.u.UnixGroup.gid = (RTGID)RTDvmMapGetFormatType(pThis->pVfsVol->hVolMgr);
610 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),
611 RTDvmMapGetFormatName(pThis->pVfsVol->hVolMgr));
612 break;
613
614 case RTFSOBJATTRADD_EASIZE:
615 pObjInfo->Attr.u.EASize.cb = 0;
616 break;
617
618 default:
619 return VERR_INVALID_PARAMETER;
620 }
621 return VINF_SUCCESS;
622}
623
624
625/**
626 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
627 */
628static DECLCALLBACK(int) rtDvmVfsDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
629{
630 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
631 return VERR_NOT_SUPPORTED;
632}
633
634
635/**
636 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
637 */
638static DECLCALLBACK(int) rtDvmVfsDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
639 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
640{
641 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
642 return VERR_NOT_SUPPORTED;
643}
644
645
646/**
647 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
648 */
649static DECLCALLBACK(int) rtDvmVfsDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
650{
651 RT_NOREF(pvThis, uid, gid);
652 return VERR_NOT_SUPPORTED;
653}
654
655
656static int rtDvmVfsDir_FindEntry(PRTDVMVFSDIR pThis, const char *pszEntry, PRTDVMVOLUME phVolume)
657{
658 /*
659 * Enumerate the volumes and try match the volume name.
660 */
661 int rc;
662 PRTDVMVFSVOL pVfsVol = pThis->pVfsVol;
663 if (pVfsVol->cVolumes > 0)
664 {
665 /* The first volume. */
666 uint32_t iVol = 0;
667 RTDVMVOLUME hVol;
668 rc = RTDvmMapQueryFirstVolume(pThis->pVfsVol->hVolMgr, &hVol);
669 while (RT_SUCCESS(rc))
670 {
671 /* Match the name. */
672 bool fMatch;
673 char *pszVolName;
674 rc = RTDvmVolumeQueryName(hVol, &pszVolName);
675 if (RT_SUCCESS(rc))
676 {
677 fMatch = RTStrCmp(pszEntry, pszVolName) == 0 && *pszVolName != '\0';
678 RTStrFree(pszVolName);
679 }
680 else if (rc == VERR_NOT_SUPPORTED)
681 fMatch = false;
682 else
683 {
684 RTDvmVolumeRelease(hVol);
685 break;
686 }
687
688 /* Match the sequential volume number. */
689 if (!fMatch)
690 {
691 char szTmp[16];
692 RTStrPrintf(szTmp, sizeof(szTmp), "vol%u", iVol);
693 fMatch = RTStrCmp(pszEntry, szTmp) == 0;
694 }
695
696 if (fMatch)
697 {
698 *phVolume = hVol;
699 return VINF_SUCCESS;
700 }
701
702 /* More volumes? */
703 iVol++;
704 if (iVol >= pVfsVol->cVolumes)
705 {
706 RTDvmVolumeRelease(hVol);
707 rc = VERR_FILE_NOT_FOUND;
708 break;
709 }
710
711 /* Get the next volume. */
712 RTDVMVOLUME hVolNext;
713 rc = RTDvmMapQueryNextVolume(pThis->pVfsVol->hVolMgr, hVol, &hVolNext);
714 RTDvmVolumeRelease(hVol);
715 hVol = hVolNext;
716 }
717 }
718 else
719 rc = VERR_FILE_NOT_FOUND;
720 return rc;
721}
722
723
724/**
725 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
726 */
727static DECLCALLBACK(int) rtDvmVfsDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen, uint32_t fFlags, PRTVFSOBJ phVfsObj)
728{
729 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
730
731 /*
732 * Special case: '.' and '..'
733 */
734 if ( pszEntry[0] == '.'
735 && ( pszEntry[1] == '\0'
736 || ( pszEntry[1] == '.'
737 && pszEntry[2] == '\0')))
738 {
739 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
740 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
741 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
742 {
743 if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
744 {
745 RTVFSDIR hVfsDir;
746 int rc = rtDvmVfsVol_OpenRoot(pThis->pVfsVol, &hVfsDir);
747 if (RT_SUCCESS(rc))
748 {
749 *phVfsObj = RTVfsObjFromDir(hVfsDir);
750 RTVfsDirRelease(hVfsDir);
751 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
752 }
753 return rc;
754 }
755 return VERR_IS_A_DIRECTORY;
756 }
757 return VERR_ACCESS_DENIED;
758 }
759
760 /*
761 * Open volume file.
762 */
763 RTDVMVOLUME hVolume;
764 int rc = rtDvmVfsDir_FindEntry(pThis, pszEntry, &hVolume);
765 if (RT_SUCCESS(rc))
766 {
767 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
768 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
769 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
770 {
771 if (fFlags & (RTVFSOBJ_F_OPEN_FILE | RTVFSOBJ_F_OPEN_DEV_BLOCK))
772 {
773 if ( !(fOpen & RTFILE_O_WRITE)
774 || !pThis->pVfsVol->fReadOnly)
775 {
776 RTVFSFILE hVfsFile;
777 rc = rtDvmVfsCreateFileForVolume(pThis->pVfsVol, hVolume, fOpen, &hVfsFile);
778 if (RT_SUCCESS(rc))
779 {
780 *phVfsObj = RTVfsObjFromFile(hVfsFile);
781 RTVfsFileRelease(hVfsFile);
782 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
783 }
784 }
785 else
786 rc = VERR_WRITE_PROTECT;
787 }
788 else
789 rc = VERR_IS_A_FILE;
790 }
791 else
792 rc = VERR_ALREADY_EXISTS;
793 RTDvmVolumeRelease(hVolume);
794 }
795 return rc;
796}
797
798
799/**
800 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
801 */
802static DECLCALLBACK(int) rtDvmVfsDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
803{
804 RTVFSOBJ hVfsObj;
805 int rc = rtDvmVfsDir_Open(pvThis, pszFilename, fOpen, RTVFSOBJ_F_OPEN_FILE, &hVfsObj);
806 if (RT_SUCCESS(rc))
807 {
808 *phVfsFile = RTVfsObjToFile(hVfsObj);
809 RTVfsObjRelease(hVfsObj);
810 }
811 return rc;
812}
813
814
815/**
816 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
817 */
818static DECLCALLBACK(int) rtDvmVfsDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
819{
820 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
821 return VERR_NOT_SUPPORTED;
822}
823
824
825/**
826 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
827 */
828static DECLCALLBACK(int) rtDvmVfsDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
829{
830 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
831 return VERR_NOT_SUPPORTED;
832}
833
834
835/**
836 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
837 */
838static DECLCALLBACK(int) rtDvmVfsDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
839 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
840{
841 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
842 return VERR_NOT_SUPPORTED;
843}
844
845
846/**
847 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
848 */
849static DECLCALLBACK(int) rtDvmVfsDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
850{
851 RT_NOREF(pvThis, pszEntry, fType);
852 return VERR_NOT_IMPLEMENTED;
853}
854
855
856/**
857 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
858 */
859static DECLCALLBACK(int) rtDvmVfsDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
860{
861 RT_NOREF(pvThis, pszEntry, fType, pszNewName);
862 return VERR_NOT_IMPLEMENTED;
863}
864
865
866/**
867 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
868 */
869static DECLCALLBACK(int) rtDvmVfsDir_RewindDir(void *pvThis)
870{
871 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
872
873 if (pThis->hCurVolume != NIL_RTDVMVOLUME)
874 {
875 RTDvmVolumeRelease(pThis->hCurVolume);
876 pThis->hCurVolume = NIL_RTDVMVOLUME;
877 }
878 pThis->fReturnCurrent = false;
879 pThis->offDir = 0;
880
881 return VINF_SUCCESS;
882}
883
884
885/**
886 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
887 */
888static DECLCALLBACK(int) rtDvmVfsDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
889 RTFSOBJATTRADD enmAddAttr)
890{
891 PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
892 PRTDVMVFSVOL pVfsVol = pThis->pVfsVol;
893 int rc;
894
895 /*
896 * Get the volume to return info about.
897 */
898 if (!pThis->fReturnCurrent)
899 {
900 if (pThis->offDir < pVfsVol->cVolumes)
901 {
902 RTDVMVOLUME hNextVolume;
903 if (pThis->offDir == 0)
904 rc = RTDvmMapQueryFirstVolume(pVfsVol->hVolMgr, &hNextVolume);
905 else
906 rc = RTDvmMapQueryNextVolume(pVfsVol->hVolMgr, pThis->hCurVolume, &hNextVolume);
907 if (RT_FAILURE(rc))
908 return rc;
909 RTDvmVolumeRelease(pThis->hCurVolume);
910 pThis->hCurVolume = hNextVolume;
911 }
912 else
913 {
914 RTDvmVolumeRelease(pThis->hCurVolume);
915 pThis->hCurVolume = NIL_RTDVMVOLUME;
916 return VERR_NO_MORE_FILES;
917 }
918 }
919
920 /*
921 * Figure out the name length.
922 */
923 char szVolNo[16];
924 RTStrPrintf(szVolNo, sizeof(szVolNo), "vol%u", pThis->offDir);
925
926 char *pszVolName;
927 rc = RTDvmVolumeQueryName(pThis->hCurVolume, &pszVolName);
928 if ( RT_SUCCESS(rc)
929 || rc == VERR_NOT_SUPPORTED)
930 {
931 if (rc == VERR_NOT_SUPPORTED)
932 pszVolName = szVolNo;
933 else if (*pszVolName == '\0')
934 {
935 RTStrFree(pszVolName);
936 pszVolName = szVolNo;
937 }
938
939 size_t cchVolName = strlen(pszVolName);
940 size_t cbNeeded = RT_OFFSETOF(RTDIRENTRYEX, szName[cchVolName + 1]);
941 if (cbNeeded <= *pcbDirEntry)
942 {
943 *pcbDirEntry = cbNeeded;
944
945 /* Do the names. */
946 pDirEntry->cbName = (uint16_t)cchVolName;
947 memcpy(pDirEntry->szName, pszVolName, cchVolName + 1);
948 if (pszVolName != szVolNo)
949 {
950 RTStrFree(pszVolName);
951
952 PRTUTF16 pwszShortName = pDirEntry->wszShortName;
953 size_t cwcShortName = 0;
954 rc = RTStrToUtf16Ex(szVolNo, RTSTR_MAX, &pwszShortName, RT_ELEMENTS(pDirEntry->wszShortName), &cwcShortName);
955 AssertRC(rc);
956 pDirEntry->cwcShortName = (uint16_t)cwcShortName;
957 }
958 else
959 {
960 pDirEntry->cwcShortName = 0;
961 pDirEntry->wszShortName[0] = '\0';
962 }
963
964 /* Do the rest. */
965 rc = rtDvmVfsFile_QueryInfoWorker(pThis->hCurVolume, pVfsVol->hVolMgr, pVfsVol->fReadOnly,
966 &pDirEntry->Info, enmAddAttr);
967 pThis->fReturnCurrent = !RT_SUCCESS(rc);
968 pThis->offDir += RT_SUCCESS(rc);
969 return rc;
970 }
971
972 *pcbDirEntry = cbNeeded;
973 rc = VERR_BUFFER_OVERFLOW;
974
975 if (pszVolName != szVolNo)
976 RTStrFree(pszVolName);
977 }
978
979 pThis->fReturnCurrent = true;
980 return rc;
981}
982
983
984/**
985 * DVM (root) directory operations.
986 */
987static const RTVFSDIROPS g_rtDvmVfsDirOps =
988{
989 { /* Obj */
990 RTVFSOBJOPS_VERSION,
991 RTVFSOBJTYPE_DIR,
992 "DvmDir",
993 rtDvmVfsDir_Close,
994 rtDvmVfsDir_QueryInfo,
995 RTVFSOBJOPS_VERSION
996 },
997 RTVFSDIROPS_VERSION,
998 0,
999 { /* ObjSet */
1000 RTVFSOBJSETOPS_VERSION,
1001 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
1002 rtDvmVfsDir_SetMode,
1003 rtDvmVfsDir_SetTimes,
1004 rtDvmVfsDir_SetOwner,
1005 RTVFSOBJSETOPS_VERSION
1006 },
1007 rtDvmVfsDir_Open,
1008 NULL /* pfnFollowAbsoluteSymlink */,
1009 rtDvmVfsDir_OpenFile,
1010 NULL /* pfnOpenDir */,
1011 rtDvmVfsDir_CreateDir,
1012 rtDvmVfsDir_OpenSymlink,
1013 rtDvmVfsDir_CreateSymlink,
1014 NULL /* pfnQueryEntryInfo */,
1015 rtDvmVfsDir_UnlinkEntry,
1016 rtDvmVfsDir_RenameEntry,
1017 rtDvmVfsDir_RewindDir,
1018 rtDvmVfsDir_ReadDir,
1019 RTVFSDIROPS_VERSION,
1020};
1021
1022
1023
1024/**
1025 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
1026 */
1027static DECLCALLBACK(int) rtDvmVfsVol_Close(void *pvThis)
1028{
1029 PRTDVMVFSVOL pThis = (PRTDVMVFSVOL)pvThis;
1030 LogFlow(("rtDvmVfsVol_Close(%p)\n", pThis));
1031
1032 if ( pThis->fCloseDvm
1033 && pThis->hVolMgr != NIL_RTDVM )
1034 RTDvmRelease(pThis->hVolMgr);
1035 pThis->hVolMgr = NIL_RTDVM;
1036
1037 return VINF_SUCCESS;
1038}
1039
1040
1041/**
1042 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
1043 */
1044static DECLCALLBACK(int) rtDvmVfsVol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1045{
1046 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
1047 return VERR_WRONG_TYPE;
1048}
1049
1050
1051/**
1052 * @interface_method_impl{RTVFSOPS,pfnOpenRoot}
1053 */
1054static DECLCALLBACK(int) rtDvmVfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
1055{
1056 PRTDVMVFSVOL pThis = (PRTDVMVFSVOL)pvThis;
1057
1058 PRTDVMVFSDIR pNewDir;
1059 int rc = RTVfsNewDir(&g_rtDvmVfsDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf,
1060 NIL_RTVFSLOCK /*use volume lock*/, phVfsDir, (void **)&pNewDir);
1061 if (RT_SUCCESS(rc))
1062 {
1063 pNewDir->offDir = 0;
1064 pNewDir->pVfsVol = pThis;
1065 pNewDir->fReturnCurrent = false;
1066 pNewDir->hCurVolume = NIL_RTDVMVOLUME;
1067 }
1068 return rc;
1069}
1070
1071
1072/**
1073 * @interface_method_impl{RTVFSOPS,pfnIsRangeInUse}
1074 */
1075static DECLCALLBACK(int) rtDvmVfsVol_IsRangeInUse(void *pvThis, RTFOFF off, size_t cb, bool *pfUsed)
1076{
1077 RT_NOREF(pvThis, off, cb, pfUsed);
1078 return VERR_NOT_IMPLEMENTED;
1079}
1080
1081
1082DECL_HIDDEN_CONST(const RTVFSOPS) g_rtDvmVfsVolOps =
1083{
1084 { /* Obj */
1085 RTVFSOBJOPS_VERSION,
1086 RTVFSOBJTYPE_VFS,
1087 "DvmVol",
1088 rtDvmVfsVol_Close,
1089 rtDvmVfsVol_QueryInfo,
1090 RTVFSOBJOPS_VERSION
1091 },
1092 RTVFSOPS_VERSION,
1093 0 /* fFeatures */,
1094 rtDvmVfsVol_OpenRoot,
1095 rtDvmVfsVol_IsRangeInUse,
1096 RTVFSOPS_VERSION
1097};
1098
1099
1100
1101/**
1102 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
1103 */
1104static DECLCALLBACK(int) rtDvmVfsChain_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
1105 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
1106{
1107 RT_NOREF(pProviderReg, pSpec);
1108
1109 /*
1110 * Basic checks.
1111 */
1112 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
1113 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
1114 if (pElement->enmType != RTVFSOBJTYPE_VFS)
1115 return VERR_VFS_CHAIN_ONLY_VFS;
1116
1117 if (pElement->cArgs > 1)
1118 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
1119
1120 /*
1121 * Parse the flag if present, save in pElement->uProvider.
1122 */
1123 /** @todo allow specifying sector size */
1124 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
1125 if (pElement->cArgs > 0)
1126 {
1127 const char *psz = pElement->paArgs[0].psz;
1128 if (*psz)
1129 {
1130 if ( !strcmp(psz, "ro")
1131 || !strcmp(psz, "r"))
1132 fReadOnly = true;
1133 else if (!strcmp(psz, "rw"))
1134 fReadOnly = false;
1135 else
1136 {
1137 *poffError = pElement->paArgs[0].offSpec;
1138 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
1139 }
1140 }
1141 }
1142
1143 pElement->uProvider = fReadOnly;
1144 return VINF_SUCCESS;
1145}
1146
1147
1148/**
1149 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
1150 */
1151static DECLCALLBACK(int) rtDvmVfsChain_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
1152 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
1153 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
1154{
1155 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
1156 AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
1157
1158 /*
1159 * Instantiate the volume manager and open the map stuff.
1160 */
1161 RTVFSFILE hPrevVfsFile = RTVfsObjToFile(hPrevVfsObj);
1162 AssertReturn(hPrevVfsFile != NIL_RTVFSFILE, VERR_VFS_CHAIN_CAST_FAILED);
1163
1164 RTDVM hVolMgr;
1165 int rc = RTDvmCreate(&hVolMgr, hPrevVfsFile, 512, 0 /*fFlags*/);
1166 RTVfsFileRelease(hPrevVfsFile);
1167 if (RT_SUCCESS(rc))
1168 {
1169 rc = RTDvmMapOpen(hVolMgr);
1170 if (RT_SUCCESS(rc))
1171 {
1172 /*
1173 * Create a VFS instance for the volume manager.
1174 */
1175 RTVFS hVfs = NIL_RTVFS;
1176 PRTDVMVFSVOL pThis = NULL;
1177 rc = RTVfsNew(&g_rtDvmVfsVolOps, sizeof(RTDVMVFSVOL), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
1178 if (RT_SUCCESS(rc))
1179 {
1180 pThis->hVolMgr = hVolMgr;
1181 pThis->fCloseDvm = true;
1182 pThis->fReadOnly = pElement->uProvider == (uint64_t)true;
1183 pThis->cVolumes = RTDvmMapGetValidVolumes(hVolMgr);
1184 pThis->hVfsSelf = hVfs;
1185
1186 *phVfsObj = RTVfsObjFromVfs(hVfs);
1187 RTVfsRelease(hVfs);
1188 return *phVfsObj != NIL_RTVFSOBJ ? VINF_SUCCESS : VERR_VFS_CHAIN_CAST_FAILED;
1189 }
1190 }
1191 else
1192 rc = RTErrInfoSetF(pErrInfo, rc, "RTDvmMapOpen failed: %Rrc", rc);
1193 RTDvmRelease(hVolMgr);
1194 }
1195 else
1196 rc = RTErrInfoSetF(pErrInfo, rc, "RTDvmCreate failed: %Rrc", rc);
1197 return rc;
1198}
1199
1200
1201/**
1202 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
1203 */
1204static DECLCALLBACK(bool) rtDvmVfsChain_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
1205 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
1206 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
1207{
1208 RT_NOREF(pProviderReg, pSpec, pElement, pReuseSpec, pReuseElement);
1209 return false;
1210}
1211
1212
1213/** VFS chain element 'file'. */
1214static RTVFSCHAINELEMENTREG g_rtVfsChainIsoFsVolReg =
1215{
1216 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
1217 /* fReserved = */ 0,
1218 /* pszName = */ "dvm",
1219 /* ListEntry = */ { NULL, NULL },
1220 /* pszHelp = */ "Opens a container image using the VD API.\n"
1221 "Optionally takes one parameter 'ro' (read only) or 'rw' (read write).\n",
1222 /* pfnValidate = */ rtDvmVfsChain_Validate,
1223 /* pfnInstantiate = */ rtDvmVfsChain_Instantiate,
1224 /* pfnCanReuseElement = */ rtDvmVfsChain_CanReuseElement,
1225 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
1226};
1227
1228RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainIsoFsVolReg, rtVfsChainIsoFsVolReg);
1229
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