VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstdpipe.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: 10.1 KB
Line 
1/* $Id: vfsstdpipe.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Pipe I/O stream 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/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, PCRTSGBUF 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 pThis->offFakePos += pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
114 }
115 else
116 {
117 size_t cbSeg = 0;
118 size_t cbRead = 0;
119 size_t cbReadSeg = 0;
120 size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
121 rc = VINF_SUCCESS;
122
123 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
124 {
125 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
126 cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
127
128 cbReadSeg = cbSeg;
129 if (fBlocking)
130 rc = RTPipeReadBlocking(pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
131 else
132 rc = RTPipeRead( pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
133 if (RT_FAILURE(rc))
134 break;
135 pThis->offFakePos += pcbRead ? cbReadSeg : cbSeg;
136 cbRead += cbReadSeg;
137 if (rc != VINF_SUCCESS)
138 break;
139 AssertBreakStmt(!pcbRead || cbReadSeg == cbSeg, rc = VINF_TRY_AGAIN);
140 }
141
142 if (pcbRead)
143 *pcbRead = cbRead;
144 }
145
146 return rc;
147}
148
149
150/**
151 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
152 */
153static DECLCALLBACK(int) rtVfsStdPipe_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
154{
155 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
156 int rc;
157 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
158
159 if (pSgBuf->cSegs == 1)
160 {
161 if (fBlocking)
162 rc = RTPipeWriteBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
163 else
164 rc = RTPipeWrite( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
165 if (RT_SUCCESS(rc))
166 pThis->offFakePos += pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg;
167 }
168 else
169 {
170 size_t cbWritten = 0;
171 size_t cbWrittenSeg;
172 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
173 rc = VINF_SUCCESS;
174
175 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
176 {
177 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
178 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
179
180 cbWrittenSeg = 0;
181 if (fBlocking)
182 rc = RTPipeWriteBlocking(pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
183 else
184 rc = RTPipeWrite( pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
185 if (RT_FAILURE(rc))
186 break;
187 pThis->offFakePos += pcbWritten ? cbWrittenSeg : cbSeg;
188 if (pcbWritten)
189 {
190 cbWritten += cbWrittenSeg;
191 if (rc != VINF_SUCCESS)
192 break;
193 AssertStmt(cbWrittenSeg == cbSeg, rc = VINF_TRY_AGAIN);
194 }
195 else
196 AssertBreak(rc == VINF_SUCCESS);
197 }
198
199 if (pcbWritten)
200 *pcbWritten = cbWritten;
201 }
202
203 return rc;
204}
205
206
207/**
208 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
209 */
210static DECLCALLBACK(int) rtVfsStdPipe_Flush(void *pvThis)
211{
212 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
213 return RTPipeFlush(pThis->hPipe);
214}
215
216
217/**
218 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
219 */
220static DECLCALLBACK(int) rtVfsStdPipe_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
221 uint32_t *pfRetEvents)
222{
223 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
224 uint32_t const fPossibleEvt = pThis->fReadPipe ? RTPOLL_EVT_READ : RTPOLL_EVT_WRITE;
225
226 int rc = RTPipeSelectOne(pThis->hPipe, cMillies);
227 if (RT_SUCCESS(rc))
228 {
229 if (fEvents & fPossibleEvt)
230 *pfRetEvents = fPossibleEvt;
231 else
232 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
233 }
234 else if ( rc != VERR_TIMEOUT
235 && rc != VERR_INTERRUPTED
236 && rc != VERR_TRY_AGAIN /* paranoia */)
237 {
238 *pfRetEvents = RTPOLL_EVT_ERROR;
239 rc = VINF_SUCCESS;
240 }
241
242 return rc;
243}
244
245
246/**
247 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
248 */
249static DECLCALLBACK(int) rtVfsStdPipe_Tell(void *pvThis, PRTFOFF poffActual)
250{
251 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
252 *poffActual = pThis->offFakePos;
253 return VINF_SUCCESS;
254}
255
256
257/**
258 * Standard pipe operations.
259 */
260DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfsStdPipeOps =
261{
262 { /* Obj */
263 RTVFSOBJOPS_VERSION,
264 RTVFSOBJTYPE_IO_STREAM,
265 "StdFile",
266 rtVfsStdPipe_Close,
267 rtVfsStdPipe_QueryInfo,
268 NULL,
269 RTVFSOBJOPS_VERSION
270 },
271 RTVFSIOSTREAMOPS_VERSION,
272 0,
273 rtVfsStdPipe_Read,
274 rtVfsStdPipe_Write,
275 rtVfsStdPipe_Flush,
276 rtVfsStdPipe_PollOne,
277 rtVfsStdPipe_Tell,
278 NULL /*rtVfsStdPipe_Skip*/,
279 NULL /*ZeroFill*/,
280 RTVFSIOSTREAMOPS_VERSION,
281};
282
283
284/**
285 * Internal worker for RTVfsIosFromRTPipe and later some create API.
286 *
287 * @returns IRPT status code.
288 * @param hPipe The IPRT file handle.
289 * @param fOpen The RTFILE_O_XXX flags.
290 * @param fLeaveOpen Whether to leave it open or close it.
291 * @param phVfsFile Where to return the handle.
292 */
293static int rtVfsFileFromRTPipe(RTPIPE hPipe, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
294{
295 PRTVFSSTDPIPE pThis;
296 RTVFSIOSTREAM hVfsIos;
297 int rc = RTVfsNewIoStream(&g_rtVfsStdPipeOps, sizeof(RTVFSSTDPIPE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
298 &hVfsIos, (void **)&pThis);
299 if (RT_FAILURE(rc))
300 return rc;
301
302 pThis->hPipe = hPipe;
303 pThis->fLeaveOpen = fLeaveOpen;
304 *phVfsIos = hVfsIos;
305 return VINF_SUCCESS;
306}
307
308
309RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
310{
311 /*
312 * Check the handle validity and read/write mode, then create a stream for it.
313 */
314 RTFSOBJINFO ObjInfo;
315 int rc = RTPipeQueryInfo(hPipe, &ObjInfo, RTFSOBJATTRADD_NOTHING);
316 if (RT_SUCCESS(rc))
317 rc = rtVfsFileFromRTPipe(hPipe,
318 ObjInfo.Attr.fMode & RTFS_DOS_READONLY ? RTFILE_O_READ : RTFILE_O_WRITE,
319 fLeaveOpen, phVfsIos);
320 return rc;
321}
322
323/** @todo Create pipe API? */
324
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