FAT12 hell

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
MrASCII

FAT12 hell

Post by MrASCII »

Hi all!

I'm currently writing a FAT12 driver, which is giving me some problems. I'm a bit confused about how to read the FAT entries, and finding the next cluster in chain. The weird problem is that a small file ( 1 or 2 clusters ) starting at an even cluster works just fine, but big files jump over all the place. I'm thinking about it, but I can't get the math straigt. As I've read over and over, odd clusters shift 4 to the right, even clusters mask with 0x0FFF. But what I don't get, if I use this method, some bytes will be missing. Because we use ?r the first 12 bits of a word, or the upper 12 bits. I.e. every FAT entry starts at bit 0 or bit 4 of a word. But as far as I can imagine, FAT entries can also start at bit 8 or 12 right? Or am I thinking to complicated?

My cat function:

Code: Select all

... some BPB reading here...

int cluster = (block[(c*32)+26] )  + ( block[(c*32)+27] * 0xFF ) ;   // Starting cluster from dir entry
int  next_cluster=0, fat_offset=0;
BYTE FAT[0x1200];
fd_read_block(1,FAT, 9);    // read the FAt, I know this is not the right way to go ;)
                         
while(cluster < 0x0FF8) {       
   double fat_entry = (cluster * 3)/2;
          
        fat_offset = FAT[(int)fat_entry] + (FAT[(int)fat_entry + 1] * 0xFF);
                                                     
        if(floor(fat_entry) == fat_entry){
           next_cluster = fat_offset >> 4;
        } else {
           next_cluster = (fat_offset & 0x0FFF);
        }
                            
        show_sector(cluster);  // This function displays the contect of cluster x
        cluster = next_cluster;
}

User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:FAT12 hell

Post by Brendan »

Hi,

You might want to replace this bit:

Code: Select all

        fat_offset = FAT[(int)fat_entry] + (FAT[(int)fat_entry + 1] * 0xFF);
                                                     
        if(floor(fat_entry) == fat_entry){
           next_cluster = fat_offset >> 4;
        } else {
           next_cluster = (fat_offset & 0x0FFF);
        }
With:

Code: Select all

        fat_offset = FAT[(int)fat_entry] + (FAT[(int)fat_entry + 1] * 0x100);
                                                     
        if(floor(cluster) == cluster){
           next_cluster = fat_offset >> 4;
        } else {
           next_cluster = (fat_offset & 0x0FFF);
        }
I think it'll work after that...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
MrASCII

Re:FAT12 hell

Post by MrASCII »

The 0xFF - 0x100 mistake was rather dumb, but I've experimented with this code so many times it's all f*cked up. So now I have a freshly written loop but the problem remains. I've some output, the loop is:

Code: Select all

while(cluster < 0x0FF8) {       
   double fat_entry = (cluster * 3)/2;
          
   fat_offset = FAT[(int)fat_entry] + (FAT[(int)fat_entry + 1] * 0x100);
                                                   
        if(floor(cluster) == cluster){
             next_cluster = fat_offset >> 4;
        } else {
             next_cluster = (fat_offset & 0x0FFF);
        }
                            
        k_printf("fat_offset: %i next_cluster: %i cluster: %i\n", fat_offset, next_cluster, cluster);
   //show_sector(cluster);
   cluster = next_cluster;
}
The output I'm getting is:

Code: Select all

Welcome to ProtOS.

fd:test
fat_offset: 975 next_cluster: 60 cluster: 59
fat_offset: 57405 next_cluster: 3587 cluster: 60
fat_offset: 26190 next_cluster: 1636 cluster: 3587
fat_offset: 0 next_cluster: 0 cluster: 1636
fat_offset: 65520 next_cluster: 4095 cluster: 0

fd:ls
KERNEL  BIN     28672   A       cluster:2
CHANGE~1TXT     297     A       cluster:58
LICENSE TXT     18009   A       cluster:59
README  TXT     782     HA      cluster:95
TEST                    D       cluster:97

fd:
I've read some raw sectors and I know the file is located at cluster 59-60-61-62-63-etc... ( I limited the results to 5 )

The shift 4 part is working OK, I'm guessing that the masking is going all wrong... Taking a piece of paper and writing it all in binary, but the results make no sense. I end up with a FAT entry which starts at bit 12 of a word... ??
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:FAT12 hell

Post by Brendan »

Hi,

Ok, try this instead:

Code: Select all

        if(floor(cluster) == cluster){
             next_cluster = (fat_offset & 0x0FFF);
        } else {
             next_cluster = fat_offset >> 4;
        }
I think it'll work this time :).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
MrASCII

Re:FAT12 hell

Post by MrASCII »

Nope, but I finally fixed it. We were both way off. The right way to mask it is:
while(cluster < 0x0FF8) {
   fat_offset = (cluster + (cluster >> 1));
   next_cluster = FAT[(int)fat_offset] + (FAT[(int)fat_offset + 1] * 0x100);

   if (cluster % 2)
      next_cluster = ((next_cluster & 0xFFF0) >> 4);
   else
      next_cluster = (next_cluster & 0x0FFF);

   show_sector(cluster);
   cluster = next_cluster;
}
This works! :D Now some memory management to load the file at a proper place would be nice... 8)
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:FAT12 hell

Post by Solar »

MrASCII wrote: The 0xFF - 0x100 mistake was rather dumb, but I've experimented with this code so many times it's all f*cked up.
I urgently suggest you use some kind of version tracking system. RCS could suffice for local use and is easy to set up / administrate. CVS or Subversion are more complete solutions.

You just voiced the best reason yourself: You tend to edit your code to death otherwise, and the clean-up after such a trial-and-error session becomes much easier if you have a revision history on file.
Every good solution is obvious once you've found it.
Post Reply