VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsprogress.cpp@ 67221

Last change on this file since 67221 was 67221, checked in by vboxsync, 8 years ago

IPRT: Adding RTVfsIoStrmGetOpenFlags, RTVfsFileGetOpenFlags, RTVfsCreateProcessForIoStream and RTVfsCreateProcessForFile.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/* $Id: vfsprogress.cpp 67221 2017-06-01 21:44:24Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, progress filter for files.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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/vfs.h>
32#include <iprt/vfslowlevel.h>
33
34#include <iprt/assert.h>
35#include <iprt/err.h>
36#include <iprt/file.h>
37#include <iprt/poll.h>
38#include <iprt/string.h>
39#include <iprt/thread.h>
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45/**
46 * Private data of a standard file.
47 */
48typedef struct RTVFSPROGRESSFILE
49{
50 /** RTVFSPROGRESS_F_XXX. */
51 uint32_t fFlags;
52 /** Progress callback. */
53 PFNRTPROGRESS pfnProgress;
54 /** User argument for the callback. */
55 void *pvUser;
56 /** The I/O stream handle. */
57 RTVFSIOSTREAM hVfsIos;
58 /** The file handle. NIL_RTFILE if a pure I/O stream. */
59 RTVFSFILE hVfsFile;
60 /** Total number of bytes expected to be read and written. */
61 uint64_t cbExpected;
62 /** The number of bytes expected to be read. */
63 uint64_t cbExpectedRead;
64 /** The number of bytes expected to be written. */
65 uint64_t cbExpectedWritten;
66 /** Number of bytes currently read. */
67 uint64_t cbCurrentlyRead;
68 /** Number of bytes currently written. */
69 uint64_t cbCurrentlyWritten;
70 /** Current precentage. */
71 unsigned uCurPct;
72} RTVFSPROGRESSFILE;
73/** Pointer to the private data of a standard file. */
74typedef RTVFSPROGRESSFILE *PRTVFSPROGRESSFILE;
75
76
77/**
78 * Update the progress and do the progress callback if necessary.
79 *
80 * @param pThis The file progress instance.
81 */
82static void rtVfsProgressFile_UpdateProgress(PRTVFSPROGRESSFILE pThis)
83{
84 uint64_t cbDone = RT_MIN(pThis->cbCurrentlyRead, pThis->cbExpectedRead)
85 + RT_MIN(pThis->cbCurrentlyWritten, pThis->cbExpectedWritten);
86 unsigned uPct = cbDone / pThis->cbExpected;
87 if (uPct == pThis->uCurPct)
88 return;
89 pThis->uCurPct = uPct;
90 pThis->pfnProgress(uPct, pThis->pvUser);
91 /* Yes, we ignore the return code. */
92}
93
94
95/**
96 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
97 */
98static DECLCALLBACK(int) rtVfsProgressFile_Close(void *pvThis)
99{
100 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
101
102 if (pThis->hVfsFile != NIL_RTVFSFILE)
103 {
104 RTVfsFileRelease(pThis->hVfsFile);
105 pThis->hVfsFile = NIL_RTVFSFILE;
106 }
107 RTVfsIoStrmRelease(pThis->hVfsIos);
108 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
109
110 pThis->pfnProgress = NULL;
111
112 return VINF_SUCCESS;
113}
114
115
116/**
117 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
118 */
119static DECLCALLBACK(int) rtVfsProgressFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
120{
121 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
122 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
123}
124
125
126/**
127 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
128 */
129static DECLCALLBACK(int) rtVfsProgressFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
130{
131 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
132
133 /* Simplify a little there if a seeks is implied and assume the read goes well. */
134 if ( off >= 0
135 && (pThis->fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ))
136 {
137 uint64_t offCurrent = RTVfsFileTell(pThis->hVfsFile);
138 if (offCurrent < (uint64_t)off)
139 pThis->cbCurrentlyRead += off - offCurrent;
140 }
141
142 /* Calc the request before calling down the stack. */
143 size_t cbReq = 0;
144 unsigned i = pSgBuf->cSegs;
145 while (i-- > 0)
146 cbReq += pSgBuf->paSegs[i].cbSeg;
147
148 /* Do the read. */
149 int rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
150 if (RT_SUCCESS(rc))
151 {
152 /* Update the progress (we cannot cancel here, sorry). */
153 pThis->cbCurrentlyRead += pcbRead ? *pcbRead : cbReq;
154 rtVfsProgressFile_UpdateProgress(pThis);
155 }
156
157 return rc;
158}
159
160
161/**
162 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
163 */
164static DECLCALLBACK(int) rtVfsProgressFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
165{
166 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
167
168 /* Simplify a little there if a seeks is implied and assume the write goes well. */
169 if ( off >= 0
170 && (pThis->fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE))
171 {
172 uint64_t offCurrent = RTVfsFileTell(pThis->hVfsFile);
173 if (offCurrent < (uint64_t)off)
174 pThis->cbCurrentlyWritten += off - offCurrent;
175 }
176
177 /* Calc the request before calling down the stack. */
178 size_t cbReq = 0;
179 unsigned i = pSgBuf->cSegs;
180 while (i-- > 0)
181 cbReq += pSgBuf->paSegs[i].cbSeg;
182
183 /* Do the read. */
184 int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbWritten);
185 if (RT_SUCCESS(rc))
186 {
187 /* Update the progress (we cannot cancel here, sorry). */
188 pThis->cbCurrentlyWritten += pcbWritten ? *pcbWritten : cbReq;
189 rtVfsProgressFile_UpdateProgress(pThis);
190 }
191
192 return rc;
193}
194
195
196/**
197 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
198 */
199static DECLCALLBACK(int) rtVfsProgressFile_Flush(void *pvThis)
200{
201 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
202 return RTVfsIoStrmFlush(pThis->hVfsIos);
203}
204
205
206/**
207 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
208 */
209static DECLCALLBACK(int)
210rtVfsProgressFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
211{
212 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
213 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
214}
215
216
217/**
218 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
219 */
220static DECLCALLBACK(int) rtVfsProgressFile_Tell(void *pvThis, PRTFOFF poffActual)
221{
222 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
223 *poffActual = RTVfsIoStrmTell(pThis->hVfsIos);
224 return *poffActual >= 0 ? VINF_SUCCESS : (int)*poffActual;
225}
226
227
228/**
229 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
230 */
231static DECLCALLBACK(int) rtVfsProgressFile_Skip(void *pvThis, RTFOFF cb)
232{
233 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
234 int rc = RTVfsIoStrmSkip(pThis->hVfsIos, cb);
235 if (RT_SUCCESS(rc))
236 {
237 pThis->cbCurrentlyRead += cb;
238 rtVfsProgressFile_UpdateProgress(pThis);
239 }
240 return rc;
241}
242
243
244/**
245 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnZeroFill}
246 */
247static DECLCALLBACK(int) rtVfsProgressFile_ZeroFill(void *pvThis, RTFOFF cb)
248{
249 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
250 int rc = RTVfsIoStrmZeroFill(pThis->hVfsIos, cb);
251 if (RT_SUCCESS(rc))
252 {
253 pThis->cbCurrentlyWritten += cb;
254 rtVfsProgressFile_UpdateProgress(pThis);
255 }
256 return rc;
257}
258
259
260/**
261 * I/O stream progress operations.
262 */
263DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfsProgressIosOps =
264{
265 { /* Obj */
266 RTVFSOBJOPS_VERSION,
267 RTVFSOBJTYPE_IO_STREAM,
268 "I/O Stream Progress",
269 rtVfsProgressFile_Close,
270 rtVfsProgressFile_QueryInfo,
271 RTVFSOBJOPS_VERSION
272 },
273 RTVFSIOSTREAMOPS_VERSION,
274 0,
275 rtVfsProgressFile_Read,
276 rtVfsProgressFile_Write,
277 rtVfsProgressFile_Flush,
278 rtVfsProgressFile_PollOne,
279 rtVfsProgressFile_Tell,
280 rtVfsProgressFile_Skip,
281 rtVfsProgressFile_ZeroFill,
282 RTVFSIOSTREAMOPS_VERSION,
283};
284
285
286
287/**
288 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
289 */
290static DECLCALLBACK(int) rtVfsProgressFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
291{
292 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
293 //return RTVfsFileSetMode(pThis->hVfsIos, fMode, fMask); - missing
294 RT_NOREF(pThis, fMode, fMask);
295 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
296}
297
298
299/**
300 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
301 */
302static DECLCALLBACK(int) rtVfsProgressFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
303 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
304{
305 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
306 //return RTVfsFileSetTimes(pThis->hVfsIos, pAccessTime, pModificationTime, pChangeTime, pBirthTime); - missing
307 RT_NOREF(pThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
308 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
309}
310
311
312/**
313 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
314 */
315static DECLCALLBACK(int) rtVfsProgressFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
316{
317 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
318 //return RTVfsFileSetOwern(pThis->hVfsIos, uid, gid); - missing
319 RT_NOREF(pThis, uid, gid);
320 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
321}
322
323
324/**
325 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
326 */
327static DECLCALLBACK(int) rtVfsProgressFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
328{
329 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
330
331 uint64_t offPrev = UINT64_MAX;
332 if (pThis->fFlags & (RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ | RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE))
333 offPrev = RTVfsFileTell(pThis->hVfsFile);
334
335 uint64_t offActual = 0;
336 int rc = RTVfsFileSeek(pThis->hVfsFile, offSeek, uMethod, &offActual);
337 if (RT_SUCCESS(rc))
338 {
339 if (poffActual)
340 *poffActual = offActual;
341
342 /* Do progress updates as requested. */
343 if (pThis->fFlags & (RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ | RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE))
344 {
345 if (offActual > offPrev)
346 {
347 if (pThis->fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ)
348 pThis->cbCurrentlyRead += offActual - offPrev;
349 else
350 pThis->cbCurrentlyWritten += offActual - offPrev;
351 rtVfsProgressFile_UpdateProgress(pThis);
352 }
353 }
354 }
355 return rc;
356}
357
358
359/**
360 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
361 */
362static DECLCALLBACK(int) rtVfsProgressFile_QuerySize(void *pvThis, uint64_t *pcbFile)
363{
364 PRTVFSPROGRESSFILE pThis = (PRTVFSPROGRESSFILE)pvThis;
365 return RTVfsFileGetSize(pThis->hVfsFile, pcbFile);
366}
367
368
369/**
370 * File progress operations.
371 */
372DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsProgressFileOps =
373{
374 { /* Stream */
375 { /* Obj */
376 RTVFSOBJOPS_VERSION,
377 RTVFSOBJTYPE_FILE,
378 "File Progress",
379 rtVfsProgressFile_Close,
380 rtVfsProgressFile_QueryInfo,
381 RTVFSOBJOPS_VERSION
382 },
383 RTVFSIOSTREAMOPS_VERSION,
384 0,
385 rtVfsProgressFile_Read,
386 rtVfsProgressFile_Write,
387 rtVfsProgressFile_Flush,
388 rtVfsProgressFile_PollOne,
389 rtVfsProgressFile_Tell,
390 rtVfsProgressFile_Skip,
391 rtVfsProgressFile_ZeroFill,
392 RTVFSIOSTREAMOPS_VERSION,
393 },
394 RTVFSFILEOPS_VERSION,
395 0,
396 { /* ObjSet */
397 RTVFSOBJSETOPS_VERSION,
398 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
399 rtVfsProgressFile_SetMode,
400 rtVfsProgressFile_SetTimes,
401 rtVfsProgressFile_SetOwner,
402 RTVFSOBJSETOPS_VERSION
403 },
404 rtVfsProgressFile_Seek,
405 rtVfsProgressFile_QuerySize,
406 RTVFSFILEOPS_VERSION
407};
408
409
410RTDECL(int) RTVfsIoStrmCreateProgress(RTVFSIOSTREAM hVfsIos, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags,
411 uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSIOSTREAM phVfsIos)
412{
413 AssertPtrReturn(pfnProgress, VERR_INVALID_POINTER);
414 AssertReturn(!(fFlags & ~RTVFSPROGRESS_F_VALID_MASK), VERR_INVALID_FLAGS);
415 AssertReturn(!(fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ) || !(fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE),
416 VERR_INVALID_FLAGS);
417
418 uint32_t cRefs = RTVfsIoStrmRetain(hVfsIos);
419 AssertReturn(cRefs == UINT32_MAX, VERR_INVALID_HANDLE);
420
421 PRTVFSPROGRESSFILE pThis;
422 int rc = RTVfsNewIoStream(&g_rtVfsProgressIosOps, sizeof(*pThis), RTVfsIoStrmGetOpenFlags(hVfsIos),
423 NIL_RTVFS, NIL_RTVFSLOCK, phVfsIos, (void **)&pThis);
424 if (RT_SUCCESS(rc))
425 {
426 pThis->fFlags = fFlags;
427 pThis->pfnProgress = pfnProgress;
428 pThis->pvUser = pvUser;
429 pThis->hVfsIos = hVfsIos;
430 pThis->hVfsFile = RTVfsIoStrmToFile(hVfsIos);
431 pThis->cbCurrentlyRead = 0;
432 pThis->cbCurrentlyWritten = 0;
433 pThis->cbExpectedRead = cbExpectedRead;
434 pThis->cbExpectedWritten = cbExpectedWritten;
435 pThis->cbExpected = cbExpectedRead + cbExpectedWritten;
436 if (!pThis->cbExpected)
437 pThis->cbExpected = 1;
438 pThis->uCurPct = 0;
439 }
440 return rc;
441}
442
443
444RTDECL(int) RTVfsFileCreateProgress(RTVFSFILE hVfsFile, PFNRTPROGRESS pfnProgress, void *pvUser, uint32_t fFlags,
445 uint64_t cbExpectedRead, uint64_t cbExpectedWritten, PRTVFSFILE phVfsFile)
446{
447 AssertPtrReturn(pfnProgress, VERR_INVALID_POINTER);
448 AssertReturn(!(fFlags & ~RTVFSPROGRESS_F_VALID_MASK), VERR_INVALID_FLAGS);
449 AssertReturn(!(fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_READ) || !(fFlags & RTVFSPROGRESS_F_FORWARD_SEEK_AS_WRITE),
450 VERR_INVALID_FLAGS);
451
452 uint32_t cRefs = RTVfsFileRetain(hVfsFile);
453 AssertReturn(cRefs == UINT32_MAX, VERR_INVALID_HANDLE);
454
455 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile);
456 AssertReturnStmt(hVfsIos != NIL_RTVFSIOSTREAM, RTVfsFileRelease(hVfsFile), VERR_INVALID_HANDLE);
457
458 PRTVFSPROGRESSFILE pThis;
459 int rc = RTVfsNewFile(&g_rtVfsProgressFileOps, sizeof(*pThis), RTVfsFileGetOpenFlags(hVfsFile),
460 NIL_RTVFS, NIL_RTVFSLOCK, phVfsFile, (void **)&pThis);
461 if (RT_SUCCESS(rc))
462 {
463 pThis->fFlags = fFlags;
464 pThis->pfnProgress = pfnProgress;
465 pThis->pvUser = pvUser;
466 pThis->hVfsIos = hVfsIos;
467 pThis->hVfsFile = hVfsFile;
468 pThis->cbCurrentlyRead = 0;
469 pThis->cbCurrentlyWritten = 0;
470 pThis->cbExpectedRead = cbExpectedRead;
471 pThis->cbExpectedWritten = cbExpectedWritten;
472 pThis->cbExpected = cbExpectedRead + cbExpectedWritten;
473 if (!pThis->cbExpected)
474 pThis->cbExpected = 1;
475 pThis->uCurPct = 0;
476 }
477 return rc;
478}
479
480
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