VirtualBox

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

Last change on this file since 73097 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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