VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp@ 94291

Last change on this file since 94291 was 94291, checked in by vboxsync, 3 years ago

IPRT,Storage: Adding RTVfsQueryLabel and internally a generic pfnQueryInfoEx method to the RTVFSOBJOPS function table. Untested implementation of the latter for iso/udf. bugref:9781

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 KB
Line 
1/* $Id: vfsstdfile.cpp 94291 2022-03-17 13:29:52Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard File Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2022 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#include <iprt/vfs.h>
32#include <iprt/vfslowlevel.h>
33
34#include <iprt/assert.h>
35#include <iprt/err.h>
36#include <iprt/file.h>
37#include <iprt/poll.h>
38#include <iprt/string.h>
39#include <iprt/thread.h>
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45/**
46 * Private data of a standard file.
47 */
48typedef struct RTVFSSTDFILE
49{
50 /** The file handle. */
51 RTFILE hFile;
52 /** Whether to leave the handle open when the VFS handle is closed. */
53 bool fLeaveOpen;
54} RTVFSSTDFILE;
55/** Pointer to the private data of a standard file. */
56typedef RTVFSSTDFILE *PRTVFSSTDFILE;
57
58
59/**
60 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
61 */
62static DECLCALLBACK(int) rtVfsStdFile_Close(void *pvThis)
63{
64 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
65
66 int rc;
67 if (!pThis->fLeaveOpen)
68 rc = RTFileClose(pThis->hFile);
69 else
70 rc = VINF_SUCCESS;
71 pThis->hFile = NIL_RTFILE;
72
73 return rc;
74}
75
76
77/**
78 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
79 */
80static DECLCALLBACK(int) rtVfsStdFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
81{
82 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
83 return RTFileQueryInfo(pThis->hFile, pObjInfo, enmAddAttr);
84}
85
86
87/**
88 * RTFileRead and RTFileReadAt does not return VINF_EOF or VINF_TRY_AGAIN, this
89 * function tries to fix this as best as it can.
90 *
91 * This fixing can be subject to races if some other thread or process is
92 * modifying the file size between the read and our size query here.
93 *
94 * @returns VINF_SUCCESS, VINF_EOF or VINF_TRY_AGAIN.
95 * @param pThis The instance data.
96 * @param off The offset parameter.
97 * @param cbToRead The number of bytes attempted read .
98 * @param cbActuallyRead The number of bytes actually read.
99 */
100DECLINLINE(int) rtVfsStdFile_ReadFixRC(PRTVFSSTDFILE pThis, RTFOFF off, size_t cbToRead, size_t cbActuallyRead)
101{
102 /* If the read returned less bytes than requested, it means the end of the
103 file has been reached. */
104 if (cbToRead > cbActuallyRead)
105 return VINF_EOF;
106
107 /* The other case here is the very special zero byte read at the end of the
108 file, where we're supposed to indicate EOF. */
109 if (cbToRead > 0)
110 return VINF_SUCCESS;
111
112 uint64_t cbFile;
113 int rc = RTFileQuerySize(pThis->hFile, &cbFile);
114 if (RT_FAILURE(rc))
115 return rc;
116
117 uint64_t off2;
118 if (off >= 0)
119 off2 = off;
120 else
121 {
122 rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &off2);
123 if (RT_FAILURE(rc))
124 return rc;
125 }
126
127 return off2 >= cbFile ? VINF_EOF : VINF_SUCCESS;
128}
129
130
131/**
132 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
133 */
134static DECLCALLBACK(int) rtVfsStdFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
135{
136 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
137 int rc;
138
139 NOREF(fBlocking);
140 if (pSgBuf->cSegs == 1)
141 {
142 if (off < 0)
143 rc = RTFileRead( pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
144 else
145 {
146 rc = RTFileReadAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
147 if (RT_SUCCESS(rc)) /* RTFileReadAt() doesn't increment the file-position indicator on some platforms */
148 rc = RTFileSeek(pThis->hFile, off + (pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg), RTFILE_SEEK_BEGIN, NULL);
149 }
150 if (rc == VINF_SUCCESS && pcbRead)
151 rc = rtVfsStdFile_ReadFixRC(pThis, off, pSgBuf->paSegs[0].cbSeg, *pcbRead);
152 }
153 else
154 {
155 size_t cbSeg = 0;
156 size_t cbRead = 0;
157 size_t cbReadSeg = 0;
158 rc = VINF_SUCCESS;
159
160 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
161 {
162 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
163 cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
164
165 cbReadSeg = cbSeg;
166 if (off < 0)
167 rc = RTFileRead( pThis->hFile, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
168 else
169 {
170 rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
171 if (RT_SUCCESS(rc)) /* RTFileReadAt() doesn't increment the file-position indicator on some platforms */
172 rc = RTFileSeek(pThis->hFile, off + cbReadSeg, RTFILE_SEEK_BEGIN, NULL);
173 }
174 if (RT_FAILURE(rc))
175 break;
176 if (off >= 0)
177 off += cbReadSeg;
178 cbRead += cbReadSeg;
179 if ((pcbRead && cbReadSeg != cbSeg) || rc != VINF_SUCCESS)
180 break;
181 }
182
183 if (pcbRead)
184 {
185 *pcbRead = cbRead;
186 if (rc == VINF_SUCCESS)
187 rc = rtVfsStdFile_ReadFixRC(pThis, off, cbSeg, cbReadSeg);
188 }
189 }
190
191 return rc;
192}
193
194
195/**
196 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
197 */
198static DECLCALLBACK(int) rtVfsStdFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
199{
200 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
201 int rc;
202
203 NOREF(fBlocking);
204 if (pSgBuf->cSegs == 1)
205 {
206 if (off < 0)
207 rc = RTFileWrite(pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
208 else
209 {
210 rc = RTFileWriteAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
211 if (RT_SUCCESS(rc)) /* RTFileWriteAt() doesn't increment the file-position indicator on some platforms */
212 rc = RTFileSeek(pThis->hFile, off + (pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg), RTFILE_SEEK_BEGIN,
213 NULL);
214 }
215 }
216 else
217 {
218 size_t cbWritten = 0;
219 size_t cbWrittenSeg;
220 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
221 rc = VINF_SUCCESS;
222
223 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
224 {
225 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
226 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
227
228 cbWrittenSeg = 0;
229 if (off < 0)
230 rc = RTFileWrite(pThis->hFile, pvSeg, cbSeg, pcbWrittenSeg);
231 else
232 {
233 rc = RTFileWriteAt(pThis->hFile, off, pvSeg, cbSeg, pcbWrittenSeg);
234 if (RT_SUCCESS(rc))
235 {
236 off += pcbWrittenSeg ? *pcbWrittenSeg : cbSeg;
237 /* RTFileWriteAt() doesn't increment the file-position indicator on some platforms */
238 rc = RTFileSeek(pThis->hFile, off, RTFILE_SEEK_BEGIN, NULL);
239 }
240 }
241 if (RT_FAILURE(rc))
242 break;
243 if (pcbWritten)
244 {
245 cbWritten += cbWrittenSeg;
246 if (cbWrittenSeg != cbSeg)
247 break;
248 }
249 }
250
251 if (pcbWritten)
252 *pcbWritten = cbWritten;
253 }
254
255 return rc;
256}
257
258
259/**
260 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
261 */
262static DECLCALLBACK(int) rtVfsStdFile_Flush(void *pvThis)
263{
264 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
265 int rc = RTFileFlush(pThis->hFile);
266#ifdef RT_OS_WINDOWS
267 /* Workaround for console handles. */ /** @todo push this further down? */
268 if ( rc == VERR_INVALID_HANDLE
269 && RTFileIsValid(pThis->hFile))
270 rc = VINF_NOT_SUPPORTED; /* not flushable */
271#endif
272 return rc;
273}
274
275
276/**
277 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
278 */
279static DECLCALLBACK(int) rtVfsStdFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
280 uint32_t *pfRetEvents)
281{
282 NOREF(pvThis);
283 int rc;
284 if (fEvents != RTPOLL_EVT_ERROR)
285 {
286 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
287 rc = VINF_SUCCESS;
288 }
289 else if (fIntr)
290 rc = RTThreadSleep(cMillies);
291 else
292 {
293 uint64_t uMsStart = RTTimeMilliTS();
294 do
295 rc = RTThreadSleep(cMillies);
296 while ( rc == VERR_INTERRUPTED
297 && !fIntr
298 && RTTimeMilliTS() - uMsStart < cMillies);
299 if (rc == VERR_INTERRUPTED)
300 rc = VERR_TIMEOUT;
301 }
302 return rc;
303}
304
305
306/**
307 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
308 */
309static DECLCALLBACK(int) rtVfsStdFile_Tell(void *pvThis, PRTFOFF poffActual)
310{
311 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
312 uint64_t offActual;
313 int rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &offActual);
314 if (RT_SUCCESS(rc))
315 *poffActual = (RTFOFF)offActual;
316 return rc;
317}
318
319
320/**
321 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
322 */
323static DECLCALLBACK(int) rtVfsStdFile_Skip(void *pvThis, RTFOFF cb)
324{
325 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
326 uint64_t offIgnore;
327 return RTFileSeek(pThis->hFile, cb, RTFILE_SEEK_CURRENT, &offIgnore);
328}
329
330
331/**
332 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
333 */
334static DECLCALLBACK(int) rtVfsStdFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
335{
336 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
337 if (fMask != ~RTFS_TYPE_MASK)
338 {
339#if 0
340 RTFMODE fCurMode;
341 int rc = RTFileGetMode(pThis->hFile, &fCurMode);
342 if (RT_FAILURE(rc))
343 return rc;
344 fMode |= ~fMask & fCurMode;
345#else
346 RTFSOBJINFO ObjInfo;
347 int rc = RTFileQueryInfo(pThis->hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
348 if (RT_FAILURE(rc))
349 return rc;
350 fMode |= ~fMask & ObjInfo.Attr.fMode;
351#endif
352 }
353 return RTFileSetMode(pThis->hFile, fMode);
354}
355
356
357/**
358 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
359 */
360static DECLCALLBACK(int) rtVfsStdFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
361 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
362{
363 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
364 return RTFileSetTimes(pThis->hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
365}
366
367
368/**
369 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
370 */
371static DECLCALLBACK(int) rtVfsStdFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
372{
373#if 0
374 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
375 return RTFileSetOwner(pThis->hFile, uid, gid);
376#else
377 NOREF(pvThis); NOREF(uid); NOREF(gid);
378 return VERR_NOT_IMPLEMENTED;
379#endif
380}
381
382
383/**
384 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
385 */
386static DECLCALLBACK(int) rtVfsStdFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
387{
388 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
389 uint64_t offActual = 0;
390 int rc = RTFileSeek(pThis->hFile, offSeek, uMethod, &offActual);
391 if (RT_SUCCESS(rc))
392 *poffActual = offActual;
393 return rc;
394}
395
396
397/**
398 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
399 */
400static DECLCALLBACK(int) rtVfsStdFile_QuerySize(void *pvThis, uint64_t *pcbFile)
401{
402 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
403 return RTFileQuerySize(pThis->hFile, pcbFile);
404}
405
406
407/**
408 * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
409 */
410static DECLCALLBACK(int) rtVfsStdFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
411{
412 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
413 switch (fFlags & RTVFSFILE_SIZE_F_ACTION_MASK)
414 {
415 case RTVFSFILE_SIZE_F_NORMAL:
416 return RTFileSetSize(pThis->hFile, cbFile);
417 case RTVFSFILE_SIZE_F_GROW:
418 return RTFileSetAllocationSize(pThis->hFile, cbFile, RTFILE_ALLOC_SIZE_F_DEFAULT);
419 case RTVFSFILE_SIZE_F_GROW_KEEP_SIZE:
420 return RTFileSetAllocationSize(pThis->hFile, cbFile, RTFILE_ALLOC_SIZE_F_KEEP_SIZE);
421 default:
422 return VERR_NOT_SUPPORTED;
423 }
424}
425
426
427/**
428 * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
429 */
430static DECLCALLBACK(int) rtVfsStdFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
431{
432 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
433 RTFOFF cbMax = 0;
434 int rc = RTFileQueryMaxSizeEx(pThis->hFile, &cbMax);
435 if (RT_SUCCESS(rc))
436 *pcbMax = cbMax;
437 return rc;
438}
439
440
441/**
442 * Standard file operations.
443 */
444DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsStdFileOps =
445{
446 { /* Stream */
447 { /* Obj */
448 RTVFSOBJOPS_VERSION,
449 RTVFSOBJTYPE_FILE,
450 "StdFile",
451 rtVfsStdFile_Close,
452 rtVfsStdFile_QueryInfo,
453 NULL,
454 RTVFSOBJOPS_VERSION
455 },
456 RTVFSIOSTREAMOPS_VERSION,
457 0,
458 rtVfsStdFile_Read,
459 rtVfsStdFile_Write,
460 rtVfsStdFile_Flush,
461 rtVfsStdFile_PollOne,
462 rtVfsStdFile_Tell,
463 rtVfsStdFile_Skip,
464 NULL /*ZeroFill*/,
465 RTVFSIOSTREAMOPS_VERSION,
466 },
467 RTVFSFILEOPS_VERSION,
468 0,
469 { /* ObjSet */
470 RTVFSOBJSETOPS_VERSION,
471 RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
472 rtVfsStdFile_SetMode,
473 rtVfsStdFile_SetTimes,
474 rtVfsStdFile_SetOwner,
475 RTVFSOBJSETOPS_VERSION
476 },
477 rtVfsStdFile_Seek,
478 rtVfsStdFile_QuerySize,
479 rtVfsStdFile_SetSize,
480 rtVfsStdFile_QueryMaxSize,
481 RTVFSFILEOPS_VERSION
482};
483
484
485/**
486 * Internal worker for RTVfsFileFromRTFile and RTVfsFileOpenNormal.
487 *
488 * @returns IRPT status code.
489 * @param hFile The IPRT file handle.
490 * @param fOpen The RTFILE_O_XXX flags.
491 * @param fLeaveOpen Whether to leave it open or close it.
492 * @param phVfsFile Where to return the handle.
493 */
494static int rtVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
495{
496 PRTVFSSTDFILE pThis;
497 RTVFSFILE hVfsFile;
498 int rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
499 &hVfsFile, (void **)&pThis);
500 if (RT_FAILURE(rc))
501 return rc;
502
503 pThis->hFile = hFile;
504 pThis->fLeaveOpen = fLeaveOpen;
505 *phVfsFile = hVfsFile;
506 return VINF_SUCCESS;
507}
508
509
510RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
511{
512 /*
513 * Check the handle validity.
514 */
515 RTFSOBJINFO ObjInfo;
516 int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
517 if (RT_FAILURE(rc))
518 return rc;
519
520 /*
521 * Set up some fake fOpen flags if necessary and create a VFS file handle.
522 */
523 if (!fOpen)
524 fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
525
526 return rtVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, phVfsFile);
527}
528
529
530RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
531{
532 /*
533 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
534 */
535 RTFILE hFile;
536 int rc = RTFileOpen(&hFile, pszFilename, fOpen);
537 if (RT_SUCCESS(rc))
538 {
539 /*
540 * Create a VFS file handle.
541 */
542 rc = rtVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
543 if (RT_FAILURE(rc))
544 RTFileClose(hFile);
545 }
546 return rc;
547}
548
549
550RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
551{
552 RTVFSFILE hVfsFile;
553 int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
554 if (RT_SUCCESS(rc))
555 {
556 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
557 RTVfsFileRelease(hVfsFile);
558 }
559 return rc;
560}
561
562
563RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
564{
565 RTVFSFILE hVfsFile;
566 int rc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
567 if (RT_SUCCESS(rc))
568 {
569 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
570 RTVfsFileRelease(hVfsFile);
571 }
572 return rc;
573}
574
575
576
577/**
578 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
579 */
580static DECLCALLBACK(int) rtVfsChainStdFile_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
581 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
582{
583 RT_NOREF(pProviderReg);
584
585 /*
586 * Basic checks.
587 */
588 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
589 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
590 if ( pElement->enmType != RTVFSOBJTYPE_FILE
591 && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
592 return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS;
593
594 /*
595 * Join common cause with the 'open' provider.
596 */
597 return RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo);
598}
599
600
601/**
602 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
603 */
604static DECLCALLBACK(int) rtVfsChainStdFile_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
605 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
606 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
607{
608 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
609 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
610
611 RTVFSFILE hVfsFile;
612 int rc = RTVfsFileOpenNormal(pElement->paArgs[0].psz, pElement->uProvider, &hVfsFile);
613 if (RT_SUCCESS(rc))
614 {
615 *phVfsObj = RTVfsObjFromFile(hVfsFile);
616 RTVfsFileRelease(hVfsFile);
617 if (*phVfsObj != NIL_RTVFSOBJ)
618 return VINF_SUCCESS;
619 rc = VERR_VFS_CHAIN_CAST_FAILED;
620 }
621 return rc;
622}
623
624
625/**
626 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
627 */
628static DECLCALLBACK(bool) rtVfsChainStdFile_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
629 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
630 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
631{
632 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
633 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
634 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
635 return true;
636 return false;
637}
638
639
640/** VFS chain element 'file'. */
641static RTVFSCHAINELEMENTREG g_rtVfsChainStdFileReg =
642{
643 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
644 /* fReserved = */ 0,
645 /* pszName = */ "stdfile",
646 /* ListEntry = */ { NULL, NULL },
647 /* pszHelp = */ "Open a real file, providing either a file or an I/O stream object. Initial element.\n"
648 "First argument is the filename path.\n"
649 "Second argument is access mode, optional: r, w, rw.\n"
650 "Third argument is open disposition, optional: create, create-replace, open, open-create, open-append, open-truncate.\n"
651 "Forth argument is file sharing, optional: nr, nw, nrw, d.",
652 /* pfnValidate = */ rtVfsChainStdFile_Validate,
653 /* pfnInstantiate = */ rtVfsChainStdFile_Instantiate,
654 /* pfnCanReuseElement = */ rtVfsChainStdFile_CanReuseElement,
655 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
656};
657
658RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdFileReg, rtVfsChainStdFileReg);
659
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