Changeset 7576 in vbox
- Timestamp:
- Mar 26, 2008 1:25:36 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r7157 r7576 36 36 * Constants And Macros, Structures and Typedefs * 37 37 *******************************************************************************/ 38 39 /** Maximum encoded string size (including NUL) we allow for VMDK images. 40 * Deliberately not set high to avoid running out of descriptor space. */ 41 #define VMDK_ENCRYPTED_COMMENT_MAX 1024 38 42 39 43 /** VMDK descriptor DDB entry for PCHS cylinders. */ … … 231 235 232 236 /** 237 * Extents files entry. Used for opening a particular file only once. 238 */ 239 typedef struct VMDKFILE 240 { 241 /** Pointer to filename. Local copy. */ 242 const char *pszFilename; 243 /** File open flags for consistency checking. */ 244 unsigned fOpen; 245 /** File handle. */ 246 RTFILE File; 247 /** Reference counter. */ 248 unsigned uReferences; 249 /** Flag whether the file should be deleted on last close. */ 250 bool fDelete; 251 /** Pointer to next file descriptor. Singly linked list is fast enough. */ 252 struct VMDKFILE *pNext; 253 } VMDKFILE, *PVMDKFILE; 254 255 /** 233 256 * Grain table cache size. Allocated per image. 234 257 */ … … 312 335 /** Number of image extents. */ 313 336 unsigned cExtents; 337 /** Pointer to the files list, for opening a file referenced multiple 338 * times only once (happens mainly with raw partition access). */ 339 PVMDKFILE pFiles; 314 340 315 341 /** Base image name. */ … … 359 385 *******************************************************************************/ 360 386 361 static int vmdkReadGrainDirectory(PVMDKEXTENT pExtent);362 387 static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent); 363 388 364 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor); 365 static int vmdkReadMetaSparseExtent(PVMDKEXTENT pExtent); 366 static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent); 367 #ifdef VBOX_WITH_VMDK_ESX 368 static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent); 369 #endif /* VBOX_WITH_VMDK_ESX */ 370 static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete); 389 static void vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 390 bool fDelete); 371 391 372 392 static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents); … … 392 412 393 413 /** 414 * Internal: open a file (using a file descriptor cache to ensure each file 415 * is only opened once - anything else can cause locking problems). 416 */ 417 static int vmdkFileOpen(PVMDKIMAGE pImage, PRTFILE pFile, 418 const char *pszFilename, unsigned fOpen) 419 { 420 int rc = VINF_SUCCESS; 421 PVMDKFILE pVmdkFile; 422 423 for (pVmdkFile = pImage->pFiles; 424 pVmdkFile != NULL; 425 pVmdkFile = pVmdkFile->pNext) 426 { 427 if (!strcmp(pszFilename, pVmdkFile->pszFilename)) 428 { 429 Assert(fOpen == pVmdkFile->fOpen); 430 pVmdkFile->uReferences++; 431 *pFile = pVmdkFile->File; 432 return rc; 433 } 434 } 435 436 /* If we get here, there's no matching entry in the cache. */ 437 pVmdkFile = (PVMDKFILE)RTMemAllocZ(sizeof(VMDKFILE)); 438 if (!VALID_PTR(pVmdkFile)) 439 { 440 *pFile = NIL_RTFILE; 441 return VERR_NO_MEMORY; 442 } 443 444 pVmdkFile->pszFilename = RTStrDup(pszFilename); 445 if (!VALID_PTR(pVmdkFile->pszFilename)) 446 { 447 RTMemFree(pVmdkFile); 448 *pFile = NIL_RTFILE; 449 return VERR_NO_MEMORY; 450 } 451 pVmdkFile->fOpen = fOpen; 452 rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen); 453 if (VBOX_SUCCESS(rc)) 454 { 455 pVmdkFile->uReferences = 1; 456 pVmdkFile->pNext = pImage->pFiles; 457 pImage->pFiles = pVmdkFile; 458 *pFile = pVmdkFile->File; 459 } 460 else 461 { 462 RTMemFree(pVmdkFile); 463 *pFile = NIL_RTFILE; 464 } 465 466 return rc; 467 } 468 469 /** 470 * Internal: close a file, updating the file descriptor cache. 471 */ 472 static int vmdkFileClose(PVMDKIMAGE pImage, PRTFILE pFile, bool fDelete) 473 { 474 int rc = VINF_SUCCESS; 475 RTFILE File; 476 PVMDKFILE pVmdkFile, pPrev; 477 478 Assert(VALID_PTR(pFile) && *pFile != NIL_RTFILE); 479 File = *pFile; 480 481 pPrev = NULL; 482 for (pVmdkFile = pImage->pFiles; 483 pVmdkFile != NULL; 484 pVmdkFile = pVmdkFile->pNext) 485 { 486 if (File == pVmdkFile->File) 487 { 488 pVmdkFile->fDelete |= fDelete; 489 Assert(pVmdkFile->uReferences); 490 pVmdkFile->uReferences--; 491 if (pVmdkFile->uReferences == 0) 492 { 493 /* Unchain the element from the list. */ 494 if (pPrev == NULL) 495 pImage->pFiles = pVmdkFile->pNext; 496 else 497 pPrev->pNext = pVmdkFile->pNext; 498 rc = RTFileClose(File); 499 *pFile = NIL_RTFILE; 500 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete) 501 rc = RTFileDelete(pVmdkFile->pszFilename); 502 RTStrFree((char *)(void *)pVmdkFile->pszFilename); 503 RTMemFree(pVmdkFile); 504 } 505 return rc; 506 } 507 pPrev = pVmdkFile; 508 } 509 510 AssertMsgFailed(("trying to close unknown file %#p", File)); 511 return VERR_INVALID_PARAMETER; 512 } 513 514 /** 515 * Internal: check if all files are closed, prevent leaking resources. 516 */ 517 static int vmdkFileCheckAllClose(PVMDKIMAGE pImage) 518 { 519 int rc = VINF_SUCCESS, rc2; 520 PVMDKFILE pVmdkFile; 521 522 Assert(pImage->pFiles == NULL); 523 for (pVmdkFile = pImage->pFiles; 524 pVmdkFile != NULL; 525 pVmdkFile = pVmdkFile->pNext) 526 { 527 LogRel(("VMDK: leaking reference to file \"%s\"\n", 528 pVmdkFile->pszFilename)); 529 pImage->pFiles = pVmdkFile->pNext; 530 rc2 = RTFileClose(pVmdkFile->File); 531 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete) 532 rc2 = RTFileDelete(pVmdkFile->pszFilename); 533 RTStrFree((char *)(void *)pVmdkFile->pszFilename); 534 RTMemFree(pVmdkFile); 535 if (VBOX_SUCCESS(rc)) 536 rc = rc2; 537 } 538 return rc; 539 } 540 541 /** 394 542 * Internal: truncate a string (at a UTF8 code point boundary) and encode the 395 543 * critical non-ASCII characters. … … 397 545 static char *vmdkEncodeString(const char *psz) 398 546 { 399 /** @todo implement me. */ 400 return RTStrDup(psz); 547 char szEnc[VMDK_ENCRYPTED_COMMENT_MAX + 3]; 548 char *pszDst = szEnc; 549 550 Assert(VALID_PTR(psz)); 551 552 for (; *psz; psz = RTStrNextCp(psz)) 553 { 554 char *pszDstPrev = pszDst; 555 RTUNICP Cp = RTStrGetCp(psz); 556 if (Cp == '\\') 557 { 558 pszDst = RTStrPutCp(pszDst, Cp); 559 pszDst = RTStrPutCp(pszDst, Cp); 560 } 561 else if (Cp == '\n') 562 { 563 pszDst = RTStrPutCp(pszDst, '\\'); 564 pszDst = RTStrPutCp(pszDst, 'n'); 565 } 566 else if (Cp == '\r') 567 { 568 pszDst = RTStrPutCp(pszDst, '\\'); 569 pszDst = RTStrPutCp(pszDst, 'r'); 570 } 571 else 572 pszDst = RTStrPutCp(pszDst, Cp); 573 if (pszDst - szEnc >= VMDK_ENCRYPTED_COMMENT_MAX - 1) 574 { 575 pszDst = pszDstPrev; 576 break; 577 } 578 } 579 *pszDst = '\0'; 580 return RTStrDup(szEnc); 401 581 } 402 582 … … 406 586 static int vmdkDecodeString(const char *pszEncoded, char *psz, size_t cb) 407 587 { 408 /** @todo implement me. */ 588 int rc = VINF_SUCCESS; 589 char szBuf[4]; 590 409 591 if (!cb) 410 return VINF_SUCCESS; 411 strncpy(psz, pszEncoded, cb); 412 psz[cb - 1] = '\0'; 413 return VINF_SUCCESS; 592 return VERR_BUFFER_OVERFLOW; 593 594 Assert(VALID_PTR(psz)); 595 596 for (; *pszEncoded; pszEncoded = RTStrNextCp(pszEncoded)) 597 { 598 char *pszDst = szBuf; 599 RTUNICP Cp = RTStrGetCp(pszEncoded); 600 if (Cp == '\\') 601 { 602 pszEncoded = RTStrNextCp(pszEncoded); 603 RTUNICP CpQ = RTStrGetCp(pszEncoded); 604 if (CpQ == 'n') 605 RTStrPutCp(pszDst, '\n'); 606 else if (CpQ == 'r') 607 RTStrPutCp(pszDst, '\r'); 608 else if (CpQ == '\0') 609 { 610 rc = VERR_VDI_INVALID_HEADER; 611 break; 612 } 613 else 614 RTStrPutCp(pszDst, CpQ); 615 } 616 else 617 pszDst = RTStrPutCp(pszDst, Cp); 618 619 /* Need to leave space for terminating NUL. */ 620 if ((size_t)(pszDst - szBuf) + 1 >= cb) 621 { 622 rc = VERR_BUFFER_OVERFLOW; 623 break; 624 } 625 memcpy(psz, szBuf, pszDst - szBuf); 626 psz += pszDst - szBuf; 627 } 628 *psz = '\0'; 629 return rc; 414 630 } 415 631 … … 1654 1870 * Internal: read metadata belonging to a sparse extent. 1655 1871 */ 1656 static int vmdkReadMetaSparseExtent(PVMDK EXTENT pExtent)1872 static int vmdkReadMetaSparseExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent) 1657 1873 { 1658 1874 SparseExtentHeader Header; … … 1743 1959 out: 1744 1960 if (VBOX_FAILURE(rc)) 1745 vmdkFreeExtentData(p Extent, false);1961 vmdkFreeExtentData(pImage, pExtent, false); 1746 1962 1747 1963 return rc; … … 1851 2067 out: 1852 2068 if (VBOX_FAILURE(rc)) 1853 vmdkFreeExtentData(p Extent, false);2069 vmdkFreeExtentData(pImage, pExtent, false); 1854 2070 1855 2071 return rc; … … 1861 2077 * deleting the referenced files. 1862 2078 */ 1863 static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete) 2079 static void vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 2080 bool fDelete) 1864 2081 { 1865 2082 vmdkFreeGrainDirectory(pExtent); … … 1871 2088 if (pExtent->File != NIL_RTFILE) 1872 2089 { 1873 RTFileClose(pExtent->File); 1874 pExtent->File = NIL_RTFILE; 1875 if ( fDelete 1876 && strcmp(pExtent->pszFullname, pExtent->pszBasename) != 0 1877 && pExtent->pszFullname) 1878 RTFileDelete(pExtent->pszFullname); 2090 vmdkFileClose(pImage, &pExtent->File, 2091 fDelete 2092 && pExtent->pszFullname 2093 && strcmp(pExtent->pszFullname, pExtent->pszBasename)); 1879 2094 } 1880 2095 if (pExtent->pszBasename) … … 1965 2180 pImage->uOpenFlags = uOpenFlags; 1966 2181 1967 /** @todo check whether the same file is used somewhere else. don't open any file twice, leads to locking problems and can cause trouble with file caching. */1968 1969 2182 /* 1970 2183 * Open the image. 1971 2184 */ 1972 rc = RTFileOpen(&File, pImage->pszFilename,1973 uOpenFlags & VD_OPEN_FLAGS_READONLY1974 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE1975 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);2185 rc = vmdkFileOpen(pImage, &File, pImage->pszFilename, 2186 uOpenFlags & VD_OPEN_FLAGS_READONLY 2187 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2188 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 1976 2189 if (VBOX_FAILURE(rc)) 1977 2190 { … … 2002 2215 pExtent->File = File; 2003 2216 pImage->File = NIL_RTFILE; 2004 rc = vmdkReadMetaSparseExtent(p Extent);2217 rc = vmdkReadMetaSparseExtent(pImage, pExtent); 2005 2218 if (VBOX_FAILURE(rc)) 2006 2219 goto out; … … 2118 2331 { 2119 2332 case VMDKETYPE_HOSTED_SPARSE: 2120 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2121 uOpenFlags & VD_OPEN_FLAGS_READONLY2122 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE2123 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);2333 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2334 uOpenFlags & VD_OPEN_FLAGS_READONLY 2335 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2336 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2124 2337 if (VBOX_FAILURE(rc)) 2125 2338 { … … 2129 2342 goto out; 2130 2343 } 2131 rc = vmdkReadMetaSparseExtent(p Extent);2344 rc = vmdkReadMetaSparseExtent(pImage, pExtent); 2132 2345 if (VBOX_FAILURE(rc)) 2133 2346 goto out; … … 2141 2354 break; 2142 2355 case VMDKETYPE_FLAT: 2143 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2144 uOpenFlags & VD_OPEN_FLAGS_READONLY2145 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE2146 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);2356 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2357 uOpenFlags & VD_OPEN_FLAGS_READONLY 2358 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2359 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2147 2360 if (VBOX_FAILURE(rc)) 2148 2361 { … … 2242 2455 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename); 2243 2456 pExtent = &pImage->pExtents[0]; 2244 2245 rc = RTFileOpen(&pImage->File, pImage->pszFilename,2246 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);2457 /* Create raw disk descriptor file. */ 2458 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2459 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2247 2460 if (VBOX_FAILURE(rc)) 2248 2461 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename); … … 2266 2479 2267 2480 /* Open flat image, the raw disk. */ 2268 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2269 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);2481 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2482 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2270 2483 if (VBOX_FAILURE(rc)) 2271 2484 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname); … … 2315 2528 2316 2529 /* Create raw partition descriptor file. */ 2317 rc = RTFileOpen(&pImage->File, pImage->pszFilename,2318 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);2530 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2531 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2319 2532 if (VBOX_FAILURE(rc)) 2320 2533 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename); … … 2386 2599 2387 2600 /* Create partition table flat image. */ 2388 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2389 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);2601 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2602 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2390 2603 if (VBOX_FAILURE(rc)) 2391 2604 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname); … … 2433 2646 2434 2647 /* Open flat image, the raw partition. */ 2435 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2436 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);2648 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2649 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2437 2650 if (VBOX_FAILURE(rc)) 2438 2651 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname); … … 2505 2718 if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED) 2506 2719 { 2507 rc = RTFileOpen(&pImage->File, pImage->pszFilename,2508 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);2720 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2721 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2509 2722 if (VBOX_FAILURE(rc)) 2510 2723 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename); … … 2574 2787 2575 2788 /* Create file for extent. */ 2576 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,2577 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);2789 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2790 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2578 2791 if (VBOX_FAILURE(rc)) 2579 2792 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); … … 2866 3079 { 2867 3080 for (unsigned i = 0 ; i < pImage->cExtents; i++) 2868 vmdkFreeExtentData( &pImage->pExtents[i], fDelete);3081 vmdkFreeExtentData(pImage, &pImage->pExtents[i], fDelete); 2869 3082 RTMemFree(pImage->pExtents); 2870 3083 pImage->pExtents = NULL; 2871 3084 } 2872 3085 if (pImage->File != NIL_RTFILE) 2873 { 2874 RTFileClose(pImage->File); 2875 pImage->File = NIL_RTFILE; 2876 } 2877 if (fDelete && pImage->pszFilename) 2878 RTFileDelete(pImage->pszFilename); 3086 vmdkFileClose(pImage, &pImage->File, fDelete); 3087 vmdkFileCheckAllClose(pImage); 2879 3088 } 2880 3089 … … 3227 3436 pImage->File = NIL_RTFILE; 3228 3437 pImage->pExtents = NULL; 3438 pImage->pFiles = NULL; 3229 3439 pImage->pGTCache = NULL; 3230 3440 pImage->pDescData = NULL; … … 3276 3486 pImage->File = NIL_RTFILE; 3277 3487 pImage->pExtents = NULL; 3488 pImage->pFiles = NULL; 3278 3489 pImage->pGTCache = NULL; 3279 3490 pImage->pDescData = NULL; … … 3333 3544 pImage->File = NIL_RTFILE; 3334 3545 pImage->pExtents = NULL; 3546 pImage->pFiles = NULL; 3335 3547 pImage->pGTCache = NULL; 3336 3548 pImage->pDescData = NULL; … … 3944 4156 { 3945 4157 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 3946 4158 { 3947 4159 pImage->ImageUuid = *pUuid; 3948 4160 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, … … 3951 4163 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename); 3952 4164 rc = VINF_SUCCESS; 3953 3954 3955 4165 } 4166 else 4167 rc = VERR_VDI_IMAGE_READ_ONLY; 3956 4168 } 3957 4169 else … … 3995 4207 { 3996 4208 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 3997 4209 { 3998 4210 pImage->ModificationUuid = *pUuid; 3999 4211 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, … … 4002 4214 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename); 4003 4215 rc = VINF_SUCCESS; 4004 4005 4006 4216 } 4217 else 4218 rc = VERR_VDI_IMAGE_READ_ONLY; 4007 4219 } 4008 4220 else … … 4046 4258 { 4047 4259 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 4048 4260 { 4049 4261 pImage->ParentUuid = *pUuid; 4050 4262 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, … … 4053 4265 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename); 4054 4266 rc = VINF_SUCCESS; 4055 4056 4057 4267 } 4268 else 4269 rc = VERR_VDI_IMAGE_READ_ONLY; 4058 4270 } 4059 4271 else … … 4097 4309 { 4098 4310 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 4099 4311 { 4100 4312 pImage->ParentModificationUuid = *pUuid; 4101 4313 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, … … 4104 4316 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename); 4105 4317 rc = VINF_SUCCESS; 4106 4107 4108 4318 } 4319 else 4320 rc = VERR_VDI_IMAGE_READ_ONLY; 4109 4321 } 4110 4322 else
Note:
See TracChangeset
for help on using the changeset viewer.