VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsmount.cpp@ 96563

Last change on this file since 96563 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.0 KB
Line 
1/* $Id: vfsmount.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Mounting.
4 */
5
6/*
7 * Copyright (C) 2012-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_VFS
42#include <iprt/vfs.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/err.h>
47#include <iprt/file.h>
48#include <iprt/fsvfs.h>
49#include <iprt/mem.h>
50#include <iprt/log.h>
51#include <iprt/string.h>
52#include <iprt/vfslowlevel.h>
53
54#include <iprt/formats/fat.h>
55#include <iprt/formats/iso9660.h>
56#include <iprt/formats/udf.h>
57#include <iprt/formats/ext.h>
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/** Buffer structure for the detection routines. */
64typedef union RTVFSMOUNTBUF
65{
66 uint8_t ab[2048];
67 uint32_t au32[2048/4];
68 FATBOOTSECTOR Bootsector;
69 ISO9660VOLDESCHDR IsoHdr;
70} RTVFSMOUNTBUF;
71AssertCompileSize(RTVFSMOUNTBUF, 2048);
72typedef RTVFSMOUNTBUF *PRTVFSMOUNTBUF;
73
74
75
76/**
77 * Checks if the given 2K sector at offset 32KB looks like ISO-9660 or UDF.
78 *
79 * @returns true if likely ISO or UDF, otherwise false.
80 * @param pVolDescHdr Whatever is at offset 32KB. 2KB buffer.
81 */
82static bool rtVfsMountIsIsoFs(PCISO9660VOLDESCHDR pVolDescHdr)
83{
84 if ( memcmp(pVolDescHdr->achStdId, RT_STR_TUPLE(ISO9660VOLDESC_STD_ID)) == 0
85 && pVolDescHdr->bDescType <= ISO9660VOLDESC_TYPE_PARTITION
86 && pVolDescHdr->bDescVersion != 0
87 && pVolDescHdr->bDescVersion <= 3 /* don't be too picky, just increase the likelyhood */ )
88 return true;
89
90 if ( memcmp(pVolDescHdr->achStdId, RT_STR_TUPLE(UDF_EXT_VOL_DESC_STD_ID_BEGIN)) == 0
91 && pVolDescHdr->bDescType == UDF_EXT_VOL_DESC_TYPE
92 && pVolDescHdr->bDescVersion == UDF_EXT_VOL_DESC_VERSION)
93 return true;
94
95 return false;
96}
97
98
99/**
100 * Check if the given bootsector is a NTFS boot sector.
101 *
102 * @returns true if NTFS, false if not.
103 * @param pBootSector The boot sector to inspect.
104 */
105static bool rtVfsMountIsNtfs(PCFATBOOTSECTOR pBootSector)
106{
107 if (memcmp(pBootSector->achOemName, RT_STR_TUPLE("NTFS ")) != 0)
108 return false;
109
110 uint16_t cbSector = RT_LE2H_U16(pBootSector->Bpb.Bpb331.cbSector);
111 if ( cbSector < 0x100
112 || cbSector >= 0x1000
113 || (cbSector & 0xff) != 0)
114 {
115 Log2(("rtVfsMountIsNtfs: cbSector=%#x: out of range\n", cbSector));
116 return false;
117 }
118
119 if ( !RT_IS_POWER_OF_TWO(pBootSector->Bpb.Bpb331.cSectorsPerCluster)
120 || pBootSector->Bpb.Bpb331.cSectorsPerCluster == 0
121 || pBootSector->Bpb.Bpb331.cSectorsPerCluster > 128)
122 {
123 Log2(("rtVfsMountIsNtfs: cSectorsPerCluster=%#x: out of range\n", pBootSector->Bpb.Bpb331.cSectorsPerCluster));
124 return false;
125 }
126
127 if ((uint32_t)pBootSector->Bpb.Bpb331.cSectorsPerCluster * cbSector > _64K)
128 {
129 Log2(("rtVfsMountIsNtfs: cSectorsPerCluster=%#x * cbSector=%#x => %#x: out of range\n",
130 pBootSector->Bpb.Bpb331.cSectorsPerCluster, cbSector,
131 (uint32_t)pBootSector->Bpb.Bpb331.cSectorsPerCluster * cbSector));
132 return false;
133 }
134
135 if ( pBootSector->Bpb.Bpb331.cReservedSectors != 0
136 || pBootSector->Bpb.Bpb331.cMaxRootDirEntries != 0
137 || pBootSector->Bpb.Bpb331.cTotalSectors16 != 0
138 || pBootSector->Bpb.Bpb331.cTotalSectors32 != 0
139 || pBootSector->Bpb.Bpb331.cSectorsPerFat != 0
140 || pBootSector->Bpb.Bpb331.cFats != 0)
141 {
142 Log2(("rtVfsMountIsNtfs: cReservedSectors=%#x cMaxRootDirEntries=%#x cTotalSectors=%#x cTotalSectors32=%#x cSectorsPerFat=%#x cFats=%#x: should all be zero, but one or more aren't\n",
143 RT_LE2H_U16(pBootSector->Bpb.Bpb331.cReservedSectors),
144 RT_LE2H_U16(pBootSector->Bpb.Bpb331.cMaxRootDirEntries),
145 RT_LE2H_U16(pBootSector->Bpb.Bpb331.cTotalSectors16),
146 RT_LE2H_U32(pBootSector->Bpb.Bpb331.cTotalSectors32),
147 RT_LE2H_U16(pBootSector->Bpb.Bpb331.cSectorsPerFat),
148 pBootSector->Bpb.Bpb331.cFats));
149 return false;
150 }
151
152 /** @todo NTFS specific checks: MFT cluster number, cluster per index block. */
153
154 return true;
155}
156
157
158/**
159 * Check if the given bootsector is a HPFS boot sector.
160 *
161 * @returns true if NTFS, false if not.
162 * @param pBootSector The boot sector to inspect.
163 * @param hVfsFileIn The volume file.
164 * @param pBuf2 A 2nd buffer.
165 */
166static bool rtVfsMountIsHpfs(PCFATBOOTSECTOR pBootSector, RTVFSFILE hVfsFileIn, PRTVFSMOUNTBUF pBuf2)
167{
168 if (memcmp(pBootSector->Bpb.Ebpb.achType, RT_STR_TUPLE("HPFS ")) != 0)
169 return false;
170
171 /* Superblock is at sector 16, spare superblock at 17. */
172 int rc = RTVfsFileReadAt(hVfsFileIn, 16 * 512, pBuf2, 512 * 2, NULL);
173 if (RT_FAILURE(rc))
174 {
175 Log2(("rtVfsMountIsHpfs: Error reading superblock: %Rrc\n", rc));
176 return false;
177 }
178
179 if ( RT_LE2H_U32(pBuf2->au32[0]) != UINT32_C(0xf995e849)
180 || RT_LE2H_U32(pBuf2->au32[1]) != UINT32_C(0xfa53e9c5)
181 || RT_LE2H_U32(pBuf2->au32[512/4 + 0]) != UINT32_C(0xf9911849)
182 || RT_LE2H_U32(pBuf2->au32[512/4 + 1]) != UINT32_C(0xfa5229c5))
183 {
184 Log2(("rtVfsMountIsHpfs: Superblock or spare superblock signature mismatch: %#x %#x %#x %#x\n",
185 RT_LE2H_U32(pBuf2->au32[0]), RT_LE2H_U32(pBuf2->au32[1]),
186 RT_LE2H_U32(pBuf2->au32[512/4 + 0]), RT_LE2H_U32(pBuf2->au32[512/4 + 1]) ));
187 return false;
188 }
189
190 return true;
191}
192
193
194/**
195 * Check if the given bootsector is a FAT boot sector.
196 *
197 * @returns true if NTFS, false if not.
198 * @param pBootSector The boot sector to inspect.
199 * @param pbRaw Pointer to the raw boot sector buffer.
200 * @param cbRaw Number of bytes read starting with the boot
201 * sector (which @a pbRaw points to).
202 * @param hVfsFileIn The volume file.
203 * @param pBuf2 A 2nd buffer.
204 */
205static bool rtVfsMountIsFat(PCFATBOOTSECTOR pBootSector, uint8_t const *pbRaw, size_t cbRaw,
206 RTVFSFILE hVfsFileIn, PRTVFSMOUNTBUF pBuf2)
207{
208 Assert(cbRaw >= 1024);
209
210 /*
211 * Check the DOS signature first. The PC-DOS 1.0 boot floppy does not have
212 * a signature and we ASSUME this is the case for all floppies formated by it.
213 */
214 if (pBootSector->uSignature != FATBOOTSECTOR_SIGNATURE)
215 {
216 if (pBootSector->uSignature != 0)
217 return false;
218
219 /*
220 * PC-DOS 1.0 does a 2fh byte short jump w/o any NOP following it.
221 * Instead the following are three words and a 9 byte build date
222 * string. The remaining space is zero filled.
223 *
224 * Note! No idea how this would look like for 8" floppies, only got 5"1/4'.
225 *
226 * ASSUME all non-BPB disks are using this format.
227 */
228 if ( pBootSector->abJmp[0] != 0xeb /* jmp rel8 */
229 || pBootSector->abJmp[1] < 0x2f
230 || pBootSector->abJmp[1] >= 0x80
231 || pBootSector->abJmp[2] == 0x90 /* nop */)
232 {
233 Log2(("rtVfsMountIsFat: No DOS v1.0 bootsector either - invalid jmp: %.3Rhxs\n", pBootSector->abJmp));
234 return false;
235 }
236
237 /* Check the FAT ID so we can tell if this is double or single sided, as well as being a valid FAT12 start. */
238 if ( (pbRaw[512] != 0xfe && pbRaw[0] != 0xff)
239 || pbRaw[512 + 1] != 0xff
240 || pbRaw[512 + 2] != 0xff)
241 {
242 Log2(("rtVfsMountIsFat: No DOS v1.0 bootsector either - unexpected start of FAT: %.3Rhxs\n", &pbRaw[512]));
243 return false;
244 }
245
246 uint32_t const offJump = 2 + pBootSector->abJmp[1];
247 uint32_t const offFirstZero = 2 /*jmp */ + 3 * 2 /* words */ + 9 /* date string */;
248 Assert(offFirstZero >= RT_UOFFSETOF(FATBOOTSECTOR, Bpb));
249 uint32_t const cbZeroPad = RT_MIN(offJump - offFirstZero,
250 sizeof(pBootSector->Bpb.Bpb20) - (offFirstZero - RT_UOFFSETOF(FATBOOTSECTOR, Bpb)));
251
252 if (!ASMMemIsAllU8((uint8_t const *)pBootSector + offFirstZero, cbZeroPad, 0))
253 {
254 Log2(("rtVfsMountIsFat: No DOS v1.0 bootsector either - expected zero padding %#x LB %#x: %.*Rhxs\n",
255 offFirstZero, cbZeroPad, cbZeroPad, (uint8_t const *)pBootSector + offFirstZero));
256 return false;
257 }
258 }
259 else
260 {
261 /*
262 * DOS 2.0 or later.
263 *
264 * Start by checking if we've got a known jump instruction first, because
265 * that will give us a max (E)BPB size hint.
266 */
267 uint8_t offJmp = UINT8_MAX;
268 if ( pBootSector->abJmp[0] == 0xeb
269 && pBootSector->abJmp[1] <= 0x7f)
270 offJmp = pBootSector->abJmp[1] + 2;
271 else if ( pBootSector->abJmp[0] == 0x90
272 && pBootSector->abJmp[1] == 0xeb
273 && pBootSector->abJmp[2] <= 0x7f)
274 offJmp = pBootSector->abJmp[2] + 3;
275 else if ( pBootSector->abJmp[0] == 0xe9
276 && pBootSector->abJmp[2] <= 0x7f)
277 offJmp = RT_MIN(127, RT_MAKE_U16(pBootSector->abJmp[1], pBootSector->abJmp[2]));
278 uint8_t const cbMaxBpb = offJmp - RT_UOFFSETOF(FATBOOTSECTOR, Bpb);
279 if (cbMaxBpb < sizeof(FATBPB20))
280 {
281 Log2(("rtVfsMountIsFat: DOS signature, but jmp too short for any BPB: %#x (max %#x BPB)\n", offJmp, cbMaxBpb));
282 return false;
283 }
284
285 if ( pBootSector->Bpb.Bpb20.cFats == 0
286 || pBootSector->Bpb.Bpb20.cFats > 4)
287 {
288 if (pBootSector->Bpb.Bpb20.cFats == 0)
289 Log2(("rtVfsMountIsFat: DOS signature, number of FATs is zero, so not FAT file system\n"));
290 else
291 Log2(("rtVfsMountIsFat: DOS signature, too many FATs: %#x\n", pBootSector->Bpb.Bpb20.cFats));
292 return false;
293 }
294
295 if (!FATBPB_MEDIA_IS_VALID(pBootSector->Bpb.Bpb20.bMedia))
296 {
297 Log2(("rtVfsMountIsFat: DOS signature, invalid media byte: %#x\n", pBootSector->Bpb.Bpb20.bMedia));
298 return false;
299 }
300
301 uint16_t cbSector = RT_LE2H_U16(pBootSector->Bpb.Bpb20.cbSector);
302 if ( cbSector != 512
303 && cbSector != 4096
304 && cbSector != 1024
305 && cbSector != 128)
306 {
307 Log2(("rtVfsMountIsFat: DOS signature, unsupported sector size: %#x\n", cbSector));
308 return false;
309 }
310
311 if ( !RT_IS_POWER_OF_TWO(pBootSector->Bpb.Bpb20.cSectorsPerCluster)
312 || !pBootSector->Bpb.Bpb20.cSectorsPerCluster)
313 {
314 Log2(("rtVfsMountIsFat: DOS signature, cluster size not non-zero power of two: %#x",
315 pBootSector->Bpb.Bpb20.cSectorsPerCluster));
316 return false;
317 }
318
319 uint16_t const cReservedSectors = RT_LE2H_U16(pBootSector->Bpb.Bpb20.cReservedSectors);
320 if ( cReservedSectors == 0
321 || cReservedSectors >= _32K)
322 {
323 Log2(("rtVfsMountIsFat: DOS signature, bogus reserved sector count: %#x\n", cReservedSectors));
324 return false;
325 }
326
327 /*
328 * Match the media byte with the first FAT byte and check that the next
329 * 4 bits are set. (To match further bytes in the FAT we'd need to
330 * determin the FAT type, which is too much hazzle to do here.)
331 */
332 uint8_t const *pbFat;
333 if ((size_t)cReservedSectors * cbSector < cbRaw)
334 pbFat = &pbRaw[cReservedSectors * cbSector];
335 else
336 {
337 int rc = RTVfsFileReadAt(hVfsFileIn, cReservedSectors * cbSector, pBuf2, 512, NULL);
338 if (RT_FAILURE(rc))
339 {
340 Log2(("rtVfsMountIsFat: error reading first FAT sector at %#x: %Rrc\n", cReservedSectors * cbSector, rc));
341 return false;
342 }
343 pbFat = pBuf2->ab;
344 }
345 if (*pbFat != pBootSector->Bpb.Bpb20.bMedia)
346 {
347 Log2(("rtVfsMountIsFat: Media byte and FAT ID mismatch: %#x vs %#x (%.8Rhxs)\n",
348 pbFat[0], pBootSector->Bpb.Bpb20.bMedia, pbFat));
349 return false;
350 }
351 if ((pbFat[1] & 0xf) != 0xf)
352 {
353 Log2(("rtVfsMountIsFat: Media byte and FAT ID mismatch: %#x vs %#x (%.8Rhxs)\n",
354 pbFat[0], pBootSector->Bpb.Bpb20.bMedia, pbFat));
355 return false;
356 }
357 }
358
359 return true;
360}
361
362
363/**
364 * Check if the given bootsector is an ext2/3/4 super block.
365 *
366 * @returns true if NTFS, false if not.
367 * @param pSuperBlock The ext2 superblock.
368 */
369static bool rtVfsMountIsExt(PCEXTSUPERBLOCK pSuperBlock)
370{
371 if (RT_LE2H_U16(pSuperBlock->u16Signature) != EXT_SB_SIGNATURE)
372 return false;
373
374 uint32_t cShift = RT_LE2H_U32(pSuperBlock->cLogBlockSize);
375 if (cShift > 54)
376 {
377 Log2(("rtVfsMountIsExt: cLogBlockSize=%#x: out of range\n", cShift));
378 return false;
379 }
380
381 cShift = RT_LE2H_U32(pSuperBlock->cLogClusterSize);
382 if (cShift > 54)
383 {
384 Log2(("rtVfsMountIsExt: cLogClusterSize=%#x: out of range\n", cShift));
385 return false;
386 }
387
388 /* Some more checks here would be nice actually since a 16-bit word and a
389 couple of field limits doesn't feel all that conclusive. */
390
391 return true;
392}
393
394
395/**
396 * Does the file system detection and mounting.
397 *
398 * Since we only support a handful of file systems at the moment and the
399 * interface isn't yet extensible in any way, we combine the file system
400 * recognition code for all. This reduces the number of reads we need to do and
401 * avoids unnecessary processing.
402 *
403 * @returns IPRT status code.
404 * @param hVfsFileIn The volume file.
405 * @param fFlags RTVFSMTN_F_XXX.
406 * @param pBuf Pointer to the primary buffer
407 * @param pBuf2 Pointer to the secondary buffer.
408 * @param phVfs Where to return the .
409 * @param pErrInfo Where to return additional error information.
410 * Optional.
411 */
412static int rtVfsMountInner(RTVFSFILE hVfsFileIn, uint32_t fFlags, RTVFSMOUNTBUF *pBuf,
413 RTVFSMOUNTBUF *pBuf2, PRTVFS phVfs, PRTERRINFO pErrInfo)
414{
415 AssertCompile(sizeof(*pBuf) >= ISO9660_SECTOR_SIZE);
416
417 /* Start by checking for ISO-9660 and UDFS since these may have confusing
418 data at the start of the volume. */
419 int rc = RTVfsFileReadAt(hVfsFileIn, _32K, pBuf, ISO9660_SECTOR_SIZE, NULL);
420 if (RT_SUCCESS(rc))
421 {
422 if (rtVfsMountIsIsoFs(&pBuf->IsoHdr))
423 {
424 Log(("RTVfsMount: Detected ISO-9660 or UDF.\n"));
425 return RTFsIso9660VolOpen(hVfsFileIn, 0 /*fFlags*/, phVfs, pErrInfo);
426 }
427 }
428
429 /* Now read the boot sector and whatever the next 1536 bytes may contain.
430 With ext2 superblock at 1024, we can recognize quite a bit thru this read. */
431 rc = RTVfsFileReadAt(hVfsFileIn, 0, pBuf, sizeof(*pBuf), NULL);
432 if (RT_FAILURE(rc))
433 return RTErrInfoSet(pErrInfo, rc, "Error reading boot sector");
434
435 if (rtVfsMountIsNtfs(&pBuf->Bootsector))
436 return RTFsNtfsVolOpen(hVfsFileIn, fFlags, 0 /*fNtfsFlags*/, phVfs, pErrInfo);
437
438 if (rtVfsMountIsHpfs(&pBuf->Bootsector, hVfsFileIn, pBuf2))
439 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "HPFS not yet supported");
440
441 if (rtVfsMountIsFat(&pBuf->Bootsector, pBuf->ab, sizeof(*pBuf), hVfsFileIn, pBuf2))
442 {
443 Log(("RTVfsMount: Detected ISO-9660 or UDF.\n"));
444 return RTFsFatVolOpen(hVfsFileIn, RT_BOOL(fFlags & RTVFSMNT_F_READ_ONLY), 0 /*offBootSector*/, phVfs, pErrInfo);
445 }
446
447 AssertCompile(sizeof(*pBuf) >= 1024 + sizeof(EXTSUPERBLOCK));
448 if (rtVfsMountIsExt((PCEXTSUPERBLOCK)&pBuf->ab[1024]))
449 {
450 Log(("RTVfsMount: Detected EXT2/3/4.\n"));
451 return RTFsExtVolOpen(hVfsFileIn, fFlags, 0 /*fExt2Flags*/, phVfs, pErrInfo);
452 }
453
454 return VERR_VFS_UNSUPPORTED_FORMAT;
455}
456
457
458RTDECL(int) RTVfsMountVol(RTVFSFILE hVfsFileIn, uint32_t fFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
459{
460 AssertReturn(!(fFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
461 AssertPtrReturn(hVfsFileIn, VERR_INVALID_HANDLE);
462 AssertPtrReturn(phVfs, VERR_INVALID_HANDLE);
463
464 *phVfs = NIL_RTVFS;
465
466 RTVFSMOUNTBUF *pBufs = (RTVFSMOUNTBUF *)RTMemTmpAlloc(sizeof(*pBufs) * 2);
467 AssertReturn(pBufs, VERR_NO_TMP_MEMORY);
468
469 int rc = rtVfsMountInner(hVfsFileIn, fFlags, pBufs, pBufs + 1, phVfs, pErrInfo);
470
471 RTMemTmpFree(pBufs);
472
473 return rc;
474}
475
476
477/**
478 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
479 */
480static DECLCALLBACK(int) rtVfsChainMountVol_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
481 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
482{
483 RT_NOREF(pProviderReg);
484
485 /*
486 * Basic checks.
487 */
488 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
489 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
490 if ( pElement->enmType != RTVFSOBJTYPE_VFS
491 && pElement->enmType != RTVFSOBJTYPE_DIR)
492 return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
493 if (pElement->cArgs > 1)
494 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
495
496 /*
497 * Parse the flag if present, save in pElement->uProvider.
498 */
499 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
500 if (pElement->cArgs > 0)
501 {
502 const char *psz = pElement->paArgs[0].psz;
503 if (*psz)
504 {
505 if (!strcmp(psz, "ro"))
506 fReadOnly = true;
507 else if (!strcmp(psz, "rw"))
508 fReadOnly = false;
509 else
510 {
511 *poffError = pElement->paArgs[0].offSpec;
512 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
513 }
514 }
515 }
516
517 pElement->uProvider = fReadOnly ? RTVFSMNT_F_READ_ONLY : 0;
518 return VINF_SUCCESS;
519}
520
521
522/**
523 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
524 */
525static DECLCALLBACK(int) rtVfsChainMountVol_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
526 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
527 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
528{
529 RT_NOREF(pProviderReg, pSpec, poffError);
530
531 int rc;
532 RTVFSFILE hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
533 if (hVfsFileIn != NIL_RTVFSFILE)
534 {
535 RTVFS hVfs;
536 rc = RTVfsMountVol(hVfsFileIn, (uint32_t)pElement->uProvider, &hVfs, pErrInfo);
537 RTVfsFileRelease(hVfsFileIn);
538 if (RT_SUCCESS(rc))
539 {
540 *phVfsObj = RTVfsObjFromVfs(hVfs);
541 RTVfsRelease(hVfs);
542 if (*phVfsObj != NIL_RTVFSOBJ)
543 return VINF_SUCCESS;
544 rc = VERR_VFS_CHAIN_CAST_FAILED;
545 }
546 }
547 else
548 rc = VERR_VFS_CHAIN_CAST_FAILED;
549 return rc;
550}
551
552
553/**
554 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
555 */
556static DECLCALLBACK(bool) rtVfsChainMountVol_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
557 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
558 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
559{
560 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
561 if ( pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
562 || !pReuseElement->paArgs[0].uProvider)
563 return true;
564 return false;
565}
566
567
568/** VFS chain element 'file'. */
569static RTVFSCHAINELEMENTREG g_rtVfsChainMountVolReg =
570{
571 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
572 /* fReserved = */ 0,
573 /* pszName = */ "mount",
574 /* ListEntry = */ { NULL, NULL },
575 /* pszHelp = */ "Open a file system, requires a file object on the left side.\n"
576 "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
577 /* pfnValidate = */ rtVfsChainMountVol_Validate,
578 /* pfnInstantiate = */ rtVfsChainMountVol_Instantiate,
579 /* pfnCanReuseElement = */ rtVfsChainMountVol_CanReuseElement,
580 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
581};
582
583RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainMountVolReg, rtVfsChainMountVolReg);
584
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