VirtualBox

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

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