- Timestamp:
- Apr 26, 2017 12:00:54 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/fat.h
r66669 r66676 520 520 /** The directory entry name. 521 521 * First character serves as a flag to indicate deleted or not. */ 522 charachName[8+3];522 uint8_t achName[8+3]; 523 523 /** Attributes (FAT_ATTR_XXX). */ 524 524 uint8_t fAttrib; … … 588 588 /** @} */ 589 589 590 /** @name FATDIRENTRY_C ASE_F_XXX - FATDIRENTRY::fCase flags.590 /** @name FATDIRENTRY_CH0_XXX - FATDIRENTRY::achName[0] 591 591 * @{ */ 592 592 /** Deleted entry. */ … … 636 636 typedef FATDIRNAMESLOT const *PCFATDIRNAMESLOT; 637 637 638 /** Slot ID flag indicating that it's the first slot. */ 639 #define FATDIRNAMESLOT_FIRST_SLOT_FLAG UINT8_C(0x40) 640 /** Highest slot ID recognized. This allows for 260 characters, however many 641 * implementation limits it to 255 or 250. */ 642 #define FATDIRNAMESLOT_HIGHEST_SLOT_ID UINT8_C(0x14) 643 /** Max number of slots recognized. (This is the same as the higest slot ID 644 * because the 0 isn't a valid ID.) */ 645 #define FATDIRNAMESLOT_MAX_SLOTS FATDIRNAMESLOT_HIGHEST_SLOT_ID 646 /** Number of UTF-16 units per slot. */ 647 #define FATDIRNAMESLOT_CHARS_PER_SLOT (5 + 6 + 2) 648 649 638 650 639 651 /** -
trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp
r66674 r66676 51 51 * Defined Constants And Macros * 52 52 *********************************************************************************************************************************/ 53 /** Gets the cluster from a directory entry. 53 /** 54 * Gets the cluster from a directory entry. 55 * 54 56 * @param a_pDirEntry Pointer to the directory entry. 55 57 * @param a_pVol Pointer to the volume. … … 59 61 ? RT_MAKE_U32((a_pDirEntry)->idxCluster, (a_pDirEntry)->u.idxClusterHigh) \ 60 62 : (a_pDirEntry)->idxCluster ) 63 64 /** 65 * Rotates a unsigned 8-bit value one bit to the right. 66 * 67 * @returns Rotated 8-bit value. 68 * @param a_bValue The value to rotate. 69 */ 70 #define RTFSFAT_ROT_R1_U8(a_bValue) (((a_bValue) >> 1) | (uint8_t)((a_bValue) << 7)) 61 71 62 72 … … 478 488 pChain->cClusters = 0; 479 489 RTListInit(&pChain->ListParts); 490 } 491 492 493 /** 494 * Deletes a chain, freeing it's resources. 495 * 496 * @param pChain The chain. 497 */ 498 static void rtFsFatChain_Delete(PRTFSFATCHAIN pChain) 499 { 500 Assert(RT_IS_POWER_OF_TWO(pChain->cbCluster)); 501 Assert(RT_BIT_32(pChain->cClusterByteShift) == pChain->cbCluster); 502 503 PRTFSFATCHAINPART pPart = RTListRemoveLast(&pChain->ListParts, RTFSFATCHAINPART, ListEntry); 504 while (pPart) 505 { 506 RTMemFree(pPart); 507 pPart = RTListRemoveLast(&pChain->ListParts, RTFSFATCHAINPART, ListEntry); 508 } 509 510 pChain->cbChain = 0; 511 pChain->cClusters = 0; 480 512 } 481 513 … … 1281 1313 1282 1314 /** 1315 * Allocates clusters. 1316 * 1317 * Will free the clusters if it fails to allocate all of them. 1318 * 1319 * @returns IPRT status code. 1320 * @param pThis The FAT volume instance. 1321 * @param pChain The chain. 1322 * @param cClusters Number of clusters to add to the chain. 1323 */ 1324 static int rtFsFatClusterMap_AllocateMoreClusters(PRTFSFATVOL pThis, PRTFSFATCHAIN pChain, uint32_t cClusters) 1325 { 1326 int rc = VINF_SUCCESS; 1327 uint32_t const cOldClustersInChain = pChain->cClusters; 1328 uint32_t const idxOldLastCluster = rtFsFatChain_GetLastCluster(pChain); 1329 uint32_t idxPrevCluster = idxOldLastCluster; 1330 uint32_t iCluster = 0; 1331 while (iCluster < cClusters) 1332 { 1333 uint32_t idxCluster; 1334 rc = rtFsFatClusterMap_AllocateCluster(pThis, idxPrevCluster, &idxCluster); 1335 if (RT_SUCCESS(rc)) 1336 { 1337 rc = rtFsFatChain_Append(pChain, idxCluster); 1338 if (RT_SUCCESS(rc)) 1339 { 1340 /* next */ 1341 iCluster++; 1342 continue; 1343 } 1344 1345 /* Bail out, freeing any clusters we've managed to allocate by now. */ 1346 rtFsFatClusterMap_FreeCluster(pThis, idxCluster); 1347 } 1348 if (idxOldLastCluster != UINT32_MAX) 1349 rtFsFatClusterMap_SetEndOfChain(pThis, idxOldLastCluster); 1350 while (iCluster-- > 0) 1351 rtFsFatClusterMap_FreeCluster(pThis, rtFsFatChain_GetClusterByIndex(pChain, cOldClustersInChain + iCluster)); 1352 rtFsFatChain_Shrink(pChain, iCluster); 1353 break; 1354 } 1355 return rc; 1356 } 1357 1358 1359 1360 /** 1283 1361 * Converts a FAT timestamp into an IPRT timesspec. 1284 1362 * … … 1289 1367 * @param pVol The volume. 1290 1368 */ 1291 static void rtFsFatD osDateTimeToSpec(PRTTIMESPEC pTimeSpec, uint16_t uDate, uint16_t uTime,1369 static void rtFsFatDateTime2TimeSpec(PRTTIMESPEC pTimeSpec, uint16_t uDate, uint16_t uTime, 1292 1370 uint8_t cCentiseconds, PCRTFSFATVOL pVol) 1293 1371 { … … 1315 1393 1316 1394 RTTimeImplode(pTimeSpec, RTTimeNormalize(&Time)); 1317 RTTimeSpecAddNano(pTimeSpec, pVol->offNanoUTC); 1395 RTTimeSpecSubNano(pTimeSpec, pVol->offNanoUTC); 1396 } 1397 1398 1399 /** 1400 * Converts an IPRT timespec to a FAT timestamp. 1401 * 1402 * @returns The centiseconds part. 1403 * @param pVol The volume. 1404 * @param pTimeSpec The IPRT timespec to convert (UTC). 1405 * @param puDate Where to return the date part of the FAT timestamp. 1406 * @param puTime Where to return the time part of the FAT timestamp. 1407 */ 1408 static uint8_t rtFsFatTimeSpec2FatDateTime(PCRTFSFATVOL pVol, PCRTTIMESPEC pTimeSpec, uint16_t *puDate, uint16_t *puTime) 1409 { 1410 RTTIMESPEC TimeSpec = *pTimeSpec; 1411 RTTIME Time; 1412 RTTimeExplode(&Time, RTTimeSpecSubNano(&TimeSpec, pVol->offNanoUTC)); 1413 1414 if (puDate) 1415 *puDate = ((RT_MIN(Time.i32Year, 1980) - 1980) << 9) 1416 | (Time.u8Month << 5) 1417 | Time.u8MonthDay; 1418 if (puTime) 1419 *puTime = (Time.u8Hour << 11) 1420 | (Time.u8Minute << 5) 1421 | (Time.u8Second >> 1); 1422 return (Time.u8Second & 1) * 100 + Time.u32Nanosecond / 10000000; 1423 1424 } 1425 1426 1427 /** 1428 * Gets the current FAT timestamp. 1429 * 1430 * @returns The centiseconds part. 1431 * @param pVol The volume. 1432 * @param puDate Where to return the date part of the FAT timestamp. 1433 * @param puTime Where to return the time part of the FAT timestamp. 1434 */ 1435 static uint8_t rtFsFatCurrentFatDateTime(PCRTFSFATVOL pVol, uint16_t *puDate, uint16_t *puTime) 1436 { 1437 RTTIMESPEC TimeSpec; 1438 return rtFsFatTimeSpec2FatDateTime(pVol, RTTimeNow(&TimeSpec), puDate, puTime); 1318 1439 } 1319 1440 … … 1340 1461 pObj->fMaybeDirtyFat = false; 1341 1462 pObj->fMaybeDirtyDirEnt = false; 1342 rtFsFatD osDateTimeToSpec(&pObj->ModificationTime, pDirEntry->uModifyDate, pDirEntry->uModifyTime, 0, pVol);1343 rtFsFatD osDateTimeToSpec(&pObj->BirthTime, pDirEntry->uBirthDate, pDirEntry->uBirthTime, pDirEntry->uBirthCentiseconds, pVol);1344 rtFsFatD osDateTimeToSpec(&pObj->AccessTime, pDirEntry->uAccessDate, 0, 0, pVol);1463 rtFsFatDateTime2TimeSpec(&pObj->ModificationTime, pDirEntry->uModifyDate, pDirEntry->uModifyTime, 0, pVol); 1464 rtFsFatDateTime2TimeSpec(&pObj->BirthTime, pDirEntry->uBirthDate, pDirEntry->uBirthTime, pDirEntry->uBirthCentiseconds, pVol); 1465 rtFsFatDateTime2TimeSpec(&pObj->AccessTime, pDirEntry->uAccessDate, 0, 0, pVol); 1345 1466 } 1346 1467 … … 1411 1532 if (pObj->pParentDir) 1412 1533 rtFsFatDir_RemoveOpenChild(pObj->pParentDir, pObj); 1534 rtFsFatChain_Delete(&pObj->Clusters); 1413 1535 return rc; 1414 1536 } … … 1502 1624 uint32_t cbFileLeft = pThis->Core.cbObject - (uint32_t)off; 1503 1625 uint32_t cbRead = 0; 1504 uint32_tcbLeft = pSgBuf->paSegs[0].cbSeg;1626 size_t cbLeft = pSgBuf->paSegs[0].cbSeg; 1505 1627 uint8_t *pbDst = (uint8_t *)pSgBuf->paSegs[0].pvSeg; 1506 1628 while (cbLeft > 0) … … 1513 1635 uint32_t cbToRead = pThis->Core.Clusters.cbCluster - ((uint32_t)off & (pThis->Core.Clusters.cbCluster - 1)); 1514 1636 if (cbToRead > cbLeft) 1515 cbToRead = cbLeft;1637 cbToRead = (uint32_t)cbLeft; 1516 1638 if (cbToRead > cbFileLeft) 1517 1639 cbToRead = cbFileLeft; … … 1649 1771 int rc = VINF_SUCCESS; 1650 1772 uint32_t cbWritten = 0; 1651 uint32_tcbLeft = pSgBuf->paSegs[0].cbSeg;1773 size_t cbLeft = pSgBuf->paSegs[0].cbSeg; 1652 1774 uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg; 1653 1775 while (cbLeft > 0) … … 1656 1778 uint32_t cbToWrite = pThis->Core.Clusters.cbCluster - ((uint32_t)off & (pThis->Core.Clusters.cbCluster - 1)); 1657 1779 if (cbToWrite > cbLeft) 1658 cbToWrite = cbLeft;1780 cbToWrite = (uint32_t)cbLeft; 1659 1781 uint64_t offNew = (uint64_t)off + cbToWrite; 1660 1782 if (offNew < _4G) … … 2149 2271 2150 2272 2273 /** 2274 * Release a directory buffer after done reading from it. 2275 * 2276 * This is currently just a placeholder. 2277 * 2278 * @param pThis The directory. 2279 * @param uBufferReadLock The buffer lock. 2280 */ 2151 2281 static void rtFsFatDir_ReleaseBufferAfterReading(PRTFSFATDIR pThis, uint32_t uBufferReadLock) 2152 2282 { … … 2290 2420 2291 2421 /** 2422 * Calculates the checksum of a directory entry. 2423 * @returns Checksum. 2424 * @param pDirEntry The directory entry to checksum. 2425 */ 2426 static uint8_t rtFsFatDir_CalcChecksum(PCFATDIRENTRY pDirEntry) 2427 { 2428 uint8_t bChecksum = pDirEntry->achName[0]; 2429 for (uint8_t off = 1; off < RT_ELEMENTS(pDirEntry->achName); off++) 2430 { 2431 bChecksum = RTFSFAT_ROT_R1_U8(bChecksum); 2432 bChecksum += pDirEntry->achName[off]; 2433 } 2434 return bChecksum; 2435 } 2436 2437 2438 /** 2292 2439 * Locates a directory entry in a directory. 2293 2440 * … … 2310 2457 * Turn pszEntry into a 8.3 filename, if possible. 2311 2458 */ 2312 char szName8Dot3[12+1];2313 bool fIs8Dot3Name = rtFsFatDir_StringTo8Dot3(szName8Dot3, pszEntry);2459 char szName8Dot3[12+1]; 2460 bool fIs8Dot3Name = rtFsFatDir_StringTo8Dot3(szName8Dot3, pszEntry); 2314 2461 2315 2462 /* 2316 2463 * Scan the directory buffer by buffer. 2317 2464 */ 2465 RTUTF16 wszName[260+1]; 2466 uint8_t bChecksum = UINT8_MAX; 2467 uint8_t idNextSlot = UINT8_MAX; 2468 size_t cwcName = 0; 2318 2469 uint32_t offEntryInDir = 0; 2319 2470 uint32_t const cbDir = pThis->Core.cbObject; 2320 2471 Assert(RT_ALIGN_32(cbDir, sizeof(*pDirEntry)) == cbDir); 2472 AssertCompile(FATDIRNAMESLOT_MAX_SLOTS * FATDIRNAMESLOT_CHARS_PER_SLOT < RT_ELEMENTS(wszName)); 2473 wszName[260] = '\0'; 2321 2474 2322 2475 while (offEntryInDir < cbDir) … … 2340 2493 break; 2341 2494 case FATDIRENTRY_CH0_DELETED: 2495 cwcName = 0; 2342 2496 continue; 2343 2497 case FATDIRENTRY_CH0_END_OF_DIR: … … 2347 2501 return VERR_FILE_NOT_FOUND; 2348 2502 } 2503 cwcName = 0; 2349 2504 break; /* Technically a valid entry before DOS 2.0, or so some claim. */ 2350 2505 } 2506 2507 /* 2508 * Check for long filename slot. 2509 */ 2351 2510 if ( paEntries[iEntry].Slot.fAttrib == FAT_ATTR_NAME_SLOT 2352 && (paEntries[iEntry].Slot.idSlot - (uint8_t)'A') <= 202353 2511 && paEntries[iEntry].Slot.idxZero == 0 2354 && paEntries[iEntry].Slot.fZero == 0) 2512 && paEntries[iEntry].Slot.fZero == 0 2513 && (paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG) <= FATDIRNAMESLOT_HIGHEST_SLOT_ID 2514 && (paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG) != 0) 2355 2515 { 2356 /** @todo long filenames. */ 2516 /* New slot? */ 2517 if (paEntries[iEntry].Slot.idSlot & FATDIRNAMESLOT_FIRST_SLOT_FLAG) 2518 { 2519 idNextSlot = paEntries[iEntry].Slot.idSlot & ~FATDIRNAMESLOT_FIRST_SLOT_FLAG; 2520 bChecksum = paEntries[iEntry].Slot.bChecksum; 2521 cwcName = idNextSlot * FATDIRNAMESLOT_CHARS_PER_SLOT; 2522 wszName[cwcName] = '\0'; 2523 } 2524 /* Is valid next entry? */ 2525 else if ( paEntries[iEntry].Slot.idSlot == idNextSlot 2526 && paEntries[iEntry].Slot.bChecksum == bChecksum) 2527 { /* likely */ } 2528 else 2529 cwcName = 0; 2530 if (cwcName) 2531 { 2532 idNextSlot--; 2533 size_t offName = idNextSlot * FATDIRNAMESLOT_CHARS_PER_SLOT; 2534 memcpy(&wszName[offName], paEntries[iEntry].Slot.awcName0, sizeof(paEntries[iEntry].Slot.awcName0)); 2535 memcpy(&wszName[offName + 5], paEntries[iEntry].Slot.awcName1, sizeof(paEntries[iEntry].Slot.awcName1)); 2536 memcpy(&wszName[offName + 5 + 6], paEntries[iEntry].Slot.awcName2, sizeof(paEntries[iEntry].Slot.awcName2)); 2537 } 2357 2538 } 2539 /* 2540 * Regular directory entry. Do the matching, first 8.3 then long name. 2541 */ 2358 2542 else if ( fIs8Dot3Name 2359 2543 && memcmp(paEntries[iEntry].Entry.achName, szName8Dot3, sizeof(paEntries[iEntry].Entry.achName)) == 0) … … 2365 2549 return VINF_SUCCESS; 2366 2550 } 2551 else if ( cwcName != 0 2552 && idNextSlot == 0 2553 && rtFsFatDir_CalcChecksum(&paEntries[iEntry].Entry) == bChecksum 2554 && RTUtf16ICmpUtf8(wszName, pszEntry) == 0) 2555 { 2556 *poffEntryInDir = offEntryInDir; 2557 *pDirEntry = paEntries[iEntry].Entry; 2558 *pfLong = true; 2559 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 2560 return VINF_SUCCESS; 2561 } 2562 else 2563 cwcName = 0; 2367 2564 } 2368 2565 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); … … 2372 2569 } 2373 2570 2571 2572 /** 2573 * Calculates the FATDIRENTRY::fCase flags for the given name. 2574 * 2575 * ASSUMES that the name is a 8.3 name. 2576 * 2577 * @returns Case flag mask. 2578 * @param pszName The name. 2579 */ 2580 static uint8_t rtFsFatDir_CalcCaseFlags(const char *pszName) 2581 { 2582 uint8_t bRet = FATDIRENTRY_CASE_F_LOWER_BASE | FATDIRENTRY_CASE_F_LOWER_EXT; 2583 uint8_t bCurrent = FATDIRENTRY_CASE_F_LOWER_BASE; 2584 for (;;) 2585 { 2586 RTUNICP uc; 2587 int rc = RTStrGetCpEx(&pszName, &uc); 2588 if (RT_SUCCESS(rc)) 2589 { 2590 if (uc != 0) 2591 { 2592 if (uc != '.') 2593 { 2594 if (RTUniCpIsUpper(uc)) 2595 { 2596 bRet &= ~bCurrent; 2597 if (!bRet) 2598 return 0; 2599 } 2600 } 2601 else 2602 bCurrent = FATDIRENTRY_CASE_F_LOWER_EXT; 2603 } 2604 else if (bCurrent == FATDIRENTRY_CASE_F_LOWER_BASE) 2605 return bRet & ~FATDIRENTRY_CASE_F_LOWER_EXT; 2606 else 2607 return bRet; 2608 } 2609 else 2610 return 0; 2611 } 2612 } 2613 2614 2615 /** 2616 * Considers whether we need to create a long name or not. 2617 * 2618 * If a long name is needed and the name wasn't 8-dot-3 compatible, a 8-dot-3 2619 * name will be generated and stored in *pDirEntry. 2620 * 2621 * @returns IPRT status code 2622 * @param pThis The directory. 2623 * @param pszEntry The name. 2624 * @param fIs8Dot3Name Whether we have a 8-dot-3 name already. 2625 * @param pDirEntry Where to return the generated 8-dot-3 name. 2626 * @param paSlots Where to return the long name entries. The array 2627 * can hold at least FATDIRNAMESLOT_MAX_SLOTS entries. 2628 * @param pcSlots Where to return the actual number of slots used. 2629 */ 2630 static int rtFsFatDir_MaybeCreateLongNameAndShortAlias(PRTFSFATDIR pThis, const char *pszEntry, bool fIs8Dot3Name, 2631 PFATDIRENTRY pDirEntry, PFATDIRNAMESLOT paSlots, uint32_t *pcSlots) 2632 { 2633 RT_NOREF(pThis, pDirEntry, paSlots, pszEntry); 2634 if (fIs8Dot3Name) 2635 { 2636 *pcSlots = 0; 2637 return VINF_SUCCESS; 2638 } 2639 *pcSlots = UINT32_MAX; 2640 return VERR_INVALID_NAME; 2641 } 2642 2643 2644 /** 2645 * Searches the directory for a given number of free directory entries. 2646 * 2647 * The free entries must be consecutive of course. 2648 * 2649 * @returns IPRT status code. 2650 * @retval VERR_DISK_FULL if no space was found, *pcFreeTail set. 2651 * @param pThis The directory to search. 2652 * @param cEntriesNeeded How many entries we need. 2653 * @param poffEntryInDir Where to return the offset of the first entry we 2654 * found. 2655 * @param pcFreeTail Where to return the number of free entries at the 2656 * end of the directory when VERR_DISK_FULL is 2657 * returned. 2658 */ 2659 static int rtFsFatChain_FindFreeEntries(PRTFSFATDIR pThis, uint32_t cEntriesNeeded, 2660 uint32_t *poffEntryInDir, uint32_t *pcFreeTail) 2661 { 2662 uint32_t offStartFreeEntries = UINT32_MAX; 2663 uint32_t cFreeEntries = 0; 2664 uint32_t offEntryInDir = 0; 2665 uint32_t const cbDir = pThis->Core.cbObject; 2666 Assert(RT_ALIGN_32(cbDir, sizeof(FATDIRENTRY)) == cbDir); 2667 while (offEntryInDir < cbDir) 2668 { 2669 /* Get chunk of entries starting at offEntryInDir. */ 2670 uint32_t uBufferLock = UINT32_MAX; 2671 uint32_t cEntries = 0; 2672 PCFATDIRENTRYUNION paEntries = NULL; 2673 int rc = rtFsFatDir_GetEntriesAt(pThis, offEntryInDir, &paEntries, &cEntries, &uBufferLock); 2674 if (RT_FAILURE(rc)) 2675 return rc; 2676 2677 /* 2678 * Now work thru each of the entries. 2679 */ 2680 for (uint32_t iEntry = 0; iEntry < cEntries; iEntry++, offEntryInDir += sizeof(FATDIRENTRY)) 2681 { 2682 uint8_t const bFirst = paEntries[iEntry].Entry.achName[0]; 2683 if ( bFirst == FATDIRENTRY_CH0_DELETED 2684 || bFirst == FATDIRENTRY_CH0_END_OF_DIR) 2685 { 2686 if (offStartFreeEntries != UINT32_MAX) 2687 cFreeEntries++; 2688 else 2689 { 2690 offStartFreeEntries = offEntryInDir; 2691 cFreeEntries = 1; 2692 } 2693 if (cFreeEntries >= cEntriesNeeded) 2694 { 2695 *pcFreeTail = cEntriesNeeded; 2696 *poffEntryInDir = offStartFreeEntries; 2697 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 2698 return VINF_SUCCESS; 2699 } 2700 2701 if (bFirst == FATDIRENTRY_CH0_END_OF_DIR) 2702 { 2703 if (pThis->Core.pVol->enmBpbVersion >= RTFSFATBPBVER_DOS_2_0) 2704 { 2705 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 2706 *pcFreeTail = cFreeEntries = (cbDir - offStartFreeEntries) / sizeof(FATDIRENTRY); 2707 if (cFreeEntries >= cEntriesNeeded) 2708 { 2709 *poffEntryInDir = offStartFreeEntries; 2710 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 2711 return VINF_SUCCESS; 2712 } 2713 return VERR_DISK_FULL; 2714 } 2715 } 2716 } 2717 else if (offStartFreeEntries != UINT32_MAX) 2718 { 2719 offStartFreeEntries = UINT32_MAX; 2720 cFreeEntries = 0; 2721 } 2722 } 2723 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 2724 } 2725 2726 *pcFreeTail = cFreeEntries; 2727 *poffEntryInDir = UINT32_MAX; 2728 return VERR_DISK_FULL; 2729 } 2730 2731 2732 /** 2733 * Try grow the directory. 2734 * 2735 * This is not called on the root directory. 2736 * 2737 * @returns IPRT status code. 2738 * @retval VERR_DISK_FULL if we failed to allocated new space. 2739 * @param pThis The directory to grow. 2740 * @param cMinNewEntries The minimum number of new entries to allocated. 2741 */ 2742 static int rtFsFatChain_GrowDirectory(PRTFSFATDIR pThis, uint32_t cMinNewEntries) 2743 { 2744 RT_NOREF(pThis, cMinNewEntries); 2745 return VERR_DISK_FULL; 2746 } 2747 2748 2749 /** 2750 * Inserts a directory with zero of more long name slots preceeding it. 2751 * 2752 * @returns IPRT status code. 2753 * @param pThis The directory. 2754 * @param pDirEntry The directory entry. 2755 * @param paSlots The long name slots. 2756 * @param cSlots The number of long name slots. 2757 * @param poffEntryInDir Where to return the directory offset. 2758 */ 2759 static int rtFsFatChain_InsertEntries(PRTFSFATDIR pThis, PCFATDIRENTRY pDirEntry, PFATDIRNAMESLOT paSlots, uint32_t cSlots, 2760 uint32_t *poffEntryInDir) 2761 { 2762 uint32_t const cTotalEntries = cSlots + 1; 2763 2764 /* 2765 * Find somewhere to put the entries. Try extend the directory if we're 2766 * not successful at first. 2767 */ 2768 uint32_t cFreeTailEntries; 2769 uint32_t offFirstInDir; 2770 int rc = rtFsFatChain_FindFreeEntries(pThis, cTotalEntries, &offFirstInDir, &cFreeTailEntries); 2771 if (rc == VERR_DISK_FULL) 2772 { 2773 Assert(cFreeTailEntries < cTotalEntries); 2774 2775 /* Try grow it and use the newly allocated space. */ 2776 if ( pThis->Core.pParentDir 2777 && pThis->cEntries < _64K /* Don't grow beyond 64K entries */) 2778 { 2779 offFirstInDir = pThis->Core.cbObject - cFreeTailEntries * sizeof(FATDIRENTRY); 2780 rc = rtFsFatChain_GrowDirectory(pThis, cTotalEntries - cFreeTailEntries); 2781 } 2782 2783 if (rc == VERR_DISK_FULL) 2784 { 2785 /** @todo Try compact the directory if we couldn't grow it. */ 2786 } 2787 } 2788 if (RT_SUCCESS(rc)) 2789 { 2790 /* 2791 * Update the directory. 2792 */ 2793 uint32_t offCurrent = offFirstInDir; 2794 for (uint32_t iSrcSlot = 0; iSrcSlot < cTotalEntries; iSrcSlot++, offCurrent += sizeof(FATDIRENTRY)) 2795 { 2796 uint32_t uBufferLock; 2797 PFATDIRENTRY pDstEntry; 2798 rc = rtFsFatDir_GetEntryForUpdate(pThis, offCurrent, &pDstEntry, &uBufferLock); 2799 if (RT_SUCCESS(rc)) 2800 { 2801 if (iSrcSlot < cSlots) 2802 memcpy(pDstEntry, &paSlots[iSrcSlot], sizeof(*pDstEntry)); 2803 else 2804 memcpy(pDstEntry, pDirEntry, sizeof(*pDstEntry)); 2805 rc = rtFsFatDir_PutEntryAfterUpdate(pThis, pDstEntry, uBufferLock); 2806 if (RT_SUCCESS(rc)) 2807 continue; 2808 2809 /* 2810 * Bail out: Try mark any edited entries as deleted. 2811 */ 2812 iSrcSlot++; 2813 } 2814 while (iSrcSlot-- > 0) 2815 { 2816 int rc2 = rtFsFatDir_GetEntryForUpdate(pThis, offFirstInDir + iSrcSlot * sizeof(FATDIRENTRY), 2817 &pDstEntry, &uBufferLock); 2818 if (RT_SUCCESS(rc2)) 2819 { 2820 pDstEntry->achName[0] = FATDIRENTRY_CH0_DELETED; 2821 rtFsFatDir_PutEntryAfterUpdate(pThis, pDstEntry, uBufferLock); 2822 } 2823 } 2824 *poffEntryInDir = UINT32_MAX; 2825 return rc; 2826 } 2827 AssertRC(rc); 2828 2829 /* 2830 * Successfully inserted all. 2831 */ 2832 *poffEntryInDir = offFirstInDir + cSlots * sizeof(FATDIRENTRY); 2833 return VINF_SUCCESS; 2834 } 2835 2836 *poffEntryInDir = UINT32_MAX; 2837 return rc; 2838 } 2839 2840 2841 2842 /** 2843 * Creates a new directory entry. 2844 * 2845 * @returns IPRT status code 2846 * @param pThis The directory. 2847 * @param pszEntry The name of the new entry. 2848 * @param fAttrib The attributes. 2849 * @param cbInitial The initialize size. 2850 * @param poffEntryInDir Where to return the offset of the directory entry. 2851 * @param pDirEntry Where to return a copy of the directory entry. 2852 * 2853 * @remarks ASSUMES caller has already called rtFsFatDir_FindEntry to make sure 2854 * the entry doesn't exist. 2855 */ 2856 static int rtFsFatDir_CreateEntry(PRTFSFATDIR pThis, const char *pszEntry, uint8_t fAttrib, uint32_t cbInitial, 2857 uint32_t *poffEntryInDir, PFATDIRENTRY pDirEntry) 2858 { 2859 PRTFSFATVOL pVol = pThis->Core.pVol; 2860 *poffEntryInDir = UINT32_MAX; 2861 2862 /* 2863 * Create the directory entries on the stack. 2864 */ 2865 bool fIs8Dot3Name = rtFsFatDir_StringTo8Dot3((char *)pDirEntry->achName, pszEntry); 2866 pDirEntry->fAttrib = fAttrib; 2867 pDirEntry->fCase = fIs8Dot3Name ? rtFsFatDir_CalcCaseFlags(pszEntry) : 0; 2868 pDirEntry->uBirthCentiseconds = rtFsFatCurrentFatDateTime(pVol, &pDirEntry->uBirthDate, &pDirEntry->uBirthTime); 2869 pDirEntry->uAccessDate = pDirEntry->uBirthDate; 2870 pDirEntry->uModifyDate = pDirEntry->uBirthDate; 2871 pDirEntry->uModifyTime = pDirEntry->uBirthTime; 2872 pDirEntry->idxCluster = 0; /* Will fill this in later if cbInitial is non-zero. */ 2873 pDirEntry->u.idxClusterHigh = 0; 2874 pDirEntry->cbFile = cbInitial; 2875 2876 /* 2877 * Create long filename slots if necessary. 2878 */ 2879 uint32_t cSlots = UINT32_MAX; 2880 FATDIRNAMESLOT aSlots[FATDIRNAMESLOT_MAX_SLOTS]; 2881 int rc = rtFsFatDir_MaybeCreateLongNameAndShortAlias(pThis, pszEntry, fIs8Dot3Name, pDirEntry, aSlots, &cSlots); 2882 if (RT_SUCCESS(rc)) 2883 { 2884 Assert(cSlots <= FATDIRNAMESLOT_MAX_SLOTS); 2885 2886 /* 2887 * Allocate initial clusters if requested. 2888 */ 2889 RTFSFATCHAIN Clusters; 2890 rtFsFatChain_InitEmpty(&Clusters, pVol); 2891 if (cbInitial > 0) 2892 { 2893 rc = rtFsFatClusterMap_AllocateMoreClusters(pVol, &Clusters, 2894 (cbInitial + Clusters.cbCluster - 1) >> Clusters.cClusterByteShift); 2895 if (RT_SUCCESS(rc)) 2896 { 2897 uint32_t idxFirstCluster = rtFsFatChain_GetFirstCluster(&Clusters); 2898 pDirEntry->idxCluster = (uint16_t)idxFirstCluster; 2899 if (pVol->enmFatType >= RTFSFATTYPE_FAT32) 2900 pDirEntry->u.idxClusterHigh = (uint16_t)(idxFirstCluster >> 16); 2901 } 2902 } 2903 if (RT_SUCCESS(rc)) 2904 { 2905 /* 2906 * Insert the directory entry and name slots. 2907 */ 2908 rc = rtFsFatChain_InsertEntries(pThis, pDirEntry, aSlots, cSlots, poffEntryInDir); 2909 if (RT_SUCCESS(rc)) 2910 { 2911 rtFsFatChain_Delete(&Clusters); 2912 return VINF_SUCCESS; 2913 } 2914 2915 for (uint32_t iClusterToFree = 0; iClusterToFree < Clusters.cClusters; iClusterToFree++) 2916 rtFsFatClusterMap_FreeCluster(pVol, rtFsFatChain_GetClusterByIndex(&Clusters, iClusterToFree)); 2917 rtFsFatChain_Delete(&Clusters); 2918 } 2919 } 2920 else 2921 rc = VERR_NET_NOT_UNIQUE_NAME; 2922 return rc; 2923 } 2374 2924 2375 2925 … … 2455 3005 { 2456 3006 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis; 3007 3008 /* 3009 * Try open existing file. 3010 */ 2457 3011 uint32_t offEntryInDir; 2458 3012 bool fLong; … … 2466 3020 if ( !(DirEntry.fAttrib & FAT_ATTR_READONLY) 2467 3021 || !(fOpen & RTFILE_O_WRITE)) 2468 rc = rtFsFatFile_New(pThis->Core.pVol, pThis, &DirEntry, offEntryInDir, fOpen, phVfsFile); 3022 { 3023 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN 3024 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE 3025 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE) 3026 rc = rtFsFatFile_New(pThis->Core.pVol, pThis, &DirEntry, offEntryInDir, fOpen, phVfsFile); 3027 else 3028 rc = VERR_ALREADY_EXISTS; 3029 } 2469 3030 else 2470 3031 rc = VERR_ACCESS_DENIED; … … 2478 3039 break; 2479 3040 } 3041 } 3042 /* 3043 * Create the file? 3044 */ 3045 else if ( rc == VERR_FILE_NOT_FOUND 3046 && ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE 3047 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE 3048 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE) ) 3049 { 3050 rc = rtFsFatDir_CreateEntry(pThis, pszFilename, FAT_ATTR_ARCHIVE, 0 /*cbInitial*/, &offEntryInDir, &DirEntry); 3051 if (RT_SUCCESS(rc)) 3052 rc = rtFsFatFile_New(pThis->Core.pVol, pThis, &DirEntry, offEntryInDir, fOpen, phVfsFile); 2480 3053 } 2481 3054 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.