Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencheck.c
Go to the documentation of this file.
00001 /* check.c - Check and repair a PC/MS-DOS file system */ 00002 00003 /* Written 1993 by Werner Almesberger */ 00004 00005 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998 00006 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */ 00007 00008 #include "vfatlib.h" 00009 00010 #define NDEBUG 00011 #include <debug.h> 00012 00013 static DOS_FILE *root; 00014 00015 /* get start field of a dir entry */ 00016 #define FSTART(p,fs) \ 00017 ((unsigned long)CF_LE_W(p->dir_ent.start) | \ 00018 (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0)) 00019 00020 #define MODIFY(p,i,v) \ 00021 do { \ 00022 if (p->offset) { \ 00023 p->dir_ent.i = v; \ 00024 fs_write(p->offset+offsetof(DIR_ENT,i), \ 00025 sizeof(p->dir_ent.i),&p->dir_ent.i); \ 00026 } \ 00027 } while(0) 00028 00029 #define MODIFY_START(p,v,fs) \ 00030 do { \ 00031 unsigned long __v = (v); \ 00032 if (!p->offset) { \ 00033 /* writing to fake entry for FAT32 root dir */ \ 00034 if (!__v) die("Oops, deleting FAT32 root dir!"); \ 00035 fs->root_cluster = __v; \ 00036 p->dir_ent.start = CT_LE_W(__v&0xffff); \ 00037 p->dir_ent.starthi = CT_LE_W(__v>>16); \ 00038 __v = CT_LE_L(__v); \ 00039 fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \ 00040 sizeof(((struct boot_sector *)0)->root_cluster), \ 00041 &__v); \ 00042 } \ 00043 else { \ 00044 MODIFY(p,start,CT_LE_W((__v)&0xffff)); \ 00045 if (fs->fat_bits == 32) \ 00046 MODIFY(p,starthi,CT_LE_W((__v)>>16)); \ 00047 } \ 00048 } while(0) 00049 00050 00051 loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern) 00052 { 00053 static int curr_num = 0; 00054 loff_t offset; 00055 00056 if (fs->root_cluster) { 00057 DIR_ENT d2; 00058 int i = 0, got = 0; 00059 unsigned long clu_num, prev = 0; 00060 loff_t offset2; 00061 00062 clu_num = fs->root_cluster; 00063 offset = cluster_start(fs,clu_num); 00064 while (clu_num > 0 && clu_num != -1) { 00065 fs_read(offset,sizeof(DIR_ENT),&d2); 00066 if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) { 00067 got = 1; 00068 break; 00069 } 00070 i += sizeof(DIR_ENT); 00071 offset += sizeof(DIR_ENT); 00072 if ((i % fs->cluster_size) == 0) { 00073 prev = clu_num; 00074 if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) 00075 break; 00076 offset = cluster_start(fs,clu_num); 00077 } 00078 } 00079 if (!got) { 00080 /* no free slot, need to extend root dir: alloc next free cluster 00081 * after previous one */ 00082 if (!prev) 00083 die("Root directory has no cluster allocated!"); 00084 for (clu_num = prev+1; clu_num != prev; clu_num++) { 00085 if (clu_num >= fs->clusters+2) clu_num = 2; 00086 if (!fs->fat[clu_num].value) 00087 break; 00088 } 00089 if (clu_num == prev) 00090 die("Root directory full and no free cluster"); 00091 set_fat(fs,prev,clu_num); 00092 set_fat(fs,clu_num,-1); 00093 set_owner(fs, clu_num, get_owner(fs, fs->root_cluster)); 00094 /* clear new cluster */ 00095 memset( &d2, 0, sizeof(d2) ); 00096 offset = cluster_start(fs,clu_num); 00097 for( i = 0; i < (int)fs->cluster_size; i += sizeof(DIR_ENT) ) 00098 fs_write( offset+i, sizeof(d2), &d2 ); 00099 } 00100 memset(de,0,sizeof(DIR_ENT)); 00101 while (1) { 00102 sprintf((char*)de->name,pattern,curr_num); 00103 clu_num = fs->root_cluster; 00104 i = 0; 00105 offset2 = cluster_start(fs,clu_num); 00106 while (clu_num > 0 && clu_num != -1) { 00107 fs_read(offset2,sizeof(DIR_ENT),&d2); 00108 if (offset2 != offset && 00109 !strncmp((char*)d2.name,(char*)de->name,MSDOS_NAME)) 00110 break; 00111 i += sizeof(DIR_ENT); 00112 offset2 += sizeof(DIR_ENT); 00113 if ((i % fs->cluster_size) == 0) { 00114 if ((clu_num = next_cluster(fs,clu_num)) == 0 || 00115 clu_num == -1) 00116 break; 00117 offset2 = cluster_start(fs,clu_num); 00118 } 00119 } 00120 if (clu_num == 0 || clu_num == -1) 00121 break; 00122 if (++curr_num >= 10000) die("Unable to create unique name"); 00123 } 00124 } 00125 else { 00126 DIR_ENT *root; 00127 int next_free = 0, scan; 00128 00129 root = vfalloc(fs->root_entries*sizeof(DIR_ENT)); 00130 fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root); 00131 00132 while (next_free < (int)fs->root_entries) 00133 if (IS_FREE(root[next_free].name) && 00134 root[next_free].attr != VFAT_LN_ATTR) 00135 break; 00136 else next_free++; 00137 if (next_free == (int)fs->root_entries) 00138 die("Root directory is full."); 00139 offset = fs->root_start+next_free*sizeof(DIR_ENT); 00140 memset(de,0,sizeof(DIR_ENT)); 00141 while (1) { 00142 sprintf((char*)de->name,pattern,curr_num); 00143 for (scan = 0; scan < (int)fs->root_entries; scan++) 00144 if (scan != next_free && 00145 !strncmp((char*)root[scan].name,(char*)de->name,MSDOS_NAME)) 00146 break; 00147 if (scan == (int)fs->root_entries) break; 00148 if (++curr_num >= 10000) die("Unable to create unique name"); 00149 } 00150 vffree(root); 00151 } 00152 ++FsCheckTotalFiles; 00153 return offset; 00154 } 00155 00156 00157 static char *path_name(DOS_FILE *file) 00158 { 00159 // static char path[PATH_MAX*2]; 00160 static char path[MAX_PATH*2]; 00161 00162 if (!file) *path = 0; 00163 else { 00164 if (strlen(path_name(file->parent)) > MAX_PATH) 00165 die("Path name too long."); 00166 if (strcmp(path,"/") != 0) strcat(path,"/"); 00167 strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name)); 00168 } 00169 return path; 00170 } 00171 00172 00173 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; 00174 /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ 00175 00176 00177 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ 00178 00179 time_t date_dos2unix(unsigned short time,unsigned short date) 00180 { 00181 int month,year; 00182 time_t secs; 00183 00184 month = ((date >> 5) & 15)-1; 00185 year = date >> 9; 00186 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* 00187 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && 00188 month < 2 ? 1 : 0)+3653); 00189 /* days since 1.1.70 plus 80's leap day */ 00190 return secs; 00191 } 00192 00193 00194 static char *file_stat(DOS_FILE *file) 00195 { 00196 static char temp[100]; 00197 char tmp[100]; 00198 time_t date; 00199 LARGE_INTEGER time; 00200 TIME_FIELDS time_fields; 00201 00202 date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file-> 00203 dir_ent.date)); 00204 00205 RtlSecondsSince1970ToTime(date, &time); 00206 RtlTimeToTimeFields(&time, &time_fields); 00207 00208 _snprintf(tmp, sizeof(tmp), "%d:%d:%d %d.%d.%d", 00209 time_fields.Hour, time_fields.Minute, time_fields.Second, 00210 time_fields.Day, time_fields.Month, time_fields.Year); 00211 00212 _snprintf(temp, sizeof(temp), " Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp); 00213 return temp; 00214 } 00215 00216 00217 static int bad_name(unsigned char *name) 00218 { 00219 int i, spc, suspicious = 0; 00220 char *bad_chars = "*?<>|\"\\/:"; 00221 00222 /* Do not complain about (and auto-correct) the extended attribute files 00223 * of OS/2. */ 00224 if (strncmp((char*)name,"EA DATA SF",11) == 0 || 00225 strncmp((char*)name,"WP ROOT SF",11) == 0) return 0; 00226 00227 for (i = 0; i < 8; i++) { 00228 if (name[i] < ' ' || name[i] == 0x7f) return 1; 00229 if (name[i] > 0x7f) ++suspicious; 00230 if (strchr(bad_chars,name[i])) return 1; 00231 } 00232 00233 for (i = 8; i < 11; i++) { 00234 if (name[i] < ' ' || name[i] == 0x7f) return 1; 00235 if (name[i] > 0x7f) ++suspicious; 00236 if (strchr(bad_chars,name[i])) return 1; 00237 } 00238 00239 spc = 0; 00240 for (i = 0; i < 8; i++) { 00241 if (name[i] == ' ') 00242 spc = 1; 00243 else if (spc) 00244 /* non-space after a space not allowed, space terminates the name 00245 * part */ 00246 return 1; 00247 } 00248 00249 spc = 0; 00250 for (i = 8; i < 11; i++) { 00251 if (name[i] == ' ') 00252 spc = 1; 00253 else if (spc) 00254 /* non-space after a space not allowed, space terminates the name 00255 * part */ 00256 return 1; 00257 } 00258 00259 /* Only complain about too much suspicious chars in interactive mode, 00260 * never correct them automatically. The chars are all basically ok, so we 00261 * shouldn't auto-correct such names. */ 00262 if ((FsCheckFlags & FSCHECK_INTERACTIVE) && suspicious > 6) 00263 return 1; 00264 return 0; 00265 } 00266 00267 00268 static void drop_file(DOS_FS *fs,DOS_FILE *file) 00269 { 00270 unsigned long cluster; 00271 00272 MODIFY(file,name[0],DELETED_FLAG); 00273 for (cluster = FSTART(file,fs); cluster > 0 && cluster < 00274 fs->clusters+2; cluster = next_cluster(fs,cluster)) 00275 set_owner(fs,cluster,NULL); 00276 --FsCheckTotalFiles; 00277 } 00278 00279 00280 static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters) 00281 { 00282 int deleting; 00283 unsigned long walk,next; 00284 //unsigned long prev; 00285 00286 walk = FSTART(file,fs); 00287 //prev = 0; 00288 if ((deleting = !clusters)) MODIFY_START(file,0,fs); 00289 while (walk > 0 && walk != -1) { 00290 next = next_cluster(fs,walk); 00291 if (deleting) set_fat(fs,walk,0); 00292 else if ((deleting = !--clusters)) set_fat(fs,walk,-1); 00293 //prev = walk; 00294 walk = next; 00295 } 00296 } 00297 00298 00299 static void auto_rename(DOS_FILE *file) 00300 { 00301 DOS_FILE *first,*walk; 00302 int number; 00303 00304 if (!file->offset) return; /* cannot rename FAT32 root dir */ 00305 first = file->parent ? file->parent->first : root; 00306 number = 0; 00307 while (1) { 00308 sprintf((char*)file->dir_ent.name,"FSCK%04d",number); 00309 strncpy((char*)file->dir_ent.ext,"REN",3); 00310 for (walk = first; walk; walk = walk->next) 00311 if (walk != file && !strncmp((char*)walk->dir_ent.name,(char*)file->dir_ent. 00312 name,MSDOS_NAME)) break; 00313 if (!walk) { 00314 fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); 00315 return; 00316 } 00317 number++; 00318 } 00319 die("Can't generate a unique name."); 00320 } 00321 00322 00323 static void rename_file(DOS_FILE *file) 00324 { 00325 //unsigned char name[46]; 00326 //unsigned char *walk,*here; 00327 00328 if (!file->offset) { 00329 VfatPrint( "Cannot rename FAT32 root dir\n" ); 00330 return; /* cannot rename FAT32 root dir */ 00331 } 00332 while (1) { 00333 VfatPrint("New name: "); 00334 #if 0 00335 fflush(stdout); 00336 if (fgets((char*)name,45,stdin)) { 00337 if ((here = (unsigned char*)strchr((char*)name,'\n'))) *here = 0; 00338 for (walk = (unsigned char*)strrchr((char*)name,0); walk >= name && (*walk == ' ' || 00339 *walk == '\t'); walk--); 00340 walk[1] = 0; 00341 for (walk = name; *walk == ' ' || *walk == '\t'; walk++); 00342 if (file_cvt(walk,file->dir_ent.name)) { 00343 fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); 00344 return; 00345 } 00346 } 00347 #else 00348 return; 00349 #endif 00350 } 00351 } 00352 00353 00354 static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots) 00355 { 00356 char *name; 00357 00358 name = strncmp((char*)file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : "."; 00359 if (!(file->dir_ent.attr & ATTR_DIR)) { 00360 VfatPrint("%s\n Is a non-directory.\n",path_name(file)); 00361 if (FsCheckFlags & FSCHECK_INTERACTIVE) 00362 VfatPrint("1) Drop it\n2) Auto-rename\n3) Rename\n" 00363 "4) Convert to directory\n"); 00364 else VfatPrint(" Auto-renaming it.\n"); 00365 switch ((FsCheckFlags & FSCHECK_INTERACTIVE) ? get_key("1234","?") : '2') { 00366 case '1': 00367 drop_file(fs,file); 00368 return 1; 00369 case '2': 00370 auto_rename(file); 00371 VfatPrint(" Renamed to %s\n",file_name(file->dir_ent.name)); 00372 return 0; 00373 case '3': 00374 rename_file(file); 00375 return 0; 00376 case '4': 00377 MODIFY(file,size,CT_LE_L(0)); 00378 MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR); 00379 break; 00380 } 00381 } 00382 if (!dots) { 00383 VfatPrint("Root contains directory \"%s\". Dropping it.\n",name); 00384 drop_file(fs,file); 00385 return 1; 00386 } 00387 return 0; 00388 } 00389 00390 00391 static int check_file(DOS_FS *fs,DOS_FILE *file) 00392 { 00393 DOS_FILE *owner; 00394 int restart; 00395 unsigned long expect,curr,this,clusters,prev,walk,clusters2; 00396 00397 if (file->dir_ent.attr & ATTR_DIR) { 00398 if (CF_LE_L(file->dir_ent.size)) { 00399 VfatPrint("%s\n Directory has non-zero size. Fixing it.\n", 00400 path_name(file)); 00401 MODIFY(file,size,CT_LE_L(0)); 00402 } 00403 if (file->parent && !strncmp((char*)file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) { 00404 expect = FSTART(file->parent,fs); 00405 if (FSTART(file,fs) != expect) { 00406 VfatPrint("%s\n Start (%ld) does not point to parent (%ld)\n", 00407 path_name(file),FSTART(file,fs),expect); 00408 MODIFY_START(file,expect,fs); 00409 } 00410 return 0; 00411 } 00412 if (file->parent && !strncmp((char*)file->dir_ent.name,MSDOS_DOTDOT, 00413 MSDOS_NAME)) { 00414 expect = file->parent->parent ? FSTART(file->parent->parent,fs):0; 00415 if (fs->root_cluster && expect == fs->root_cluster) 00416 expect = 0; 00417 if (FSTART(file,fs) != expect) { 00418 VfatPrint("%s\n Start (%lu) does not point to .. (%lu)\n", 00419 path_name(file),FSTART(file,fs),expect); 00420 MODIFY_START(file,expect,fs); 00421 } 00422 return 0; 00423 } 00424 if (FSTART(file,fs)==0){ 00425 VfatPrint ("%s\n Start does point to root directory. Deleting dir. \n", 00426 path_name(file)); 00427 MODIFY(file,name[0],DELETED_FLAG); 00428 return 0; 00429 } 00430 } 00431 if (FSTART(file,fs) >= fs->clusters+2) { 00432 VfatPrint("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n", 00433 path_name(file),FSTART(file,fs),fs->clusters+1); 00434 if (!file->offset) 00435 die( "Bad FAT32 root directory! (bad start cluster)\n" ); 00436 MODIFY_START(file,0,fs); 00437 } 00438 clusters = prev = 0; 00439 for (curr = FSTART(file,fs) ? FSTART(file,fs) : 00440 -1; curr != -1; curr = next_cluster(fs,curr)) { 00441 if (!fs->fat[curr].value || bad_cluster(fs,curr)) { 00442 VfatPrint("%s\n Contains a %s cluster (%lu). Assuming EOF.\n", 00443 path_name(file),fs->fat[curr].value ? "bad" : "free",curr); 00444 if (prev) set_fat(fs,prev,-1); 00445 else if (!file->offset) 00446 die( "FAT32 root dir starts with a bad cluster!" ); 00447 else MODIFY_START(file,0,fs); 00448 break; 00449 } 00450 if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <= 00451 clusters*fs->cluster_size) { 00452 VfatPrint("%s\n File size is %u bytes, cluster chain length is > %lu " 00453 "bytes.\n Truncating file to %u bytes.\n",path_name(file), 00454 CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size, 00455 CF_LE_L(file->dir_ent.size)); 00456 truncate_file(fs,file,clusters); 00457 break; 00458 } 00459 if ((owner = get_owner(fs,curr))) { 00460 int do_trunc = 0; 00461 VfatPrint("%s and\n",path_name(owner)); 00462 VfatPrint("%s\n share clusters.\n",path_name(file)); 00463 clusters2 = 0; 00464 for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk = 00465 next_cluster(fs,walk)) 00466 if (walk == curr) break; 00467 else clusters2++; 00468 restart = file->dir_ent.attr & ATTR_DIR; 00469 if (!owner->offset) { 00470 VfatPrint( " Truncating second to %lu bytes because first " 00471 "is FAT32 root dir.\n", clusters2*fs->cluster_size ); 00472 do_trunc = 2; 00473 } 00474 else if (!file->offset) { 00475 VfatPrint( " Truncating first to %lu bytes because second " 00476 "is FAT32 root dir.\n", clusters*fs->cluster_size ); 00477 do_trunc = 1; 00478 } 00479 else if (FsCheckFlags & FSCHECK_INTERACTIVE) 00480 VfatPrint("1) Truncate first to %lu bytes%s\n" 00481 "2) Truncate second to %lu bytes\n",clusters*fs->cluster_size, 00482 restart ? " and restart" : "",clusters2*fs->cluster_size); 00483 else VfatPrint(" Truncating second to %lu bytes.\n",clusters2* 00484 fs->cluster_size); 00485 if (do_trunc != 2 && 00486 (do_trunc == 1 || 00487 ((FsCheckFlags & FSCHECK_INTERACTIVE) && get_key("12","?") == '1'))) { 00488 prev = 0; 00489 clusters = 0; 00490 for (this = FSTART(owner,fs); this > 0 && this != -1; this = 00491 next_cluster(fs,this)) { 00492 if (this == curr) { 00493 if (prev) set_fat(fs,prev,-1); 00494 else MODIFY_START(owner,0,fs); 00495 MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size)); 00496 if (restart) return 1; 00497 while (this > 0 && this != -1) { 00498 set_owner(fs,this,NULL); 00499 this = next_cluster(fs,this); 00500 } 00501 break; 00502 } 00503 clusters++; 00504 prev = this; 00505 } 00506 if (this != curr) 00507 die("Internal error: didn't find cluster %d in chain" 00508 " starting at %d",curr,FSTART(owner,fs)); 00509 } 00510 else { 00511 if (prev) set_fat(fs,prev,-1); 00512 else MODIFY_START(file,0,fs); 00513 break; 00514 } 00515 } 00516 set_owner(fs,curr,file); 00517 clusters++; 00518 prev = curr; 00519 } 00520 if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) > 00521 clusters*fs->cluster_size) { 00522 VfatPrint("%s\n File size is %u bytes, cluster chain length is %lu bytes." 00523 "\n Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file-> 00524 dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size); 00525 MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size)); 00526 } 00527 return 0; 00528 } 00529 00530 00531 static int check_files(DOS_FS *fs,DOS_FILE *start) 00532 { 00533 while (start) { 00534 if (check_file(fs,start)) return 1; 00535 start = start->next; 00536 } 00537 return 0; 00538 } 00539 00540 00541 static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots) 00542 { 00543 DOS_FILE *parent,**walk,**scan; 00544 int dot,dotdot,skip,redo; 00545 int good,bad; 00546 00547 if (!*root) return 0; 00548 parent = (*root)->parent; 00549 good = bad = 0; 00550 for (walk = root; *walk; walk = &(*walk)->next) 00551 if (bad_name((*walk)->dir_ent.name)) bad++; 00552 else good++; 00553 if (*root && parent && good+bad > 4 && bad > good/2) { 00554 VfatPrint("%s\n Has a large number of bad entries. (%d/%d)\n", 00555 path_name(parent),bad,good+bad); 00556 if (!dots) VfatPrint( " Not dropping root directory.\n" ); 00557 else if (!(FsCheckFlags & FSCHECK_INTERACTIVE)) VfatPrint(" Not dropping it in auto-mode.\n"); 00558 else if (get_key("yn","Drop directory ? (y/n)") == 'y') { 00559 truncate_file(fs,parent,0); 00560 MODIFY(parent,name[0],DELETED_FLAG); 00561 /* buglet: deleted directory stays in the list. */ 00562 return 1; 00563 } 00564 } 00565 dot = dotdot = redo = 0; 00566 walk = root; 00567 while (*walk) { 00568 if (!strncmp((char*)(*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) || 00569 !strncmp((char*)(*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) { 00570 if (handle_dot(fs,*walk,dots)) { 00571 *walk = (*walk)->next; 00572 continue; 00573 } 00574 if (!strncmp((char*)(*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++; 00575 else dotdot++; 00576 } 00577 if (!((*walk)->dir_ent.attr & ATTR_VOLUME) && 00578 bad_name((*walk)->dir_ent.name)) { 00579 VfatPrint("%s\n Bad file name.\n",path_name(*walk)); 00580 if (FsCheckFlags & FSCHECK_INTERACTIVE) 00581 VfatPrint("1) Drop file\n2) Rename file\n3) Auto-rename\n" 00582 "4) Keep it\n"); 00583 else VfatPrint(" Auto-renaming it.\n"); 00584 switch ((FsCheckFlags & FSCHECK_INTERACTIVE) ? get_key("1234","?") : '3') { 00585 case '1': 00586 drop_file(fs,*walk); 00587 walk = &(*walk)->next; 00588 continue; 00589 case '2': 00590 rename_file(*walk); 00591 redo = 1; 00592 break; 00593 case '3': 00594 auto_rename(*walk); 00595 VfatPrint(" Renamed to %s\n",file_name((*walk)->dir_ent. 00596 name)); 00597 break; 00598 case '4': 00599 break; 00600 } 00601 } 00602 /* don't check for duplicates of the volume label */ 00603 if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) { 00604 scan = &(*walk)->next; 00605 skip = 0; 00606 while (*scan && !skip) { 00607 if (!((*scan)->dir_ent.attr & ATTR_VOLUME) && 00608 !strncmp((char*)(*walk)->dir_ent.name,(char*)(*scan)->dir_ent.name,MSDOS_NAME)) { 00609 VfatPrint("%s\n Duplicate directory entry.\n First %s\n", 00610 path_name(*walk),file_stat(*walk)); 00611 VfatPrint(" Second %s\n",file_stat(*scan)); 00612 if (FsCheckFlags & FSCHECK_INTERACTIVE) 00613 VfatPrint("1) Drop first\n2) Drop second\n3) Rename first\n" 00614 "4) Rename second\n5) Auto-rename first\n" 00615 "6) Auto-rename second\n"); 00616 else VfatPrint(" Auto-renaming second.\n"); 00617 switch ((FsCheckFlags & FSCHECK_INTERACTIVE) ? get_key("123456","?") : '6') { 00618 case '1': 00619 drop_file(fs,*walk); 00620 *walk = (*walk)->next; 00621 skip = 1; 00622 break; 00623 case '2': 00624 drop_file(fs,*scan); 00625 *scan = (*scan)->next; 00626 continue; 00627 case '3': 00628 rename_file(*walk); 00629 VfatPrint(" Renamed to %s\n",path_name(*walk)); 00630 redo = 1; 00631 break; 00632 case '4': 00633 rename_file(*scan); 00634 VfatPrint(" Renamed to %s\n",path_name(*walk)); 00635 redo = 1; 00636 break; 00637 case '5': 00638 auto_rename(*walk); 00639 VfatPrint(" Renamed to %s\n",file_name((*walk)->dir_ent. 00640 name)); 00641 break; 00642 case '6': 00643 auto_rename(*scan); 00644 VfatPrint(" Renamed to %s\n",file_name((*scan)->dir_ent. 00645 name)); 00646 break; 00647 } 00648 } 00649 scan = &(*scan)->next; 00650 } 00651 if (skip) continue; 00652 } 00653 if (!redo) walk = &(*walk)->next; 00654 else { 00655 walk = root; 00656 dot = dotdot = redo = 0; 00657 } 00658 } 00659 if (dots && !dot) 00660 VfatPrint("%s\n \".\" is missing. Can't fix this yet.\n", 00661 path_name(parent)); 00662 if (dots && !dotdot) 00663 VfatPrint("%s\n \"..\" is missing. Can't fix this yet.\n", 00664 path_name(parent)); 00665 return 0; 00666 } 00667 00668 00669 static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test) 00670 { 00671 DOS_FILE *owner; 00672 unsigned long walk,prev,clusters,next_clu; 00673 00674 prev = clusters = 0; 00675 for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2; 00676 walk = next_clu) { 00677 next_clu = next_cluster(fs,walk); 00678 if ((owner = get_owner(fs,walk))) { 00679 if (owner == file) { 00680 VfatPrint("%s\n Circular cluster chain. Truncating to %lu " 00681 "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" : 00682 "s"); 00683 if (prev) set_fat(fs,prev,-1); 00684 else if (!file->offset) 00685 die( "Bad FAT32 root directory! (bad start cluster)\n" ); 00686 else MODIFY_START(file,0,fs); 00687 } 00688 break; 00689 } 00690 if (bad_cluster(fs,walk)) break; 00691 if (read_test) { 00692 if (fs_test(cluster_start(fs,walk),fs->cluster_size)) { 00693 prev = walk; 00694 clusters++; 00695 } 00696 else { 00697 VfatPrint("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n", 00698 path_name(file),clusters,walk); 00699 if (prev) set_fat(fs,prev,next_cluster(fs,walk)); 00700 else MODIFY_START(file,next_cluster(fs,walk),fs); 00701 set_fat(fs,walk,-2); 00702 } 00703 } 00704 set_owner(fs,walk,file); 00705 } 00706 for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2; 00707 walk = next_cluster(fs,walk)) 00708 if (bad_cluster(fs,walk)) break; 00709 else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL); 00710 else break; 00711 } 00712 00713 00714 static void undelete(DOS_FS *fs,DOS_FILE *file) 00715 { 00716 unsigned long clusters,left,prev,walk; 00717 00718 clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/ 00719 fs->cluster_size; 00720 prev = 0; 00721 for (walk = FSTART(file,fs); left && walk >= 2 && walk < 00722 fs->clusters+2 && !fs->fat[walk].value; walk++) { 00723 left--; 00724 if (prev) set_fat(fs,prev,walk); 00725 prev = walk; 00726 } 00727 if (prev) set_fat(fs,prev,-1); 00728 else MODIFY_START(file,0,fs); 00729 if (left) 00730 VfatPrint("Warning: Did only undelete %lu of %lu cluster%s.\n",clusters-left, 00731 clusters,clusters == 1 ? "" : "s"); 00732 00733 } 00734 00735 00736 static void new_dir( void ) 00737 { 00738 lfn_reset(); 00739 } 00740 00741 00742 static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent, 00743 loff_t offset,FDSC **cp) 00744 { 00745 DOS_FILE *new; 00746 DIR_ENT de; 00747 FD_TYPE type; 00748 00749 if (offset) { 00750 fs_read(offset,sizeof(DIR_ENT),&de); 00751 } else { 00752 memcpy(de.name," ",MSDOS_NAME); 00753 de.attr = ATTR_DIR; 00754 de.size = de.time = de.date = 0; 00755 de.start = CT_LE_W(fs->root_cluster & 0xffff); 00756 de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff); 00757 } 00758 if ((type = file_type(cp,(char*)de.name)) != fdt_none) { 00759 if (type == fdt_undelete && (de.attr & ATTR_DIR)) 00760 die("Can't undelete directories."); 00761 file_modify(cp,de.name); 00762 fs_write(offset,1,&de); 00763 } 00764 if (IS_FREE(de.name)) { 00765 lfn_check_orphaned(); 00766 return; 00767 } 00768 if (de.attr == VFAT_LN_ATTR) { 00769 lfn_add_slot(&de,offset); 00770 return; 00771 } 00772 new = qalloc(&FsCheckMemQueue,sizeof(DOS_FILE)); 00773 new->lfn = lfn_get(&de); 00774 new->offset = offset; 00775 memcpy(&new->dir_ent,&de,sizeof(de)); 00776 new->next = new->first = NULL; 00777 new->parent = parent; 00778 if (type == fdt_undelete) undelete(fs,new); 00779 **chain = new; 00780 *chain = &new->next; 00781 if (FsCheckFlags & FSCHECK_LIST_FILES) { 00782 VfatPrint("Checking file %s",path_name(new)); 00783 if (new->lfn) 00784 VfatPrint(" (%s)", file_name(new->dir_ent.name) ); 00785 VfatPrint("\n"); 00786 } 00787 if (offset && 00788 strncmp((char*)de.name,MSDOS_DOT,MSDOS_NAME) != 0 && 00789 strncmp((char*)de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0) 00790 ++FsCheckTotalFiles; 00791 test_file(fs,new,FsCheckFlags & FSCHECK_TEST_READ); 00792 } 00793 00794 00795 static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp); 00796 00797 00798 static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp) 00799 { 00800 DOS_FILE **chain; 00801 int i; 00802 unsigned long clu_num; 00803 00804 chain = &this->first; 00805 i = 0; 00806 clu_num = FSTART(this,fs); 00807 new_dir(); 00808 while (clu_num > 0 && clu_num != -1) { 00809 add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs-> 00810 cluster_size),cp); 00811 i += sizeof(DIR_ENT); 00812 if (!(i % fs->cluster_size)) 00813 if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) 00814 break; 00815 } 00816 lfn_check_orphaned(); 00817 if (check_dir(fs,&this->first,this->offset)) return 0; 00818 if (check_files(fs,this->first)) return 1; 00819 return subdirs(fs,this,cp); 00820 } 00821 00822 00823 static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp) 00824 { 00825 DOS_FILE *walk; 00826 00827 for (walk = parent ? parent->first : root; walk; walk = walk->next) 00828 if (walk->dir_ent.attr & ATTR_DIR) 00829 if (strncmp((char*)walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) && 00830 strncmp((char*)walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) 00831 if (scan_dir(fs,walk,file_cd(cp,(char*)walk->dir_ent.name))) return 1; 00832 return 0; 00833 } 00834 00835 00836 int scan_root(DOS_FS *fs) 00837 { 00838 DOS_FILE **chain; 00839 int i; 00840 00841 root = NULL; 00842 chain = &root; 00843 new_dir(); 00844 if (fs->root_cluster) { 00845 add_file(fs,&chain,NULL,0,&fp_root); 00846 } 00847 else { 00848 for (i = 0; i < fs->root_entries; i++) 00849 add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root); 00850 } 00851 lfn_check_orphaned(); 00852 (void) check_dir(fs,&root,0); 00853 if (check_files(fs,root)) return 1; 00854 return subdirs(fs,NULL,&fp_root); 00855 } 00856 00857 /* Local Variables: */ 00858 /* tab-width: 8 */ 00859 /* End: */ Generated on Sun May 27 2012 04:33:25 for ReactOS by
1.7.6.1
|