Page 1 of 1

[SOLVED]Problems following cluster chains

Posted: Sat Dec 03, 2011 1:59 pm
by nathan2175
I've been following the tutorials at http://www.brokenthorn.com/Resources/OSDev22.html to implement FAT12 filesystem support in my OS. Unfortunately, I've run into a problem. The code that follows the FAT cluster chain doesn't seem to work on files that have been resized. Specifically, the file that it is trying to read was originally 1KB, then it was increased to 9KB, then lowered to 2KB. I put in some code that made it display the clusters it was reading, and this is what it displayed:
Reading cluster 513
Reading cluster 514
Reading cluster 1058
I viewed the floppy disk with a hex editor and found that the correct cluster should be 704 instead of 1058. I also found that that cluster 1058 has not yet been used by the file system to store data. Is this a bug somewhere in the code, or is it something else?

Here's the code that I'm using:

Code: Select all

void fread (FILE *file, unsigned char* Buffer, unsigned int Length)
{
    int i;
    for (i = 0; i <= (Length / 512); i++)
    {
        printf ("Reading cluster %d\n", file->currentCluster);
        fread_sector(file, Buffer + (i * 512), 512);
        if (file->eof)
            return;
    }
}

void fread_sector(FILE *file, unsigned char* Buffer, unsigned int Length)
{
    if (file)
    {
		unsigned int physSector = 32 + (file->currentCluster - 1);

		unsigned char* sector = (unsigned char*) flpydsk_read_sector ( physSector );

		memcpy (Buffer, sector, 512);

        unsigned int FAT_Offset = file->currentCluster + (file->currentCluster / 2); //multiply by 1.5
        unsigned int FAT_Sector = 1 + (FAT_Offset / SECTOR_SIZE);
        unsigned int entryOffset = FAT_Offset % SECTOR_SIZE;

        sector = (unsigned char*) flpydsk_read_sector ( FAT_Sector );
        memcpy (FAT, sector, 512);

        sector = (unsigned char*) flpydsk_read_sector ( FAT_Sector + 1 );
        memcpy (FAT + SECTOR_SIZE, sector, 512);

        unsigned short nextCluster = *(unsigned short *)&FAT[entryOffset];

        if (entryOffset & 0x1)
            nextCluster >>= 4;      //grab high 12 bits
        else
            nextCluster &= 0x0FFF;   //grab low 12 bits

        if ( nextCluster >= 0xff8)
        {
            file->eof = 1;
            return;
        }

        if ( nextCluster == 0 )
        {
            file->eof = 1;
            return;
        }

        file->currentCluster = nextCluster;
    }
}

Re: Problems following cluster chains

Posted: Sat Dec 03, 2011 6:04 pm
by nathan2175
berkus wrote:What is the type of 'FAT'?
It's a floppy disk, so it uses FAT12.

Re: Problems following cluster chains

Posted: Sun Dec 04, 2011 2:06 am
by xenos
I guess berkus meant: "What is the type of the variable named 'FAT' in your code?"

It appears that you are somehow trying to read a char array at half-byte offsets... You cannot read a packed array of 12 bit integers that way.

Re: Problems following cluster chains

Posted: Sun Dec 04, 2011 7:01 am
by nathan2175
berkus wrote:What is the type of the C variable FAT in your code?.
'FAT' is a char array 1024 bytes long

Code: Select all

#define SECTOR_SIZE 512

unsigned char FAT [SECTOR_SIZE*2];

Re: Problems following cluster chains

Posted: Sun Dec 04, 2011 1:52 pm
by nathan2175
berkus wrote:So did you dump it to see what's in there then?
I made the code display the raw value that it was reading and the offset that it was reading it from:
Reading cluster 513
Offset: 257 Raw data: 0x202F
Reading cluster 514
Offset: 259 Raw data: 0x4203
The first entry has an odd offset, so the code right-shifts the value by 4 (0x202, 514 decimal). The next entry's offset is also odd, but when the code right-shifts the value, it comes out with 0x420 (which is 1056 decimal). I then realized that this line

Code: Select all

if (entryOffset & 0x1)
is checking to see if the offset from the start of 'FAT' is odd (which it always is) #-o. I changed it to

Code: Select all

if (!((entryOffset / 2) & 0x1))
which made it work correctly. :D