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