VFAT i_pos value

Kai Meyer kai at gnukai.com
Thu Dec 1 15:46:15 EST 2011



On 12/01/2011 12:20 PM, OGAWA Hirofumi wrote:
> Kai Meyer<kai at gnukai.com>  writes:
>
>>> The i_pos means directory entry (contains inode information in unix-fs)
>>> position,
>>>
>>>       block number == i_pos / (logical-blocksize / 32)
>>>       offset       == i_pos&   (logical-blocksize / 32)
>>>
>>> the above position's directory entry contains information for
>>> problematic file. This is how to use i_pos information.
>>>
>>> FWIW, in this error case, the cluster chain in FAT table which is
>>> pointed by that entry, it has invalid cluster value.
>>>
>>> Thanks.
>> If you would verify my math for me, I would appreciate it.
>>
>> In this case, my logical block size is 4096, because byte 13 of the 8Gb
>> file system is 8, and I take that to be 8 * 512, which is 4096. So:
>>
>> block_number = 523791 / (4096 / 32) = 4092
>> offset = 523791 % (4096 / 32) = 15  // I assume you meant modulo in your
>> original post, and not binary AND.
> Whoops, you are right. (I forgot "-1")
>
>> So if the block_number is 4092, I would multiply that by 8 (sectors per
>> logical block) to get the sector number:
>> 32736
> Right.
>
>> Does the error indicate that sector contains the corrupted data?
> No.
>
>> Or is it the sector that contains the information that points to the
>> corrupted data?
> Right.
>
> The i_pos is pointing a directory entry (include/linux/msdos_fs.h:
> struct msdos_dir_entry).
>
> And starthi (if FAT32) and start contain the pointer to next cluster
> number. That message was outputted when walking in cluster chain.
>
> If you want to see actual corrupted data, you can check the cluster
> chain by pointing from that directory entry.
>
> Thanks.

Thanks for the helpful response. I'm not entirely sure I understand the 
next part though. I hacked a dirty entry dumper tool:

#include <stdio.h>
#include <linux/msdos_fs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char** argv)
{
         off_t pos = atoi(argv[2]);
         unsigned long block;
         off_t sector;
         unsigned int offset;
         int fd = open(argv[1], O_RDONLY);
         char buf[512];
         struct msdos_dir_entry dirent;
         block = pos / (4096 / 32);
         sector = block * 8;
         offset = pos % (4096 / 32);
         printf("block %lu, sector %lu, offset %u\n", block, sector, 
offset);
         lseek(fd, sector * 512, SEEK_SET);
         if (read(fd, buf, 512) < 0) {
                 fprintf(stderr, "Unable to read from device %s\n", 
argv[1]);
                 return -1;
         }
         memcpy(&dirent, buf + offset, sizeof(dirent));
         printf("name      %s\n", dirent.name);
         printf("attr      %u\n", dirent.attr);
         printf("lcase     %u\n", dirent.lcase);
         printf("ctime_cs  %u\n", dirent.ctime_cs);
         printf("ctime     %u\n", dirent.ctime);
         printf("cdate     %u\n", dirent.cdate);
         printf("adate     %u\n", dirent.adate);
         printf("starthi   %u\n", dirent.starthi);
         printf("time      %u\n", dirent.time);
         printf("date      %u\n", dirent.date);
         printf("start     %u\n", dirent.start);
         printf("size      %u\n", dirent.size);
}

Here's what it outputs:

./vfat_entry /dev/sblsnap0 523793
block 4092, sector 32736, offset 17
name
attr      255
lcase     255
ctime_cs  255
ctime     12799
cdate     12670
adate     8224
starthi   8224
time      23072
date      21061
start     32
size      2171155456

So, I take starthi, and shift 16 bits left, then and in the start value. 
That should give me the byte address of the first cluster of the file, 
correct?

Then I need to follow the cluster chain until I get a bad value.

Thanks



More information about the Kernelnewbies mailing list