VirtualBox

source: vbox/trunk/src/VBox/Storage/RAW.cpp@ 58591

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

Storage/RAW: Fix too large images when creating raw images with sequential access

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 KB
Line 
1/* $Id: RAW.cpp 58321 2015-10-19 19:33:51Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_VD_RAW
23#include <VBox/vd-plugin.h>
24#include <VBox/err.h>
25
26#include <VBox/log.h>
27#include <iprt/assert.h>
28#include <iprt/alloc.h>
29#include <iprt/path.h>
30
31#include "VDBackends.h"
32
33
34/*********************************************************************************************************************************
35* Constants And Macros, Structures and Typedefs *
36*********************************************************************************************************************************/
37
38/**
39 * Raw image data structure.
40 */
41typedef struct RAWIMAGE
42{
43 /** Image name. */
44 const char *pszFilename;
45 /** Storage handle. */
46 PVDIOSTORAGE pStorage;
47
48 /** Pointer to the per-disk VD interface list. */
49 PVDINTERFACE pVDIfsDisk;
50 /** Pointer to the per-image VD interface list. */
51 PVDINTERFACE pVDIfsImage;
52 /** Error interface. */
53 PVDINTERFACEERROR pIfError;
54 /** I/O interface. */
55 PVDINTERFACEIOINT pIfIo;
56
57 /** Open flags passed by VBoxHD layer. */
58 unsigned uOpenFlags;
59 /** Image flags defined during creation or determined during open. */
60 unsigned uImageFlags;
61 /** Total size of the image. */
62 uint64_t cbSize;
63 /** Position in the image (only truly used for sequential access). */
64 uint64_t offAccess;
65 /** Flag if this is a newly created image. */
66 bool fCreate;
67 /** Physical geometry of this image. */
68 VDGEOMETRY PCHSGeometry;
69 /** Logical geometry of this image. */
70 VDGEOMETRY LCHSGeometry;
71 /** Sector size of the image. */
72 uint32_t cbSector;
73} RAWIMAGE, *PRAWIMAGE;
74
75
76/** Size of write operations when filling an image with zeroes. */
77#define RAW_FILL_SIZE (128 * _1K)
78
79/** The maximum reasonable size of a floppy image (big format 2.88MB medium). */
80#define RAW_MAX_FLOPPY_IMG_SIZE (512 * 82 * 48 * 2)
81
82
83/*********************************************************************************************************************************
84* Static Variables *
85*********************************************************************************************************************************/
86
87/** NULL-terminated array of supported file extensions. */
88static const VDFILEEXTENSION s_aRawFileExtensions[] =
89{
90 {"iso", VDTYPE_DVD},
91 {"cdr", VDTYPE_DVD},
92 {"img", VDTYPE_FLOPPY},
93 {"ima", VDTYPE_FLOPPY},
94 {"dsk", VDTYPE_FLOPPY},
95 {"flp", VDTYPE_FLOPPY},
96 {"vfd", VDTYPE_FLOPPY},
97 {NULL, VDTYPE_INVALID}
98};
99
100
101/*********************************************************************************************************************************
102* Internal Functions *
103*********************************************************************************************************************************/
104
105/**
106 * Internal. Flush image data to disk.
107 */
108static int rawFlushImage(PRAWIMAGE pImage)
109{
110 int rc = VINF_SUCCESS;
111
112 if ( pImage->pStorage
113 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
114 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
115
116 return rc;
117}
118
119/**
120 * Internal. Free all allocated space for representing an image except pImage,
121 * and optionally delete the image from disk.
122 */
123static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
124{
125 int rc = VINF_SUCCESS;
126
127 /* Freeing a never allocated image (e.g. because the open failed) is
128 * not signalled as an error. After all nothing bad happens. */
129 if (pImage)
130 {
131 if (pImage->pStorage)
132 {
133 /* No point updating the file that is deleted anyway. */
134 if (!fDelete)
135 {
136 /* For newly created images in sequential mode fill it to
137 * the nominal size. */
138 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
139 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
140 && pImage->fCreate)
141 {
142 /* Fill rest of image with zeroes, a must for sequential
143 * images to reach the nominal size. */
144 uint64_t uOff;
145 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
146 if (!pvBuf)
147 goto out;
148
149 uOff = pImage->offAccess;
150 /* Write data to all image blocks. */
151 while (uOff < pImage->cbSize)
152 {
153 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize - uOff,
154 RAW_FILL_SIZE);
155
156 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
157 uOff, pvBuf, cbChunk);
158 if (RT_FAILURE(rc))
159 goto out;
160
161 uOff += cbChunk;
162 }
163out:
164 if (pvBuf)
165 RTMemTmpFree(pvBuf);
166 }
167 rawFlushImage(pImage);
168 }
169
170 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
171 pImage->pStorage = NULL;
172 }
173
174 if (fDelete && pImage->pszFilename)
175 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
176 }
177
178 LogFlowFunc(("returns %Rrc\n", rc));
179 return rc;
180}
181
182/**
183 * Internal: Open an image, constructing all necessary data structures.
184 */
185static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
186{
187 int rc;
188
189 pImage->uOpenFlags = uOpenFlags;
190 pImage->fCreate = false;
191
192 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
193 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
194 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
195
196 /*
197 * Open the image.
198 */
199 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
200 VDOpenFlagsToFileOpenFlags(uOpenFlags,
201 false /* fCreate */),
202 &pImage->pStorage);
203 if (RT_FAILURE(rc))
204 {
205 /* Do NOT signal an appropriate error here, as the VD layer has the
206 * choice of retrying the open if it failed. */
207 goto out;
208 }
209
210 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbSize);
211 if (RT_FAILURE(rc))
212 goto out;
213 if (pImage->cbSize % 512)
214 {
215 rc = VERR_VD_RAW_SIZE_MODULO_512;
216 goto out;
217 }
218 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
219
220out:
221 if (RT_FAILURE(rc))
222 rawFreeImage(pImage, false);
223 return rc;
224}
225
226/**
227 * Internal: Create a raw image.
228 */
229static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
230 unsigned uImageFlags, const char *pszComment,
231 PCVDGEOMETRY pPCHSGeometry,
232 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
233 PFNVDPROGRESS pfnProgress, void *pvUser,
234 unsigned uPercentStart, unsigned uPercentSpan)
235{
236 int rc;
237 RTFOFF cbFree = 0;
238 uint64_t uOff;
239 void *pvBuf = NULL;
240 int32_t fOpen;
241
242 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
243
244 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
245
246 pImage->uImageFlags = uImageFlags;
247 pImage->fCreate = true;
248 pImage->PCHSGeometry = *pPCHSGeometry;
249 pImage->LCHSGeometry = *pLCHSGeometry;
250
251 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
252 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
253 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
254
255 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
256 {
257 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
258 goto out;
259 }
260
261 /* Create image file. */
262 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
263 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
264 fOpen &= ~RTFILE_O_READ;
265 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
266 if (RT_FAILURE(rc))
267 {
268 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
269 goto out;
270 }
271
272 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
273 {
274 /* Check the free space on the disk and leave early if there is not
275 * sufficient space available. */
276 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
277 if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
278 {
279 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
280 goto out;
281 }
282
283 /* Allocate & commit whole file if fixed image, it must be more
284 * effective than expanding file by write operations. */
285 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
286 if (RT_FAILURE(rc))
287 {
288 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: setting image size failed for '%s'"), pImage->pszFilename);
289 goto out;
290 }
291
292 /* Fill image with zeroes. We do this for every fixed-size image since
293 * on some systems (for example Windows Vista), it takes ages to write
294 * a block near the end of a sparse file and the guest could complain
295 * about an ATA timeout. */
296 pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
297 if (!pvBuf)
298 {
299 rc = VERR_NO_MEMORY;
300 goto out;
301 }
302
303 uOff = 0;
304 /* Write data to all image blocks. */
305 while (uOff < cbSize)
306 {
307 unsigned cbChunk = (unsigned)RT_MIN(cbSize - uOff, RAW_FILL_SIZE);
308
309 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOff,
310 pvBuf, cbChunk);
311 if (RT_FAILURE(rc))
312 {
313 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: writing block failed for '%s'"), pImage->pszFilename);
314 goto out;
315 }
316
317 uOff += cbChunk;
318
319 if (pfnProgress)
320 {
321 rc = pfnProgress(pvUser,
322 uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100));
323 if (RT_FAILURE(rc))
324 goto out;
325 }
326 }
327 }
328
329 if (RT_SUCCESS(rc) && pfnProgress)
330 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
331
332 pImage->cbSize = cbSize;
333
334 rc = rawFlushImage(pImage);
335
336out:
337 if (pvBuf)
338 RTMemTmpFree(pvBuf);
339
340 if (RT_SUCCESS(rc) && pfnProgress)
341 pfnProgress(pvUser, uPercentStart + uPercentSpan);
342
343 if (RT_FAILURE(rc))
344 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
345 return rc;
346}
347
348
349/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
350static DECLCALLBACK(int) rawCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
351 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
352{
353 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
354 PVDIOSTORAGE pStorage = NULL;
355 uint64_t cbFile;
356 int rc = VINF_SUCCESS;
357 char *pszSuffix = NULL;
358
359 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
360 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
361
362 if ( !VALID_PTR(pszFilename)
363 || !*pszFilename)
364 {
365 rc = VERR_INVALID_PARAMETER;
366 goto out;
367 }
368
369 pszSuffix = RTPathSuffix(pszFilename);
370
371 /*
372 * Open the file and read the footer.
373 */
374 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
375 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
376 false /* fCreate */),
377 &pStorage);
378 if (RT_SUCCESS(rc))
379 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
380
381 /* Try to guess the image type based on the extension. */
382 if ( RT_SUCCESS(rc)
383 && pszSuffix)
384 {
385 if ( !RTStrICmp(pszSuffix, ".iso")
386 || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */
387 {
388 /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
389 * between raw floppy and CD images based on their size (and cannot be reliably done
390 * based on contents, either).
391 */
392 if (cbFile % 2048)
393 rc = VERR_VD_RAW_SIZE_MODULO_2048;
394 else if (cbFile <= 32768)
395 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
396 else
397 {
398 *penmType = VDTYPE_DVD;
399 rc = VINF_SUCCESS;
400 }
401 }
402 else if ( !RTStrICmp(pszSuffix, ".img")
403 || !RTStrICmp(pszSuffix, ".ima")
404 || !RTStrICmp(pszSuffix, ".dsk")
405 || !RTStrICmp(pszSuffix, ".flp")
406 || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
407 {
408 if (cbFile % 512)
409 rc = VERR_VD_RAW_SIZE_MODULO_512;
410 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
411 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
412 else
413 {
414 *penmType = VDTYPE_FLOPPY;
415 rc = VINF_SUCCESS;
416 }
417 }
418 else
419 rc = VERR_VD_RAW_INVALID_HEADER;
420 }
421 else
422 rc = VERR_VD_RAW_INVALID_HEADER;
423
424 if (pStorage)
425 vdIfIoIntFileClose(pIfIo, pStorage);
426
427out:
428 LogFlowFunc(("returns %Rrc\n", rc));
429 return rc;
430}
431
432/** @copydoc VBOXHDDBACKEND::pfnOpen */
433static DECLCALLBACK(int) rawOpen(const char *pszFilename, unsigned uOpenFlags,
434 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
435 VDTYPE enmType, void **ppBackendData)
436{
437 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
438 int rc;
439 PRAWIMAGE pImage;
440
441 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
442
443 /* Check open flags. All valid flags are supported. */
444 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
445 {
446 rc = VERR_INVALID_PARAMETER;
447 goto out;
448 }
449
450 /* Check remaining arguments. */
451 if ( !VALID_PTR(pszFilename)
452 || !*pszFilename)
453 {
454 rc = VERR_INVALID_PARAMETER;
455 goto out;
456 }
457
458
459 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
460 if (!pImage)
461 {
462 rc = VERR_NO_MEMORY;
463 goto out;
464 }
465 pImage->pszFilename = pszFilename;
466 pImage->pStorage = NULL;
467 pImage->pVDIfsDisk = pVDIfsDisk;
468 pImage->pVDIfsImage = pVDIfsImage;
469
470 rc = rawOpenImage(pImage, uOpenFlags);
471 if (RT_SUCCESS(rc))
472 {
473 if (enmType == VDTYPE_DVD)
474 pImage->cbSector = 2048;
475 else
476 pImage->cbSector = 512;
477 *ppBackendData = pImage;
478 }
479 else
480 RTMemFree(pImage);
481
482out:
483 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
484 return rc;
485}
486
487/** @copydoc VBOXHDDBACKEND::pfnCreate */
488static DECLCALLBACK(int) rawCreate(const char *pszFilename, uint64_t cbSize,
489 unsigned uImageFlags, const char *pszComment,
490 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
491 PCRTUUID pUuid, unsigned uOpenFlags,
492 unsigned uPercentStart, unsigned uPercentSpan,
493 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
494 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
495 void **ppBackendData)
496{
497 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p",
498 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
499 int rc;
500 PRAWIMAGE pImage;
501
502 PFNVDPROGRESS pfnProgress = NULL;
503 void *pvUser = NULL;
504 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
505 if (pIfProgress)
506 {
507 pfnProgress = pIfProgress->pfnProgress;
508 pvUser = pIfProgress->Core.pvUser;
509 }
510
511 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
512 * various tools using this backend for hard disk images will fail. */
513 if (enmType != VDTYPE_HDD && enmType != VDTYPE_DVD && enmType != VDTYPE_FLOPPY)
514 {
515 rc = VERR_VD_INVALID_TYPE;
516 goto out;
517 }
518
519 /* Check open flags. All valid flags are supported. */
520 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
521 {
522 rc = VERR_INVALID_PARAMETER;
523 goto out;
524 }
525
526 /* Check remaining arguments. */
527 if ( !VALID_PTR(pszFilename)
528 || !*pszFilename
529 || !VALID_PTR(pPCHSGeometry)
530 || !VALID_PTR(pLCHSGeometry))
531 {
532 rc = VERR_INVALID_PARAMETER;
533 goto out;
534 }
535
536 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
537 if (!pImage)
538 {
539 rc = VERR_NO_MEMORY;
540 goto out;
541 }
542 pImage->pszFilename = pszFilename;
543 pImage->pStorage = NULL;
544 pImage->pVDIfsDisk = pVDIfsDisk;
545 pImage->pVDIfsImage = pVDIfsImage;
546
547 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
548 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
549 pfnProgress, pvUser, uPercentStart, uPercentSpan);
550 if (RT_SUCCESS(rc))
551 {
552 /* So far the image is opened in read/write mode. Make sure the
553 * image is opened in read-only mode if the caller requested that. */
554 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
555 {
556 rawFreeImage(pImage, false);
557 rc = rawOpenImage(pImage, uOpenFlags);
558 if (RT_FAILURE(rc))
559 {
560 RTMemFree(pImage);
561 goto out;
562 }
563 }
564 *ppBackendData = pImage;
565 }
566 else
567 RTMemFree(pImage);
568
569out:
570 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
571 return rc;
572}
573
574/** @copydoc VBOXHDDBACKEND::pfnRename */
575static DECLCALLBACK(int) rawRename(void *pBackendData, const char *pszFilename)
576{
577 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
578 int rc = VINF_SUCCESS;
579 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
580
581 /* Check arguments. */
582 if ( !pImage
583 || !pszFilename
584 || !*pszFilename)
585 {
586 rc = VERR_INVALID_PARAMETER;
587 goto out;
588 }
589
590 /* Close the image. */
591 rc = rawFreeImage(pImage, false);
592 if (RT_FAILURE(rc))
593 goto out;
594
595 /* Rename the file. */
596 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
597 if (RT_FAILURE(rc))
598 {
599 /* The move failed, try to reopen the original image. */
600 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
601 if (RT_FAILURE(rc2))
602 rc = rc2;
603
604 goto out;
605 }
606
607 /* Update pImage with the new information. */
608 pImage->pszFilename = pszFilename;
609
610 /* Open the old image with new name. */
611 rc = rawOpenImage(pImage, pImage->uOpenFlags);
612 if (RT_FAILURE(rc))
613 goto out;
614
615out:
616 LogFlowFunc(("returns %Rrc\n", rc));
617 return rc;
618}
619
620/** @copydoc VBOXHDDBACKEND::pfnClose */
621static DECLCALLBACK(int) rawClose(void *pBackendData, bool fDelete)
622{
623 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
624 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
625 int rc;
626
627 rc = rawFreeImage(pImage, fDelete);
628 RTMemFree(pImage);
629
630 LogFlowFunc(("returns %Rrc\n", rc));
631 return rc;
632}
633
634/** @copydoc VBOXHDDBACKEND::pfnRead */
635static DECLCALLBACK(int) rawRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
636 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
637{
638 int rc = VINF_SUCCESS;
639 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
640
641 /* For sequential access do not allow to go back. */
642 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
643 && uOffset < pImage->offAccess)
644 {
645 *pcbActuallyRead = 0;
646 return VERR_INVALID_PARAMETER;
647 }
648
649 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
650 pIoCtx, cbRead);
651 if (RT_SUCCESS(rc))
652 {
653 *pcbActuallyRead = cbRead;
654 pImage->offAccess = uOffset + cbRead;
655 }
656
657 return rc;
658}
659
660/** @copydoc VBOXHDDBACKEND::pfnWrite */
661static DECLCALLBACK(int) rawWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
662 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
663 size_t *pcbPostRead, unsigned fWrite)
664{
665 int rc = VINF_SUCCESS;
666 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
667
668 /* For sequential access do not allow to go back. */
669 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
670 && uOffset < pImage->offAccess)
671 {
672 *pcbWriteProcess = 0;
673 *pcbPostRead = 0;
674 *pcbPreRead = 0;
675 return VERR_INVALID_PARAMETER;
676 }
677
678 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
679 pIoCtx, cbWrite, NULL, NULL);
680 if (RT_SUCCESS(rc))
681 {
682 *pcbWriteProcess = cbWrite;
683 *pcbPostRead = 0;
684 *pcbPreRead = 0;
685 pImage->offAccess = uOffset + cbWrite;
686 }
687
688 return rc;
689}
690
691/** @copydoc VBOXHDDBACKEND::pfnFlush */
692static DECLCALLBACK(int) rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
693{
694 int rc = VINF_SUCCESS;
695 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
696
697 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
698 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
699 NULL, NULL);
700
701 return rc;
702}
703
704/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
705static DECLCALLBACK(unsigned) rawGetVersion(void *pBackendData)
706{
707 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
708 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
709
710 AssertPtr(pImage);
711
712 if (pImage)
713 return 1;
714 else
715 return 0;
716}
717
718/** @copydoc VBOXHDDBACKEND::pfnGetSize */
719static DECLCALLBACK(uint32_t) rawGetSectorSize(void *pBackendData)
720{
721 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
722 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
723 uint32_t cb = 0;
724
725 AssertPtr(pImage);
726
727 if (pImage && pImage->pStorage)
728 cb = pImage->cbSector;
729
730 LogFlowFunc(("returns %u\n", cb));
731 return cb;
732}
733
734/** @copydoc VBOXHDDBACKEND::pfnGetSize */
735static DECLCALLBACK(uint64_t) rawGetSize(void *pBackendData)
736{
737 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
738 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
739 uint64_t cb = 0;
740
741 AssertPtr(pImage);
742
743 if (pImage && pImage->pStorage)
744 cb = pImage->cbSize;
745
746 LogFlowFunc(("returns %llu\n", cb));
747 return cb;
748}
749
750/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
751static DECLCALLBACK(uint64_t) rawGetFileSize(void *pBackendData)
752{
753 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
754 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
755 uint64_t cb = 0;
756
757 AssertPtr(pImage);
758
759 if (pImage)
760 {
761 uint64_t cbFile;
762 if (pImage->pStorage)
763 {
764 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
765 if (RT_SUCCESS(rc))
766 cb += cbFile;
767 }
768 }
769
770 LogFlowFunc(("returns %lld\n", cb));
771 return cb;
772}
773
774/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
775static DECLCALLBACK(int) rawGetPCHSGeometry(void *pBackendData,
776 PVDGEOMETRY pPCHSGeometry)
777{
778 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
779 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
780 int rc;
781
782 AssertPtr(pImage);
783
784 if (pImage)
785 {
786 if (pImage->PCHSGeometry.cCylinders)
787 {
788 *pPCHSGeometry = pImage->PCHSGeometry;
789 rc = VINF_SUCCESS;
790 }
791 else
792 rc = VERR_VD_GEOMETRY_NOT_SET;
793 }
794 else
795 rc = VERR_VD_NOT_OPENED;
796
797 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
798 return rc;
799}
800
801/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
802static DECLCALLBACK(int) rawSetPCHSGeometry(void *pBackendData,
803 PCVDGEOMETRY pPCHSGeometry)
804{
805 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
806 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
807 int rc;
808
809 AssertPtr(pImage);
810
811 if (pImage)
812 {
813 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
814 {
815 rc = VERR_VD_IMAGE_READ_ONLY;
816 goto out;
817 }
818
819 pImage->PCHSGeometry = *pPCHSGeometry;
820 rc = VINF_SUCCESS;
821 }
822 else
823 rc = VERR_VD_NOT_OPENED;
824
825out:
826 LogFlowFunc(("returns %Rrc\n", rc));
827 return rc;
828}
829
830/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
831static DECLCALLBACK(int) rawGetLCHSGeometry(void *pBackendData,
832 PVDGEOMETRY pLCHSGeometry)
833{
834 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
835 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
836 int rc;
837
838 AssertPtr(pImage);
839
840 if (pImage)
841 {
842 if (pImage->LCHSGeometry.cCylinders)
843 {
844 *pLCHSGeometry = pImage->LCHSGeometry;
845 rc = VINF_SUCCESS;
846 }
847 else
848 rc = VERR_VD_GEOMETRY_NOT_SET;
849 }
850 else
851 rc = VERR_VD_NOT_OPENED;
852
853 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
854 return rc;
855}
856
857/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
858static DECLCALLBACK(int) rawSetLCHSGeometry(void *pBackendData,
859 PCVDGEOMETRY pLCHSGeometry)
860{
861 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
862 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
863 int rc;
864
865 AssertPtr(pImage);
866
867 if (pImage)
868 {
869 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
870 {
871 rc = VERR_VD_IMAGE_READ_ONLY;
872 goto out;
873 }
874
875 pImage->LCHSGeometry = *pLCHSGeometry;
876 rc = VINF_SUCCESS;
877 }
878 else
879 rc = VERR_VD_NOT_OPENED;
880
881out:
882 LogFlowFunc(("returns %Rrc\n", rc));
883 return rc;
884}
885
886/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
887static DECLCALLBACK(unsigned) rawGetImageFlags(void *pBackendData)
888{
889 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
890 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
891 unsigned uImageFlags;
892
893 AssertPtr(pImage);
894
895 if (pImage)
896 uImageFlags = pImage->uImageFlags;
897 else
898 uImageFlags = 0;
899
900 LogFlowFunc(("returns %#x\n", uImageFlags));
901 return uImageFlags;
902}
903
904/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
905static DECLCALLBACK(unsigned) rawGetOpenFlags(void *pBackendData)
906{
907 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
908 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
909 unsigned uOpenFlags;
910
911 AssertPtr(pImage);
912
913 if (pImage)
914 uOpenFlags = pImage->uOpenFlags;
915 else
916 uOpenFlags = 0;
917
918 LogFlowFunc(("returns %#x\n", uOpenFlags));
919 return uOpenFlags;
920}
921
922/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
923static DECLCALLBACK(int) rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
924{
925 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
926 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
927 int rc;
928
929 /* Image must be opened and the new flags must be valid. */
930 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
931 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
932 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
933 {
934 rc = VERR_INVALID_PARAMETER;
935 goto out;
936 }
937
938 /* Implement this operation via reopening the image. */
939 rc = rawFreeImage(pImage, false);
940 if (RT_FAILURE(rc))
941 goto out;
942 rc = rawOpenImage(pImage, uOpenFlags);
943
944out:
945 LogFlowFunc(("returns %Rrc\n", rc));
946 return rc;
947}
948
949/** @copydoc VBOXHDDBACKEND::pfnGetComment */
950static DECLCALLBACK(int) rawGetComment(void *pBackendData, char *pszComment,
951 size_t cbComment)
952{
953 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
954 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
955 int rc;
956
957 AssertPtr(pImage);
958
959 if (pImage)
960 rc = VERR_NOT_SUPPORTED;
961 else
962 rc = VERR_VD_NOT_OPENED;
963
964 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
965 return rc;
966}
967
968/** @copydoc VBOXHDDBACKEND::pfnSetComment */
969static DECLCALLBACK(int) rawSetComment(void *pBackendData, const char *pszComment)
970{
971 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
972 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
973 int rc;
974
975 AssertPtr(pImage);
976
977 if (pImage)
978 {
979 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
980 rc = VERR_VD_IMAGE_READ_ONLY;
981 else
982 rc = VERR_NOT_SUPPORTED;
983 }
984 else
985 rc = VERR_VD_NOT_OPENED;
986
987 LogFlowFunc(("returns %Rrc\n", rc));
988 return rc;
989}
990
991/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
992static DECLCALLBACK(int) rawGetUuid(void *pBackendData, PRTUUID pUuid)
993{
994 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
995 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
996 int rc;
997
998 AssertPtr(pImage);
999
1000 if (pImage)
1001 rc = VERR_NOT_SUPPORTED;
1002 else
1003 rc = VERR_VD_NOT_OPENED;
1004
1005 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1006 return rc;
1007}
1008
1009/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
1010static DECLCALLBACK(int) rawSetUuid(void *pBackendData, PCRTUUID pUuid)
1011{
1012 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1013 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1014 int rc;
1015
1016 LogFlowFunc(("%RTuuid\n", pUuid));
1017 AssertPtr(pImage);
1018
1019 if (pImage)
1020 {
1021 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1022 rc = VERR_NOT_SUPPORTED;
1023 else
1024 rc = VERR_VD_IMAGE_READ_ONLY;
1025 }
1026 else
1027 rc = VERR_VD_NOT_OPENED;
1028
1029 LogFlowFunc(("returns %Rrc\n", rc));
1030 return rc;
1031}
1032
1033/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1034static DECLCALLBACK(int) rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1035{
1036 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1037 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1038 int rc;
1039
1040 AssertPtr(pImage);
1041
1042 if (pImage)
1043 rc = VERR_NOT_SUPPORTED;
1044 else
1045 rc = VERR_VD_NOT_OPENED;
1046
1047 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1048 return rc;
1049}
1050
1051/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1052static DECLCALLBACK(int) rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1053{
1054 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1055 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1056 int rc;
1057
1058 AssertPtr(pImage);
1059
1060 if (pImage)
1061 {
1062 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1063 rc = VERR_NOT_SUPPORTED;
1064 else
1065 rc = VERR_VD_IMAGE_READ_ONLY;
1066 }
1067 else
1068 rc = VERR_VD_NOT_OPENED;
1069
1070 LogFlowFunc(("returns %Rrc\n", rc));
1071 return rc;
1072}
1073
1074/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1075static DECLCALLBACK(int) rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
1076{
1077 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1078 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1079 int rc;
1080
1081 AssertPtr(pImage);
1082
1083 if (pImage)
1084 rc = VERR_NOT_SUPPORTED;
1085 else
1086 rc = VERR_VD_NOT_OPENED;
1087
1088 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1089 return rc;
1090}
1091
1092/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1093static DECLCALLBACK(int) rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1094{
1095 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1096 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1097 int rc;
1098
1099 AssertPtr(pImage);
1100
1101 if (pImage)
1102 {
1103 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1104 rc = VERR_NOT_SUPPORTED;
1105 else
1106 rc = VERR_VD_IMAGE_READ_ONLY;
1107 }
1108 else
1109 rc = VERR_VD_NOT_OPENED;
1110
1111 LogFlowFunc(("returns %Rrc\n", rc));
1112 return rc;
1113}
1114
1115/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1116static DECLCALLBACK(int) rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1117{
1118 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1119 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1120 int rc;
1121
1122 AssertPtr(pImage);
1123
1124 if (pImage)
1125 rc = VERR_NOT_SUPPORTED;
1126 else
1127 rc = VERR_VD_NOT_OPENED;
1128
1129 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1130 return rc;
1131}
1132
1133/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1134static DECLCALLBACK(int) rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1135{
1136 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1137 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1138 int rc;
1139
1140 AssertPtr(pImage);
1141
1142 if (pImage)
1143 {
1144 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1145 rc = VERR_NOT_SUPPORTED;
1146 else
1147 rc = VERR_VD_IMAGE_READ_ONLY;
1148 }
1149 else
1150 rc = VERR_VD_NOT_OPENED;
1151
1152 LogFlowFunc(("returns %Rrc\n", rc));
1153 return rc;
1154}
1155
1156/** @copydoc VBOXHDDBACKEND::pfnDump */
1157static DECLCALLBACK(void) rawDump(void *pBackendData)
1158{
1159 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1160
1161 AssertPtr(pImage);
1162 if (pImage)
1163 {
1164 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1165 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1166 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1167 pImage->cbSize / 512);
1168 }
1169}
1170
1171
1172
1173const VBOXHDDBACKEND g_RawBackend =
1174{
1175 /* pszBackendName */
1176 "RAW",
1177 /* cbSize */
1178 sizeof(VBOXHDDBACKEND),
1179 /* uBackendCaps */
1180 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1181 /* paFileExtensions */
1182 s_aRawFileExtensions,
1183 /* paConfigInfo */
1184 NULL,
1185 /* pfnCheckIfValid */
1186 rawCheckIfValid,
1187 /* pfnOpen */
1188 rawOpen,
1189 /* pfnCreate */
1190 rawCreate,
1191 /* pfnRename */
1192 rawRename,
1193 /* pfnClose */
1194 rawClose,
1195 /* pfnRead */
1196 rawRead,
1197 /* pfnWrite */
1198 rawWrite,
1199 /* pfnFlush */
1200 rawFlush,
1201 /* pfnDiscard */
1202 NULL,
1203 /* pfnGetVersion */
1204 rawGetVersion,
1205 /* pfnGetSectorSize */
1206 rawGetSectorSize,
1207 /* pfnGetSize */
1208 rawGetSize,
1209 /* pfnGetFileSize */
1210 rawGetFileSize,
1211 /* pfnGetPCHSGeometry */
1212 rawGetPCHSGeometry,
1213 /* pfnSetPCHSGeometry */
1214 rawSetPCHSGeometry,
1215 /* pfnGetLCHSGeometry */
1216 rawGetLCHSGeometry,
1217 /* pfnSetLCHSGeometry */
1218 rawSetLCHSGeometry,
1219 /* pfnGetImageFlags */
1220 rawGetImageFlags,
1221 /* pfnGetOpenFlags */
1222 rawGetOpenFlags,
1223 /* pfnSetOpenFlags */
1224 rawSetOpenFlags,
1225 /* pfnGetComment */
1226 rawGetComment,
1227 /* pfnSetComment */
1228 rawSetComment,
1229 /* pfnGetUuid */
1230 rawGetUuid,
1231 /* pfnSetUuid */
1232 rawSetUuid,
1233 /* pfnGetModificationUuid */
1234 rawGetModificationUuid,
1235 /* pfnSetModificationUuid */
1236 rawSetModificationUuid,
1237 /* pfnGetParentUuid */
1238 rawGetParentUuid,
1239 /* pfnSetParentUuid */
1240 rawSetParentUuid,
1241 /* pfnGetParentModificationUuid */
1242 rawGetParentModificationUuid,
1243 /* pfnSetParentModificationUuid */
1244 rawSetParentModificationUuid,
1245 /* pfnDump */
1246 rawDump,
1247 /* pfnGetTimestamp */
1248 NULL,
1249 /* pfnGetParentTimestamp */
1250 NULL,
1251 /* pfnSetParentTimestamp */
1252 NULL,
1253 /* pfnGetParentFilename */
1254 NULL,
1255 /* pfnSetParentFilename */
1256 NULL,
1257 /* pfnComposeLocation */
1258 genericFileComposeLocation,
1259 /* pfnComposeName */
1260 genericFileComposeName,
1261 /* pfnCompact */
1262 NULL,
1263 /* pfnResize */
1264 NULL,
1265 /* pfnRepair */
1266 NULL,
1267 /* pfnTraverseMetadata */
1268 NULL
1269};
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