[SOLVED]Problems following cluster chains

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
nathan2175
Posts: 4
Joined: Thu Dec 01, 2011 7:47 pm
Location: JMP Location

[SOLVED]Problems following cluster chains

Post 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;
    }
}
Last edited by nathan2175 on Wed Dec 07, 2011 4:29 pm, edited 1 time in total.
User avatar
nathan2175
Posts: 4
Joined: Thu Dec 01, 2011 7:47 pm
Location: JMP Location

Re: Problems following cluster chains

Post by nathan2175 »

berkus wrote:What is the type of 'FAT'?
It's a floppy disk, so it uses FAT12.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Problems following cluster chains

Post 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.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
User avatar
nathan2175
Posts: 4
Joined: Thu Dec 01, 2011 7:47 pm
Location: JMP Location

Re: Problems following cluster chains

Post 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];
User avatar
nathan2175
Posts: 4
Joined: Thu Dec 01, 2011 7:47 pm
Location: JMP Location

Re: Problems following cluster chains

Post 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
Post Reply