VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp@ 66602

Last change on this file since 66602 was 66602, checked in by vboxsync, 8 years ago

IPRT/vfs-chains: Pass around an pErrInfo buffer too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.5 KB
Line 
1/* $Id: fatvfs.cpp 66602 2017-04-18 15:27:30Z vboxsync $ */
2/** @file
3 * IPRT - FAT Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32//#include <iprt/???.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/file.h>
38#include <iprt/err.h>
39#include <iprt/poll.h>
40#include <iprt/string.h>
41#include <iprt/thread.h>
42#include <iprt/vfs.h>
43#include <iprt/vfslowlevel.h>
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * A part of the cluster chain covering up to 252 clusters.
56 */
57typedef struct RTFSFATCHAINPART
58{
59 /** List entry. */
60 RTLISTNODE ListEntry;
61 /** Chain entries. */
62 uint32_t aEntries[256 - 4];
63} RTFSFATCHAINPART;
64AssertCompile(sizeof(RTFSFATCHAINPART) <= _1K);
65typedef RTFSFATCHAINPART *PRTFSFATCHAINPART;
66typedef RTFSFATCHAINPART const *PCRTFSFATCHAINPART;
67
68/**
69 * A FAT cluster chain.
70 */
71typedef struct RTFSFATCHAIN
72{
73 /** The chain size in bytes. */
74 uint32_t cbChain;
75 /** The chain size in entries. */
76 uint32_t cClusters;
77 /** List of chain parts (RTFSFATCHAINPART). */
78 RTLISTANCHOR ListParts;
79} RTFSFATCHAIN;
80typedef RTFSFATCHAIN *PRTFSFATCHAIN;
81
82/**
83 * FAT file system object (common part to files and dirs).
84 */
85typedef struct RTFSFATOBJ
86{
87 /** The byte offset of the directory entry.
88 * This is set to UINT64_MAX if special FAT12/16 root directory. */
89 uint64_t offDirEntry;
90 /** Attributes. */
91 RTFMODE fAttrib;
92 /** The object size. */
93 uint32_t cbObject;
94 /** The access time. */
95 RTTIMESPEC AccessTime;
96 /** The modificaton time. */
97 RTTIMESPEC ModificationTime;
98 /** The birth time. */
99 RTTIMESPEC BirthTime;
100 /** Cluster chain. */
101 RTFSFATCHAIN Clusters;
102 /** Pointer to the volume. */
103 struct RTFSFATVOL *pVol;
104} RTFSFATOBJ;
105
106typedef struct RTFSFATFILE
107{
108 /** Core FAT object info. */
109 RTFSFATOBJ Core;
110 /** The current file offset. */
111 uint32_t offFile;
112} RTFSFATFILE;
113typedef RTFSFATFILE *PRTFSFATFILE;
114
115/**
116 * FAT directory.
117 */
118typedef struct RTFSFATDIR
119{
120 /** Core FAT object info. */
121 RTFSFATOBJ Core;
122} RTFSFATDIR;
123typedef RTFSFATDIR *PRTFSFATDIR;
124
125
126/**
127 * FAT type (format).
128 */
129typedef enum RTFSFATTYPE
130{
131 RTFSFATTYPE_INVALID = 0,
132 RTFSFATTYPE_FAT12,
133 RTFSFATTYPE_FAT16,
134 RTFSFATTYPE_FAT32,
135 RTFSFATTYPE_END
136} RTFSFATTYPE;
137
138/**
139 * A FAT volume.
140 */
141typedef struct RTFSFATVOL
142{
143 /** Set if read-only mode. */
144 bool fReadOnly;
145
146 /** The cluster size in bytes. */
147 uint32_t cbCluster;
148 /** The number of data clusters. */
149 uint32_t cClusters;
150 /** The offset of the first cluster. */
151 uint64_t offFirstCluster;
152
153 /** The FAT type. */
154 RTFSFATTYPE enmFatType;
155 /** Number of FAT entries (clusters). */
156 uint32_t cFatEntries;
157 /** Number of FATs. */
158 uint32_t cFats;
159 /** FAT byte offsets. */
160 uint64_t aoffFats[8];
161
162 /** The root directory byte offset. */
163 uint64_t offRootDir;
164
165} RTFSFATVOL;
166
167
168/**
169 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
170 */
171static DECLCALLBACK(int) rtFsFatFile_Close(void *pvThis)
172{
173 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
174 RT_NOREF(pThis);
175 return VERR_NOT_IMPLEMENTED;
176}
177
178
179/**
180 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
181 */
182static DECLCALLBACK(int) rtFsFatObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
183{
184 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
185
186 pObjInfo->cbObject = pThis->Core.cbObject;
187 pObjInfo->cbAllocated = pThis->Core.Clusters.cClusters * pThis->Core.pVol->cbCluster;
188 pObjInfo->AccessTime = pThis->Core.AccessTime;
189 pObjInfo->ModificationTime = pThis->Core.ModificationTime;
190 pObjInfo->ChangeTime = pThis->Core.ModificationTime;
191 pObjInfo->BirthTime = pThis->Core.BirthTime;
192 pObjInfo->Attr.fMode = pThis->Core.fAttrib;
193 pObjInfo->Attr.enmAdditional = enmAddAttr;
194
195 switch (enmAddAttr)
196 {
197 case RTFSOBJATTRADD_NOTHING: /* fall thru */
198 case RTFSOBJATTRADD_UNIX:
199 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
200 pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
201 pObjInfo->Attr.u.Unix.cHardlinks = 1;
202 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
203 pObjInfo->Attr.u.Unix.INodeId = 0; /* Could probably use the directory entry offset. */
204 pObjInfo->Attr.u.Unix.fFlags = 0;
205 pObjInfo->Attr.u.Unix.GenerationId = 0;
206 pObjInfo->Attr.u.Unix.Device = 0;
207 break;
208 case RTFSOBJATTRADD_UNIX_OWNER:
209 pObjInfo->Attr.u.UnixOwner.uid = 0;
210 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
211 break;
212 case RTFSOBJATTRADD_UNIX_GROUP:
213 pObjInfo->Attr.u.UnixGroup.gid = 0;
214 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
215 break;
216 case RTFSOBJATTRADD_EASIZE:
217 pObjInfo->Attr.u.EASize.cb = 0;
218 break;
219 default:
220 return VERR_INVALID_PARAMETER;
221 }
222 return VINF_SUCCESS;
223}
224
225
226/**
227 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
228 */
229static DECLCALLBACK(int) rtFsFatFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
230{
231 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
232 RT_NOREF(pThis, off, pSgBuf, fBlocking, pcbRead);
233 return VERR_NOT_IMPLEMENTED;
234}
235
236
237/**
238 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
239 */
240static DECLCALLBACK(int) rtFsFatFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
241{
242 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
243 RT_NOREF(pThis, off, pSgBuf, fBlocking, pcbWritten);
244 return VERR_NOT_IMPLEMENTED;
245}
246
247
248/**
249 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
250 */
251static DECLCALLBACK(int) rtFsFatFile_Flush(void *pvThis)
252{
253 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
254 RT_NOREF(pThis);
255 return VERR_NOT_IMPLEMENTED;
256}
257
258
259/**
260 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
261 */
262static DECLCALLBACK(int) rtFsFatFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
263 uint32_t *pfRetEvents)
264{
265 NOREF(pvThis);
266 int rc;
267 if (fEvents != RTPOLL_EVT_ERROR)
268 {
269 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
270 rc = VINF_SUCCESS;
271 }
272 else if (fIntr)
273 rc = RTThreadSleep(cMillies);
274 else
275 {
276 uint64_t uMsStart = RTTimeMilliTS();
277 do
278 rc = RTThreadSleep(cMillies);
279 while ( rc == VERR_INTERRUPTED
280 && !fIntr
281 && RTTimeMilliTS() - uMsStart < cMillies);
282 if (rc == VERR_INTERRUPTED)
283 rc = VERR_TIMEOUT;
284 }
285 return rc;
286}
287
288
289/**
290 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
291 */
292static DECLCALLBACK(int) rtFsFatFile_Tell(void *pvThis, PRTFOFF poffActual)
293{
294 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
295 *poffActual = pThis->offFile;
296 return VINF_SUCCESS;
297}
298
299
300/**
301 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
302 */
303static DECLCALLBACK(int) rtFsFatObj_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
304{
305#if 0
306 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
307 if (fMask != ~RTFS_TYPE_MASK)
308 {
309 fMode |= ~fMask & ObjInfo.Attr.fMode;
310 }
311#else
312 RT_NOREF(pvThis, fMode, fMask);
313 return VERR_NOT_IMPLEMENTED;
314#endif
315}
316
317
318/**
319 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
320 */
321static DECLCALLBACK(int) rtFsFatObj_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
322 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
323{
324#if 0
325 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
326#else
327 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
328 return VERR_NOT_IMPLEMENTED;
329#endif
330}
331
332
333/**
334 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
335 */
336static DECLCALLBACK(int) rtFsFatObj_SetOwner(void *pvThis, RTUID uid, RTGID gid)
337{
338 RT_NOREF(pvThis, uid, gid);
339 return VERR_NOT_SUPPORTED;
340}
341
342
343/**
344 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
345 */
346static DECLCALLBACK(int) rtFsFatFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
347{
348 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
349 RTFOFF offNew;
350 switch (uMethod)
351 {
352 case RTFILE_SEEK_BEGIN:
353 offNew = offSeek;
354 break;
355 case RTFILE_SEEK_END:
356 offNew = (RTFOFF)pThis->Core.cbObject + offSeek;
357 break;
358 case RTFILE_SEEK_CURRENT:
359 offNew = (RTFOFF)pThis->offFile + offSeek;
360 break;
361 default:
362 return VERR_INVALID_PARAMETER;
363 }
364 if (offNew >= 0)
365 {
366 if (offNew <= _4G)
367 {
368 pThis->offFile = offNew;
369 *poffActual = offNew;
370 return VINF_SUCCESS;
371 }
372 return VERR_OUT_OF_RANGE;
373 }
374 return VERR_NEGATIVE_SEEK;
375}
376
377
378/**
379 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
380 */
381static DECLCALLBACK(int) rtFsFatFile_QuerySize(void *pvThis, uint64_t *pcbFile)
382{
383 PRTFSFATFILE pThis = (PRTFSFATFILE)pvThis;
384 *pcbFile = pThis->Core.cbObject;
385 return VINF_SUCCESS;
386}
387
388
389/**
390 * FAT file operations.
391 */
392DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtFsFatFileOps =
393{
394 { /* Stream */
395 { /* Obj */
396 RTVFSOBJOPS_VERSION,
397 RTVFSOBJTYPE_FILE,
398 "FatFile",
399 rtFsFatFile_Close,
400 rtFsFatObj_QueryInfo,
401 RTVFSOBJOPS_VERSION
402 },
403 RTVFSIOSTREAMOPS_VERSION,
404 0,
405 rtFsFatFile_Read,
406 rtFsFatFile_Write,
407 rtFsFatFile_Flush,
408 rtFsFatFile_PollOne,
409 rtFsFatFile_Tell,
410 NULL /*pfnSkip*/,
411 NULL /*pfnZeroFill*/,
412 RTVFSIOSTREAMOPS_VERSION,
413 },
414 RTVFSFILEOPS_VERSION,
415 0,
416 { /* ObjSet */
417 RTVFSOBJSETOPS_VERSION,
418 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
419 rtFsFatObj_SetMode,
420 rtFsFatObj_SetTimes,
421 rtFsFatObj_SetOwner,
422 RTVFSOBJSETOPS_VERSION
423 },
424 rtFsFatFile_Seek,
425 rtFsFatFile_QuerySize,
426 RTVFSFILEOPS_VERSION
427};
428
429
430/**
431 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
432 */
433static DECLCALLBACK(int) rtFsFatDir_Close(void *pvThis)
434{
435 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis;
436 RT_NOREF(pThis);
437 return VERR_NOT_IMPLEMENTED;
438}
439
440
441/**
442 * @interface_method_impl{RTVFSOBJOPS,pfnTraversalOpen}
443 */
444static DECLCALLBACK(int) rtFsFatDir_TraversalOpen(void *pvThis, const char *pszEntry, PRTVFSDIR phVfsDir,
445 PRTVFSSYMLINK phVfsSymlink, PRTVFS phVfsMounted)
446{
447 RT_NOREF(pvThis, pszEntry, phVfsDir, phVfsSymlink, phVfsMounted);
448 return VERR_NOT_IMPLEMENTED;
449}
450
451
452/**
453 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
454 */
455static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
456{
457 RT_NOREF(pvThis, pszFilename, fOpen, phVfsFile);
458 return VERR_NOT_IMPLEMENTED;
459}
460
461
462/**
463 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
464 */
465static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
466{
467 RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir);
468 return VERR_NOT_IMPLEMENTED;
469}
470
471
472/**
473 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
474 */
475static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
476{
477 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
478 return VERR_NOT_IMPLEMENTED;
479}
480
481
482/**
483 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
484 */
485static DECLCALLBACK(int) rtFsFatDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
486{
487 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
488 return VERR_NOT_SUPPORTED;
489}
490
491
492/**
493 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
494 */
495static DECLCALLBACK(int) rtFsFatDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
496 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
497{
498 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
499 return VERR_NOT_SUPPORTED;
500}
501
502
503/**
504 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
505 */
506static DECLCALLBACK(int) rtFsFatDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
507{
508 RT_NOREF(pvThis, pszEntry, fType);
509 return VERR_NOT_IMPLEMENTED;
510}
511
512
513/**
514 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
515 */
516static DECLCALLBACK(int) rtFsFatDir_RewindDir(void *pvThis)
517{
518 RT_NOREF(pvThis);
519 return VERR_NOT_IMPLEMENTED;
520}
521
522
523/**
524 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
525 */
526static DECLCALLBACK(int) rtFsFatDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
527 RTFSOBJATTRADD enmAddAttr)
528{
529 RT_NOREF(pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
530 return VERR_NOT_IMPLEMENTED;
531}
532
533
534/**
535 * FAT file operations.
536 */
537static const RTVFSDIROPS g_rtFsFatDirOps =
538{
539 { /* Obj */
540 RTVFSOBJOPS_VERSION,
541 RTVFSOBJTYPE_FILE,
542 "FatDir",
543 rtFsFatDir_Close,
544 rtFsFatObj_QueryInfo,
545 RTVFSOBJOPS_VERSION
546 },
547 RTVFSDIROPS_VERSION,
548 0,
549 { /* ObjSet */
550 RTVFSOBJSETOPS_VERSION,
551 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
552 rtFsFatObj_SetMode,
553 rtFsFatObj_SetTimes,
554 rtFsFatObj_SetOwner,
555 RTVFSOBJSETOPS_VERSION
556 },
557 rtFsFatDir_TraversalOpen,
558 rtFsFatDir_OpenFile,
559 rtFsFatDir_OpenDir,
560 rtFsFatDir_CreateDir,
561 rtFsFatDir_OpenSymlink,
562 rtFsFatDir_CreateSymlink,
563 rtFsFatDir_UnlinkEntry,
564 rtFsFatDir_RewindDir,
565 rtFsFatDir_ReadDir,
566 RTVFSDIROPS_VERSION,
567};
568
569
570/**
571 * @interface_method_impl{RTVFSOPS,pfnDestroy}
572 */
573static DECLCALLBACK(void) rtFsFatVol_Destroy(void *pvThis)
574{
575 RT_NOREF(pvThis);
576}
577
578
579/**
580 * @interface_method_impl{RTVFSOPS,pfnOpenRoo}
581 */
582static DECLCALLBACK(int) rtFsFatVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
583{
584 RT_NOREF(pvThis, phVfsDir);
585 return VERR_NOT_IMPLEMENTED;
586}
587
588
589/**
590 * @interface_method_impl{RTVFSOPS,pfnIsRangeInUse}
591 */
592static DECLCALLBACK(int) rtFsFatVol_IsRangeInUse(void *pvThis, RTFOFF off, size_t cb, bool *pfUsed)
593{
594 RT_NOREF(pvThis, off, cb, pfUsed);
595 return VERR_NOT_IMPLEMENTED;
596}
597
598
599DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsFatVolOps =
600{
601 RTVFSOPS_VERSION,
602 0 /* fFeatures */,
603 "FatVol",
604 rtFsFatVol_Destroy,
605 rtFsFatVol_OpenRoot,
606 rtFsFatVol_IsRangeInUse,
607 RTVFSOPS_VERSION
608};
609
610
611
612RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, PRTVFS phVfs, PRTERRINFO pErrInfo)
613{
614 RT_NOREF(hVfsFileIn, fReadOnly, pErrInfo, phVfs);
615 return VERR_NOT_IMPLEMENTED;
616}
617
618
619/**
620 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
621 */
622static DECLCALLBACK(int) rtVfsChainFatVol_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
623 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
624{
625 RT_NOREF(pProviderReg);
626
627 /*
628 * Basic checks.
629 */
630 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
631 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
632 if ( pElement->enmType != RTVFSOBJTYPE_VFS
633 && pElement->enmType != RTVFSOBJTYPE_DIR)
634 return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
635 if (pElement->cArgs > 1)
636 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
637
638 /*
639 * Parse the flag if present, save in pElement->uProvider.
640 */
641 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
642 if (pElement->cArgs > 0)
643 {
644 const char *psz = pElement->paArgs[0].psz;
645 if (*psz)
646 {
647 if (!strcmp(psz, "ro"))
648 fReadOnly = true;
649 else if (!strcmp(psz, "rw"))
650 fReadOnly = false;
651 else
652 {
653 *poffError = pElement->paArgs[0].offSpec;
654 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
655 }
656 }
657 }
658
659 pElement->uProvider = fReadOnly;
660 return VINF_SUCCESS;
661}
662
663
664/**
665 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
666 */
667static DECLCALLBACK(int) rtVfsChainFatVol_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
668 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
669 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
670{
671 RT_NOREF(pProviderReg, pSpec, poffError);
672
673 int rc;
674 RTVFSFILE hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
675 if (hVfsFileIn != NIL_RTVFSFILE)
676 {
677 RTVFS hVfs;
678 rc = RTFsFatVolOpen(hVfsFileIn, pElement->uProvider != false, &hVfs, pErrInfo);
679 RTVfsFileRelease(hVfsFileIn);
680 if (RT_SUCCESS(rc))
681 {
682 *phVfsObj = RTVfsObjFromVfs(hVfs);
683 RTVfsRelease(hVfs);
684 if (*phVfsObj != NIL_RTVFSOBJ)
685 return VINF_SUCCESS;
686 rc = VERR_VFS_CHAIN_CAST_FAILED;
687 }
688 }
689 else
690 rc = VERR_VFS_CHAIN_CAST_FAILED;
691 return rc;
692}
693
694
695/**
696 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
697 */
698static DECLCALLBACK(bool) rtVfsChainFatVol_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
699 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
700 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
701{
702 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
703 if ( pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
704 || !pReuseElement->paArgs[0].uProvider)
705 return true;
706 return false;
707}
708
709
710/** VFS chain element 'file'. */
711static RTVFSCHAINELEMENTREG g_rtVfsChainFatVolReg =
712{
713 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
714 /* fReserved = */ 0,
715 /* pszName = */ "fat",
716 /* ListEntry = */ { NULL, NULL },
717 /* pszHelp = */ "Open a FAT file system, requires a file object on the left side.\n"
718 "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
719 /* pfnValidate = */ rtVfsChainFatVol_Validate,
720 /* pfnInstantiate = */ rtVfsChainFatVol_Instantiate,
721 /* pfnCanReuseElement = */ rtVfsChainFatVol_CanReuseElement,
722 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
723};
724
725RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainFatVolReg, rtVfsChainFatVolReg);
726
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