VirtualBox

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

Last change on this file since 50988 was 48957, checked in by vboxsync, 11 years ago

Storage: Whitespace cleanups by scm.

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