2

I'm trying to implement a FAT12 file system in which there's a FAT table data structure which is an unsigned char array. I need to write a function which given an array index would write a value to the next 12 bits (because it's FAT12) which is quite tricky because part of the value needs to go to one byte and the other part needs to go the half of the second byte.

This is the get value function I came up with:

//FAT is the unsigned char array
int GetFatEntry(int FATindex, unsigned char * FAT) {
   unsigned int FATEntryCode; // The return value

   //   Calculate the offset of the WORD to get
   int FatOffset = ((FATindex * 3) / 2);

   if (FATindex % 2 == 1){   // If the index is odd

      FATEntryCode =  ((unsigned char)(&FAT[FatOffset])[0] + (((unsigned char)(&FAT[FatOffset])[1]) << 8));

      FATEntryCode >>= 4; // Extract the high-order 12 bits
   }
   else{    // If the index is even

      FATEntryCode = ((unsigned char)(&FAT[FatOffset])[0] + (((unsigned char)(&FAT[FatOffset])[1]) << 8));

      FATEntryCode &= 0x0fff; // Extract the low-order 12 bits
   }
   return FATEntryCode;
}

I'm struggling to come up with the function which would set a value given a FATindex. I would appreciate any suggestions.

Yos
  • 1,276
  • 1
  • 20
  • 40

2 Answers2

1

This seems to work. The data that should be written should be in the first 12 bits of data

void WriteFatEntry(int FATindex, unsigned char * FAT, unsigned char data[2]) {
    //   Calculate the offset of the WORD to get                                                                   
    int FatOffset = ((FATindex * 3) / 2);

    unsigned char d;
    if (FATindex % 2 != 0){   // If the index is odd                                                               
// Copy from data to d and e, and shift everything so that second half of 
// e contains first half of data[1], and first half of e contains second
// half of data[0], while second half of d contains first half of data[0]. 
// First half of d contains a copy of first four bits in FAT[FatOffset]
// so that nothing changes when it gets written
        unsigned char e=data[1];
        e>>=4;
        d=data[0];
        e|=(d<<4) & 0b11110000;
        d>>=4;
        d |= FAT[FatOffset] & 0b11110000;

        FAT[FatOffset]=d;
        FAT[FatOffset+1] = e;
    }
    else{    // If the index is even                                                                               
        d = data[1] & 0b11110000;
        d |= FAT[FatOffset+1] & 0b00001111;

        FAT[FatOffset] = data[0];
        FAT[FatOffset+1] = d;
    }
}
klutt
  • 30,332
  • 17
  • 55
  • 95
  • thank you for the explanation! would this still work if I had an `int` parameter instead of `unsigned char data[2]` could I extract the first 8 bits as follows: `data[0]=(((1 << 8) - 1) & myint` and then to extract the last 4 bits: `data[1]= (((1 << 4) - 1) & (myint >> 8))`? – Yos Jan 09 '18 at 17:50
  • 1
    It's certainly possible, but I'm not sure what it would take. However, I think it would be easier and less risky if you used `int16_t` to have a type that is guaranteed to have the same size as two chars. – klutt Jan 09 '18 at 17:55
  • 1
    @Yos Here's a pastbin with some testing code. https://pastebin.com/v5546KMu – klutt Jan 09 '18 at 18:01
  • thank you for the additional code, especially the `printBits`! When I run the following code `WriteFarEntry(0, FAT, {205, 12})` I get that `FAT[FatOffset] = 12` and `FAT[FatOffset + 1] = 208` instead of `205`. Is it something I'm missing or I'm misusing something? – Yos Jan 09 '18 at 18:34
  • I should mention that printBits is a slightly modified version of this: https://stackoverflow.com/a/3974138/6699433 – klutt Jan 09 '18 at 18:53
  • Are you seeing the same results with the array `{205, 12}`? – Yos Jan 09 '18 at 18:56
  • Did you initialize FAT? Remember that if you call it with an even index, then FAT[FatOffset+1] will contain half of what it contained before. – klutt Jan 09 '18 at 19:02
  • Even if I run a test using a test array `unsigned char array[2]={0,0}` instead of FAT I still get the same result. I'm checking both `FAT[FatOffset]` and `FAT[FatOffset + 1]` and the result is not the same value. For example if I run `WriteFatEntry(0, array, {205, 12})` the resulting `array[0]` should be 205 while `array[1]` should be 12 as far as understand. – Yos Jan 09 '18 at 19:32
  • 1
    I cannot reproduce it. The code works for me, but you're wrong about one thing. The resulting array should not be {205,12}. 12 is 00001100 in binary, and it's only the four first bits that should be written. – klutt Jan 09 '18 at 20:00
  • 1
    So if array[1] = 1 and data[1] = 16, then data[1] will be 17 after the operation, because 16 is represented by 00010000 and 1 is 00000001, so the resulting binary pattern will be 00010001 – klutt Jan 09 '18 at 20:02
  • 1
    Or in a simpler way. if array[1] is on the form ab (a being the first four bits and be the rest) and data[1] is on the form cd, then array[1] will be cb – klutt Jan 09 '18 at 20:21
0
#include <stdio.h>

#if 1 /* assuming MSB first */
#define MSB (idx)
#define LSB (idx+1)
#else /* assuming LSB first */
#define MSB (idx+1)
#define LSB (idx)
#endif

unsigned fat_getval(unsigned char * tab, unsigned num)
{
unsigned idx;
unsigned val;

idx = num + num/2;
val = (tab[MSB] <<8 ) + (tab[idx+1] ) ;
if (num %2 ==0) val >>= 4;

return val & 0xfff;
}

void fat_putval(unsigned char * tab, unsigned slot, unsigned val)
{
unsigned idx;

idx = slot + slot/2;
if (slot %2 ==0) {      /* xyz_ */
        val <<= 4;
        val |= tab[LSB] & 0xf;
        }
else    {               /* _xyz */
        val |= (tab[MSB] & 0xf0) << 8;
        }
tab[MSB] = val >>8;
tab[LSB] = val &0xff;
}
#undef MSB
#undef LSB

unsigned char fattable[] = "\x01\x23\x45\x67\x89\xab"; // 12 nibbles
int main(void)
{
unsigned idx, ret;
for (idx = 0; idx < 6; idx++) { // 6 bytes -> 12 nibbles */
        printf(" %02x", fattable[idx] );
        }
printf("\n");

printf("Put(0,0xabc):\n");
fat_putval(fattable, 0, 0xabc);
for (idx = 0; idx < 6; idx++) {
        printf(" %02x", fattable[idx] );
        }
printf("\n");

printf("Put(3,0xdef):\n");
fat_putval(fattable, 3, 0xdef);
for (idx = 0; idx < 6; idx++) {
        printf(" %02x", fattable[idx] );
        }
printf("\n");

printf("Get(0 to 4):\n");
for (idx = 0; idx < 4; idx++) { // 12 / 3 ~> 4 * 12bit entries
        ret = fat_getval( fattable, idx);
        printf("%u := %x\n", idx, ret );
        }
printf("\n");

return 0;
}
joop
  • 4,330
  • 1
  • 15
  • 26
  • *"I'm struggling to come up with the function which would set a value "* – klutt Jan 09 '18 at 17:52
  • Aha, his text conflicts wih his code, so it seems. He never masks bach the unchanged nibble, for instance. Now I see, he **has** constructed the get-function and **he wants us** to write the put-function, without showing any attempt himself. – joop Jan 09 '18 at 17:54