Changeset 66652 in vbox
- Timestamp:
- Apr 24, 2017 9:48:49 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
-
include/iprt/formats/fat.h (modified) (2 diffs)
-
include/iprt/vfslowlevel.h (modified) (1 diff)
-
src/VBox/Runtime/common/filesystem/fatvfs.cpp (modified) (41 diffs)
-
src/VBox/Runtime/common/vfs/vfsbase.cpp (modified) (1 diff)
-
src/VBox/Runtime/common/vfs/vfschain.cpp (modified) (1 diff)
-
src/VBox/Runtime/common/vfs/vfsstdfile.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/fat.h
r66615 r66652 560 560 #define FAT_ATTR_DEVICE UINT8_C(0x40) 561 561 #define FAT_ATTR_RESERVED UINT8_C(0x80) 562 #define FAT_ATTR_NAME_SLOT UINT8_C(0x0f) /**< Special attribute value for FATDIRNAMESLOT. */ 562 563 /** @} */ 563 564 … … 570 571 /** @} */ 571 572 573 /** @name FATDIRENTRY_CASE_F_XXX - FATDIRENTRY::fCase flags. 574 * @{ */ 575 /** Deleted entry. */ 576 #define FATDIRENTRY_CH0_DELETED UINT8_C(0xe5) 577 /** End of used directory entries (MS-DOS 1.25+, PC-DOS 2.0+). */ 578 #define FATDIRENTRY_CH0_END_OF_DIR UINT8_C(0x00) 579 /** The special dot or dot-dot dir aliases (MS-DOS 1.40+, PC-DOS 2.0+). 580 * @remarks 0x2e is the ascii table entry of the '.' character. */ 581 #define FATDIRENTRY_CH0_DOT_ALIAS UINT8_C(0x2e) 582 /** Escaped 0xe5 leadcharacter (DOS 3.0+). */ 583 #define FATDIRENTRY_CH0_ESC_E5 UINT8_C(0x05) 584 /** @} */ 585 572 586 573 587 /** 574 588 * FAT directory alias name slot. 575 */ 576 #pragma pack(1) 577 typedef struct FATDIRNAMELOT 589 * 590 * Each slot holds 13 UTF-16 (/ UCS-2) characters, so it takes 20 slots to cover 591 * a 255 character long name. 592 */ 593 #pragma pack(1) 594 typedef struct FATDIRNAMESLOT 578 595 { 579 596 /** The slot sequence number. */ -
trunk/include/iprt/vfslowlevel.h
r66615 r66652 455 455 * @returns IPRT status code. 456 456 * @retval VERR_PATH_NOT_FOUND if @a pszEntry was not found. 457 * @retval VERR_NOT_A_DIRECTORY if @a pszEntry isn't a directory or symlink. 457 458 * @param pvThis The implementation specific directory data. 458 459 * @param pszEntry The name of the directory entry to remove. -
trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp
r66615 r66652 42 42 #include <iprt/sg.h> 43 43 #include <iprt/thread.h> 44 #include <iprt/uni.h> 44 45 #include <iprt/vfs.h> 45 46 #include <iprt/vfslowlevel.h> … … 50 51 * Defined Constants And Macros * 51 52 *********************************************************************************************************************************/ 53 /** Gets the cluster from a directory entry. 54 * @param a_pDirEntry Pointer to the directory entry. 55 * @param a_pVol Pointer to the volume. 56 */ 57 #define RTFSFAT_GET_CLUSTER(a_pDirEntry, a_pVol) \ 58 ( (a_pVol)->enmFatType >= RTFSFATTYPE_FAT32 \ 59 ? RT_MAKE_U32((a_pDirEntry)->idxCluster, (a_pDirEntry)->u.idxClusterHigh) \ 60 : (a_pDirEntry)->idxCluster ) 52 61 53 62 … … 55 64 * Structures and Typedefs * 56 65 *********************************************************************************************************************************/ 66 /** Pointer to a FAT directory instance. */ 67 typedef struct RTFSFATDIR *PRTFSFATDIR; 68 69 57 70 /** 58 71 * A part of the cluster chain covering up to 252 clusters. … … 78 91 /** The chain size in entries. */ 79 92 uint32_t cClusters; 93 /** The cluster size. */ 94 uint32_t cbCluster; 95 /** The shift count for converting between clusters and bytes. */ 96 uint8_t cClusterByteShift; 80 97 /** List of chain parts (RTFSFATCHAINPART). */ 81 98 RTLISTANCHOR ListParts; … … 92 109 /** The parent directory keeps a list of open objects (RTFSFATOBJ). */ 93 110 RTLISTNODE Entry; 94 /** The byte offset of the directory entry. 95 * This is set to UINT64_MAX if special FAT12/16 root directory. */ 96 uint64_t offDirEntry; 111 /** The parent directory (not released till all children are close). */ 112 PRTFSFATDIR pParentDir; 113 /** The byte offset of the directory entry in the parent dir. 114 * This is set to UINT32_MAX for the root directory. */ 115 uint32_t offEntryInDir; 97 116 /** Attributes. */ 98 117 RTFMODE fAttrib; … … 137 156 /** Core FAT object info. */ 138 157 RTFSFATOBJ Core; 158 /** The VFS handle for this directory (for reference counting). */ 159 RTVFSDIR hVfsSelf; 139 160 /** Open child objects (RTFSFATOBJ). */ 140 161 RTLISTNODE OpenChildren; … … 146 167 bool fFullyBuffered; 147 168 /** Set if this is a linear root directory. */ 148 bool fIsFlatRootDir; 149 169 bool fIsLinearRootDir; 170 /** The size of the memory paEntries points at. */ 171 uint32_t cbAllocatedForEntries; 172 173 /** Pointer to the directory buffer. 174 * In fully buffering mode, this is the whole of the directory. Otherwise it's 175 * just a sector worth of buffers. */ 176 PFATDIRENTRYUNION paEntries; 177 /** The disk offset corresponding to what paEntries points to. 178 * UINT64_MAX if notthing read into paEntries yet. */ 179 uint64_t offEntriesOnDisk; 150 180 union 151 181 { … … 157 187 struct 158 188 { 159 /** Directory offset. */160 uint64_t offDir;161 189 /** Number of sectors mapped by paEntries and pbDirtySectors. */ 162 190 uint32_t cSectors; 163 191 /** Number of dirty sectors. */ 164 192 uint32_t cDirtySectors; 165 /** Pointer to the linear mapping of the directory entries. */166 PFATDIRENTRYUNION paEntries;167 193 /** Dirty sector map. */ 168 194 uint8_t *pbDirtySectors; … … 172 198 struct 173 199 { 174 /** The disk offset of the current sector, UINT64_MAX if invalid. */175 uint64_t offOnDisk;176 200 /** The directory offset, UINT32_MAX if invalid. */ 177 201 uint32_t offInDir; 178 uint32_t u32Reserved; /**< Puts pbSector and paEntries at the same location */179 /** Sector buffer. */180 PFATDIRENTRYUNION *paEntries;181 202 /** Dirty flag. */ 182 203 bool fDirty; … … 238 259 } RTFSFATTYPE; 239 260 261 262 /** 263 * BPB version. 264 */ 265 typedef enum RTFSFATBPBVER 266 { 267 RTFSFATBPBVER_INVALID = 0, 268 RTFSFATBPBVER_NO_BPB, 269 RTFSFATBPBVER_DOS_2_0, 270 //RTFSFATBPBVER_DOS_3_2, - we don't try identify this one. 271 RTFSFATBPBVER_DOS_3_31, 272 RTFSFATBPBVER_EXT_28, 273 RTFSFATBPBVER_EXT_29, 274 RTFSFATBPBVER_FAT32_28, 275 RTFSFATBPBVER_FAT32_29, 276 RTFSFATBPBVER_END 277 } RTFSFATBPBVER; 278 279 240 280 /** 241 281 * A FAT volume. … … 257 297 /** Reserved sectors. */ 258 298 uint32_t cReservedSectors; 299 /** The BPB version. Gives us an idea of the FAT file system version. */ 300 RTFSFATBPBVER enmBpbVersion; 259 301 260 302 /** Logical sector size. */ 261 303 uint32_t cbSector; 304 /** The shift count for converting between sectors and bytes. */ 305 uint8_t cSectorByteShift; 306 /** The shift count for converting between clusters and bytes. */ 307 uint8_t cClusterByteShift; 262 308 /** The cluster size in bytes. */ 263 309 uint32_t cbCluster; … … 321 367 typedef RTFSFATVOL *PRTFSFATVOL; 322 368 369 370 371 /********************************************************************************************************************************* 372 * Global Variables * 373 *********************************************************************************************************************************/ 374 /** Codepage 437 translation table with invalid 8.3 characters marked as 0xffff. 375 * @remarks The valid first 128 entries are 1:1 with unicode. 376 * @remarks Lower case characters are all marked invalid. 377 */ 378 static RTUTF16 g_awchFatCp437Chars[] = 379 { /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 380 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 381 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 382 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0xffff, 0xffff, 0xffff, 0x002d, 0xffff, 0xffff, 383 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 384 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 385 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0xffff, 0xffff, 0xffff, 0x005e, 0x005f, 386 0x0060, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 387 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x007e, 0xffff, 388 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 389 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 390 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 391 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 392 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 393 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 394 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 395 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 396 }; 397 AssertCompileSize(g_awchFatCp437Chars, 256*2); 398 399 400 /********************************************************************************************************************************* 401 * Internal Functions * 402 *********************************************************************************************************************************/ 403 static void rtFsFatDir_AddOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild); 404 static int rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir, 405 uint32_t idxCluster, uint64_t offDisk, uint32_t cbDir, PRTVFSDIR phVfsDir, PRTFSFATDIR *ppDir); 406 407 408 /** 409 * Convers a cluster to a disk offset. 410 * 411 * @returns Disk byte offset, UINT64_MAX on invalid cluster. 412 * @param pThis The FAT volume instance. 413 * @param idxCluster The cluster number. 414 */ 415 DECLINLINE(uint64_t) rtFsFatClusterToDiskOffset(PRTFSFATVOL pThis, uint32_t idxCluster) 416 { 417 AssertReturn(idxCluster >= FAT_FIRST_DATA_CLUSTER, UINT64_MAX); 418 AssertReturn(idxCluster < pThis->cClusters, UINT64_MAX); 419 return (idxCluster - FAT_FIRST_DATA_CLUSTER) * (uint64_t)pThis->cbCluster 420 + pThis->offFirstCluster; 421 } 422 423 424 /** 425 * Initializes an empty cluster chain. 426 * 427 * @param pChain The chain. 428 * @param pVol The volume. 429 */ 430 static void rtFsFatChain_InitEmpty(PRTFSFATCHAIN pChain, PRTFSFATVOL pVol) 431 { 432 pChain->cbCluster = pVol->cbCluster; 433 pChain->cClusterByteShift = pVol->cClusterByteShift; 434 pChain->cbChain = 0; 435 pChain->cClusters = 0; 436 RTListInit(&pChain->ListParts); 437 } 438 439 440 /** 441 * Converts a file offset to a disk offset. 442 * 443 * The disk offset is only valid until the end of the cluster it is within. 444 * 445 * @returns Disk offset. UINT64_MAX if invalid file offset. 446 * @param pChain The chain. 447 * @param offFile The file offset. 448 */ 449 static uint64_t rtFsFatChain_FileOffsetToDiskOff(PCRTFSFATCHAIN pChain, uint32_t offFile) 450 { 451 uint32_t idxCluster = offFile >> pChain->cClusterByteShift; 452 if (idxCluster < pChain->cClusters) 453 { 454 PRTFSFATCHAINPART pPart = RTListGetFirst(&pChain->ListParts, RTFSFATCHAINPART, ListEntry); 455 while (idxCluster >= RT_ELEMENTS(pPart->aEntries)) 456 { 457 idxCluster -= RT_ELEMENTS(pPart->aEntries); 458 pPart = RTListGetNext(&pChain->ListParts, pPart, RTFSFATCHAINPART, ListEntry); 459 } 460 return pPart->aEntries[idxCluster] + (offFile & ~(pChain->cbCluster - 1)); 461 } 462 return UINT64_MAX; 463 } 323 464 324 465 … … 618 759 static int rtFsFatClusterMap_ReadClusterChain(PRTFSFATVOL pThis, uint32_t idxFirstCluster, PRTFSFATCHAIN pChain) 619 760 { 620 pChain->cClusters = 0; 621 pChain->cbChain = 0; 761 pChain->cbCluster = pThis->cbCluster; 762 pChain->cClusterByteShift = pThis->cClusterByteShift; 763 pChain->cClusters = 0; 764 pChain->cbChain = 0; 622 765 RTListInit(&pChain->ListParts); 623 766 … … 633 776 { 634 777 RTTIME Time; 778 Time.offUTC = 0; 635 779 Time.i32Year = 1980 + (uDate >> 9); 636 780 Time.u8Month = ((uDate >> 5) & 0xf); … … 655 799 656 800 657 static void rtFsFatObj_InitFromDirEntry(PRTFSFATOBJ pObj, PCFATDIRENTRY pDirEntry, uint 64_t offDirEntry, PRTFSFATVOL pThis)801 static void rtFsFatObj_InitFromDirEntry(PRTFSFATOBJ pObj, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir, PRTFSFATVOL pThis) 658 802 { 659 803 RTListInit(&pObj->Entry); 804 pObj->pParentDir = NULL; 660 805 pObj->pVol = pThis; 661 pObj->off DirEntry = offDirEntry;806 pObj->offEntryInDir = offEntryInDir; 662 807 pObj->fAttrib = ((RTFMODE)pDirEntry->fAttrib << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2; 663 808 pObj->cbObject = pDirEntry->cbFile; … … 668 813 669 814 670 static void rtFsFatObj_InitDummy(PRTFSFATOBJ pObj, uint 64_t offDirEntry, uint32_t cbObject, RTFMODE fAttrib, PRTFSFATVOL pThis)815 static void rtFsFatObj_InitDummy(PRTFSFATOBJ pObj, uint32_t offEntryInDir, uint32_t cbObject, RTFMODE fAttrib, PRTFSFATVOL pThis) 671 816 { 672 817 RTListInit(&pObj->Entry); 818 pObj->pParentDir = NULL; 673 819 pObj->pVol = pThis; 674 pObj->off DirEntry = offDirEntry;820 pObj->offEntryInDir = offEntryInDir; 675 821 pObj->fAttrib = fAttrib; 676 822 pObj->cbObject = cbObject; … … 944 1090 945 1091 /** 1092 * Instantiates a new directory. 1093 * 1094 * @returns IPRT status code. 1095 * @param pThis The FAT volume instance. 1096 * @param pParentDir The parent directory. 1097 * @param pDirEntry The parent directory entry. 1098 * @param offEntryInDir The byte offset of the directory entry in the parent 1099 * directory. 1100 * @param fOpen RTFILE_O_XXX flags. 1101 * @param phVfsFile Where to return the file handle. 1102 */ 1103 static int rtFsFatFile_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir, 1104 uint64_t fOpen, PRTVFSFILE phVfsFile) 1105 { 1106 AssertPtr(pParentDir); 1107 Assert(!(offEntryInDir & (sizeof(FATDIRENTRY) - 1))); 1108 1109 PRTFSFATFILE pNewFile; 1110 int rc = RTVfsNewFile(&g_rtFsFatFileOps, sizeof(*pNewFile), fOpen, pThis->hVfsSelf, NIL_RTVFSLOCK /*use volume lock*/, 1111 phVfsFile, (void **)&pNewFile); 1112 if (RT_SUCCESS(rc)) 1113 { 1114 /* 1115 * Initialize it all so rtFsFatFile_Close doesn't trip up in anyway. 1116 */ 1117 rtFsFatObj_InitFromDirEntry(&pNewFile->Core, pDirEntry, offEntryInDir, pThis); 1118 pNewFile->offFile = 0; 1119 rc = rtFsFatClusterMap_ReadClusterChain(pThis, RTFSFAT_GET_CLUSTER(pDirEntry, pThis), &pNewFile->Core.Clusters); 1120 if (RT_SUCCESS(rc)) 1121 { 1122 /* 1123 * Link into parent directory so we can use it to update 1124 * our directory entry. 1125 */ 1126 rtFsFatDir_AddOpenChild(pParentDir, &pNewFile->Core); 1127 return VINF_SUCCESS; 1128 } 1129 1130 RTVfsFileRelease(*phVfsFile); 1131 } 1132 *phVfsFile = NIL_RTVFSFILE; 1133 return rc; 1134 } 1135 1136 1137 1138 1139 static int rtFsFatDir_FlushFullyBuffered(PRTFSFATDIR pThis) 1140 { 1141 Assert(pThis->fFullyBuffered); 1142 return VINF_SUCCESS; 1143 } 1144 1145 1146 static int rtFsFatDir_FlushSimple(PRTFSFATDIR pThis) 1147 { 1148 Assert(!pThis->fFullyBuffered); 1149 int rc; 1150 if ( !pThis->u.Simple.fDirty 1151 || pThis->offEntriesOnDisk != UINT64_MAX) 1152 rc = VINF_SUCCESS; 1153 else 1154 { 1155 Assert(pThis->u.Simple.offInDir != UINT32_MAX); 1156 rc = RTVfsFileWriteAt(pThis->Core.pVol->hVfsBacking, pThis->offEntriesOnDisk, 1157 pThis->paEntries, pThis->Core.pVol->cbSector, NULL); 1158 if (RT_SUCCESS(rc)) 1159 pThis->u.Simple.fDirty = false; 1160 } 1161 return rc; 1162 } 1163 1164 1165 static int rtFsFatDir_Flush(PRTFSFATDIR pThis) 1166 { 1167 if (pThis->fFullyBuffered) 1168 return rtFsFatDir_FlushFullyBuffered(pThis); 1169 return rtFsFatDir_FlushSimple(pThis); 1170 } 1171 1172 1173 static void rtFsFatDir_ReleaseBufferAfterReading(PRTFSFATDIR pThis, uint32_t uBufferReadLock) 1174 { 1175 RT_NOREF(pThis, uBufferReadLock); 1176 } 1177 1178 1179 /** 1180 * Gets one or more entires at @a offEntryInDir. 1181 * 1182 * @returns IPRT status code. 1183 * @param pThis The directory. 1184 * @param offEntryInDir The directory offset in bytes. 1185 * @param ppaEntries Where to return pointer to the entry at 1186 * @a offEntryInDir. 1187 * @param pcEntries Where to return the number of entries 1188 * @a *ppaEntries points to. 1189 * @param puBufferReadLock Where to return the buffer read lock handle. 1190 * Call rtFsFatDir_ReleaseBufferAfterReading when 1191 * done. 1192 */ 1193 static int rtFsFatDir_GetEntriesAt(PRTFSFATDIR pThis, uint32_t offEntryInDir, 1194 PCFATDIRENTRYUNION *ppaEntries, uint32_t *pcEntries, uint32_t *puBufferReadLock) 1195 { 1196 *puBufferReadLock = UINT32_MAX; 1197 1198 int rc; 1199 Assert(RT_ALIGN_32(offEntryInDir, sizeof(FATDIRENTRY)) == offEntryInDir); 1200 Assert(pThis->Core.cbObject / sizeof(FATDIRENTRY) == pThis->cEntries); 1201 uint32_t const idxEntryInDir = offEntryInDir / sizeof(FATDIRENTRY); 1202 if (idxEntryInDir < pThis->cEntries) 1203 { 1204 if (pThis->fFullyBuffered) 1205 { 1206 /* 1207 * Fully buffered: Return pointer to all the entires starting at offEntryInDir. 1208 */ 1209 *ppaEntries = &pThis->paEntries[idxEntryInDir]; 1210 *pcEntries = pThis->cEntries - idxEntryInDir; 1211 *puBufferReadLock = 1; 1212 rc = VINF_SUCCESS; 1213 } 1214 else 1215 { 1216 /* 1217 * Simple buffering: If hit, return the number of entries. 1218 */ 1219 PRTFSFATVOL pVol = pThis->Core.pVol; 1220 uint32_t off = offEntryInDir - pThis->u.Simple.offInDir; 1221 if (off < pVol->cbSector) 1222 { 1223 *ppaEntries = &pThis->paEntries[off / sizeof(FATDIRENTRY)]; 1224 *pcEntries = (pVol->cbSector - off) / sizeof(FATDIRENTRY); 1225 *puBufferReadLock = 1; 1226 rc = VINF_SUCCESS; 1227 } 1228 else 1229 { 1230 /* 1231 * Simple buffering: Miss. 1232 * Flush dirty. Read in new sector. Return entries in sector starting 1233 * at offEntryInDir. 1234 */ 1235 if (!pThis->u.Simple.fDirty) 1236 rc = VINF_SUCCESS; 1237 else 1238 rc = rtFsFatDir_FlushSimple(pThis); 1239 if (RT_SUCCESS(rc)) 1240 { 1241 off = offEntryInDir & (pVol->cbSector - 1); 1242 pThis->u.Simple.offInDir = (offEntryInDir & ~(pVol->cbSector - 1)); 1243 pThis->offEntriesOnDisk = rtFsFatChain_FileOffsetToDiskOff(&pThis->Core.Clusters, pThis->u.Simple.offInDir); 1244 rc = RTVfsFileReadAt(pThis->Core.pVol->hVfsBacking, pThis->offEntriesOnDisk, 1245 pThis->paEntries, pVol->cbSector, NULL); 1246 if (RT_SUCCESS(rc)) 1247 { 1248 *ppaEntries = &pThis->paEntries[off / sizeof(FATDIRENTRY)]; 1249 *pcEntries = (pVol->cbSector - off) / sizeof(FATDIRENTRY); 1250 *puBufferReadLock = 1; 1251 rc = VINF_SUCCESS; 1252 } 1253 else 1254 { 1255 pThis->u.Simple.offInDir = UINT32_MAX; 1256 pThis->offEntriesOnDisk = UINT64_MAX; 1257 } 1258 } 1259 } 1260 } 1261 } 1262 else 1263 rc = VERR_FILE_NOT_FOUND; 1264 return rc; 1265 } 1266 1267 1268 /** 1269 * Translates a unicode codepoint to an uppercased CP437 index. 1270 * 1271 * @returns CP437 index if valie, UINT16_MAX if not. 1272 * @param uc The codepoint to convert. 1273 */ 1274 static uint16_t rtFsFatUnicodeCodepointToUpperCodepage(RTUNICP uc) 1275 { 1276 /* 1277 * The first 128 chars have 1:1 translation for valid FAT chars. 1278 */ 1279 if (uc < 128) 1280 { 1281 if (g_awchFatCp437Chars[uc] == uc) 1282 return (uint16_t)uc; 1283 if (RT_C_IS_LOWER(uc)) 1284 return uc - 0x20; 1285 return UINT16_MAX; 1286 } 1287 1288 /* 1289 * Try for uppercased, settle for lower case if no upper case variant in the table. 1290 * This is really expensive, btw. 1291 */ 1292 RTUNICP ucUpper = RTUniCpToUpper(uc); 1293 for (unsigned i = 128; i < 256; i++) 1294 if (g_awchFatCp437Chars[i] == ucUpper) 1295 return i; 1296 if (ucUpper != uc) 1297 for (unsigned i = 128; i < 256; i++) 1298 if (g_awchFatCp437Chars[i] == uc) 1299 return i; 1300 return UINT16_MAX; 1301 } 1302 1303 1304 /** 1305 * Convert filename string to 8-dot-3 format, doing necessary ASCII uppercasing 1306 * and such. 1307 * 1308 * @returns true if 8.3 formattable name, false if not. 1309 * @param pszName8Dot3 Where to return the 8-dot-3 name when returning 1310 * @c true. Filled with zero on false. 12+1 bytes. 1311 * @param pszName The filename to convert. 1312 */ 1313 static bool rtFsFatDir_StringTo8Dot3(char *pszName8Dot3, const char *pszName) 1314 { 1315 /* 1316 * Don't try convert names with more than 12 unicode chars in them. 1317 */ 1318 size_t const cucName = RTStrUniLen(pszName); 1319 if (cucName <= 12 && cucName > 0) 1320 { 1321 /* 1322 * Recode the input string as CP437, uppercasing it, validating the 1323 * name, formatting it as a FAT directory entry string. 1324 */ 1325 size_t offDst = 0; 1326 bool fExt = false; 1327 for (;;) 1328 { 1329 RTUNICP uc; 1330 int rc = RTStrGetCpEx(&pszName, &uc); 1331 if (RT_SUCCESS(rc)) 1332 { 1333 if (uc) 1334 { 1335 if (offDst < 8+3) 1336 { 1337 uint16_t idxCp = rtFsFatUnicodeCodepointToUpperCodepage(uc); 1338 if (idxCp != UINT16_MAX) 1339 { 1340 pszName8Dot3[offDst++] = (char)idxCp; 1341 Assert(uc != '.'); 1342 continue; 1343 } 1344 1345 /* Maybe the dot? */ 1346 if ( uc == '.' 1347 && !fExt 1348 && offDst <= 8) 1349 { 1350 fExt = true; 1351 while (offDst < 8) 1352 pszName8Dot3[offDst++] = ' '; 1353 continue; 1354 } 1355 } 1356 } 1357 /* String terminator: Check length, pad and convert 0xe5. */ 1358 else if (offDst <= (size_t)(fExt ? 8 + 3 : 8)) 1359 { 1360 while (offDst < 8 + 3) 1361 pszName8Dot3[offDst++] = ' '; 1362 Assert(offDst == 8 + 3); 1363 pszName8Dot3[offDst] = '\0'; 1364 1365 if (pszName8Dot3[0] == FATDIRENTRY_CH0_DELETED) 1366 pszName8Dot3[0] = FATDIRENTRY_CH0_ESC_E5; 1367 return true; 1368 } 1369 } 1370 /* invalid */ 1371 break; 1372 } 1373 } 1374 memset(&pszName8Dot3[0], 0, 12+1); 1375 return false; 1376 } 1377 1378 1379 /** 1380 * Locates a directory entry in a directory. 1381 * 1382 * @returns IPRT status code. 1383 * @param pThis The directory to search. 1384 * @param pszEntry The entry to look for. 1385 * @param poffEntryInDir Where to return the offset of the directory 1386 * entry. 1387 * @param pfLong Where to return long name indicator. 1388 * @param pDirEntry Where to return a copy of the directory entry. 1389 */ 1390 static int rtFsFatDir_FindEntry(PRTFSFATDIR pThis, const char *pszEntry, uint32_t *poffEntryInDir, bool *pfLong, 1391 PFATDIRENTRY pDirEntry) 1392 { 1393 /* Set return values. */ 1394 *pfLong = false; 1395 *poffEntryInDir = UINT32_MAX; 1396 1397 /* 1398 * Turn pszEntry into a 8.3 filename, if possible. 1399 */ 1400 char szName8Dot3[12+1]; 1401 bool fIs8Dot3Name = rtFsFatDir_StringTo8Dot3(szName8Dot3, pszEntry); 1402 1403 /* 1404 * Scan the directory buffer by buffer. 1405 */ 1406 uint32_t offEntryInDir = 0; 1407 uint32_t const cbDir = pThis->Core.cbObject; 1408 Assert(RT_ALIGN_32(cbDir, sizeof(*pDirEntry)) == cbDir); 1409 1410 while (offEntryInDir < cbDir) 1411 { 1412 /* Get chunk of entries starting at offEntryInDir. */ 1413 uint32_t uBufferLock = UINT32_MAX; 1414 uint32_t cEntries = 0; 1415 PCFATDIRENTRYUNION paEntries = NULL; 1416 int rc = rtFsFatDir_GetEntriesAt(pThis, offEntryInDir, &paEntries, &cEntries, &uBufferLock); 1417 if (RT_FAILURE(rc)) 1418 return rc; 1419 1420 /* 1421 * Now work thru each of the entries. 1422 */ 1423 for (uint32_t iEntry = 0; iEntry < cEntries; iEntry++, offEntryInDir += sizeof(FATDIRENTRY)) 1424 { 1425 switch (paEntries[iEntry].Entry.achName[0]) 1426 { 1427 default: 1428 break; 1429 case FATDIRENTRY_CH0_DELETED: 1430 continue; 1431 case FATDIRENTRY_CH0_END_OF_DIR: 1432 if (pThis->Core.pVol->enmBpbVersion >= RTFSFATBPBVER_DOS_2_0) 1433 { 1434 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 1435 return VERR_FILE_NOT_FOUND; 1436 } 1437 break; /* Technically a valid entry before DOS 2.0, or so some claim. */ 1438 } 1439 if ( paEntries[iEntry].Slot.fAttrib == FAT_ATTR_NAME_SLOT 1440 && (paEntries[iEntry].Slot.idSlot - (uint8_t)'A') <= 20 1441 && paEntries[iEntry].Slot.idxZero == 0 1442 && paEntries[iEntry].Slot.fZero == 0) 1443 { 1444 /** @todo long filenames. */ 1445 } 1446 else if ( fIs8Dot3Name 1447 && memcmp(paEntries[iEntry].Entry.achName, szName8Dot3, sizeof(paEntries[iEntry].Entry.achName)) == 0) 1448 { 1449 *poffEntryInDir = offEntryInDir; 1450 *pDirEntry = paEntries[iEntry].Entry; 1451 *pfLong = false; 1452 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 1453 return VINF_SUCCESS; 1454 } 1455 } 1456 rtFsFatDir_ReleaseBufferAfterReading(pThis, uBufferLock); 1457 } 1458 1459 return VERR_FILE_NOT_FOUND; 1460 } 1461 1462 1463 1464 1465 /** 946 1466 * @interface_method_impl{RTVFSOBJOPS,pfnClose} 947 1467 */ … … 949 1469 { 950 1470 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis; 951 RT_NOREF(pThis); 952 return VERR_NOT_IMPLEMENTED; 1471 if (pThis->paEntries) 1472 { 1473 /** @todo flush */ 1474 1475 RTMemFree(pThis->paEntries); 1476 pThis->paEntries = NULL; 1477 } 1478 return VINF_SUCCESS; 953 1479 } 954 1480 … … 960 1486 PRTVFSSYMLINK phVfsSymlink, PRTVFS phVfsMounted) 961 1487 { 962 RT_NOREF(pvThis, pszEntry, phVfsDir, phVfsSymlink, phVfsMounted); 1488 /* 1489 * FAT doesn't do symbolic links and mounting file systems within others 1490 * haven't been implemented yet, I think, so only care if a directory is 1491 * asked for. 1492 */ 1493 int rc; 1494 if (phVfsSymlink) 1495 *phVfsSymlink = NIL_RTVFSSYMLINK; 1496 if (phVfsMounted) 1497 *phVfsMounted = NIL_RTVFS; 1498 if (phVfsDir) 1499 { 1500 *phVfsDir = NIL_RTVFSDIR; 1501 1502 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis; 1503 uint32_t offEntryInDir; 1504 bool fLong; 1505 FATDIRENTRY DirEntry; 1506 rc = rtFsFatDir_FindEntry(pThis, pszEntry, &offEntryInDir, &fLong, &DirEntry); 1507 if (RT_SUCCESS(rc)) 1508 { 1509 switch (DirEntry.fAttrib & (FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME)) 1510 { 1511 case FAT_ATTR_DIRECTORY: 1512 { 1513 rc = rtFsFatDir_New(pThis->Core.pVol, pThis, &DirEntry, offEntryInDir, 1514 RTFSFAT_GET_CLUSTER(&DirEntry, pThis->Core.pVol), UINT64_MAX /*offDisk*/, 1515 DirEntry.cbFile, phVfsDir, NULL /*ppDir*/); 1516 break; 1517 } 1518 case 0: 1519 rc = VERR_NOT_A_DIRECTORY; 1520 break; 1521 default: 1522 rc = VERR_PATH_NOT_FOUND; 1523 break; 1524 } 1525 } 1526 else if (rc == VERR_FILE_NOT_FOUND) 1527 rc = VERR_PATH_NOT_FOUND; 1528 } 1529 else 1530 rc = VERR_PATH_NOT_FOUND; 1531 return rc; 1532 } 1533 1534 1535 /** 1536 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile} 1537 */ 1538 static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile) 1539 { 1540 PRTFSFATDIR pThis = (PRTFSFATDIR)pvThis; 1541 uint32_t offEntryInDir; 1542 bool fLong; 1543 FATDIRENTRY DirEntry; 1544 int rc = rtFsFatDir_FindEntry(pThis, pszFilename, &offEntryInDir, &fLong, &DirEntry); 1545 if (RT_SUCCESS(rc)) 1546 { 1547 switch (DirEntry.fAttrib & (FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME)) 1548 { 1549 case 0: 1550 if ( !(DirEntry.fAttrib & FAT_ATTR_READONLY) 1551 || !(fOpen & RTFILE_O_WRITE)) 1552 rc = rtFsFatFile_New(pThis->Core.pVol, pThis, &DirEntry, offEntryInDir, fOpen, phVfsFile); 1553 else 1554 rc = VERR_ACCESS_DENIED; 1555 break; 1556 1557 case FAT_ATTR_DIRECTORY: 1558 rc = VERR_NOT_A_FILE; 1559 break; 1560 default: 1561 rc = VERR_PATH_NOT_FOUND; 1562 break; 1563 } 1564 } 1565 return rc; 1566 } 1567 1568 1569 /** 1570 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir} 1571 */ 1572 static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir) 1573 { 1574 RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir); 1575 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir); 963 1576 return VERR_NOT_IMPLEMENTED; 964 1577 } … … 966 1579 967 1580 /** 968 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile} 969 */ 970 static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile) 971 { 972 RT_NOREF(pvThis, pszFilename, fOpen, phVfsFile); 1581 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir} 1582 */ 1583 static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir) 1584 { 1585 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir); 1586 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir); 973 1587 return VERR_NOT_IMPLEMENTED; 974 1588 } … … 976 1590 977 1591 /** 978 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}979 */980 static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)981 {982 RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir);983 return VERR_NOT_IMPLEMENTED;984 }985 986 987 /**988 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}989 */990 static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)991 {992 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);993 return VERR_NOT_IMPLEMENTED;994 }995 996 997 /**998 1592 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink} 999 1593 */ … … 1001 1595 { 1002 1596 RT_NOREF(pvThis, pszSymlink, phVfsSymlink); 1597 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink); 1003 1598 return VERR_NOT_SUPPORTED; 1004 1599 } … … 1012 1607 { 1013 1608 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink); 1609 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink); 1014 1610 return VERR_NOT_SUPPORTED; 1015 1611 } … … 1022 1618 { 1023 1619 RT_NOREF(pvThis, pszEntry, fType); 1620 RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry); 1024 1621 return VERR_NOT_IMPLEMENTED; 1025 1622 } … … 1032 1629 { 1033 1630 RT_NOREF(pvThis); 1631 RTAssertMsg2("%s\n", __FUNCTION__); 1034 1632 return VERR_NOT_IMPLEMENTED; 1035 1633 } … … 1043 1641 { 1044 1642 RT_NOREF(pvThis, pDirEntry, pcbDirEntry, enmAddAttr); 1643 RTAssertMsg2("%s\n", __FUNCTION__); 1045 1644 return VERR_NOT_IMPLEMENTED; 1046 1645 } … … 1054 1653 { /* Obj */ 1055 1654 RTVFSOBJOPS_VERSION, 1056 RTVFSOBJTYPE_ FILE,1655 RTVFSOBJTYPE_DIR, 1057 1656 "FatDir", 1058 1657 rtFsFatDir_Close, … … 1064 1663 { /* ObjSet */ 1065 1664 RTVFSOBJSETOPS_VERSION, 1066 RT_OFFSETOF(RTVFS FILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),1665 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet), 1067 1666 rtFsFatObj_SetMode, 1068 1667 rtFsFatObj_SetTimes, … … 1084 1683 1085 1684 /** 1685 * Adds an open child to the parent directory. 1686 * 1687 * Maintains an additional reference to the parent dir to prevent it from going 1688 * away. If @a pDir is the root directory, it also ensures the volume is 1689 * referenced and sticks around until the last open object is gone. 1690 * 1691 * @param pDir The directory. 1692 * @param pChild The child being opened. 1693 * @sa rtFsFatDir_RemoveOpenChild 1694 */ 1695 static void rtFsFatDir_AddOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild) 1696 { 1697 /* First child that gets opened retains the parent directory. This is 1698 released by the final open child. */ 1699 if (RTListIsEmpty(&pDir->OpenChildren)) 1700 { 1701 uint32_t cRefs = RTVfsDirRetain(pDir->hVfsSelf); 1702 Assert(cRefs != UINT32_MAX); NOREF(cRefs); 1703 1704 /* Root also retains the whole file system. */ 1705 if (!pDir->Core.pParentDir) 1706 { 1707 Assert(pDir->Core.pVol); 1708 Assert(pDir->Core.pVol == pChild->pVol); 1709 cRefs = RTVfsRetain(pDir->Core.pVol->hVfsSelf); 1710 Assert(cRefs != UINT32_MAX); NOREF(cRefs); 1711 } 1712 } 1713 RTListAppend(&pDir->OpenChildren, &pChild->Entry); 1714 pChild->pParentDir = pDir; 1715 } 1716 1717 1718 /** 1719 * Removes an open child to the parent directory. 1720 * 1721 * @param pDir The directory. 1722 * @param pChild The child being removed. 1723 * 1724 * @remarks This is the very last thing you do as it may cause a few other 1725 * objects to be released recursively (parent dir and the volume). 1726 * 1727 * @sa rtFsFatDir_AddOpenChild 1728 */ 1729 static void rtFsFatDir_RemoveOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild) 1730 { 1731 AssertReturnVoid(pChild->pParentDir == pDir); 1732 RTListNodeRemove(&pChild->Entry); 1733 pChild->pParentDir = NULL; 1734 1735 /* Final child? If so, release directory. */ 1736 if (RTListIsEmpty(&pDir->OpenChildren)) 1737 { 1738 uint32_t cRefs = RTVfsDirRelease(pDir->hVfsSelf); 1739 Assert(cRefs != UINT32_MAX); NOREF(cRefs); 1740 1741 /* Root directory releases the file system as well. Since the volume 1742 holds a reference to the root directory, it will remain valid after 1743 the above release. */ 1744 if (!pDir->Core.pParentDir) 1745 { 1746 Assert(cRefs > 0); 1747 Assert(pDir->Core.pVol); 1748 Assert(pDir->Core.pVol == pChild->pVol); 1749 cRefs = RTVfsRetain(pDir->Core.pVol->hVfsSelf); 1750 Assert(cRefs != UINT32_MAX); NOREF(cRefs); 1751 } 1752 } 1753 } 1754 1755 1756 /** 1086 1757 * Instantiates a new directory. 1087 1758 * 1088 1759 * @returns IPRT status code. 1089 * @param pThis The FAT volume instance. 1090 * @param pParentDir The parent directory. This is NULL for the root 1091 * directory. 1092 * @param pDirEntry The parent directory entry. This is NULL for the root 1093 * directory. 1094 * @param offDirEntry The byte offset of the directory entry. UINT64_MAX if 1095 * root directory. 1096 * @param idxCluster The cluster where the directory content is to be found. 1097 * This can be UINT32_MAX if a root FAT12/16 directory. 1098 * @param offDisk The disk byte offset of the FAT12/16 root directory. 1099 * This is UINT64_MAX if idxCluster is given. 1100 * @param cbDir The size of the directory. 1101 * @param phVfsDir Where to return the directory handle. 1102 * @param ppDir Where to return the FAT directory instance data. 1103 */ 1104 static int rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint64_t offDirEntry, 1760 * @param pThis The FAT volume instance. 1761 * @param pParentDir The parent directory. This is NULL for the root 1762 * directory. 1763 * @param pDirEntry The parent directory entry. This is NULL for the 1764 * root directory. 1765 * @param offEntryInDir The byte offset of the directory entry in the parent 1766 * directory. UINT32_MAX if root directory. 1767 * @param idxCluster The cluster where the directory content is to be 1768 * found. This can be UINT32_MAX if a root FAT12/16 1769 * directory. 1770 * @param offDisk The disk byte offset of the FAT12/16 root directory. 1771 * This is UINT64_MAX if idxCluster is given. 1772 * @param cbDir The size of the directory. 1773 * @param phVfsDir Where to return the directory handle. 1774 * @param ppDir Where to return the FAT directory instance data. 1775 */ 1776 static int rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir, 1105 1777 uint32_t idxCluster, uint64_t offDisk, uint32_t cbDir, PRTVFSDIR phVfsDir, PRTFSFATDIR *ppDir) 1106 1778 { 1107 1779 Assert((idxCluster == UINT32_MAX) != (offDisk == UINT64_MAX)); 1108 *ppDir = NULL; 1780 Assert((pDirEntry == NULL) == (offEntryInDir == UINT32_MAX)); 1781 if (ppDir) 1782 *ppDir = NULL; 1109 1783 1110 1784 PRTFSFATDIR pNewDir; 1111 int rc = RTVfsNewDir(&g_rtFsFatDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, 1112 NIL_RTVFSLOCK,phVfsDir, (void **)&pNewDir);1785 int rc = RTVfsNewDir(&g_rtFsFatDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK /*use volume lock*/, 1786 phVfsDir, (void **)&pNewDir); 1113 1787 if (RT_SUCCESS(rc)) 1114 1788 { … … 1118 1792 RTListInit(&pNewDir->OpenChildren); 1119 1793 if (pDirEntry) 1120 rtFsFatObj_InitFromDirEntry(&pNewDir->Core, pDirEntry, off DirEntry, pThis);1794 rtFsFatObj_InitFromDirEntry(&pNewDir->Core, pDirEntry, offEntryInDir, pThis); 1121 1795 else 1122 rtFsFatObj_InitDummy(&pNewDir->Core, offDirEntry, cbDir, RTFS_DOS_DIRECTORY, pThis); 1123 1124 pNewDir->cEntries = cbDir / sizeof(FATDIRENTRY); 1125 pNewDir->fIsFlatRootDir = idxCluster == UINT32_MAX; 1126 pNewDir->fFullyBuffered = pNewDir->fIsFlatRootDir; 1796 rtFsFatObj_InitDummy(&pNewDir->Core, offEntryInDir, cbDir, RTFS_DOS_DIRECTORY, pThis); 1797 1798 pNewDir->hVfsSelf = *phVfsDir; 1799 pNewDir->cEntries = cbDir / sizeof(FATDIRENTRY); 1800 pNewDir->fIsLinearRootDir = idxCluster == UINT32_MAX; 1801 pNewDir->fFullyBuffered = pNewDir->fIsLinearRootDir; 1802 pNewDir->paEntries = NULL; 1803 pNewDir->offEntriesOnDisk = UINT64_MAX; 1127 1804 if (pNewDir->fFullyBuffered) 1128 { 1129 pNewDir->u.Full.offDir = UINT64_MAX; 1130 pNewDir->u.Full.cSectors = 0; 1131 pNewDir->u.Full.cDirtySectors = 0; 1132 pNewDir->u.Full.paEntries = NULL; 1133 pNewDir->u.Full.pbDirtySectors = NULL; 1134 } 1805 pNewDir->cbAllocatedForEntries = RT_ALIGN_32(cbDir, pThis->cbSector); 1135 1806 else 1136 { 1137 pNewDir->u.Simple.offOnDisk = UINT64_MAX; 1138 pNewDir->u.Simple.offInDir = UINT32_MAX; 1139 pNewDir->u.Simple.u32Reserved = 0; 1140 pNewDir->u.Simple.paEntries = NULL; 1141 pNewDir->u.Simple.fDirty = false; 1142 } 1807 pNewDir->cbAllocatedForEntries = pThis->cbSector; 1143 1808 1144 1809 /* … … 1153 1818 && pNewDir->Core.Clusters.cbChain <= _64K 1154 1819 && rtFsFatChain_IsContiguous(&pNewDir->Core.Clusters)) 1820 { 1821 Assert(pNewDir->Core.Clusters.cbChain >= cbDir); 1822 pNewDir->cbAllocatedForEntries = pNewDir->Core.Clusters.cbChain; 1155 1823 pNewDir->fFullyBuffered = true; 1824 } 1156 1825 } 1157 1826 } 1158 1827 else 1828 rtFsFatChain_InitEmpty(&pNewDir->Core.Clusters, pThis); 1159 1829 if (RT_SUCCESS(rc)) 1160 1830 { 1161 RT_NOREF(pParentDir); 1831 /* 1832 * Allocate and initialize the buffering. Fill the buffer. 1833 */ 1834 pNewDir->paEntries = (PFATDIRENTRYUNION)RTMemAlloc(pNewDir->cbAllocatedForEntries); 1835 if (!pNewDir->paEntries) 1836 { 1837 if (pNewDir->fFullyBuffered && !pNewDir->fIsLinearRootDir) 1838 { 1839 pNewDir->fFullyBuffered = false; 1840 pNewDir->cbAllocatedForEntries = pThis->cbSector; 1841 pNewDir->paEntries = (PFATDIRENTRYUNION)RTMemAlloc(pNewDir->cbAllocatedForEntries); 1842 } 1843 if (!pNewDir->paEntries) 1844 rc = VERR_NO_MEMORY; 1845 } 1846 1847 if (RT_SUCCESS(rc)) 1848 { 1849 if (pNewDir->fFullyBuffered) 1850 { 1851 pNewDir->u.Full.cDirtySectors = 0; 1852 pNewDir->u.Full.cSectors = pNewDir->cbAllocatedForEntries / pThis->cbSector; 1853 pNewDir->u.Full.pbDirtySectors = (uint8_t *)RTMemAllocZ((pNewDir->u.Full.cSectors + 63) / 8); 1854 if (pNewDir->u.Full.pbDirtySectors) 1855 pNewDir->offEntriesOnDisk = offDisk != UINT64_MAX ? offDisk 1856 : rtFsFatClusterToDiskOffset(pThis, idxCluster); 1857 else 1858 rc = VERR_NO_MEMORY; 1859 } 1860 else 1861 { 1862 pNewDir->offEntriesOnDisk = rtFsFatClusterToDiskOffset(pThis, idxCluster); 1863 pNewDir->u.Simple.offInDir = 0; 1864 pNewDir->u.Simple.fDirty = false; 1865 } 1866 if (RT_SUCCESS(rc)) 1867 rc = RTVfsFileReadAt(pThis->hVfsBacking, pNewDir->offEntriesOnDisk, 1868 pNewDir->paEntries, pNewDir->cbAllocatedForEntries, NULL); 1869 if (RT_SUCCESS(rc)) 1870 { 1871 /* 1872 * Link into parent directory so we can use it to update 1873 * our directory entry. 1874 */ 1875 if (pParentDir) 1876 rtFsFatDir_AddOpenChild(pParentDir, &pNewDir->Core); 1877 if (ppDir) 1878 *ppDir = pNewDir; 1879 return VINF_SUCCESS; 1880 } 1881 } 1882 1883 /* Free the buffer on failure so rtFsFatDir_Close doesn't try do anything with it. */ 1884 RTMemFree(pNewDir->paEntries); 1885 pNewDir->paEntries = NULL; 1162 1886 } 1163 1887 … … 1165 1889 } 1166 1890 *phVfsDir = NIL_RTVFSDIR; 1167 *ppDir = NULL; 1891 if (ppDir) 1892 *ppDir = NULL; 1168 1893 return rc; 1169 1894 } … … 1212 1937 static DECLCALLBACK(int) rtFsFatVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir) 1213 1938 { 1214 RT_NOREF(pvThis, phVfsDir); 1215 return VERR_NOT_IMPLEMENTED; 1939 PRTFSFATVOL pThis = (PRTFSFATVOL)pvThis; 1940 uint32_t cRefs = RTVfsDirRetain(pThis->hVfsRootDir); 1941 if (cRefs != UINT32_MAX) 1942 { 1943 *phVfsDir = pThis->hVfsRootDir; 1944 return VINF_SUCCESS; 1945 } 1946 return VERR_INTERNAL_ERROR_5; 1216 1947 } 1217 1948 … … 1301 2032 */ 1302 2033 pThis->enmFatType = RTFSFATTYPE_FAT12; 2034 pThis->enmBpbVersion = RTFSFATBPBVER_NO_BPB; 1303 2035 pThis->bMedia = pbFatSector[0]; 1304 2036 pThis->cReservedSectors = 1; … … 1331 2063 static int rtFsFatVolTryInitDos2PlusBpb(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, bool fMaybe331, PRTERRINFO pErrInfo) 1332 2064 { 2065 pThis->enmBpbVersion = RTFSFATBPBVER_DOS_2_0; 2066 1333 2067 /* 1334 2068 * Figure total sector count. Could both be zero, in which case we have to … … 1339 2073 else if ( pBootSector->Bpb.Bpb331.cTotalSectors32 != 0 1340 2074 && fMaybe331) 2075 { 2076 pThis->enmBpbVersion = RTFSFATBPBVER_DOS_3_31; 1341 2077 pThis->cbTotalSize = pBootSector->Bpb.Bpb331.cTotalSectors32 * (uint64_t)pThis->cbSector; 2078 } 1342 2079 else 1343 2080 pThis->cbTotalSize = pThis->cbBacking - pThis->offBootSector; … … 1445 2182 static int rtFsFatVolTryInitDos2PlusFat32(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, PRTERRINFO pErrInfo) 1446 2183 { 1447 pThis->enmFatType = RTFSFATTYPE_FAT32; 1448 pThis->fFat32Flags = pBootSector->Bpb.Fat32Ebpb.fFlags; 2184 pThis->enmFatType = RTFSFATTYPE_FAT32; 2185 pThis->enmBpbVersion = pBootSector->Bpb.Fat32Ebpb.bExtSignature == FATEBPB_SIGNATURE 2186 ? RTFSFATBPBVER_FAT32_29 : RTFSFATBPBVER_FAT32_28; 2187 pThis->fFat32Flags = pBootSector->Bpb.Fat32Ebpb.fFlags; 1449 2188 1450 2189 if (pBootSector->Bpb.Fat32Ebpb.uVersion != FAT32EBPB_VERSION_0_0) … … 1707 2446 pBootSector->Bpb.Ebpb.achLabel, pBootSector->Bpb.Ebpb.achType); 1708 2447 rc = rtFsFatVolTryInitDos2PlusBpb(pThis, pBootSector, true /*fMaybe331*/, pErrInfo); 2448 pThis->enmBpbVersion = pBootSector->Bpb.Ebpb.bExtSignature == FATEBPB_SIGNATURE 2449 ? RTFSFATBPBVER_EXT_29 : RTFSFATBPBVER_EXT_28; 1709 2450 } 1710 2451 else … … 1765 2506 1766 2507 /** 2508 * Given a power of two value @a cb return exponent value. 2509 * 2510 * @returns Shift count 2511 * @param cb The value. 2512 */ 2513 static uint8_t rtFsFatVolCalcByteShiftCount(uint32_t cb) 2514 { 2515 Assert(RT_IS_POWER_OF_TWO(cb)); 2516 unsigned iBit = ASMBitFirstSetU32(cb); 2517 Assert(iBit >= 1); 2518 iBit--; 2519 return iBit; 2520 } 2521 2522 2523 /** 1767 2524 * Worker for RTFsFatVolOpen. 1768 2525 * … … 1864 2621 1865 2622 /* 2623 * Calc shift counts. 2624 */ 2625 pThis->cSectorByteShift = rtFsFatVolCalcByteShiftCount(pThis->cbSector); 2626 pThis->cClusterByteShift = rtFsFatVolCalcByteShiftCount(pThis->cbCluster); 2627 2628 /* 1866 2629 * Setup the FAT cache. 1867 2630 */ … … 1874 2637 */ 1875 2638 if (pThis->idxRootDirCluster == UINT32_MAX) 1876 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, 0 /*offDirEntry*/,2639 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, UINT32_MAX /*offEntryInDir*/, 1877 2640 UINT32_MAX, pThis->offRootDir, pThis->cbRootDir, 1878 2641 &pThis->hVfsRootDir, &pThis->pRootDir); 1879 2642 else 1880 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, 0 /*offDirEntry*/,2643 rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, UINT32_MAX /*offEntryInDir*/, 1881 2644 pThis->idxRootDirCluster, UINT64_MAX, pThis->cbRootDir, 1882 2645 &pThis->hVfsRootDir, &pThis->pRootDir); 1883 if (RT_FAILURE(rc)) 1884 return rc; 1885 1886 1887 return RTErrInfoSetF(pErrInfo, VERR_NOT_IMPLEMENTED, 1888 "cbSector=%#x cbCluster=%#x cReservedSectors=%#x\n" 1889 "cFats=%#x cbFat=%#x offFirstFat=%#RX64 offSecondFat=%#RX64\n" 1890 "cbRootDir=%#x offRootDir=%#RX64 offFirstCluster=%#RX64", 1891 pThis->cbSector, pThis->cbCluster, pThis->cReservedSectors, 1892 pThis->cFats, pThis->cbFat, pThis->aoffFats[0], pThis->aoffFats[1], 1893 pThis->cbRootDir, pThis->offRootDir, pThis->offFirstCluster); 2646 return rc; 1894 2647 } 1895 2648 -
trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
r66615 r66652 1415 1415 RTVfsLockReleaseRead(pCurDir->Base.hLock); 1416 1416 *pszEntryEnd = '\0'; 1417 if (rc == VERR_PATH_NOT_FOUND) 1417 if ( rc == VERR_PATH_NOT_FOUND 1418 || rc == VERR_NOT_A_DIRECTORY) 1418 1419 rc = VINF_SUCCESS; 1419 1420 if (RT_FAILURE(rc)) -
trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
r66602 r66652 163 163 * If the input is a FSS, we have to make sure it's a read-only operation. 164 164 */ 165 if ( pElement->enmType != RTVFSOBJTYPE_FILE166 && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)165 if ( pElement->enmType == RTVFSOBJTYPE_FILE 166 || pElement->enmType == RTVFSOBJTYPE_IO_STREAM) 167 167 { 168 168 int rc = RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo); -
trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
r66602 r66652 530 530 return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS; 531 531 532 533 532 /* 534 533 * Join common cause with the 'open' provider.
Note:
See TracChangeset
for help on using the changeset viewer.

