VirtualBox

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

Last change on this file since 99040 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

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