VirtualBox

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

Last change on this file since 45234 was 41549, checked in by vboxsync, 13 years ago

VFS/Filesystem: Convert the filesystem specific code to the VFS framework and make it work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/* $Id: dvmvfs.cpp 41549 2012-06-01 17:29:05Z 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 NOREF(fBlocking);
96
97 /*
98 * Find the current position and check if it's within the volume.
99 */
100 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
101 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
102 {
103 if (pcbRead)
104 {
105 *pcbRead = 0;
106 pThis->offCurPos = offUnsigned;
107 return VINF_EOF;
108 }
109 return VERR_EOF;
110 }
111
112 size_t cbLeftToRead;
113 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
114 {
115 if (!pcbRead)
116 return VERR_EOF;
117 *pcbRead = cbLeftToRead = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
118 }
119 else
120 {
121 cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
122 if (pcbRead)
123 *pcbRead = cbLeftToRead;
124 }
125
126 /*
127 * Ok, we've got a valid stretch within the file. Do the reading.
128 */
129 if (cbLeftToRead > 0)
130 {
131 rc = RTDvmVolumeRead(pThis->hVol, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbLeftToRead);
132 if (RT_SUCCESS(rc))
133 offUnsigned += cbLeftToRead;
134 }
135
136 pThis->offCurPos = offUnsigned;
137 return rc;
138}
139
140
141/**
142 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
143 */
144static DECLCALLBACK(int) rtDvmVfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
145{
146 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
147 int rc = VINF_SUCCESS;
148
149 Assert(pSgBuf->cSegs == 1);
150 NOREF(fBlocking);
151
152 /*
153 * Find the current position and check if it's within the volume.
154 * Writing beyond the end of a volume is not supported.
155 */
156 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
157 if (offUnsigned >= RTDvmVolumeGetSize(pThis->hVol))
158 {
159 if (pcbWritten)
160 {
161 *pcbWritten = 0;
162 pThis->offCurPos = offUnsigned;
163 }
164 return VERR_NOT_SUPPORTED;
165 }
166
167 size_t cbLeftToWrite;
168 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > RTDvmVolumeGetSize(pThis->hVol))
169 {
170 if (!pcbWritten)
171 return VERR_EOF;
172 *pcbWritten = cbLeftToWrite = (size_t)(RTDvmVolumeGetSize(pThis->hVol) - offUnsigned);
173 }
174 else
175 {
176 cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
177 if (pcbWritten)
178 *pcbWritten = cbLeftToWrite;
179 }
180
181 /*
182 * Ok, we've got a valid stretch within the file. Do the reading.
183 */
184 if (cbLeftToWrite > 0)
185 {
186 rc = RTDvmVolumeWrite(pThis->hVol, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
187 if (RT_SUCCESS(rc))
188 offUnsigned += cbLeftToWrite;
189 }
190
191 pThis->offCurPos = offUnsigned;
192 return rc;
193}
194
195
196/**
197 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
198 */
199static DECLCALLBACK(int) rtDvmVfsFile_Flush(void *pvThis)
200{
201 NOREF(pvThis);
202 return VINF_SUCCESS; /* @todo: Implement missing DVM API. */
203}
204
205
206/**
207 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
208 */
209static DECLCALLBACK(int) rtDvmVfsFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
210 uint32_t *pfRetEvents)
211{
212 NOREF(pvThis);
213 int rc;
214 if (fEvents != RTPOLL_EVT_ERROR)
215 {
216 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
217 rc = VINF_SUCCESS;
218 }
219 else
220 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
221 return rc;
222}
223
224
225/**
226 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
227 */
228static DECLCALLBACK(int) rtDvmVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
229{
230 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
231 *poffActual = pThis->offCurPos;
232 return VINF_SUCCESS;
233}
234
235
236/**
237 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
238 */
239static DECLCALLBACK(int) rtDvmVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
240{
241 NOREF(pvThis);
242 NOREF(fMode);
243 NOREF(fMask);
244 return VERR_NOT_SUPPORTED;
245}
246
247
248/**
249 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
250 */
251static DECLCALLBACK(int) rtDvmVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
252 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
253{
254 NOREF(pvThis);
255 NOREF(pAccessTime);
256 NOREF(pModificationTime);
257 NOREF(pChangeTime);
258 NOREF(pBirthTime);
259 return VERR_NOT_SUPPORTED;
260}
261
262
263/**
264 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
265 */
266static DECLCALLBACK(int) rtDvmVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
267{
268 NOREF(pvThis);
269 NOREF(uid);
270 NOREF(gid);
271 return VERR_NOT_SUPPORTED;
272}
273
274
275/**
276 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
277 */
278static DECLCALLBACK(int) rtDvmVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
279{
280 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
281
282 /*
283 * Seek relative to which position.
284 */
285 uint64_t offWrt;
286 switch (uMethod)
287 {
288 case RTFILE_SEEK_BEGIN:
289 offWrt = 0;
290 break;
291
292 case RTFILE_SEEK_CURRENT:
293 offWrt = pThis->offCurPos;
294 break;
295
296 case RTFILE_SEEK_END:
297 offWrt = RTDvmVolumeGetSize(pThis->hVol);
298 break;
299
300 default:
301 return VERR_INTERNAL_ERROR_5;
302 }
303
304 /*
305 * Calc new position, take care to stay within bounds.
306 *
307 * @todo: Setting position beyond the end of the volume does not make sense.
308 */
309 uint64_t offNew;
310 if (offSeek == 0)
311 offNew = offWrt;
312 else if (offSeek > 0)
313 {
314 offNew = offWrt + offSeek;
315 if ( offNew < offWrt
316 || offNew > RTFOFF_MAX)
317 offNew = RTFOFF_MAX;
318 }
319 else if ((uint64_t)-offSeek < offWrt)
320 offNew = offWrt + offSeek;
321 else
322 offNew = 0;
323
324 /*
325 * Update the state and set return value.
326 */
327 pThis->offCurPos = offNew;
328
329 *poffActual = offNew;
330 return VINF_SUCCESS;
331}
332
333
334/**
335 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
336 */
337static DECLCALLBACK(int) rtDvmVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
338{
339 PRTVFSDVMFILE pThis = (PRTVFSDVMFILE)pvThis;
340 *pcbFile = RTDvmVolumeGetSize(pThis->hVol);
341 return VINF_SUCCESS;
342}
343
344
345/**
346 * Standard file operations.
347 */
348DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtDvmVfsStdFileOps =
349{
350 { /* Stream */
351 { /* Obj */
352 RTVFSOBJOPS_VERSION,
353 RTVFSOBJTYPE_FILE,
354 "DvmFile",
355 rtDvmVfsFile_Close,
356 rtDvmVfsFile_QueryInfo,
357 RTVFSOBJOPS_VERSION
358 },
359 RTVFSIOSTREAMOPS_VERSION,
360 RTVFSIOSTREAMOPS_FEAT_NO_SG,
361 rtDvmVfsFile_Read,
362 rtDvmVfsFile_Write,
363 rtDvmVfsFile_Flush,
364 rtDvmVfsFile_PollOne,
365 rtDvmVfsFile_Tell,
366 NULL /*Skip*/,
367 NULL /*ZeroFill*/,
368 RTVFSIOSTREAMOPS_VERSION,
369 },
370 RTVFSFILEOPS_VERSION,
371 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
372 { /* ObjSet */
373 RTVFSOBJSETOPS_VERSION,
374 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
375 rtDvmVfsFile_SetMode,
376 rtDvmVfsFile_SetTimes,
377 rtDvmVfsFile_SetOwner,
378 RTVFSOBJSETOPS_VERSION
379 },
380 rtDvmVfsFile_Seek,
381 rtDvmVfsFile_QuerySize,
382 RTVFSFILEOPS_VERSION
383};
384
385
386RTDECL(int) RTDvmVolumeCreateVfsFile(RTDVMVOLUME hVol, PRTVFSFILE phVfsFileOut)
387{
388 AssertPtrReturn(hVol, VERR_INVALID_HANDLE);
389 AssertPtrReturn(phVfsFileOut, VERR_INVALID_POINTER);
390
391 uint32_t cRefs = RTDvmVolumeRetain(hVol);
392 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
393
394 /*
395 * Create the volume file.
396 */
397 RTVFSFILE hVfsFile;
398 PRTVFSDVMFILE pThis;
399 int rc = RTVfsNewFile(&g_rtDvmVfsStdFileOps, sizeof(*pThis), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE,
400 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
401 if (RT_SUCCESS(rc))
402 {
403 pThis->offCurPos = 0;
404 pThis->hVol = hVol;
405
406 *phVfsFileOut = hVfsFile;
407 return VINF_SUCCESS;
408 }
409 else
410 RTDvmVolumeRelease(hVol);
411 return rc;
412}
413
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