VirtualBox

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

Last change on this file was 100908, checked in by vboxsync, 9 months ago

IPRT,Storage,Puel: Changed the pfnRead and pfnWrite VFS methods and the RTVfsIoStrmSgRead, RTVfsIoStrmSgWrite, RTVfsFileSgRead and RTVfsFileSgWrite APIs to advance pSgBuf and respect the incoming position just like RTFileSgRead & RTFileSgWrite.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use