VirtualBox

Changeset 66652 in vbox


Ignore:
Timestamp:
Apr 24, 2017 9:48:49 AM (7 years ago)
Author:
vboxsync
Message:

IPRT: Some more fat bits.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/formats/fat.h

    r66615 r66652  
    560560#define FAT_ATTR_DEVICE             UINT8_C(0x40)
    561561#define FAT_ATTR_RESERVED           UINT8_C(0x80)
     562#define FAT_ATTR_NAME_SLOT          UINT8_C(0x0f) /**< Special attribute value for FATDIRNAMESLOT. */
    562563/** @} */
    563564
     
    570571/** @} */
    571572
     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
    572586
    573587/**
    574588 * 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)
     594typedef struct FATDIRNAMESLOT
    578595{
    579596    /** The slot sequence number. */
  • trunk/include/iprt/vfslowlevel.h

    r66615 r66652  
    455455     * @returns IPRT status code.
    456456     * @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.
    457458     * @param   pvThis          The implementation specific directory data.
    458459     * @param   pszEntry        The name of the directory entry to remove.
  • trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp

    r66615 r66652  
    4242#include <iprt/sg.h>
    4343#include <iprt/thread.h>
     44#include <iprt/uni.h>
    4445#include <iprt/vfs.h>
    4546#include <iprt/vfslowlevel.h>
     
    5051*   Defined Constants And Macros                                                                                                 *
    5152*********************************************************************************************************************************/
     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 )
    5261
    5362
     
    5564*   Structures and Typedefs                                                                                                      *
    5665*********************************************************************************************************************************/
     66/** Pointer to a FAT directory instance. */
     67typedef struct RTFSFATDIR *PRTFSFATDIR;
     68
     69
    5770/**
    5871 * A part of the cluster chain covering up to 252 clusters.
     
    7891    /** The chain size in entries. */
    7992    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;
    8097    /** List of chain parts (RTFSFATCHAINPART). */
    8198    RTLISTANCHOR    ListParts;
     
    92109    /** The parent directory keeps a list of open objects (RTFSFATOBJ). */
    93110    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;
    97116    /** Attributes. */
    98117    RTFMODE             fAttrib;
     
    137156    /** Core FAT object info.  */
    138157    RTFSFATOBJ          Core;
     158    /** The VFS handle for this directory (for reference counting). */
     159    RTVFSDIR            hVfsSelf;
    139160    /** Open child objects (RTFSFATOBJ). */
    140161    RTLISTNODE          OpenChildren;
     
    146167    bool                fFullyBuffered;
    147168    /** 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;
    150180    union
    151181    {
     
    157187        struct
    158188        {
    159             /** Directory offset. */
    160             uint64_t            offDir;
    161189            /** Number of sectors mapped by paEntries and pbDirtySectors. */
    162190            uint32_t            cSectors;
    163191            /** Number of dirty sectors. */
    164192            uint32_t            cDirtySectors;
    165             /** Pointer to the linear mapping of the directory entries. */
    166             PFATDIRENTRYUNION   paEntries;
    167193            /** Dirty sector map. */
    168194            uint8_t            *pbDirtySectors;
     
    172198        struct
    173199        {
    174             /** The disk offset of the current sector, UINT64_MAX if invalid. */
    175             uint64_t            offOnDisk;
    176200            /** The directory offset, UINT32_MAX if invalid. */
    177201            uint32_t            offInDir;
    178             uint32_t            u32Reserved; /**< Puts pbSector and paEntries at the same location */
    179             /** Sector buffer. */
    180             PFATDIRENTRYUNION  *paEntries;
    181202            /** Dirty flag. */
    182203            bool                fDirty;
     
    238259} RTFSFATTYPE;
    239260
     261
     262/**
     263 * BPB version.
     264 */
     265typedef 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
    240280/**
    241281 * A FAT volume.
     
    257297    /** Reserved sectors. */
    258298    uint32_t        cReservedSectors;
     299    /** The BPB version.  Gives us an idea of the FAT file system version. */
     300    RTFSFATBPBVER   enmBpbVersion;
    259301
    260302    /** Logical sector size. */
    261303    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;
    262308    /** The cluster size in bytes. */
    263309    uint32_t        cbCluster;
     
    321367typedef RTFSFATVOL *PRTFSFATVOL;
    322368
     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 */
     378static 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};
     397AssertCompileSize(g_awchFatCp437Chars, 256*2);
     398
     399
     400/*********************************************************************************************************************************
     401*   Internal Functions                                                                                                           *
     402*********************************************************************************************************************************/
     403static void rtFsFatDir_AddOpenChild(PRTFSFATDIR pDir, PRTFSFATOBJ pChild);
     404static 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 */
     415DECLINLINE(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 */
     430static 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 */
     449static 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}
    323464
    324465
     
    618759static int rtFsFatClusterMap_ReadClusterChain(PRTFSFATVOL pThis, uint32_t idxFirstCluster, PRTFSFATCHAIN pChain)
    619760{
    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;
    622765    RTListInit(&pChain->ListParts);
    623766
     
    633776{
    634777    RTTIME Time;
     778    Time.offUTC     = 0;
    635779    Time.i32Year    = 1980 + (uDate >> 9);
    636780    Time.u8Month    = ((uDate >> 5) & 0xf);
     
    655799
    656800
    657 static void rtFsFatObj_InitFromDirEntry(PRTFSFATOBJ pObj, PCFATDIRENTRY pDirEntry, uint64_t offDirEntry, PRTFSFATVOL pThis)
     801static void rtFsFatObj_InitFromDirEntry(PRTFSFATOBJ pObj, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir, PRTFSFATVOL pThis)
    658802{
    659803    RTListInit(&pObj->Entry);
     804    pObj->pParentDir    = NULL;
    660805    pObj->pVol          = pThis;
    661     pObj->offDirEntry   = offDirEntry;
     806    pObj->offEntryInDir = offEntryInDir;
    662807    pObj->fAttrib       = ((RTFMODE)pDirEntry->fAttrib << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2;
    663808    pObj->cbObject      = pDirEntry->cbFile;
     
    668813
    669814
    670 static void rtFsFatObj_InitDummy(PRTFSFATOBJ pObj, uint64_t offDirEntry, uint32_t cbObject, RTFMODE fAttrib, PRTFSFATVOL pThis)
     815static void rtFsFatObj_InitDummy(PRTFSFATOBJ pObj, uint32_t offEntryInDir, uint32_t cbObject, RTFMODE fAttrib, PRTFSFATVOL pThis)
    671816{
    672817    RTListInit(&pObj->Entry);
     818    pObj->pParentDir    = NULL;
    673819    pObj->pVol          = pThis;
    674     pObj->offDirEntry   = offDirEntry;
     820    pObj->offEntryInDir = offEntryInDir;
    675821    pObj->fAttrib       = fAttrib;
    676822    pObj->cbObject      = cbObject;
     
    9441090
    9451091/**
     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 */
     1103static 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
     1139static int rtFsFatDir_FlushFullyBuffered(PRTFSFATDIR pThis)
     1140{
     1141    Assert(pThis->fFullyBuffered);
     1142    return VINF_SUCCESS;
     1143}
     1144
     1145
     1146static 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
     1165static int rtFsFatDir_Flush(PRTFSFATDIR pThis)
     1166{
     1167    if (pThis->fFullyBuffered)
     1168        return rtFsFatDir_FlushFullyBuffered(pThis);
     1169    return rtFsFatDir_FlushSimple(pThis);
     1170}
     1171
     1172
     1173static 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 */
     1193static 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 */
     1274static 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 */
     1313static 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 */
     1390static 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/**
    9461466 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
    9471467 */
     
    9491469{
    9501470    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;
    9531479}
    9541480
     
    9601486                                                  PRTVFSSYMLINK phVfsSymlink, PRTVFS phVfsMounted)
    9611487{
    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 */
     1538static 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 */
     1572static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
     1573{
     1574    RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir);
     1575RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir);
    9631576    return VERR_NOT_IMPLEMENTED;
    9641577}
     
    9661579
    9671580/**
    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 */
     1583static DECLCALLBACK(int) rtFsFatDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
     1584{
     1585    RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
     1586RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSubDir);
    9731587    return VERR_NOT_IMPLEMENTED;
    9741588}
     
    9761590
    9771591/**
    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 /**
    9981592 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
    9991593 */
     
    10011595{
    10021596    RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
     1597RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);
    10031598    return VERR_NOT_SUPPORTED;
    10041599}
     
    10121607{
    10131608    RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
     1609RTAssertMsg2("%s: %s\n", __FUNCTION__, pszSymlink);
    10141610    return VERR_NOT_SUPPORTED;
    10151611}
     
    10221618{
    10231619    RT_NOREF(pvThis, pszEntry, fType);
     1620RTAssertMsg2("%s: %s\n", __FUNCTION__, pszEntry);
    10241621    return VERR_NOT_IMPLEMENTED;
    10251622}
     
    10321629{
    10331630    RT_NOREF(pvThis);
     1631RTAssertMsg2("%s\n", __FUNCTION__);
    10341632    return VERR_NOT_IMPLEMENTED;
    10351633}
     
    10431641{
    10441642    RT_NOREF(pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
     1643RTAssertMsg2("%s\n", __FUNCTION__);
    10451644    return VERR_NOT_IMPLEMENTED;
    10461645}
     
    10541653    { /* Obj */
    10551654        RTVFSOBJOPS_VERSION,
    1056         RTVFSOBJTYPE_FILE,
     1655        RTVFSOBJTYPE_DIR,
    10571656        "FatDir",
    10581657        rtFsFatDir_Close,
     
    10641663    { /* ObjSet */
    10651664        RTVFSOBJSETOPS_VERSION,
    1066         RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
     1665        RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
    10671666        rtFsFatObj_SetMode,
    10681667        rtFsFatObj_SetTimes,
     
    10841683
    10851684/**
     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 */
     1695static 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 */
     1729static 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/**
    10861757 * Instantiates a new directory.
    10871758 *
    10881759 * @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 */
     1776static int rtFsFatDir_New(PRTFSFATVOL pThis, PRTFSFATDIR pParentDir, PCFATDIRENTRY pDirEntry, uint32_t offEntryInDir,
    11051777                          uint32_t idxCluster, uint64_t offDisk, uint32_t cbDir, PRTVFSDIR phVfsDir, PRTFSFATDIR *ppDir)
    11061778{
    11071779    Assert((idxCluster == UINT32_MAX) != (offDisk == UINT64_MAX));
    1108     *ppDir = NULL;
     1780    Assert((pDirEntry == NULL) == (offEntryInDir == UINT32_MAX));
     1781    if (ppDir)
     1782        *ppDir = NULL;
    11091783
    11101784    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);
    11131787    if (RT_SUCCESS(rc))
    11141788    {
     
    11181792        RTListInit(&pNewDir->OpenChildren);
    11191793        if (pDirEntry)
    1120             rtFsFatObj_InitFromDirEntry(&pNewDir->Core, pDirEntry, offDirEntry, pThis);
     1794            rtFsFatObj_InitFromDirEntry(&pNewDir->Core, pDirEntry, offEntryInDir, pThis);
    11211795        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;
    11271804        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);
    11351806        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;
    11431808
    11441809        /*
     
    11531818                    && pNewDir->Core.Clusters.cbChain   <= _64K
    11541819                    && rtFsFatChain_IsContiguous(&pNewDir->Core.Clusters))
     1820                {
     1821                    Assert(pNewDir->Core.Clusters.cbChain >= cbDir);
     1822                    pNewDir->cbAllocatedForEntries = pNewDir->Core.Clusters.cbChain;
    11551823                    pNewDir->fFullyBuffered = true;
     1824                }
    11561825            }
    11571826        }
    1158 
     1827        else
     1828            rtFsFatChain_InitEmpty(&pNewDir->Core.Clusters, pThis);
    11591829        if (RT_SUCCESS(rc))
    11601830        {
    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;
    11621886        }
    11631887
     
    11651889    }
    11661890    *phVfsDir = NIL_RTVFSDIR;
    1167     *ppDir    = NULL;
     1891    if (ppDir)
     1892        *ppDir = NULL;
    11681893    return rc;
    11691894}
     
    12121937static DECLCALLBACK(int) rtFsFatVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
    12131938{
    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;
    12161947}
    12171948
     
    13012032     */
    13022033    pThis->enmFatType       = RTFSFATTYPE_FAT12;
     2034    pThis->enmBpbVersion    = RTFSFATBPBVER_NO_BPB;
    13032035    pThis->bMedia           = pbFatSector[0];
    13042036    pThis->cReservedSectors = 1;
     
    13312063static int rtFsFatVolTryInitDos2PlusBpb(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, bool fMaybe331, PRTERRINFO pErrInfo)
    13322064{
     2065    pThis->enmBpbVersion = RTFSFATBPBVER_DOS_2_0;
     2066
    13332067    /*
    13342068     * Figure total sector count.  Could both be zero, in which case we have to
     
    13392073    else if (   pBootSector->Bpb.Bpb331.cTotalSectors32 != 0
    13402074             && fMaybe331)
     2075    {
     2076        pThis->enmBpbVersion = RTFSFATBPBVER_DOS_3_31;
    13412077        pThis->cbTotalSize = pBootSector->Bpb.Bpb331.cTotalSectors32 * (uint64_t)pThis->cbSector;
     2078    }
    13422079    else
    13432080        pThis->cbTotalSize = pThis->cbBacking - pThis->offBootSector;
     
    14452182static int rtFsFatVolTryInitDos2PlusFat32(PRTFSFATVOL pThis, PCFATBOOTSECTOR pBootSector, PRTERRINFO pErrInfo)
    14462183{
    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;
    14492188
    14502189    if (pBootSector->Bpb.Fat32Ebpb.uVersion != FAT32EBPB_VERSION_0_0)
     
    17072446                                         pBootSector->Bpb.Ebpb.achLabel, pBootSector->Bpb.Ebpb.achType);
    17082447            rc = rtFsFatVolTryInitDos2PlusBpb(pThis, pBootSector, true /*fMaybe331*/, pErrInfo);
     2448            pThis->enmBpbVersion = pBootSector->Bpb.Ebpb.bExtSignature == FATEBPB_SIGNATURE
     2449                                 ? RTFSFATBPBVER_EXT_29 : RTFSFATBPBVER_EXT_28;
    17092450        }
    17102451        else
     
    17652506
    17662507/**
     2508 * Given a power of two value @a cb return exponent value.
     2509 *
     2510 * @returns Shift count
     2511 * @param   cb              The value.
     2512 */
     2513static 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/**
    17672524 * Worker for RTFsFatVolOpen.
    17682525 *
     
    18642621
    18652622    /*
     2623     * Calc shift counts.
     2624     */
     2625    pThis->cSectorByteShift  = rtFsFatVolCalcByteShiftCount(pThis->cbSector);
     2626    pThis->cClusterByteShift = rtFsFatVolCalcByteShiftCount(pThis->cbCluster);
     2627
     2628    /*
    18662629     * Setup the FAT cache.
    18672630     */
     
    18742637     */
    18752638    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*/,
    18772640                            UINT32_MAX, pThis->offRootDir, pThis->cbRootDir,
    18782641                            &pThis->hVfsRootDir, &pThis->pRootDir);
    18792642    else
    1880         rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, 0 /*offDirEntry*/,
     2643        rc = rtFsFatDir_New(pThis, NULL /*pParentDir*/, NULL /*pDirEntry*/, UINT32_MAX /*offEntryInDir*/,
    18812644                            pThis->idxRootDirCluster, UINT64_MAX, pThis->cbRootDir,
    18822645                            &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;
    18942647}
    18952648
  • trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp

    r66615 r66652  
    14151415            RTVfsLockReleaseRead(pCurDir->Base.hLock);
    14161416            *pszEntryEnd = '\0';
    1417             if (rc == VERR_PATH_NOT_FOUND)
     1417            if (   rc == VERR_PATH_NOT_FOUND
     1418                || rc == VERR_NOT_A_DIRECTORY)
    14181419                rc = VINF_SUCCESS;
    14191420            if (RT_FAILURE(rc))
  • trunk/src/VBox/Runtime/common/vfs/vfschain.cpp

    r66602 r66652  
    163163     * If the input is a FSS, we have to make sure it's a read-only operation.
    164164     */
    165     if (   pElement->enmType != RTVFSOBJTYPE_FILE
    166         && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
     165    if (   pElement->enmType == RTVFSOBJTYPE_FILE
     166        || pElement->enmType == RTVFSOBJTYPE_IO_STREAM)
    167167    {
    168168        int rc = RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo);
  • trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp

    r66602 r66652  
    530530        return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS;
    531531
    532 
    533532    /*
    534533     * Join common cause with the 'open' provider.
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette