VirtualBox

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

Last change on this file since 62477 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: vfsstdpipe.cpp 62477 2016-07-22 18:27:37Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Pipe I/O stream Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2016 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/pipe.h>
38#include <iprt/poll.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Private data of a standard pipe.
46 */
47typedef struct RTVFSSTDPIPE
48{
49 /** The pipe handle. */
50 RTPIPE hPipe;
51 /** Whether to leave the handle open when the VFS handle is closed. */
52 bool fLeaveOpen;
53 /** Set if primarily read, clear if write. */
54 bool fReadPipe;
55 /** Fake stream position. */
56 uint64_t offFakePos;
57} RTVFSSTDPIPE;
58/** Pointer to the private data of a standard pipe. */
59typedef RTVFSSTDPIPE *PRTVFSSTDPIPE;
60
61
62/**
63 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
64 */
65static DECLCALLBACK(int) rtVfsStdPipe_Close(void *pvThis)
66{
67 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
68
69 int rc;
70 if (!pThis->fLeaveOpen)
71 rc = RTPipeClose(pThis->hPipe);
72 else
73 rc = VINF_SUCCESS;
74 pThis->hPipe = NIL_RTPIPE;
75
76 return rc;
77}
78
79
80/**
81 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
82 */
83static DECLCALLBACK(int) rtVfsStdPipe_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
84{
85 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
86 return RTPipeQueryInfo(pThis->hPipe, pObjInfo, enmAddAttr);
87}
88
89
90/**
91 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
92 */
93static DECLCALLBACK(int) rtVfsStdPipe_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
94{
95 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
96 int rc;
97 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
98
99 NOREF(fBlocking);
100 if (pSgBuf->cSegs == 1)
101 {
102 if (fBlocking)
103 rc = RTPipeReadBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
104 else
105 rc = RTPipeRead( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
106 if (RT_SUCCESS(rc))
107 pThis->offFakePos += pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
108 }
109 else
110 {
111 size_t cbSeg = 0;
112 size_t cbRead = 0;
113 size_t cbReadSeg = 0;
114 size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
115 rc = VINF_SUCCESS;
116
117 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
118 {
119 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
120 cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
121
122 cbReadSeg = cbSeg;
123 if (fBlocking)
124 rc = RTPipeReadBlocking(pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
125 else
126 rc = RTPipeRead( pThis->hPipe, pvSeg, cbSeg, pcbReadSeg);
127 if (RT_FAILURE(rc))
128 break;
129 pThis->offFakePos += pcbRead ? cbReadSeg : cbSeg;
130 cbRead += cbReadSeg;
131 if (rc != VINF_SUCCESS)
132 break;
133 AssertBreakStmt(!pcbRead || cbReadSeg == cbSeg, rc = VINF_TRY_AGAIN);
134 }
135
136 if (pcbRead)
137 *pcbRead = cbRead;
138 }
139
140 return rc;
141}
142
143
144/**
145 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
146 */
147static DECLCALLBACK(int) rtVfsStdPipe_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
148{
149 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
150 int rc;
151 AssertReturn(off < 0 || pThis->offFakePos == (uint64_t)off, VERR_SEEK_ON_DEVICE);
152
153 if (pSgBuf->cSegs == 1)
154 {
155 if (fBlocking)
156 rc = RTPipeWriteBlocking(pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
157 else
158 rc = RTPipeWrite( pThis->hPipe, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
159 if (RT_SUCCESS(rc))
160 pThis->offFakePos += pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg;
161 }
162 else
163 {
164 size_t cbWritten = 0;
165 size_t cbWrittenSeg;
166 size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
167 rc = VINF_SUCCESS;
168
169 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
170 {
171 void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
172 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
173
174 cbWrittenSeg = 0;
175 if (fBlocking)
176 rc = RTPipeWriteBlocking(pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
177 else
178 rc = RTPipeWrite( pThis->hPipe, pvSeg, cbSeg, pcbWrittenSeg);
179 if (RT_FAILURE(rc))
180 break;
181 pThis->offFakePos += pcbWritten ? cbWrittenSeg : cbSeg;
182 if (pcbWritten)
183 {
184 cbWritten += cbWrittenSeg;
185 if (rc != VINF_SUCCESS)
186 break;
187 AssertStmt(cbWrittenSeg == cbSeg, rc = VINF_TRY_AGAIN);
188 }
189 else
190 AssertBreak(rc == VINF_SUCCESS);
191 }
192
193 if (pcbWritten)
194 *pcbWritten = cbWritten;
195 }
196
197 return rc;
198}
199
200
201/**
202 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
203 */
204static DECLCALLBACK(int) rtVfsStdPipe_Flush(void *pvThis)
205{
206 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
207 return RTPipeFlush(pThis->hPipe);
208}
209
210
211/**
212 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
213 */
214static DECLCALLBACK(int) rtVfsStdPipe_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
215 uint32_t *pfRetEvents)
216{
217 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
218 uint32_t const fPossibleEvt = pThis->fReadPipe ? RTPOLL_EVT_READ : RTPOLL_EVT_WRITE;
219
220 int rc = RTPipeSelectOne(pThis->hPipe, cMillies);
221 if (RT_SUCCESS(rc))
222 {
223 if (fEvents & fPossibleEvt)
224 *pfRetEvents = fPossibleEvt;
225 else
226 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
227 }
228 else if ( rc != VERR_TIMEOUT
229 && rc != VERR_INTERRUPTED
230 && rc != VERR_TRY_AGAIN /* paranoia */)
231 {
232 *pfRetEvents = RTPOLL_EVT_ERROR;
233 rc = VINF_SUCCESS;
234 }
235
236 return rc;
237}
238
239
240/**
241 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
242 */
243static DECLCALLBACK(int) rtVfsStdPipe_Tell(void *pvThis, PRTFOFF poffActual)
244{
245 PRTVFSSTDPIPE pThis = (PRTVFSSTDPIPE)pvThis;
246 *poffActual = pThis->offFakePos;
247 return VINF_SUCCESS;
248}
249
250
251/**
252 * Standard pipe operations.
253 */
254DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfsStdPipeOps =
255{
256 { /* Obj */
257 RTVFSOBJOPS_VERSION,
258 RTVFSOBJTYPE_IO_STREAM,
259 "StdFile",
260 rtVfsStdPipe_Close,
261 rtVfsStdPipe_QueryInfo,
262 RTVFSOBJOPS_VERSION
263 },
264 RTVFSIOSTREAMOPS_VERSION,
265 0,
266 rtVfsStdPipe_Read,
267 rtVfsStdPipe_Write,
268 rtVfsStdPipe_Flush,
269 rtVfsStdPipe_PollOne,
270 rtVfsStdPipe_Tell,
271 NULL /*rtVfsStdPipe_Skip*/,
272 NULL /*ZeroFill*/,
273 RTVFSIOSTREAMOPS_VERSION,
274};
275
276
277/**
278 * Internal worker for RTVfsIosFromRTPipe and later some create API.
279 *
280 * @returns IRPT status code.
281 * @param hPipe The IPRT file handle.
282 * @param fOpen The RTFILE_O_XXX flags.
283 * @param fLeaveOpen Whether to leave it open or close it.
284 * @param phVfsFile Where to return the handle.
285 */
286static int rtVfsFileFromRTPipe(RTPIPE hPipe, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
287{
288 PRTVFSSTDPIPE pThis;
289 RTVFSIOSTREAM hVfsIos;
290 int rc = RTVfsNewIoStream(&g_rtVfsStdPipeOps, sizeof(RTVFSSTDPIPE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
291 &hVfsIos, (void **)&pThis);
292 if (RT_FAILURE(rc))
293 return rc;
294
295 pThis->hPipe = hPipe;
296 pThis->fLeaveOpen = fLeaveOpen;
297 *phVfsIos = hVfsIos;
298 return VINF_SUCCESS;
299}
300
301
302RTDECL(int) RTVfsIoStrmFromRTPipe(RTPIPE hPipe, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
303{
304 /*
305 * Check the handle validity and read/write mode, then create a stream for it.
306 */
307 RTFSOBJINFO ObjInfo;
308 int rc = RTPipeQueryInfo(hPipe, &ObjInfo, RTFSOBJATTRADD_NOTHING);
309 if (RT_SUCCESS(rc))
310 rc = rtVfsFileFromRTPipe(hPipe,
311 ObjInfo.Attr.fMode & RTFS_DOS_READONLY ? RTFILE_O_READ : RTFILE_O_WRITE,
312 fLeaveOpen, phVfsIos);
313 return rc;
314}
315
316/** @todo Create pipe API? */
317
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