VirtualBox

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

Last change on this file since 74888 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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