check.c 24 KB

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