VirtualBox

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

Last change on this file was 100908, checked in by vboxsync, 10 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: 10.4 KB
RevLine 
[33820]1/* $Id: vfsstdpipe.cpp 100908 2023-08-19 02:57:05Z vboxsync $ */
2/** @file
[57643]3 * IPRT - Virtual File System, Standard Pipe I/O stream Implementation.
[33820]4 */
5
6/*
[98103]7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
[33820]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[33820]11 *
[96407]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 *
[33820]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]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
[33820]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.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[33820]35 */
36
37
[57358]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[33820]41#include <iprt/vfs.h>
42#include <iprt/vfslowlevel.h>
43
[57643]44#include <iprt/assert.h>
[33820]45#include <iprt/err.h>
46#include <iprt/file.h>
[57643]47#include <iprt/pipe.h>
[33820]48#include <iprt/poll.h>
49
50
[57358]51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
[33820]54/**
[57643]55 * Private data of a standard pipe.
[33820]56 */
[57643]57typedef struct RTVFSSTDPIPE
[33820]58{
[57643]59 /** The pipe handle. */
60 RTPIPE hPipe;
[33820]61 /** Whether to leave the handle open when the VFS handle is closed. */
62 bool fLeaveOpen;
[57643]63 /** Set if primarily read, clear if write. */
64 bool fReadPipe;
65 /** Fake stream position. */
66 uint64_t offFakePos;
67} RTVFSSTDPIPE;
68/** Pointer to the private data of a standard pipe. */
69typedef RTVFSSTDPIPE *PRTVFSSTDPIPE;
[33820]70
71
72/**
73 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
74 */
[57643]75static DECLCALLBACK(int) rtVfsStdPipe_Close(void *pvThis)
[33820]76{
[57643]77 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
[33820]78
[86413]79 int rc = RTPipeCloseEx(pThis->hPipe, pThis->fLeaveOpen);
[57643]80 pThis->hPipe = NIL_RTPIPE;
[33820]81
82 return rc;
83}
84
85
86/**
87 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
88 */
[57643]89static DECLCALLBACK(int) rtVfsStdPipe_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
[33820]90{
[57643]91 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
92 return RTPipeQueryInfo(pThis->hPipe, pObjInfo, enmAddAttr);
[33820]93}
94
95
96/**
97 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
98 */
[100908]99static DECLCALLBACK(int) rtVfsStdPipe_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
[33820]100{
[57643]101 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
[33820]102 int rc;
[57644]103 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
[33820]104
105 NOREF(fBlocking);
106 if (pSgBuf->cSegs == 1)
107 {
[57643]108 if (fBlocking)
109 rc = RTPipeReadBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
[33820]110 else
[57643]111 rc = RTPipeRead( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
112 if (RT_SUCCESS(rc))
[100908]113 {
114 size_t const cbAdv = pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
115 pThis->offFakePos += cbAdv;
116 RTSgBufAdvance(pSgBuf, cbAdv);
117 }
[33820]118 }
119 else
120 {
121 size_t cbRead = 0;
[33903]122 size_t cbReadSeg = 0;
[57643]123 size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
[33821]124 rc = VINF_SUCCESS;
[33820]125
[100908]126 while (!RTSgBufIsAtEnd(pSgBuf))
[33820]127 {
[100908]128 size_t cbSeg = 0;
129 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
[33820]130
[33903]131 cbReadSeg = cbSeg;
[57643]132 if (fBlocking)
133 rc = RTPipeReadBlocking(pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
[33820]134 else
[57643]135 rc = RTPipeRead( pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
[33820]136 if (RT_FAILURE(rc))
137 break;
[100908]138
139 pThis->offFakePos += cbReadSeg;
140 cbRead += cbReadSeg;
141 RTSgBufAdvance(pSgBuf, cbReadSeg);
[57643]142 if (rc != VINF_SUCCESS)
[33903]143 break;
[57643]144 AssertBreakStmt(!pcbRead || cbReadSeg == cbSeg, rc = VINF_TRY_AGAIN);
[33820]145 }
146
147 if (pcbRead)
148 *pcbRead = cbRead;
149 }
150
151 return rc;
152}
153
154
155/**
156 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
157 */
[100908]158static DECLCALLBACK(int) rtVfsStdPipe_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
[33820]159{
[57643]160 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
[33820]161 int rc;
[57644]162 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
[33820]163
164 if (pSgBuf->cSegs == 1)
165 {
[57643]166 if (fBlocking)
167 rc = RTPipeWriteBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
[33820]168 else
[57643]169 rc = RTPipeWrite( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
170 if (RT_SUCCESS(rc))
[100908]171 {
172 size_t const cbAdv = pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg;
173 pThis->offFakePos += cbAdv;
174 RTSgBufAdvance(pSgBuf, cbAdv);
175 }
[33820]176 }
177 else
178 {
179 size_t cbWritten = 0;
180 size_t cbWrittenSeg;
181 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
[33821]182 rc = VINF_SUCCESS;
[33820]183
[100908]184 while (!RTSgBufIsAtEnd(pSgBuf))
[33820]185 {
[100908]186 size_t cbSeg = 0;
187 void const *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
[33820]188
189 cbWrittenSeg = 0;
[57643]190 if (fBlocking)
191 rc = RTPipeWriteBlocking(pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
[33820]192 else
[57643]193 rc = RTPipeWrite( pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
[33820]194 if (RT_FAILURE(rc))
195 break;
[100908]196
197 size_t const cbAdv = pcbWritten ? cbWrittenSeg : cbSeg;
198 pThis->offFakePos += cbAdv;
199 RTSgBufAdvance(pSgBuf, cbAdv);
200
[33820]201 if (pcbWritten)
202 {
203 cbWritten += cbWrittenSeg;
[57643]204 if (rc != VINF_SUCCESS)
[33820]205 break;
[57643]206 AssertStmt(cbWrittenSeg == cbSeg, rc = VINF_TRY_AGAIN);
[33820]207 }
[57643]208 else
209 AssertBreak(rc == VINF_SUCCESS);
[33820]210 }
211
212 if (pcbWritten)
213 *pcbWritten = cbWritten;
214 }
215
216 return rc;
217}
218
219
220/**
221 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
222 */
[57643]223static DECLCALLBACK(int) rtVfsStdPipe_Flush(void *pvThis)
[33820]224{
[57643]225 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
226 return RTPipeFlush(pThis->hPipe);
[33820]227}
228
229
230/**
231 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
232 */
[57643]233static DECLCALLBACK(int) rtVfsStdPipe_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
[33820]234 uint32_t *pfRetEvents)
235{
[57643]236 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
237 uint32_t const fPossibleEvt = pThis->fReadPipe ? RTPOLL_EVT_READ : RTPOLL_EVT_WRITE;
238
239 int rc = RTPipeSelectOne(pThis->hPipe, cMillies);
240 if (RT_SUCCESS(rc))
[33820]241 {
[57643]242 if (fEvents & fPossibleEvt)
243 *pfRetEvents = fPossibleEvt;
244 else
245 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
[33820]246 }
[57643]247 else if ( rc != VERR_TIMEOUT
248 && rc != VERR_INTERRUPTED
249 && rc != VERR_TRY_AGAIN /* paranoia */)
[33820]250 {
[57643]251 *pfRetEvents = RTPOLL_EVT_ERROR;
252 rc = VINF_SUCCESS;
[33820]253 }
[57643]254
[33820]255 return rc;
256}
257
258
259/**
260 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
261 */
[57643]262static DECLCALLBACK(int) rtVfsStdPipe_Tell(void *pvThis, PRTFOFF poffActual)
[33820]263{
[57643]264 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
265 *poffActual = pThis->offFakePos;
266 return VINF_SUCCESS;
[33820]267}
268
269
270/**
[57643]271 * Standard pipe operations.
[33859]272 */
[57643]273DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfsStdPipeOps =
[33859]274{
[57643]275 { /* Obj */
276 RTVFSOBJOPS_VERSION,
277 RTVFSOBJTYPE_IO_STREAM,
278 "StdFile",
279 rtVfsStdPipe_Close,
280 rtVfsStdPipe_QueryInfo,
[94291]281 NULL,
[57643]282 RTVFSOBJOPS_VERSION
[33820]283 },
[57643]284 RTVFSIOSTREAMOPS_VERSION,
[33820]285 0,
[57643]286 rtVfsStdPipe_Read,
287 rtVfsStdPipe_Write,
288 rtVfsStdPipe_Flush,
289 rtVfsStdPipe_PollOne,
290 rtVfsStdPipe_Tell,
291 NULL /*rtVfsStdPipe_Skip*/,
292 NULL /*ZeroFill*/,
293 RTVFSIOSTREAMOPS_VERSION,
[33820]294};
295
296
[47356]297/**
[57643]298 * Internal worker for RTVfsIosFromRTPipe and later some create API.
[47356]299 *
300 * @returns IRPT status code.
[57643]301 * @param hPipe The IPRT file handle.
[47356]302 * @param fOpen The RTFILE_O_XXX flags.
303 * @param fLeaveOpen Whether to leave it open or close it.
304 * @param phVfsFile Where to return the handle.
305 */
[57643]306static int rtVfsFileFromRTPipe(RTPIPE hPipe, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
[47356]307{
[57643]308 PRTVFSSTDPIPE pThis;
309 RTVFSIOSTREAM hVfsIos;
310 int rc = RTVfsNewIoStream(&g_rtVfsStdPipeOps, sizeof(RTVFSSTDPIPE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
311 &hVfsIos, (void **)&pThis);
[47356]312 if (RT_FAILURE(rc))
313 return rc;
314
[57643]315 pThis->hPipe = hPipe;
[47356]316 pThis->fLeaveOpen = fLeaveOpen;
[57643]317 *phVfsIos = hVfsIos;
[47356]318 return VINF_SUCCESS;
319}
320
321
[57643]322RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
[33820]323{
324 /*
[57643]325 * Check the handle validity and read/write mode, then create a stream for it.
[33820]326 */
327 RTFSOBJINFO ObjInfo;
[57643]328 int rc = RTPipeQueryInfo(hPipe, &ObjInfo, RTFSOBJATTRADD_NOTHING);
[47356]329 if (RT_SUCCESS(rc))
[57643]330 rc = rtVfsFileFromRTPipe(hPipe,
331 ObjInfo.Attr.fMode & RTFS_DOS_READONLY ? RTFILE_O_READ : RTFILE_O_WRITE,
332 fLeaveOpen, phVfsIos);
[47356]333 return rc;
[33820]334}
335
[57643]336/** @todo Create pipe API? */
[33973]337
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use