VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstdfile.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: 20.9 KB
Line 
1/* $Id: vfsstdfile.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard File Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-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#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, PCRTSGBUF 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 if (off < 0)
153 rc = RTFileRead( pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
154 else
155 {
156 rc = RTFileReadAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
157 if (RT_SUCCESS(rc)) /* RTFileReadAt() doesn't increment the file-position indicator on some platforms */
158 rc = RTFileSeek(pThis->hFile, off + (pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg), RTFILE_SEEK_BEGIN, NULL);
159 }
160 if (rc == VINF_SUCCESS && pcbRead)
161 rc = rtVfsStdFile_ReadFixRC(pThis, off, pSgBuf->paSegs[0].cbSeg, *pcbRead);
162 }
163 else
164 {
165 size_t cbSeg = 0;
166 size_t cbRead = 0;
167 size_t cbReadSeg = 0;
168 rc = VINF_SUCCESS;
169
170 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
171 {
172 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
173 cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
174
175 cbReadSeg = cbSeg;
176 if (off < 0)
177 rc = RTFileRead( pThis->hFile, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
178 else
179 {
180 rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
181 if (RT_SUCCESS(rc)) /* RTFileReadAt() doesn't increment the file-position indicator on some platforms */
182 rc = RTFileSeek(pThis->hFile, off + cbReadSeg, RTFILE_SEEK_BEGIN, NULL);
183 }
184 if (RT_FAILURE(rc))
185 break;
186 if (off >= 0)
187 off += cbReadSeg;
188 cbRead += cbReadSeg;
189 if ((pcbRead && cbReadSeg != cbSeg) || rc != VINF_SUCCESS)
190 break;
191 }
192
193 if (pcbRead)
194 {
195 *pcbRead = cbRead;
196 if (rc == VINF_SUCCESS)
197 rc = rtVfsStdFile_ReadFixRC(pThis, off, cbSeg, cbReadSeg);
198 }
199 }
200
201 return rc;
202}
203
204
205/**
206 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
207 */
208static DECLCALLBACK(int) rtVfsStdFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
209{
210 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
211 int rc;
212
213 NOREF(fBlocking);
214 if (pSgBuf->cSegs == 1)
215 {
216 if (off < 0)
217 rc = RTFileWrite(pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
218 else
219 {
220 rc = RTFileWriteAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
221 if (RT_SUCCESS(rc)) /* RTFileWriteAt() doesn't increment the file-position indicator on some platforms */
222 rc = RTFileSeek(pThis->hFile, off + (pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg), RTFILE_SEEK_BEGIN,
223 NULL);
224 }
225 }
226 else
227 {
228 size_t cbWritten = 0;
229 size_t cbWrittenSeg;
230 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
231 rc = VINF_SUCCESS;
232
233 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
234 {
235 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
236 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
237
238 cbWrittenSeg = 0;
239 if (off < 0)
240 rc = RTFileWrite(pThis->hFile, pvSeg, cbSeg, pcbWrittenSeg);
241 else
242 {
243 rc = RTFileWriteAt(pThis->hFile, off, pvSeg, cbSeg, pcbWrittenSeg);
244 if (RT_SUCCESS(rc))
245 {
246 off += pcbWrittenSeg ? *pcbWrittenSeg : cbSeg;
247 /* RTFileWriteAt() doesn't increment the file-position indicator on some platforms */
248 rc = RTFileSeek(pThis->hFile, off, RTFILE_SEEK_BEGIN, NULL);
249 }
250 }
251 if (RT_FAILURE(rc))
252 break;
253 if (pcbWritten)
254 {
255 cbWritten += cbWrittenSeg;
256 if (cbWrittenSeg != cbSeg)
257 break;
258 }
259 }
260
261 if (pcbWritten)
262 *pcbWritten = cbWritten;
263 }
264
265 return rc;
266}
267
268
269/**
270 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
271 */
272static DECLCALLBACK(int) rtVfsStdFile_Flush(void *pvThis)
273{
274 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
275 int rc = RTFileFlush(pThis->hFile);
276#ifdef RT_OS_WINDOWS
277 /* Workaround for console handles. */ /** @todo push this further down? */
278 if ( rc == VERR_INVALID_HANDLE
279 && RTFileIsValid(pThis->hFile))
280 rc = VINF_NOT_SUPPORTED; /* not flushable */
281#endif
282 return rc;
283}
284
285
286/**
287 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
288 */
289static DECLCALLBACK(int) rtVfsStdFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
290 uint32_t *pfRetEvents)
291{
292 NOREF(pvThis);
293 int rc;
294 if (fEvents != RTPOLL_EVT_ERROR)
295 {
296 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
297 rc = VINF_SUCCESS;
298 }
299 else if (fIntr)
300 rc = RTThreadSleep(cMillies);
301 else
302 {
303 uint64_t uMsStart = RTTimeMilliTS();
304 do
305 rc = RTThreadSleep(cMillies);
306 while ( rc == VERR_INTERRUPTED
307 && !fIntr
308 && RTTimeMilliTS() - uMsStart < cMillies);
309 if (rc == VERR_INTERRUPTED)
310 rc = VERR_TIMEOUT;
311 }
312 return rc;
313}
314
315
316/**
317 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
318 */
319static DECLCALLBACK(int) rtVfsStdFile_Tell(void *pvThis, PRTFOFF poffActual)
320{
321 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
322 uint64_t offActual;
323 int rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &offActual);
324 if (RT_SUCCESS(rc))
325 *poffActual = (RTFOFF)offActual;
326 return rc;
327}
328
329
330/**
331 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
332 */
333static DECLCALLBACK(int) rtVfsStdFile_Skip(void *pvThis, RTFOFF cb)
334{
335 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
336 uint64_t offIgnore;
337 return RTFileSeek(pThis->hFile, cb, RTFILE_SEEK_CURRENT, &offIgnore);
338}
339
340
341/**
342 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
343 */
344static DECLCALLBACK(int) rtVfsStdFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
345{
346 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
347 if (fMask != ~RTFS_TYPE_MASK)
348 {
349#if 0
350 RTFMODE fCurMode;
351 int rc = RTFileGetMode(pThis->hFile, &fCurMode);
352 if (RT_FAILURE(rc))
353 return rc;
354 fMode |= ~fMask & fCurMode;
355#else
356 RTFSOBJINFO ObjInfo;
357 int rc = RTFileQueryInfo(pThis->hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
358 if (RT_FAILURE(rc))
359 return rc;
360 fMode |= ~fMask & ObjInfo.Attr.fMode;
361#endif
362 }
363 return RTFileSetMode(pThis->hFile, fMode);
364}
365
366
367/**
368 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
369 */
370static DECLCALLBACK(int) rtVfsStdFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
371 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
372{
373 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
374 return RTFileSetTimes(pThis->hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
375}
376
377
378/**
379 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
380 */
381static DECLCALLBACK(int) rtVfsStdFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
382{
383#if 0
384 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
385 return RTFileSetOwner(pThis->hFile, uid, gid);
386#else
387 NOREF(pvThis); NOREF(uid); NOREF(gid);
388 return VERR_NOT_IMPLEMENTED;
389#endif
390}
391
392
393/**
394 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
395 */
396static DECLCALLBACK(int) rtVfsStdFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
397{
398 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
399 uint64_t offActual = 0;
400 int rc = RTFileSeek(pThis->hFile, offSeek, uMethod, &offActual);
401 if (RT_SUCCESS(rc))
402 *poffActual = offActual;
403 return rc;
404}
405
406
407/**
408 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
409 */
410static DECLCALLBACK(int) rtVfsStdFile_QuerySize(void *pvThis, uint64_t *pcbFile)
411{
412 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
413 return RTFileQuerySize(pThis->hFile, pcbFile);
414}
415
416
417/**
418 * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
419 */
420static DECLCALLBACK(int) rtVfsStdFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
421{
422 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
423 switch (fFlags & RTVFSFILE_SIZE_F_ACTION_MASK)
424 {
425 case RTVFSFILE_SIZE_F_NORMAL:
426 return RTFileSetSize(pThis->hFile, cbFile);
427 case RTVFSFILE_SIZE_F_GROW:
428 return RTFileSetAllocationSize(pThis->hFile, cbFile, RTFILE_ALLOC_SIZE_F_DEFAULT);
429 case RTVFSFILE_SIZE_F_GROW_KEEP_SIZE:
430 return RTFileSetAllocationSize(pThis->hFile, cbFile, RTFILE_ALLOC_SIZE_F_KEEP_SIZE);
431 default:
432 return VERR_NOT_SUPPORTED;
433 }
434}
435
436
437/**
438 * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
439 */
440static DECLCALLBACK(int) rtVfsStdFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
441{
442 PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
443 RTFOFF cbMax = 0;
444 int rc = RTFileQueryMaxSizeEx(pThis->hFile, &cbMax);
445 if (RT_SUCCESS(rc))
446 *pcbMax = cbMax;
447 return rc;
448}
449
450
451/**
452 * Standard file operations.
453 */
454DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsStdFileOps =
455{
456 { /* Stream */
457 { /* Obj */
458 RTVFSOBJOPS_VERSION,
459 RTVFSOBJTYPE_FILE,
460 "StdFile",
461 rtVfsStdFile_Close,
462 rtVfsStdFile_QueryInfo,
463 NULL,
464 RTVFSOBJOPS_VERSION
465 },
466 RTVFSIOSTREAMOPS_VERSION,
467 0,
468 rtVfsStdFile_Read,
469 rtVfsStdFile_Write,
470 rtVfsStdFile_Flush,
471 rtVfsStdFile_PollOne,
472 rtVfsStdFile_Tell,
473 rtVfsStdFile_Skip,
474 NULL /*ZeroFill*/,
475 RTVFSIOSTREAMOPS_VERSION,
476 },
477 RTVFSFILEOPS_VERSION,
478 0,
479 { /* ObjSet */
480 RTVFSOBJSETOPS_VERSION,
481 RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
482 rtVfsStdFile_SetMode,
483 rtVfsStdFile_SetTimes,
484 rtVfsStdFile_SetOwner,
485 RTVFSOBJSETOPS_VERSION
486 },
487 rtVfsStdFile_Seek,
488 rtVfsStdFile_QuerySize,
489 rtVfsStdFile_SetSize,
490 rtVfsStdFile_QueryMaxSize,
491 RTVFSFILEOPS_VERSION
492};
493
494
495/**
496 * Internal worker for RTVfsFileFromRTFile and RTVfsFileOpenNormal.
497 *
498 * @returns IRPT status code.
499 * @param hFile The IPRT file handle.
500 * @param fOpen The RTFILE_O_XXX flags.
501 * @param fLeaveOpen Whether to leave it open or close it.
502 * @param phVfsFile Where to return the handle.
503 */
504static int rtVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
505{
506 PRTVFSSTDFILE pThis;
507 RTVFSFILE hVfsFile;
508 int rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
509 &hVfsFile, (void **)&pThis);
510 if (RT_FAILURE(rc))
511 return rc;
512
513 pThis->hFile = hFile;
514 pThis->fLeaveOpen = fLeaveOpen;
515 *phVfsFile = hVfsFile;
516 return VINF_SUCCESS;
517}
518
519
520RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
521{
522 /*
523 * Check the handle validity.
524 */
525 RTFSOBJINFO ObjInfo;
526 int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
527 if (RT_FAILURE(rc))
528 return rc;
529
530 /*
531 * Set up some fake fOpen flags if necessary and create a VFS file handle.
532 */
533 if (!fOpen)
534 fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
535
536 return rtVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, phVfsFile);
537}
538
539
540RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
541{
542 /*
543 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
544 */
545 RTFILE hFile;
546 int rc = RTFileOpen(&hFile, pszFilename, fOpen);
547 if (RT_SUCCESS(rc))
548 {
549 /*
550 * Create a VFS file handle.
551 */
552 rc = rtVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
553 if (RT_FAILURE(rc))
554 RTFileClose(hFile);
555 }
556 return rc;
557}
558
559
560RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
561{
562 RTVFSFILE hVfsFile;
563 int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
564 if (RT_SUCCESS(rc))
565 {
566 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
567 RTVfsFileRelease(hVfsFile);
568 }
569 return rc;
570}
571
572
573RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
574{
575 RTVFSFILE hVfsFile;
576 int rc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
577 if (RT_SUCCESS(rc))
578 {
579 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
580 RTVfsFileRelease(hVfsFile);
581 }
582 return rc;
583}
584
585
586
587/**
588 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
589 */
590static DECLCALLBACK(int) rtVfsChainStdFile_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
591 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
592{
593 RT_NOREF(pProviderReg);
594
595 /*
596 * Basic checks.
597 */
598 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
599 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
600 if ( pElement->enmType != RTVFSOBJTYPE_FILE
601 && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
602 return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS;
603
604 /*
605 * Join common cause with the 'open' provider.
606 */
607 return RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo);
608}
609
610
611/**
612 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
613 */
614static DECLCALLBACK(int) rtVfsChainStdFile_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
615 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
616 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
617{
618 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
619 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
620
621 RTVFSFILE hVfsFile;
622 int rc = RTVfsFileOpenNormal(pElement->paArgs[0].psz, pElement->uProvider, &hVfsFile);
623 if (RT_SUCCESS(rc))
624 {
625 *phVfsObj = RTVfsObjFromFile(hVfsFile);
626 RTVfsFileRelease(hVfsFile);
627 if (*phVfsObj != NIL_RTVFSOBJ)
628 return VINF_SUCCESS;
629 rc = VERR_VFS_CHAIN_CAST_FAILED;
630 }
631 return rc;
632}
633
634
635/**
636 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
637 */
638static DECLCALLBACK(bool) rtVfsChainStdFile_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
639 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
640 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
641{
642 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
643 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
644 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
645 return true;
646 return false;
647}
648
649
650/** VFS chain element 'file'. */
651static RTVFSCHAINELEMENTREG g_rtVfsChainStdFileReg =
652{
653 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
654 /* fReserved = */ 0,
655 /* pszName = */ "stdfile",
656 /* ListEntry = */ { NULL, NULL },
657 /* pszHelp = */ "Open a real file, providing either a file or an I/O stream object. Initial element.\n"
658 "First argument is the filename path.\n"
659 "Second argument is access mode, optional: r, w, rw.\n"
660 "Third argument is open disposition, optional: create, create-replace, open, open-create, open-append, open-truncate.\n"
661 "Forth argument is file sharing, optional: nr, nw, nrw, d.",
662 /* pfnValidate = */ rtVfsChainStdFile_Validate,
663 /* pfnInstantiate = */ rtVfsChainStdFile_Instantiate,
664 /* pfnCanReuseElement = */ rtVfsChainStdFile_CanReuseElement,
665 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
666};
667
668RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdFileReg, rtVfsChainStdFileReg);
669
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