VirtualBox

source: vbox/trunk/src/VBox/Storage/VDIfVfs.cpp@ 62482

Last change on this file since 62482 was 62482, 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: 11.6 KB
Line 
1/* $Id: VDIfVfs.cpp 62482 2016-07-22 18:30:37Z vboxsync $ */
2/** @file
3 * Virtual Disk Image (VDI), I/O interface to IPRT VFS I/O stream glue.
4 */
5
6/*
7 * Copyright (C) 2012-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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/types.h>
23#include <iprt/assert.h>
24#include <iprt/mem.h>
25#include <iprt/err.h>
26#include <iprt/asm.h>
27#include <iprt/string.h>
28#include <iprt/file.h>
29#include <iprt/sg.h>
30#include <iprt/vfslowlevel.h>
31#include <iprt/poll.h>
32#include <VBox/vd.h>
33#include <VBox/vd-ifs-internal.h>
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39
40/**
41 * The internal data of an VD I/O to VFS file or I/O stream wrapper.
42 */
43typedef struct VDIFVFSIOSFILE
44{
45 /** The VD I/O interface we prefer wrap.
46 * Can be NULL, in which case pVDIfsIoInt must be valid. */
47 PVDINTERFACEIO pVDIfsIo;
48 /** The VD I/O interface we alternatively can wrap.
49 Can be NULL, in which case pVDIfsIo must be valid. */
50 PVDINTERFACEIOINT pVDIfsIoInt;
51 /** User pointer to pass to the VD I/O interface methods. */
52 PVDIOSTORAGE pStorage;
53 /** The current stream position. */
54 RTFOFF offCurPos;
55} VDIFVFSIOSFILE;
56/** Pointer to a the internal data of a DVM volume file. */
57typedef VDIFVFSIOSFILE *PVDIFVFSIOSFILE;
58
59
60
61/**
62 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
63 */
64static DECLCALLBACK(int) vdIfVfsIos_Close(void *pvThis)
65{
66 /* We don't close anything. */
67 return VINF_SUCCESS;
68}
69
70
71/**
72 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
73 */
74static DECLCALLBACK(int) vdIfVfsIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
75{
76 NOREF(pvThis);
77 NOREF(pObjInfo);
78 NOREF(enmAddAttr);
79 return VERR_NOT_SUPPORTED;
80}
81
82
83/**
84 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
85 */
86static DECLCALLBACK(int) vdIfVfsIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
87{
88 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
89 Assert(pSgBuf->cSegs == 1); NOREF(fBlocking);
90 Assert(off >= -1);
91
92 /*
93 * This may end up being a little more complicated, esp. wrt VERR_EOF.
94 */
95 if (off == -1)
96 off = pThis->offCurPos;
97 int rc;
98 if (pThis->pVDIfsIo)
99 rc = vdIfIoFileReadSync(pThis->pVDIfsIo, pThis->pStorage, off, pSgBuf[0].pvSegCur, pSgBuf->paSegs[0].cbSeg, pcbRead);
100 else
101 {
102 rc = vdIfIoIntFileReadSync(pThis->pVDIfsIoInt, (PVDIOSTORAGE)pThis->pStorage, off, pSgBuf[0].pvSegCur, pSgBuf->paSegs[0].cbSeg);
103 if (pcbRead)
104 *pcbRead = RT_SUCCESS(rc) ? pSgBuf->paSegs[0].cbSeg : 0;
105 }
106 if (RT_SUCCESS(rc))
107 {
108 size_t cbAdvance = pcbRead ? *pcbRead : pSgBuf->paSegs[0].cbSeg;
109 pThis->offCurPos = off + cbAdvance;
110 if (pcbRead && !cbAdvance)
111 rc = VINF_EOF;
112 }
113 return rc;
114}
115
116
117/**
118 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
119 */
120static DECLCALLBACK(int) vdIfVfsIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
121{
122 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
123 Assert(pSgBuf->cSegs == 1); NOREF(fBlocking);
124 Assert(off >= -1);
125
126 /*
127 * This may end up being a little more complicated, esp. wrt VERR_EOF.
128 */
129 if (off == -1)
130 off = pThis->offCurPos;
131 int rc;
132 if (pThis->pVDIfsIo)
133 rc = vdIfIoFileWriteSync(pThis->pVDIfsIo, pThis->pStorage, off, pSgBuf[0].pvSegCur, pSgBuf->paSegs[0].cbSeg, pcbWritten);
134 else
135 {
136 rc = vdIfIoIntFileWriteSync(pThis->pVDIfsIoInt, pThis->pStorage, off, pSgBuf[0].pvSegCur, pSgBuf->paSegs[0].cbSeg);
137 if (pcbWritten)
138 *pcbWritten = RT_SUCCESS(rc) ? pSgBuf->paSegs[0].cbSeg : 0;
139 }
140 if (RT_SUCCESS(rc))
141 pThis->offCurPos = off + (pcbWritten ? *pcbWritten : pSgBuf->paSegs[0].cbSeg);
142 return rc;
143}
144
145
146/**
147 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
148 */
149static DECLCALLBACK(int) vdIfVfsIos_Flush(void *pvThis)
150{
151 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
152 int rc;
153 if (pThis->pVDIfsIo)
154 rc = vdIfIoFileFlushSync(pThis->pVDIfsIo, pThis->pStorage);
155 else
156 rc = vdIfIoIntFileFlushSync(pThis->pVDIfsIoInt, pThis->pStorage);
157 return rc;
158}
159
160
161/**
162 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
163 */
164static DECLCALLBACK(int) vdIfVfsIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
165 uint32_t *pfRetEvents)
166{
167 NOREF(pvThis);
168 int rc;
169 if (fEvents != RTPOLL_EVT_ERROR)
170 {
171 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
172 rc = VINF_SUCCESS;
173 }
174 else
175 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
176 return rc;
177}
178
179
180/**
181 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
182 */
183static DECLCALLBACK(int) vdIfVfsIos_Tell(void *pvThis, PRTFOFF poffActual)
184{
185 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
186 *poffActual = pThis->offCurPos;
187 return VINF_SUCCESS;
188}
189
190
191/**
192 * VFS I/O stream operations for a VD file or stream.
193 */
194DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_vdIfVfsIosOps =
195{
196 { /* Obj */
197 RTVFSOBJOPS_VERSION,
198 RTVFSOBJTYPE_IO_STREAM,
199 "VDIfIos",
200 vdIfVfsIos_Close,
201 vdIfVfsIos_QueryInfo,
202 RTVFSOBJOPS_VERSION
203 },
204 RTVFSIOSTREAMOPS_VERSION,
205 RTVFSIOSTREAMOPS_FEAT_NO_SG,
206 vdIfVfsIos_Read,
207 vdIfVfsIos_Write,
208 vdIfVfsIos_Flush,
209 vdIfVfsIos_PollOne,
210 vdIfVfsIos_Tell,
211 NULL /*Skip*/,
212 NULL /*ZeroFill*/,
213 RTVFSIOSTREAMOPS_VERSION,
214
215};
216
217VBOXDDU_DECL(int) VDIfCreateVfsStream(PVDINTERFACEIO pVDIfsIo, void *pvStorage, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
218{
219 AssertPtrReturn(pVDIfsIo, VERR_INVALID_HANDLE);
220 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
221
222 /*
223 * Create the volume file.
224 */
225 RTVFSIOSTREAM hVfsIos;
226 PVDIFVFSIOSFILE pThis;
227 int rc = RTVfsNewIoStream(&g_vdIfVfsIosOps, sizeof(*pThis), fFlags,
228 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsIos, (void **)&pThis);
229 if (RT_SUCCESS(rc))
230 {
231 pThis->pVDIfsIo = pVDIfsIo;
232 pThis->pVDIfsIoInt = NULL;
233 pThis->pStorage = (PVDIOSTORAGE)pvStorage;
234 pThis->offCurPos = 0;
235
236 *phVfsIos = hVfsIos;
237 return VINF_SUCCESS;
238 }
239
240 return rc;
241}
242
243
244
245/**
246 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetMode}
247 */
248static DECLCALLBACK(int) vdIfVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
249{
250 NOREF(pvThis);
251 NOREF(fMode);
252 NOREF(fMask);
253 return VERR_NOT_SUPPORTED;
254}
255
256
257/**
258 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
259 */
260static DECLCALLBACK(int) vdIfVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
261 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
262{
263 NOREF(pvThis);
264 NOREF(pAccessTime);
265 NOREF(pModificationTime);
266 NOREF(pChangeTime);
267 NOREF(pBirthTime);
268 return VERR_NOT_SUPPORTED;
269}
270
271
272/**
273 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
274 */
275static DECLCALLBACK(int) vdIfVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
276{
277 NOREF(pvThis);
278 NOREF(uid);
279 NOREF(gid);
280 return VERR_NOT_SUPPORTED;
281}
282
283
284/**
285 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
286 */
287static DECLCALLBACK(int) vdIfVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
288{
289 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
290
291 uint64_t cbFile;
292 int rc;
293 if (pThis->pVDIfsIo)
294 rc = vdIfIoFileGetSize(pThis->pVDIfsIo, pThis->pStorage, &cbFile);
295 else
296 rc = vdIfIoIntFileGetSize(pThis->pVDIfsIoInt, pThis->pStorage, &cbFile);
297 if (RT_FAILURE(rc))
298 return rc;
299 if (cbFile >= (uint64_t)RTFOFF_MAX)
300 cbFile = RTFOFF_MAX;
301
302 /* Recalculate the request to RTFILE_SEEK_BEGIN. */
303 switch (uMethod)
304 {
305 case RTFILE_SEEK_BEGIN:
306 break;
307 case RTFILE_SEEK_CURRENT:
308 offSeek += pThis->offCurPos;
309 break;
310 case RTFILE_SEEK_END:
311 offSeek = cbFile + offSeek;
312 break;
313 default:
314 AssertFailedReturn(VERR_INVALID_PARAMETER);
315 }
316
317 /* Do limit checks. */
318 if (offSeek < 0)
319 offSeek = 0;
320 else if (offSeek > (RTFOFF)cbFile)
321 offSeek = cbFile;
322
323 /* Apply and return. */
324 pThis->offCurPos = offSeek;
325 if (poffActual)
326 *poffActual = offSeek;
327
328 return VINF_SUCCESS;
329}
330
331
332/**
333 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
334 */
335static DECLCALLBACK(int) vdIfVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
336{
337 PVDIFVFSIOSFILE pThis = (PVDIFVFSIOSFILE)pvThis;
338 int rc;
339 if (pThis->pVDIfsIo)
340 rc = vdIfIoFileGetSize(pThis->pVDIfsIo, pThis->pStorage, pcbFile);
341 else
342 rc = vdIfIoIntFileGetSize(pThis->pVDIfsIoInt, pThis->pStorage, pcbFile);
343 return rc;
344}
345
346
347
348/**
349 * VFS file operations for a VD file.
350 */
351DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_vdIfVfsFileOps =
352{
353 { /* I/O stream */
354 { /* Obj */
355 RTVFSOBJOPS_VERSION,
356 RTVFSOBJTYPE_FILE,
357 "VDIfFile",
358 vdIfVfsIos_Close,
359 vdIfVfsIos_QueryInfo,
360 RTVFSOBJOPS_VERSION
361 },
362 RTVFSIOSTREAMOPS_VERSION,
363 RTVFSIOSTREAMOPS_FEAT_NO_SG,
364 vdIfVfsIos_Read,
365 vdIfVfsIos_Write,
366 vdIfVfsIos_Flush,
367 vdIfVfsIos_PollOne,
368 vdIfVfsIos_Tell,
369 NULL /*Skip*/,
370 NULL /*ZeroFill*/,
371 RTVFSIOSTREAMOPS_VERSION,
372 },
373 RTVFSFILEOPS_VERSION,
374 0,
375 { /* ObjSet */
376 RTVFSOBJSETOPS_VERSION,
377 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
378 vdIfVfsFile_SetMode,
379 vdIfVfsFile_SetTimes,
380 vdIfVfsFile_SetOwner,
381 RTVFSOBJSETOPS_VERSION
382 },
383 vdIfVfsFile_Seek,
384 vdIfVfsFile_QuerySize,
385 RTVFSFILEOPS_VERSION,
386};
387
388
389VBOXDDU_DECL(int) VDIfCreateVfsFile(PVDINTERFACEIO pVDIfs, struct VDINTERFACEIOINT *pVDIfsInt, void *pvStorage, uint32_t fFlags, PRTVFSFILE phVfsFile)
390{
391 AssertReturn((pVDIfs != NULL) != (pVDIfsInt != NULL), VERR_INVALID_PARAMETER); /* Exactly one needs to be specified. */
392 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
393
394 /*
395 * Create the volume file.
396 */
397 RTVFSFILE hVfsFile;
398 PVDIFVFSIOSFILE pThis;
399 int rc = RTVfsNewFile(&g_vdIfVfsFileOps, sizeof(*pThis), fFlags,
400 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
401 if (RT_SUCCESS(rc))
402 {
403 pThis->pVDIfsIo = pVDIfs;
404 pThis->pVDIfsIoInt = pVDIfsInt;
405 pThis->pStorage = (PVDIOSTORAGE)pvStorage;
406 pThis->offCurPos = 0;
407
408 *phVfsFile = hVfsFile;
409 return VINF_SUCCESS;
410 }
411
412 return rc;
413}
414
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