VirtualBox

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

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

IPRT: VFS opening reworking in progress.

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