filesystemsosdevfat

FAT12 cluster chain just stops, can't tell what's going on


I'm working on a FAT12 driver for my OS (you can find the driver here) but I've run into a very strange roadblock, that I don't know is with my code or the driver.

I have a file called long.txt that contains about 1024 bytes of content, and it's meant to test following a chain of clusters. However, the code stops after one cluster, and says the next one is 0xFFF, which is greater than 0xFF8, so EOF.

Here is the snippet of code that causes issues:

int fatReadInternal(fsNode_t *file, uint8_t *buffer, uint32_t length) {
    if (file) {
        // Calculate and read in the starting physical sector
        uint16_t cluster = file->impl;
        uint32_t sector = ((cluster - 2) * drive->bpb->sectorsPerCluster) + drive->firstDataSector;

        uint8_t *sector_buffer;
        ideReadSectors(drive->driveNum, 1, (uint32_t)sector, sector_buffer);
        


        // Copy the sector buffer to the output buffer
        memcpy(buffer, sector_buffer, length);

        // Locate the File Allocation Table sector
        uint32_t fatOffset = cluster + (cluster / 2);
        uint32_t fatSector = drive->firstFatSector + (fatOffset / 512);
        uint32_t entryOffset = fatOffset % 512;

        // Read the FATs
        ideReadSectors(drive->driveNum, 1, fatSector, (uint8_t*)FAT);
        ideReadSectors(drive->driveNum, 1, fatSector + 1, (uint8_t*)FAT + 512);

         

        // Read entry for the next cluster
        uint16_t nextCluster = *(uint16_t*)&FAT[entryOffset];

        // Convert the cluster
        nextCluster = (cluster & 1) ? nextCluster >> 4 : nextCluster & 0xFFF;

        serialPrintf("The current cluster is 0x%x, the next cluster is 0x%x after modification.\n", cluster, nextCluster);
        

        // Test for EOF
        if (nextCluster >= 0xFF8) {
            return EOF;
        }

        // Test for file corruption
        if (nextCluster == 0) {
            return EOF;
        }

        // Set the next cluster
        file->impl = nextCluster;
    }

    return 0;
}

NOTE: It is meant to be called multiple times.

It outputs that the current cluster is 0xD and the next cluster read from the disk (not yet converted) is 0xFF0, which (from looking at a hex editor) is correct if entry offset is 0x13 (should also be calculating properly).

The problem is that after conversion this is 0xFFF, last cluster in the chain. The same is true manually calculating and checking a hex editor. I'm genuinely very confused.

The FAT driver can read the first 512 bytes of the file, but then it just returns EOF. I checked in the hex editor to see where the next cluster actually was, and its directly after the first one.

I'm not sure whether this is an issue in my code or something else, but Linux appears to read the file just fine.


Solution

  • Next cluster reading seems fine to me at a first glance. However there are two related obvious issues:

    1. The function assumes there is a single sector per cluster - it reads single sector and then moves on to the next cluster. This might be your issue - what if your image is formatted with >=1kb cluster size? Then your 1 kb file would be stored in a single cluster and 0xFFF would be expected.
    2. In a similar faction, it assumes it is always going to be called to read the entire cluster/sector. Repeated fsRead(size=1) would not work the way one would expect it works.