VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: dvmvfs.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT Disk Volume Management API (DVM) - VFS glue.
4 */
5
6/*
7 * Copyright (C) 2012-2015 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/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48
49/**
50 * The internal data of a DVM volume I/O stream.
51 */
52typedef struct RTVFSDVMFILE
53{
54 /** The volume the VFS file belongs to. */
55 RTDVMVOLUME hVol;
56 /** Current position. */
57 uint64_t offCurPos;
58} RTVFSDVMFILE;
59/** Pointer to a the internal data of a DVM volume file. */
60typedef RTVFSDVMFILE *PRTVFSDVMFILE;
61
62
63/**
64 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
65 */
66static DECLCALLBACK(int) rtDvmVfsFile_Close(void *pvThis)
67{
68 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
69
70 RTDvmVolumeRelease(pThis->hVol);
71 return VINF_SUCCESS;
72}
73
74
75/**
76 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
77 */
78static DECLCALLBACK(int) rtDvmVfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
79{
80 NOREF(pvThis);
81 NOREF(pObjInfo);
82 NOREF(enmAddAttr);
83 return VERR_NOT_SUPPORTED;
84}
85
86
87/**
88 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
89 */
90static DECLCALLBACK(int) rtDvmVfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
91{
92 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
93 int rc = VINF_SUCCESS;
94
95 Assert(pSgBuf->cSegs == 1);
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 NOREF(fBlocking);
152
153 /*
154 * Find the current position and check if it's within the volume.
155 * Writing beyond the end of a volume is not supported.
156 */
157 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
158 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
159 {
160 if (pcbWritten)
161 {
162 *pcbWritten = 0;
163 pThis->offCurPos = offUnsigned;
164 }
165 return VERR_NOT_SUPPORTED;
166 }
167
168 size_t cbLeftToWrite;
169 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
170 {
171 if (!pcbWritten)
172 return VERR_EOF;
173 *pcbWritten = cbLeftToWrite = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
174 }
175 else
176 {
177 cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
178 if (pcbWritten)
179 *pcbWritten = cbLeftToWrite;
180 }
181
182 /*
183 * Ok, we've got a valid stretch within the file. Do the reading.
184 */
185 if (cbLeftToWrite > 0)
186 {
187 rc = RTDvmVolumeWrite(pThis->hVol, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
188 if (RT_SUCCESS(rc))
189 offUnsigned += cbLeftToWrite;
190 }
191
192 pThis->offCurPos = offUnsigned;
193 return rc;
194}
195
196
197/**
198 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
199 */
200static DECLCALLBACK(int) rtDvmVfsFile_Flush(void *pvThis)
201{
202 NOREF(pvThis);
203 return VINF_SUCCESS; /* @todo: Implement missing DVM API. */
204}
205
206
207/**
208 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
209 */
210static DECLCALLBACK(int) rtDvmVfsFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
211 uint32_t *pfRetEvents)
212{
213 NOREF(pvThis);
214 int rc;
215 if (fEvents != RTPOLL_EVT_ERROR)
216 {
217 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
218 rc = VINF_SUCCESS;
219 }
220 else
221 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
222 return rc;
223}
224
225
226/**
227 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
228 */
229static DECLCALLBACK(int) rtDvmVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
230{
231 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
232 *poffActual = pThis->offCurPos;
233 return VINF_SUCCESS;
234}
235
236
237/**
238 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
239 */
240static DECLCALLBACK(int) rtDvmVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
241{
242 NOREF(pvThis);
243 NOREF(fMode);
244 NOREF(fMask);
245 return VERR_NOT_SUPPORTED;
246}
247
248
249/**
250 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
251 */
252static DECLCALLBACK(int) rtDvmVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
253 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
254{
255 NOREF(pvThis);
256 NOREF(pAccessTime);
257 NOREF(pModificationTime);
258 NOREF(pChangeTime);
259 NOREF(pBirthTime);
260 return VERR_NOT_SUPPORTED;
261}
262
263
264/**
265 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
266 */
267static DECLCALLBACK(int) rtDvmVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
268{
269 NOREF(pvThis);
270 NOREF(uid);
271 NOREF(gid);
272 return VERR_NOT_SUPPORTED;
273}
274
275
276/**
277 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
278 */
279static DECLCALLBACK(int) rtDvmVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
280{
281 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
282
283 /*
284 * Seek relative to which position.
285 */
286 uint64_t offWrt;
287 switch (uMethod)
288 {
289 case RTFILE_SEEK_BEGIN:
290 offWrt = 0;
291 break;
292
293 case RTFILE_SEEK_CURRENT:
294 offWrt = pThis->offCurPos;
295 break;
296
297 case RTFILE_SEEK_END:
298 offWrt = RTDvmVolumeGetSize(pThis->hVol);
299 break;
300
301 default:
302 return VERR_INTERNAL_ERROR_5;
303 }
304
305 /*
306 * Calc new position, take care to stay within bounds.
307 *
308 * @todo: Setting position beyond the end of the volume does not make sense.
309 */
310 uint64_t offNew;
311 if (offSeek == 0)
312 offNew = offWrt;
313 else if (offSeek > 0)
314 {
315 offNew = offWrt + offSeek;
316 if ( offNew < offWrt
317 || offNew > RTFOFF_MAX)
318 offNew = RTFOFF_MAX;
319 }
320 else if ((uint64_t)-offSeek < offWrt)
321 offNew = offWrt + offSeek;
322 else
323 offNew = 0;
324
325 /*
326 * Update the state and set return value.
327 */
328 pThis->offCurPos = offNew;
329
330 *poffActual = offNew;
331 return VINF_SUCCESS;
332}
333
334
335/**
336 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
337 */
338static DECLCALLBACK(int) rtDvmVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
339{
340 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
341 *pcbFile = RTDvmVolumeGetSize(pThis->hVol);
342 return VINF_SUCCESS;
343}
344
345
346/**
347 * Standard file operations.
348 */
349DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtDvmVfsStdFileOps =
350{
351 { /* Stream */
352 { /* Obj */
353 RTVFSOBJOPS_VERSION,
354 RTVFSOBJTYPE_FILE,
355 "DvmFile",
356 rtDvmVfsFile_Close,
357 rtDvmVfsFile_QueryInfo,
358 RTVFSOBJOPS_VERSION
359 },
360 RTVFSIOSTREAMOPS_VERSION,
361 RTVFSIOSTREAMOPS_FEAT_NO_SG,
362 rtDvmVfsFile_Read,
363 rtDvmVfsFile_Write,
364 rtDvmVfsFile_Flush,
365 rtDvmVfsFile_PollOne,
366 rtDvmVfsFile_Tell,
367 NULL /*Skip*/,
368 NULL /*ZeroFill*/,
369 RTVFSIOSTREAMOPS_VERSION,
370 },
371 RTVFSFILEOPS_VERSION,
372 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
373 { /* ObjSet */
374 RTVFSOBJSETOPS_VERSION,
375 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
376 rtDvmVfsFile_SetMode,
377 rtDvmVfsFile_SetTimes,
378 rtDvmVfsFile_SetOwner,
379 RTVFSOBJSETOPS_VERSION
380 },
381 rtDvmVfsFile_Seek,
382 rtDvmVfsFile_QuerySize,
383 RTVFSFILEOPS_VERSION
384};
385
386
387RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, PRTVFSFILE phVfsFileOut)
388{
389 AssertPtrReturn(hVol, VERR_INVALID_HANDLE);
390 AssertPtrReturn(phVfsFileOut, VERR_INVALID_POINTER);
391
392 uint32_t cRefs = RTDvmVolumeRetain(hVol);
393 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
394
395 /*
396 * Create the volume file.
397 */
398 RTVFSFILE hVfsFile;
399 PRTVFSDVMFILE pThis;
400 int rc = RTVfsNewFile(&g_rtDvmVfsStdFileOps, sizeof(*pThis), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE,
401 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
402 if (RT_SUCCESS(rc))
403 {
404 pThis->offCurPos = 0;
405 pThis->hVol = hVol;
406
407 *phVfsFileOut = hVfsFile;
408 return VINF_SUCCESS;
409 }
410 else
411 RTDvmVolumeRelease(hVol);
412 return rc;
413}
414
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