On 12/02/2011 11:23 PM, OGAWA Hirofumi wrote:
OGAWA Hirofumi<hirofumi@mail.parknet.co.jp> writes:
Kai Meyer<kai@gnukai.com> writes:
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. It looks like wrong as dirent. Did you use 523793 really? If so, I think 523791 is correct value. :) And I didn't mention about offset correctly. offset means number of entries, not bytes offset. So, bytes offset is "buf + offset * 32". (32 == sizeof(struct msdos_dir_entry))
Thanks. Ok, I fixed the buf + offset * 32. I have a new volume, so the error is now: fat_get_cluster: invalid cluster chain (i_pos 523781)
I added a few lines at the end to print the start value: pos = dirent.starthi << 16; pos |= dirent.start; printf("next pos: %u\n", sector); [root@dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 523781 block 4092, sector 32736, offset 5 name 3~1 ZER attr 32 lcase 0 ctime_cs 100 ctime 29092 cdate 16264 adate 16264 starthi 4 time 29092 date 16264 start 7427 size 37748736 next pos: 32736 [root@dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 32736 block 255, sector 2040, offset 96 name attr 0 lcase 0 ctime_cs 0 ctime 0 cdate 0 adate 0 starthi 0 time 0 date 0 start 0 size 0 next pos: 2040 Does that look like what would be causing my error? meaning, sector 2040 has bad data?