int VFATInit()

in lsvmutils/vfat.c [963:1159]


int VFATInit(
    Blkdev* dev, 
    VFAT** vfatOut)
{
    int rc = -1;
    VFAT* vfat = NULL;

    if (!dev || !vfatOut)
        GOTO(done);

    /* Allocate the vfat object */
    if (!(vfat = Calloc(1, sizeof(VFAT))))
        GOTO(done);

    /* Read the BPB */
    if (BlkdevRead(dev, 0, &vfat->bpb, sizeof(vfat->bpb)) != 0)
        GOTO(done);

    /* Check signature of BPB */
    {
        const UINT8* p = vfat->bpb.jmpBoot;

        if (!(p[0] == 0xEB && p[2] == 0x90) && !(p[0] == 0xE9))
            GOTO(done);
    }

    /* See if there is an FSI (FAT32 only) */
    if (GetFATType(&vfat->bpb) == FAT32)
    {
        /* Read the BPB */
        if (BlkdevRead(
            dev, 
            vfat->bpb.u.s32.FSInfo, 
            &vfat->fsi, 
            sizeof(vfat->fsi)) != 0)
        {
            GOTO(done);
        }

        /* Check signatures of FSI */
        if (vfat->fsi.LeadSig != 0x41615252 || vfat->fsi.TrailSig != 0xAA550000)
            GOTO(done);
    }
    
    /* Set the block device */
    vfat->dev = dev;

    /* Reject sector sizes that are not 512 */
    if (vfat->bpb.BytsPerSec != VFAT_SECTOR_SIZE)
        GOTO(done);

    /* Precompute some useful values */
    {
        /* Compute VFAT.FATSz */
        if (vfat->bpb.FATSz16 != 0)
            vfat->FATSz = vfat->bpb.FATSz16;
        else
            vfat->FATSz = vfat->bpb.u.s32.FATSz32;

        /* Compute VFAT.TotSec */
        if (vfat->bpb.TotSec16 != 0)
            vfat->TotSec = vfat->bpb.TotSec16;
        else
            vfat->TotSec = vfat->bpb.TotSec32;

        /* Compute VFAT.RootDirSectors */
        vfat->RootDirSectors = 
            ((vfat->bpb.RootEntCnt * 32) + (vfat->bpb.BytsPerSec - 1)) / 
            vfat->bpb.BytsPerSec;

        /* Compute VFAT.FirstRootDirSecNum */
        vfat->FirstRootDirSecNum = vfat->bpb.ResvdSecCnt + 
            (vfat->bpb.NumFATs * vfat->FATSz);

        /* Compute VFAT.FirstDataSector */
        vfat->FirstDataSector = vfat->bpb.ResvdSecCnt + 
            (vfat->bpb.NumFATs * vfat->FATSz) + vfat->RootDirSectors;

        /* Compute VFAT.DataSec */
        vfat->DataSec = vfat->TotSec - 
            (vfat->bpb.ResvdSecCnt + (vfat->bpb.NumFATs * vfat->FATSz) + 
            vfat->RootDirSectors);

        /* Compute VFAT.CountOfClusters */
        vfat->CountOfClusters = vfat->DataSec / vfat->bpb.SecPerClus;

        /* Compute cluster size in bytes */
        vfat->ClusterSize = vfat->bpb.SecPerClus * vfat->bpb.BytsPerSec;
    }

    /* Determine Type of FAT */
    if (vfat->CountOfClusters < 4085)
        vfat->FATType = FAT12;
    else if (vfat->CountOfClusters < 65525)
        vfat->FATType = FAT16;
    else
        vfat->FATType = FAT32;

    /* Load one of the FATs into memory */
    {
        UINTN nbytes = vfat->FATSz * vfat->bpb.BytsPerSec;

        if (BufReserve(&vfat->fat, nbytes) != 0)
            GOTO(done);

        if (BlkdevRead(
            vfat->dev, 
            vfat->bpb.ResvdSecCnt, 
            vfat->fat.data, 
            nbytes) != 0)
        {
            GOTO(done);
        }

        vfat->fat.size += nbytes;

        /* If more than one FAT, read the second one in an compare */
        if (vfat->bpb.NumFATs > 1)
        {
            Buf buf = BUF_INITIALIZER;

            if (BufReserve(&buf, nbytes) != 0)
                GOTO(done);

            if (BlkdevRead(
                vfat->dev, 
                vfat->bpb.ResvdSecCnt + vfat->FATSz, 
                buf.data,
                nbytes) != 0)
            {
                BufRelease(&buf);
                GOTO(done);
            }

            buf.size += nbytes;

            if (buf.size != vfat->fat.size ||
                Memcmp(buf.data, vfat->fat.data, buf.size) != 0)
            {
                BufRelease(&buf);
                GOTO(done);
            }

            BufRelease(&buf);
        }

#if 0
        HexDump(vfat->fat.data, vfat->fat.size);
#endif
    }

    /* Load the root directory into memory */
    if (vfat->FATType == FAT32)
    {
        /* Read the root directory file into memory */
        if (ReadClusters(vfat, vfat->bpb.u.s32.RootClus, &vfat->rootdir) != 0)
            GOTO(done);

        vfat->rootdirClustno = vfat->bpb.u.s32.RootClus;
    }
    else
    {
        UINTN nbytes = vfat->RootDirSectors * vfat->bpb.BytsPerSec;

        if (BufReserve(&vfat->rootdir, nbytes) != 0)
            GOTO(done);

        if (BlkdevRead(
            vfat->dev, 
            vfat->FirstRootDirSecNum, 
            vfat->rootdir.data, 
            nbytes) != 0)
        {
            GOTO(done);
        }

        vfat->rootdir.size += nbytes;
        vfat->rootdirClustno = 0;
    }

    *vfatOut = vfat;
    rc = 0;

done:

    if (rc != 0)
    {
        if (vfat)
        {
            /* Don't let VFATRelease() free the caller's device */
            vfat->dev = NULL;
            VFATRelease(vfat);
        }
    }

    return rc;
}