VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp@ 41234

Last change on this file since 41234 was 41094, checked in by vboxsync, 13 years ago

Runtime/Dvm: Glue for VFS

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: dvmvfs.cpp 41094 2012-04-29 22:07:23Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - VFS glue.
4 */
5
6/*
7 * Copyright (C) 2012 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/types.h>
32#include <iprt/assert.h>
33#include <iprt/mem.h>
34#include <iprt/dvm.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 "internal/dvm.h"
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47
48/**
49 * The internal data of a DVM volume I/O stream.
50 */
51typedef struct RTVFSDVMFILE
52{
53 /** The volume the VFS file belongs to. */
54 RTDVMVOLUME hVol;
55 /** Current position. */
56 uint64_t offCurPos;
57} RTVFSDVMFILE;
58/** Pointer to a the internal data of a DVM volume file. */
59typedef RTVFSDVMFILE *PRTVFSDVMFILE;
60
61
62/**
63 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
64 */
65static DECLCALLBACK(int) rtDvmVfsFile_Close(void *pvThis)
66{
67 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
68
69 RTDvmVolumeRelease(pThis->hVol);
70 return VINF_SUCCESS;
71}
72
73
74/**
75 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
76 */
77static DECLCALLBACK(int) rtDvmVfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
78{
79 NOREF(pvThis);
80 NOREF(pObjInfo);
81 NOREF(enmAddAttr);
82 return VERR_NOT_SUPPORTED;
83}
84
85
86/**
87 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
88 */
89static DECLCALLBACK(int) rtDvmVfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
90{
91 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
92 int rc = VINF_SUCCESS;
93
94 Assert(pSgBuf->cSegs == 1);
95 Assert(off < 0);
96 NOREF(fBlocking);
97
98 /*
99 * Find the current position and check if it's within the volume.
100 */
101 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
102 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
103 {
104 if (pcbRead)
105 {
106 *pcbRead = 0;
107 pThis->offCurPos = offUnsigned;
108 return VINF_EOF;
109 }
110 return VERR_EOF;
111 }
112
113 size_t cbLeftToRead;
114 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
115 {
116 if (!pcbRead)
117 return VERR_EOF;
118 *pcbRead = cbLeftToRead = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
119 }
120 else
121 {
122 cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
123 if (pcbRead)
124 *pcbRead = cbLeftToRead;
125 }
126
127 /*
128 * Ok, we've got a valid stretch within the file. Do the reading.
129 */
130 if (cbLeftToRead > 0)
131 {
132 rc = RTDvmVolumeRead(pThis->hVol, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbLeftToRead);
133 if (RT_SUCCESS(rc))
134 offUnsigned += cbLeftToRead;
135 }
136
137 pThis->offCurPos = offUnsigned;
138 return rc;
139}
140
141
142/**
143 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
144 */
145static DECLCALLBACK(int) rtDvmVfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
146{
147 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
148 int rc = VINF_SUCCESS;
149
150 Assert(pSgBuf->cSegs == 1);
151 Assert(off < 0);
152 NOREF(fBlocking);
153
154 /*
155 * Find the current position and check if it's within the volume.
156 * Writing beyond the end of a volume is not supported.
157 */
158 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
159 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
160 {
161 if (pcbWritten)
162 {
163 *pcbWritten = 0;
164 pThis->offCurPos = offUnsigned;
165 }
166 return VERR_NOT_SUPPORTED;
167 }
168
169 size_t cbLeftToWrite;
170 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
171 {
172 if (!pcbWritten)
173 return VERR_EOF;
174 *pcbWritten = cbLeftToWrite = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
175 }
176 else
177 {
178 cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
179 if (pcbWritten)
180 *pcbWritten = cbLeftToWrite;
181 }
182
183 /*
184 * Ok, we've got a valid stretch within the file. Do the reading.
185 */
186 if (cbLeftToWrite > 0)
187 {
188 rc = RTDvmVolumeWrite(pThis->hVol, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
189 if (RT_SUCCESS(rc))
190 offUnsigned += cbLeftToWrite;
191 }
192
193 pThis->offCurPos = offUnsigned;
194 return rc;
195}
196
197
198/**
199 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
200 */
201static DECLCALLBACK(int) rtDvmVfsFile_Flush(void *pvThis)
202{
203 NOREF(pvThis);
204 return VINF_SUCCESS; /* @todo: Implement missing DVM API. */
205}
206
207
208/**
209 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
210 */
211static DECLCALLBACK(int) rtDvmVfsFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
212 uint32_t *pfRetEvents)
213{
214 NOREF(pvThis);
215 int rc;
216 if (fEvents != RTPOLL_EVT_ERROR)
217 {
218 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
219 rc = VINF_SUCCESS;
220 }
221 else
222 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
223 return rc;
224}
225
226
227/**
228 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
229 */
230static DECLCALLBACK(int) rtDvmVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
231{
232 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
233 *poffActual = pThis->offCurPos;
234 return VINF_SUCCESS;
235}
236
237
238/**
239 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
240 */
241static DECLCALLBACK(int) rtDvmVfsFile_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) rtDvmVfsFile_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) rtDvmVfsFile_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) rtDvmVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
281{
282 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
283
284 /*
285 * Seek relative to which position.
286 */
287 uint64_t offWrt;
288 switch (uMethod)
289 {
290 case RTFILE_SEEK_BEGIN:
291 offWrt = 0;
292 break;
293
294 case RTFILE_SEEK_CURRENT:
295 offWrt = pThis->offCurPos;
296 break;
297
298 case RTFILE_SEEK_END:
299 offWrt = RTDvmVolumeGetSize(pThis->hVol);
300 break;
301
302 default:
303 return VERR_INTERNAL_ERROR_5;
304 }
305
306 /*
307 * Calc new position, take care to stay within bounds.
308 *
309 * @todo: Setting position beyond the end of the volume does not make sense.
310 */
311 uint64_t offNew;
312 if (offSeek == 0)
313 offNew = offWrt;
314 else if (offSeek > 0)
315 {
316 offNew = offWrt + offSeek;
317 if ( offNew < offWrt
318 || offNew > RTFOFF_MAX)
319 offNew = RTFOFF_MAX;
320 }
321 else if ((uint64_t)-offSeek < offWrt)
322 offNew = offWrt + offSeek;
323 else
324 offNew = 0;
325
326 /*
327 * Update the state and set return value.
328 */
329 pThis->offCurPos = offNew;
330
331 *poffActual = offNew;
332 return VINF_SUCCESS;
333}
334
335
336/**
337 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
338 */
339static DECLCALLBACK(int) rtDvmVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
340{
341 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
342 *pcbFile = RTDvmVolumeGetSize(pThis->hVol);
343 return VINF_SUCCESS;
344}
345
346
347/**
348 * Standard file operations.
349 */
350DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtDvmVfsStdFileOps =
351{
352 { /* Stream */
353 { /* Obj */
354 RTVFSOBJOPS_VERSION,
355 RTVFSOBJTYPE_FILE,
356 "DvmFile",
357 rtDvmVfsFile_Close,
358 rtDvmVfsFile_QueryInfo,
359 RTVFSOBJOPS_VERSION
360 },
361 RTVFSIOSTREAMOPS_VERSION,
362 RTVFSIOSTREAMOPS_FEAT_NO_SG,
363 rtDvmVfsFile_Read,
364 rtDvmVfsFile_Write,
365 rtDvmVfsFile_Flush,
366 rtDvmVfsFile_PollOne,
367 rtDvmVfsFile_Tell,
368 NULL /*Skip*/,
369 NULL /*ZeroFill*/,
370 RTVFSIOSTREAMOPS_VERSION,
371 },
372 RTVFSFILEOPS_VERSION,
373 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
374 { /* ObjSet */
375 RTVFSOBJSETOPS_VERSION,
376 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
377 rtDvmVfsFile_SetMode,
378 rtDvmVfsFile_SetTimes,
379 rtDvmVfsFile_SetOwner,
380 RTVFSOBJSETOPS_VERSION
381 },
382 rtDvmVfsFile_Seek,
383 rtDvmVfsFile_QuerySize,
384 RTVFSFILEOPS_VERSION
385};
386
387
388RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, PRTVFSFILE phVfsFileOut)
389{
390 AssertPtrReturn(hVol, VERR_INVALID_HANDLE);
391 AssertPtrReturn(phVfsFileOut, VERR_INVALID_POINTER);
392
393 uint32_t cRefs = RTDvmVolumeRetain(hVol);
394 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
395
396 /*
397 * Create the volume file.
398 */
399 RTVFSFILE hVfsFile;
400 PRTVFSDVMFILE pThis;
401 int rc = RTVfsNewFile(&g_rtDvmVfsStdFileOps, sizeof(*pThis), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE,
402 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
403 if (RT_SUCCESS(rc))
404 {
405 pThis->offCurPos = 0;
406 pThis->hVol = hVol;
407
408 *phVfsFileOut = hVfsFile;
409 return VINF_SUCCESS;
410 }
411 else
412 RTDvmVolumeRelease(hVol);
413 return rc;
414}
415
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette