ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

check.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.