"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "dosfstools-2.11/dosfsck/check.c" of archive dosfstools-2.11.src.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* check.c - Check and repair a PC/MS-DOS file system */
2
3 /* Written 1993 by Werner Almesberger */
4
5 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
6 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <limits.h>
13 #include <time.h>
14
15 #include "common.h"
16 #include "dosfsck.h"
17 #include "io.h"
18 #include "fat.h"
19 #include "file.h"
20 #include "lfn.h"
21 #include "check.h"
22
23
24 static DOS_FILE *root;
25
26 /* get start field of a dir entry */
27 #define FSTART(p,fs) \
28 ((unsigned long)CF_LE_W(p->dir_ent.start) | \
29 (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0))
30
31 #define MODIFY(p,i,v) \
32 do { \
33 if (p->offset) { \
34 p->dir_ent.i = v; \
35 fs_write(p->offset+offsetof(DIR_ENT,i), \
36 sizeof(p->dir_ent.i),&p->dir_ent.i); \
37 } \
38 } while(0)
39
40 #define MODIFY_START(p,v,fs) \
41 do { \
42 unsigned long __v = (v); \
43 if (!p->offset) { \
44 /* writing to fake entry for FAT32 root dir */ \
45 if (!__v) die("Oops, deleting FAT32 root dir!"); \
46 fs->root_cluster = __v; \
47 p->dir_ent.start = CT_LE_W(__v&0xffff); \
48 p->dir_ent.starthi = CT_LE_W(__v>>16); \
49 __v = CT_LE_L(__v); \
50 fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \
51 sizeof(((struct boot_sector *)0)->root_cluster), \
52 &__v); \
53 } \
54 else { \
55 MODIFY(p,start,CT_LE_W((__v)&0xffff)); \
56 if (fs->fat_bits == 32) \
57 MODIFY(p,starthi,CT_LE_W((__v)>>16)); \
58 } \
59 } while(0)
60
61
62 loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern)
63 {
64 static int curr_num = 0;
65 loff_t offset;
66
67 if (fs->root_cluster) {
68 DIR_ENT d2;
69 int i = 0, got = 0;
70 unsigned long clu_num, prev = 0;
71 loff_t offset2;
72
73 clu_num = fs->root_cluster;
74 offset = cluster_start(fs,clu_num);
75 while (clu_num > 0 && clu_num != -1) {
76 fs_read(offset,sizeof(DIR_ENT),&d2);
77 if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) {
78 got = 1;
79 break;
80 }
81 i += sizeof(DIR_ENT);
82 offset += sizeof(DIR_ENT);
83 if ((i % fs->cluster_size) == 0) {
84 prev = clu_num;
85 if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)
86 break;
87 offset = cluster_start(fs,clu_num);
88 }
89 }
90 if (!got) {
91 /* no free slot, need to extend root dir: alloc next free cluster
92 * after previous one */
93 if (!prev)
94 die("Root directory has no cluster allocated!");
95 for (clu_num = prev+1; clu_num != prev; clu_num++) {
96 if (clu_num >= fs->clusters+2) clu_num = 2;
97 if (!fs->fat[clu_num].value)
98 break;
99 }
100 if (clu_num == prev)
101 die("Root directory full and no free cluster");
102 set_fat(fs,prev,clu_num);
103 set_fat(fs,clu_num,-1);
104 set_owner(fs, clu_num, get_owner(fs, fs->root_cluster));
105 /* clear new cluster */
106 memset( &d2, 0, sizeof(d2) );
107 offset = cluster_start(fs,clu_num);
108 for( i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT) )
109 fs_write( offset+i, sizeof(d2), &d2 );
110 }
111 memset(de,0,sizeof(DIR_ENT));
112 while (1) {
113 sprintf(de->name,pattern,curr_num);
114 clu_num = fs->root_cluster;
115 i = 0;
116 offset2 = cluster_start(fs,clu_num);
117 while (clu_num > 0 && clu_num != -1) {
118 fs_read(offset2,sizeof(DIR_ENT),&d2);
119 if (offset2 != offset &&
120 !strncmp(d2.name,de->name,MSDOS_NAME))
121 break;
122 i += sizeof(DIR_ENT);
123 offset2 += sizeof(DIR_ENT);
124 if ((i % fs->cluster_size) == 0) {
125 if ((clu_num = next_cluster(fs,clu_num)) == 0 ||
126 clu_num == -1)
127 break;
128 offset2 = cluster_start(fs,clu_num);
129 }
130 }
131 if (clu_num == 0 || clu_num == -1)
132 break;
133 if (++curr_num >= 10000) die("Unable to create unique name");
134 }
135 }
136 else {
137 DIR_ENT *root;
138 int next_free = 0, scan;
139
140 root = alloc(fs->root_entries*sizeof(DIR_ENT));
141 fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root);
142
143 while (next_free < fs->root_entries)
144 if (IS_FREE(root[next_free].name) &&
145 root[next_free].attr != VFAT_LN_ATTR)
146 break;
147 else next_free++;
148 if (next_free == fs->root_entries)
149 die("Root directory is full.");
150 offset = fs->root_start+next_free*sizeof(DIR_ENT);
151 memset(de,0,sizeof(DIR_ENT));
152 while (1) {
153 sprintf(de->name,pattern,curr_num);
154 for (scan = 0; scan < fs->root_entries; scan++)
155 if (scan != next_free &&
156 !strncmp(root[scan].name,de->name,MSDOS_NAME))
157 break;
158 if (scan == fs->root_entries) break;
159 if (++curr_num >= 10000) die("Unable to create unique name");
160 }
161 free(root);
162 }
163 ++n_files;
164 return offset;
165 }
166
167
168 static char *path_name(DOS_FILE *file)
169 {
170 static char path[PATH_MAX*2];
171
172 if (!file) *path = 0;
173 else {
174 if (strlen(path_name(file->parent)) > PATH_MAX)
175 die("Path name too long.");
176 if (strcmp(path,"/") != 0) strcat(path,"/");
177 strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name));
178 }
179 return path;
180 }
181
182
183 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
184 /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
185
186
187 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
188
189 time_t date_dos2unix(unsigned short time,unsigned short date)
190 {
191 int month,year;
192 time_t secs;
193
194 month = ((date >> 5) & 15)-1;
195 year = date >> 9;
196 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
197 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
198 month < 2 ? 1 : 0)+3653);
199 /* days since 1.1.70 plus 80's leap day */
200 return secs;
201 }
202
203
204 static char *file_stat(DOS_FILE *file)
205 {
206 static char temp[100];
207 struct tm *tm;
208 char tmp[100];
209 time_t date;
210
211 date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file->
212 dir_ent.date));
213 tm = localtime(&date);
214 strftime(tmp,99,"%H:%M:%S %b %d %Y",tm);
215 sprintf(temp," Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp);
216 return temp;
217 }
218
219
220 static int bad_name(unsigned char *name)
221 {
222 int i, spc, suspicious = 0;
223 char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
224
225 /* Do not complain about (and auto-correct) the extended attribute files
226 * of OS/2. */
227 if (strncmp(name,"EA DATA SF",11) == 0 ||
228 strncmp(name,"WP ROOT SF",11) == 0) return 0;
229
230 for (i = 0; i < 8; i++) {
231 if (name[i] < ' ' || name[i] == 0x7f) return 1;
232 if (name[i] > 0x7f) ++suspicious;
233 if (strchr(bad_chars,name[i])) return 1;
234 }
235
236 for (i = 8; i < 11; i++) {
237 if (name[i] < ' ' || name[i] == 0x7f) return 1;
238 if (name[i] > 0x7f) ++suspicious;
239 if (strchr(bad_chars,name[i])) return 1;
240 }
241
242 spc = 0;
243 for (i = 0; i < 8; i++) {
244 if (name[i] == ' ')
245 spc = 1;
246 else if (spc)
247 /* non-space after a space not allowed, space terminates the name
248 * part */
249 return 1;
250 }
251
252 spc = 0;
253 for (i = 8; i < 11; i++) {
254 if (name[i] == ' ')
255 spc = 1;
256 else if (spc)
257 /* non-space after a space not allowed, space terminates the name
258 * part */
259 return 1;
260 }
261
262 /* Under GEMDOS, chars >= 128 are never allowed. */
263 if (atari_format && suspicious)
264 return 1;
265
266 /* Only complain about too much suspicious chars in interactive mode,
267 * never correct them automatically. The chars are all basically ok, so we
268 * shouldn't auto-correct such names. */
269 if (interactive && suspicious > 6)
270 return 1;
271 return 0;
272 }
273
274
275 static void drop_file(DOS_FS *fs,DOS_FILE *file)
276 {
277 unsigned long cluster;
278
279 MODIFY(file,name[0],DELETED_FLAG);
280 for (cluster = FSTART(file,fs); cluster > 0 && cluster <
281 fs->clusters+2; cluster = next_cluster(fs,cluster))
282 set_owner(fs,cluster,NULL);
283 --n_files;
284 }
285
286
287 static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters)
288 {
289 int deleting;
290 unsigned long walk,next,prev;
291
292 walk = FSTART(file,fs);
293 prev = 0;
294 if ((deleting = !clusters)) MODIFY_START(file,0,fs);
295 while (walk > 0 && walk != -1) {
296 next = next_cluster(fs,walk);
297 if (deleting) set_fat(fs,walk,0);
298 else if ((deleting = !--clusters)) set_fat(fs,walk,-1);
299 prev = walk;
300 walk = next;
301 }
302 }
303
304
305 static void auto_rename(DOS_FILE *file)
306 {
307 DOS_FILE *first,*walk;
308 int number;
309
310 if (!file->offset) return; /* cannot rename FAT32 root dir */
311 first = file->parent ? file->parent->first : root;
312 number = 0;
313 while (1) {
314 sprintf(file->dir_ent.name,"FSCK%04d",number);
315 strncpy(file->dir_ent.ext,"REN",3);
316 for (walk = first; walk; walk = walk->next)
317 if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent.
318 name,MSDOS_NAME)) break;
319 if (!walk) {
320 fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
321 return;
322 }
323 number++;
324 }
325 die("Can't generate a unique name.");
326 }
327
328
329 static void rename_file(DOS_FILE *file)
330 {
331 unsigned char name[46];
332 unsigned char *walk,*here;
333
334 if (!file->offset) {
335 printf( "Cannot rename FAT32 root dir\n" );
336 return; /* cannot rename FAT32 root dir */
337 }
338 while (1) {
339 printf("New name: ");
340 fflush(stdout);
341 if (fgets(name,45,stdin)) {
342 if ((here = strchr(name,'\n'))) *here = 0;
343 for (walk = strrchr(name,0); walk >= name && (*walk == ' ' ||
344 *walk == '\t'); walk--);
345 walk[1] = 0;
346 for (walk = name; *walk == ' ' || *walk == '\t'; walk++);
347 if (file_cvt(walk,file->dir_ent.name)) {
348 fs_write(file->offset,MSDOS_NAME,file->dir_ent.name);
349 return;
350 }
351 }
352 }
353 }
354
355
356 static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots)
357 {
358 char *name;
359
360 name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : ".";
361 if (!(file->dir_ent.attr & ATTR_DIR)) {
362 printf("%s\n Is a non-directory.\n",path_name(file));
363 if (interactive)
364 printf("1) Drop it\n2) Auto-rename\n3) Rename\n"
365 "4) Convert to directory\n");
366 else printf(" Auto-renaming it.\n");
367 switch (interactive ? get_key("1234","?") : '2') {
368 case '1':
369 drop_file(fs,file);
370 return 1;
371 case '2':
372 auto_rename(file);
373 printf(" Renamed to %s\n",file_name(file->dir_ent.name));
374 return 0;
375 case '3':
376 rename_file(file);
377 return 0;
378 case '4':
379 MODIFY(file,size,CT_LE_L(0));
380 MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR);
381 break;
382 }
383 }
384 if (!dots) {
385 printf("Root contains directory \"%s\". Dropping it.\n",name);
386 drop_file(fs,file);
387 return 1;
388 }
389 return 0;
390 }
391
392
393 static int check_file(DOS_FS *fs,DOS_FILE *file)
394 {
395 DOS_FILE *owner;
396 int restart;
397 unsigned long expect,curr,this,clusters,prev,walk,clusters2;
398
399 if (file->dir_ent.attr & ATTR_DIR) {
400 if (CF_LE_L(file->dir_ent.size)) {
401 printf("%s\n Directory has non-zero size. Fixing it.\n",
402 path_name(file));
403 MODIFY(file,size,CT_LE_L(0));
404 }
405 if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) {
406 expect = FSTART(file->parent,fs);
407 if (FSTART(file,fs) != expect) {
408 printf("%s\n Start (%ld) does not point to parent (%ld)\n",
409 path_name(file),FSTART(file,fs),expect);
410 MODIFY_START(file,expect,fs);
411 }
412 return 0;
413 }
414 if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT,
415 MSDOS_NAME)) {
416 expect = file->parent->parent ? FSTART(file->parent->parent,fs):0;
417 if (fs->root_cluster && expect == fs->root_cluster)
418 expect = 0;
419 if (FSTART(file,fs) != expect) {
420 printf("%s\n Start (%lu) does not point to .. (%lu)\n",
421 path_name(file),FSTART(file,fs),expect);
422 MODIFY_START(file,expect,fs);
423 }
424 return 0;
425 }
426 if (FSTART(file,fs)==0){
427 printf ("%s\n Start does point to root directory. Deleting dir. \n",
428 path_name(file));
429 MODIFY(file,name[0],DELETED_FLAG);
430 return 0;
431 }
432 }
433 if (FSTART(file,fs) >= fs->clusters+2) {
434 printf("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n",
435 path_name(file),FSTART(file,fs),fs->clusters+1);
436 if (!file->offset)
437 die( "Bad FAT32 root directory! (bad start cluster)\n" );
438 MODIFY_START(file,0,fs);
439 }
440 clusters = prev = 0;
441 for (curr = FSTART(file,fs) ? FSTART(file,fs) :
442 -1; curr != -1; curr = next_cluster(fs,curr)) {
443 if (!fs->fat[curr].value || bad_cluster(fs,curr)) {
444 printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n",
445 path_name(file),fs->fat[curr].value ? "bad" : "free",curr);
446 if (prev) set_fat(fs,prev,-1);
447 else if (!file->offset)
448 die( "FAT32 root dir starts with a bad cluster!" );
449 else MODIFY_START(file,0,fs);
450 break;
451 }
452 if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=
453 clusters*fs->cluster_size) {
454 printf("%s\n File size is %u bytes, cluster chain length is > %lu "
455 "bytes.\n Truncating file to %u bytes.\n",path_name(file),
456 CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size,
457 CF_LE_L(file->dir_ent.size));
458 truncate_file(fs,file,clusters);
459 break;
460 }
461 if ((owner = get_owner(fs,curr))) {
462 int do_trunc = 0;
463 printf("%s and\n",path_name(owner));
464 printf("%s\n share clusters.\n",path_name(file));
465 clusters2 = 0;
466 for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk =
467 next_cluster(fs,walk))
468 if (walk == curr) break;
469 else clusters2++;
470 restart = file->dir_ent.attr & ATTR_DIR;
471 if (!owner->offset) {
472 printf( " Truncating second to %lu bytes because first "
473 "is FAT32 root dir.\n", clusters2*fs->cluster_size );
474 do_trunc = 2;
475 }
476 else if (!file->offset) {
477 printf( " Truncating first to %lu bytes because second "
478 "is FAT32 root dir.\n", clusters*fs->cluster_size );
479 do_trunc = 1;
480 }
481 else if (interactive)
482 printf("1) Truncate first to %lu bytes%s\n"
483 "2) Truncate second to %lu bytes\n",clusters*fs->cluster_size,
484 restart ? " and restart" : "",clusters2*fs->cluster_size);
485 else printf(" Truncating second to %lu bytes.\n",clusters2*
486 fs->cluster_size);
487 if (do_trunc != 2 &&
488 (do_trunc == 1 ||
489 (interactive && get_key("12","?") == '1'))) {
490 prev = 0;
491 clusters = 0;
492 for (this = FSTART(owner,fs); this > 0 && this != -1; this =
493 next_cluster(fs,this)) {
494 if (this == curr) {
495 if (prev) set_fat(fs,prev,-1);
496 else MODIFY_START(owner,0,fs);
497 MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size));
498 if (restart) return 1;
499 while (this > 0 && this != -1) {
500 set_owner(fs,this,NULL);
501 this = next_cluster(fs,this);
502 }
503 break;
504 }
505 clusters++;
506 prev = this;
507 }
508 if (this != curr)
509 die("Internal error: didn't find cluster %d in chain"
510 " starting at %d",curr,FSTART(owner,fs));
511 }
512 else {
513 if (prev) set_fat(fs,prev,-1);
514 else MODIFY_START(file,0,fs);
515 break;
516 }
517 }
518 set_owner(fs,curr,file);
519 clusters++;
520 prev = curr;
521 }
522 if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >
523 clusters*fs->cluster_size) {
524 printf("%s\n File size is %u bytes, cluster chain length is %lu bytes."
525 "\n Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file->
526 dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size);
527 MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size));
528 }
529 return 0;
530 }
531
532
533 static int check_files(DOS_FS *fs,DOS_FILE *start)
534 {
535 while (start) {
536 if (check_file(fs,start)) return 1;
537 start = start->next;
538 }
539 return 0;
540 }
541
542
543 static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)
544 {
545 DOS_FILE *parent,**walk,**scan;
546 int dot,dotdot,skip,redo;
547 int good,bad;
548
549 if (!*root) return 0;
550 parent = (*root)->parent;
551 good = bad = 0;
552 for (walk = root; *walk; walk = &(*walk)->next)
553 if (bad_name((*walk)->dir_ent.name)) bad++;
554 else good++;
555 if (*root && parent && good+bad > 4 && bad > good/2) {
556 printf("%s\n Has a large number of bad entries. (%d/%d)\n",
557 path_name(parent),bad,good+bad);
558 if (!dots) printf( " Not dropping root directory.\n" );
559 else if (!interactive) printf(" Not dropping it in auto-mode.\n");
560 else if (get_key("yn","Drop directory ? (y/n)") == 'y') {
561 truncate_file(fs,parent,0);
562 MODIFY(parent,name[0],DELETED_FLAG);
563 /* buglet: deleted directory stays in the list. */
564 return 1;
565 }
566 }
567 dot = dotdot = redo = 0;
568 walk = root;
569 while (*walk) {
570 if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ||
571 !strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) {
572 if (handle_dot(fs,*walk,dots)) {
573 *walk = (*walk)->next;
574 continue;
575 }
576 if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++;
577 else dotdot++;
578 }
579 if (!((*walk)->dir_ent.attr & ATTR_VOLUME) &&
580 bad_name((*walk)->dir_ent.name)) {
581 printf("%s\n Bad file name.\n",path_name(*walk));
582 if (interactive)
583 printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
584 "4) Keep it\n");
585 else printf(" Auto-renaming it.\n");
586 switch (interactive ? get_key("1234","?") : '3') {
587 case '1':
588 drop_file(fs,*walk);
589 walk = &(*walk)->next;
590 continue;
591 case '2':
592 rename_file(*walk);
593 redo = 1;
594 break;
595 case '3':
596 auto_rename(*walk);
597 printf(" Renamed to %s\n",file_name((*walk)->dir_ent.
598 name));
599 break;
600 case '4':
601 break;
602 }
603 }
604 /* don't check for duplicates of the volume label */
605 if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {
606 scan = &(*walk)->next;
607 skip = 0;
608 while (*scan && !skip) {
609 if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&
610 !strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME)) {
611 printf("%s\n Duplicate directory entry.\n First %s\n",
612 path_name(*walk),file_stat(*walk));
613 printf(" Second %s\n",file_stat(*scan));
614 if (interactive)
615 printf("1) Drop first\n2) Drop second\n3) Rename first\n"
616 "4) Rename second\n5) Auto-rename first\n"
617 "6) Auto-rename second\n");
618 else printf(" Auto-renaming second.\n");
619 switch (interactive ? get_key("123456","?") : '6') {
620 case '1':
621 drop_file(fs,*walk);
622 *walk = (*walk)->next;
623 skip = 1;
624 break;
625 case '2':
626 drop_file(fs,*scan);
627 *scan = (*scan)->next;
628 continue;
629 case '3':
630 rename_file(*walk);
631 printf(" Renamed to %s\n",path_name(*walk));
632 redo = 1;
633 break;
634 case '4':
635 rename_file(*scan);
636 printf(" Renamed to %s\n",path_name(*walk));
637 redo = 1;
638 break;
639 case '5':
640 auto_rename(*walk);
641 printf(" Renamed to %s\n",file_name((*walk)->dir_ent.
642 name));
643 break;
644 case '6':
645 auto_rename(*scan);
646 printf(" Renamed to %s\n",file_name((*scan)->dir_ent.
647 name));
648 break;
649 }
650 }
651 scan = &(*scan)->next;
652 }
653 if (skip) continue;
654 }
655 if (!redo) walk = &(*walk)->next;
656 else {
657 walk = root;
658 dot = dotdot = redo = 0;
659 }
660 }
661 if (dots && !dot)
662 printf("%s\n \".\" is missing. Can't fix this yet.\n",
663 path_name(parent));
664 if (dots && !dotdot)
665 printf("%s\n \"..\" is missing. Can't fix this yet.\n",
666 path_name(parent));
667 return 0;
668 }
669
670
671 static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
672 {
673 DOS_FILE *owner;
674 unsigned long walk,prev,clusters,next_clu;
675
676 prev = clusters = 0;
677 for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
678 walk = next_clu) {
679 next_clu = next_cluster(fs,walk);
680 if ((owner = get_owner(fs,walk))) {
681 if (owner == file) {
682 printf("%s\n Circular cluster chain. Truncating to %lu "
683 "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" :
684 "s");
685 if (prev) set_fat(fs,prev,-1);
686 else if (!file->offset)
687 die( "Bad FAT32 root directory! (bad start cluster)\n" );
688 else MODIFY_START(file,0,fs);
689 }
690 break;
691 }
692 if (bad_cluster(fs,walk)) break;
693 if (read_test) {
694 if (fs_test(cluster_start(fs,walk),fs->cluster_size)) {
695 prev = walk;
696 clusters++;
697 }
698 else {
699 printf("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n",
700 path_name(file),clusters,walk);
701 if (prev) set_fat(fs,prev,next_cluster(fs,walk));
702 else MODIFY_START(file,next_cluster(fs,walk),fs);
703 set_fat(fs,walk,-2);
704 }
705 }
706 set_owner(fs,walk,file);
707 }
708 for (walk = FSTART(file,fs); walk