VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstdpipe.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: 10.4 KB
Line 
1/* $Id: vfsstdpipe.cpp 100908 2023-08-19 02:57:05Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Pipe I/O stream 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/pipe.h>
48#include <iprt/poll.h>
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * Private data of a standard pipe.
56 */
57typedef struct RTVFSSTDPIPE
58{
59 /** The pipe handle. */
60 RTPIPE hPipe;
61 /** Whether to leave the handle open when the VFS handle is closed. */
62 bool fLeaveOpen;
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;
70
71
72/**
73 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
74 */
75static DECLCALLBACK(int) rtVfsStdPipe_Close(void *pvThis)
76{
77 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
78
79 int rc = RTPipeCloseEx(pThis->hPipe, pThis->fLeaveOpen);
80 pThis->hPipe = NIL_RTPIPE;
81
82 return rc;
83}
84
85
86/**
87 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
88 */
89static DECLCALLBACK(int) rtVfsStdPipe_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
90{
91 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
92 return RTPipeQueryInfo(pThis->hPipe, pObjInfo, enmAddAttr);
93}
94
95
96/**
97 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
98 */
99static DECLCALLBACK(int) rtVfsStdPipe_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
100{
101 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
102 int rc;
103 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
104
105 NOREF(fBlocking);
106 if (pSgBuf->cSegs == 1)
107 {
108 if (fBlocking)
109 rc = RTPipeReadBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
110 else
111 rc = RTPipeRead( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
112 if (RT_SUCCESS(rc))
113 {
114 size_t const cbAdv = pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
115 pThis->offFakePos += cbAdv;
116 RTSgBufAdvance(pSgBuf, cbAdv);
117 }
118 }
119 else
120 {
121 size_t cbRead = 0;
122 size_t cbReadSeg = 0;
123 size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
124 rc = VINF_SUCCESS;
125
126 while (!RTSgBufIsAtEnd(pSgBuf))
127 {
128 size_t cbSeg = 0;
129 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
130
131 cbReadSeg = cbSeg;
132 if (fBlocking)
133 rc = RTPipeReadBlocking(pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
134 else
135 rc = RTPipeRead( pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
136 if (RT_FAILURE(rc))
137 break;
138
139 pThis->offFakePos += cbReadSeg;
140 cbRead += cbReadSeg;
141 RTSgBufAdvance(pSgBuf, cbReadSeg);
142 if (rc != VINF_SUCCESS)
143 break;
144 AssertBreakStmt(!pcbRead || cbReadSeg == cbSeg, rc = VINF_TRY_AGAIN);
145 }
146
147 if (pcbRead)
148 *pcbRead = cbRead;
149 }
150
151 return rc;
152}
153
154
155/**
156 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
157 */
158static DECLCALLBACK(int) rtVfsStdPipe_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
159{
160 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
161 int rc;
162 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
163
164 if (pSgBuf->cSegs == 1)
165 {
166 if (fBlocking)
167 rc = RTPipeWriteBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
168 else
169 rc = RTPipeWrite( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
170 if (RT_SUCCESS(rc))
171 {
172 size_t const cbAdv = pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg;
173 pThis->offFakePos += cbAdv;
174 RTSgBufAdvance(pSgBuf, cbAdv);
175 }
176 }
177 else
178 {
179 size_t cbWritten = 0;
180 size_t cbWrittenSeg;
181 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
182 rc = VINF_SUCCESS;
183
184 while (!RTSgBufIsAtEnd(pSgBuf))
185 {
186 size_t cbSeg = 0;
187 void const *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &cbSeg);
188
189 cbWrittenSeg = 0;
190 if (fBlocking)
191 rc = RTPipeWriteBlocking(pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
192 else
193 rc = RTPipeWrite( pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
194 if (RT_FAILURE(rc))
195 break;
196
197 size_t const cbAdv = pcbWritten ? cbWrittenSeg : cbSeg;
198 pThis->offFakePos += cbAdv;
199 RTSgBufAdvance(pSgBuf, cbAdv);
200
201 if (pcbWritten)
202 {
203 cbWritten += cbWrittenSeg;
204 if (rc != VINF_SUCCESS)
205 break;
206 AssertStmt(cbWrittenSeg == cbSeg, rc = VINF_TRY_AGAIN);
207 }
208 else
209 AssertBreak(rc == VINF_SUCCESS);
210 }
211
212 if (pcbWritten)
213 *pcbWritten = cbWritten;
214 }
215
216 return rc;
217}
218
219
220/**
221 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
222 */
223static DECLCALLBACK(int) rtVfsStdPipe_Flush(void *pvThis)
224{
225 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
226 return RTPipeFlush(pThis->hPipe);
227}
228
229
230/**
231 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
232 */
233static DECLCALLBACK(int) rtVfsStdPipe_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
234 uint32_t *pfRetEvents)
235{
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))
241 {
242 if (fEvents & fPossibleEvt)
243 *pfRetEvents = fPossibleEvt;
244 else
245 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
246 }
247 else if ( rc != VERR_TIMEOUT
248 && rc != VERR_INTERRUPTED
249 && rc != VERR_TRY_AGAIN /* paranoia */)
250 {
251 *pfRetEvents = RTPOLL_EVT_ERROR;
252 rc = VINF_SUCCESS;
253 }
254
255 return rc;
256}
257
258
259/**
260 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
261 */
262static DECLCALLBACK(int) rtVfsStdPipe_Tell(void *pvThis, PRTFOFF poffActual)
263{
264 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
265 *poffActual = pThis->offFakePos;
266 return VINF_SUCCESS;
267}
268
269
270/**
271 * Standard pipe operations.
272 */
273DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfsStdPipeOps =
274{
275 { /* Obj */
276 RTVFSOBJOPS_VERSION,
277 RTVFSOBJTYPE_IO_STREAM,
278 "StdFile",
279 rtVfsStdPipe_Close,
280 rtVfsStdPipe_QueryInfo,
281 NULL,
282 RTVFSOBJOPS_VERSION
283 },
284 RTVFSIOSTREAMOPS_VERSION,
285 0,
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,
294};
295
296
297/**
298 * Internal worker for RTVfsIosFromRTPipe and later some create API.
299 *
300 * @returns IRPT status code.
301 * @param hPipe The IPRT file handle.
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 */
306static int rtVfsFileFromRTPipe(RTPIPE hPipe, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
307{
308 PRTVFSSTDPIPE pThis;
309 RTVFSIOSTREAM hVfsIos;
310 int rc = RTVfsNewIoStream(&g_rtVfsStdPipeOps, sizeof(RTVFSSTDPIPE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
311 &hVfsIos, (void **)&pThis);
312 if (RT_FAILURE(rc))
313 return rc;
314
315 pThis->hPipe = hPipe;
316 pThis->fLeaveOpen = fLeaveOpen;
317 *phVfsIos = hVfsIos;
318 return VINF_SUCCESS;
319}
320
321
322RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
323{
324 /*
325 * Check the handle validity and read/write mode, then create a stream for it.
326 */
327 RTFSOBJINFO ObjInfo;
328 int rc = RTPipeQueryInfo(hPipe, &ObjInfo, RTFSOBJATTRADD_NOTHING);
329 if (RT_SUCCESS(rc))
330 rc = rtVfsFileFromRTPipe(hPipe,
331 ObjInfo.Attr.fMode & RTFS_DOS_READONLY ? RTFILE_O_READ : RTFILE_O_WRITE,
332 fLeaveOpen, phVfsIos);
333 return rc;
334}
335
336/** @todo Create pipe API? */
337
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use