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

fat.c
Go to the documentation of this file.
00001 /* fat.c  -  Read/write access to the FAT */
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 
00009 #include "vfatlib.h"
00010 
00011 #define NDEBUG
00012 #include <debug.h>
00013 
00014 
00015 //#pragma warning(disable: 4018)
00016 
00017 static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)
00018 {
00019     unsigned char *ptr;
00020 
00021     switch(fs->fat_bits) {
00022       case 12:
00023     ptr = &((unsigned char *) fat)[cluster*3/2];
00024     entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) :
00025       (ptr[0] | ptr[1] << 8));
00026     break;
00027       case 16:
00028     entry->value = CF_LE_W(((unsigned short *) fat)[cluster]);
00029     break;
00030       case 32:
00031     /* According to M$, the high 4 bits of a FAT32 entry are reserved and
00032      * are not part of the cluster number. So we cut them off. */
00033     {
00034         unsigned long e = CF_LE_L(((unsigned int *) fat)[cluster]);
00035         entry->value = e & 0xfffffff;
00036         entry->reserved = e >> 28;
00037     }
00038     break;
00039       default:
00040     die("Bad FAT entry size: %d bits.",fs->fat_bits);
00041     }
00042     entry->owner = NULL;
00043 }
00044 
00045 
00046 void read_fat(DOS_FS *fs)
00047 {
00048     int eff_size;
00049     unsigned long i;
00050     void *first,*second,*use;
00051     int first_ok,second_ok;
00052 
00053     eff_size = ((fs->clusters+2)*fs->fat_bits+7)/8;
00054     // TMN: Must round up to disk-sector boundary. For now, assume 512-byte disk.
00055     if (eff_size % 512) {
00056         eff_size += 512 - (eff_size % 512);
00057     }
00058     first = vfalloc(eff_size);
00059     fs_read(fs->fat_start,eff_size,first);
00060     use = first;
00061     if (fs->nfats > 1) {
00062     second = vfalloc(eff_size);
00063     fs_read(fs->fat_start+fs->fat_size,eff_size,second);
00064     }
00065     else
00066     second = NULL;
00067     if (second && memcmp(first,second,eff_size) != 0) {
00068     FAT_ENTRY first_media, second_media;
00069     memset (&first_media, 0, sizeof (first_media));
00070     memset (&second_media, 0, sizeof (second_media));
00071     get_fat(&first_media,first,0,fs);
00072     get_fat(&second_media,second,0,fs);
00073     first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
00074     second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
00075     if (first_ok && !second_ok) {
00076         VfatPrint("FATs differ - using first FAT.\n");
00077         fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
00078     }
00079     if (!first_ok && second_ok) {
00080         VfatPrint("FATs differ - using second FAT.\n");
00081         fs_write(fs->fat_start,eff_size,use = second);
00082     }
00083     if (first_ok && second_ok) {
00084         if (FsCheckFlags & FSCHECK_INTERACTIVE) {
00085         VfatPrint("FATs differ but appear to be intact. Use which FAT ?\n"
00086           "1) Use first FAT\n2) Use second FAT\n");
00087         if (get_key("12","?") == '1')
00088             fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
00089         else fs_write(fs->fat_start,eff_size,use = second);
00090         }
00091         else {
00092         VfatPrint("FATs differ but appear to be intact. Using first "
00093           "FAT.\n");
00094         fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
00095         }
00096     }
00097     if (!first_ok && !second_ok) {
00098         VfatPrint("Both FATs appear to be corrupt. Giving up.\n");
00099         //exit(1);
00100     }
00101     }
00102     fs->fat = qalloc(&FsCheckMemQueue,sizeof(FAT_ENTRY)*(fs->clusters+2));
00103     for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],use,i,fs);
00104     for (i = 2; i < fs->clusters+2; i++)
00105     if (fs->fat[i].value >= fs->clusters+2 &&
00106         (fs->fat[i].value < FAT_MIN_BAD(fs))) {
00107         VfatPrint("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
00108            i-2,fs->fat[i].value,fs->clusters+2-1);
00109         set_fat(fs,i,-1);
00110     }
00111     vffree(first);
00112     if (second)
00113     vffree(second);
00114 }
00115 
00116 
00117 void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new)
00118 {
00119     unsigned char data[4];
00120     int size = 0;
00121     loff_t offs = 0LL;
00122 
00123     if ((long)new == -1)
00124     new = FAT_EOF(fs);
00125     else if ((long)new == -2)
00126     new = FAT_BAD(fs);
00127     switch( fs->fat_bits ) {
00128       case 12:
00129     offs = fs->fat_start+cluster*3/2;
00130     if (cluster & 1) {
00131         data[0] = ((new & 0xf) << 4) | (fs->fat[cluster-1].value >> 8);
00132         data[1] = new >> 4;
00133     }
00134     else {
00135         data[0] = new & 0xff;
00136         data[1] = (new >> 8) | (cluster == fs->clusters-1 ? 0 :
00137           (0xff & fs->fat[cluster+1].value) << 4);
00138     }
00139     size = 2;
00140     break;
00141       case 16:
00142     offs = fs->fat_start+cluster*2;
00143     *(unsigned short *) data = CT_LE_W(new);
00144     size = 2;
00145     break;
00146       case 32:
00147     offs = fs->fat_start+cluster*4;
00148     /* According to M$, the high 4 bits of a FAT32 entry are reserved and
00149      * are not part of the cluster number. So we never touch them. */
00150     *(unsigned long *) data = CT_LE_L( (new & 0xfffffff) |
00151                        (fs->fat[cluster].reserved << 28) );
00152     size = 4;
00153     break;
00154       default:
00155     die("Bad FAT entry size: %d bits.",fs->fat_bits);
00156     }
00157     fs->fat[cluster].value = new;
00158     fs_write(offs,size,&data);
00159     fs_write(offs+fs->fat_size,size,&data);
00160 }
00161 
00162 
00163 int bad_cluster(DOS_FS *fs,unsigned long cluster)
00164 {
00165     return FAT_IS_BAD(fs,fs->fat[cluster].value);
00166 }
00167 
00168 
00169 unsigned long next_cluster(DOS_FS *fs,unsigned long cluster)
00170 {
00171     unsigned long value;
00172 
00173     value = fs->fat[cluster].value;
00174     if (FAT_IS_BAD(fs,value))
00175     die("Internal error: next_cluster on bad cluster");
00176     return FAT_IS_EOF(fs,value) ? -1 : value;
00177 }
00178 
00179 
00180 loff_t cluster_start(DOS_FS *fs,unsigned long cluster)
00181 {
00182     return fs->data_start+((loff_t)cluster-2)*fs->cluster_size;
00183 }
00184 
00185 
00186 void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner)
00187 {
00188     if (owner && fs->fat[cluster].owner)
00189     die("Internal error: attempt to change file owner");
00190     fs->fat[cluster].owner = owner;
00191 }
00192 
00193 
00194 DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster)
00195 {
00196     return fs->fat[cluster].owner;
00197 }
00198 
00199 
00200 void fix_bad(DOS_FS *fs)
00201 {
00202     unsigned long i;
00203 
00204     if (FsCheckFlags & FSCHECK_VERBOSE)
00205     VfatPrint("Checking for bad clusters.\n");
00206     for (i = 2; i < fs->clusters+2; i++)
00207     if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
00208         if (!fs_test(cluster_start(fs,i),fs->cluster_size)) {
00209         VfatPrint("Cluster %lu is unreadable.\n",i);
00210         set_fat(fs,i,-2);
00211         }
00212 }
00213 
00214 
00215 void reclaim_free(DOS_FS *fs)
00216 {
00217     int reclaimed;
00218     unsigned long i;
00219 
00220     if (FsCheckFlags & FSCHECK_VERBOSE)
00221     VfatPrint("Checking for unused clusters.\n");
00222     reclaimed = 0;
00223     for (i = 2; i < fs->clusters+2; i++)
00224     if (!get_owner(fs,i) && fs->fat[i].value &&
00225         !FAT_IS_BAD(fs,fs->fat[i].value)) {
00226         set_fat(fs,i,0);
00227         reclaimed++;
00228     }
00229     if (reclaimed)
00230     VfatPrint("Reclaimed %d unused cluster%s (%d bytes).\n",reclaimed,
00231       reclaimed == 1 ?  "" : "s",reclaimed*fs->cluster_size);
00232 }
00233 
00234 
00235 static void tag_free(DOS_FS *fs,DOS_FILE *ptr)
00236 {
00237     DOS_FILE *owner;
00238     int prev;
00239     unsigned long i,walk;
00240 
00241     for (i = 2; i < fs->clusters+2; i++)
00242     if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
00243         !get_owner(fs,i) && !fs->fat[i].prev) {
00244         prev = 0;
00245         for (walk = i; walk > 0 && walk != -1;
00246          walk = next_cluster(fs,walk)) {
00247         if (!(owner = get_owner(fs,walk))) set_owner(fs,walk,ptr);
00248         else if (owner != ptr)
00249                 die("Internal error: free chain collides with file");
00250             else {
00251             set_fat(fs,prev,-1);
00252             break;
00253             }
00254         prev = walk;
00255         }
00256     }
00257 }
00258 
00259 
00260 void reclaim_file(DOS_FS *fs)
00261 {
00262     DOS_FILE dummy;
00263     int reclaimed,files,changed;
00264     unsigned long i,next,walk;
00265 
00266     if (FsCheckFlags & FSCHECK_VERBOSE)
00267     VfatPrint("Reclaiming unconnected clusters.\n");
00268     for (i = 2; i < fs->clusters+2; i++) fs->fat[i].prev = 0;
00269     for (i = 2; i < fs->clusters+2; i++) {
00270     next = fs->fat[i].value;
00271     if (!get_owner(fs,i) && next && next < fs->clusters+2) {
00272         if (get_owner(fs,next) || !fs->fat[next].value ||
00273         FAT_IS_BAD(fs,fs->fat[next].value)) set_fat(fs,i,-1);
00274         else fs->fat[next].prev++;
00275     }
00276     }
00277     do {
00278     tag_free(fs,&dummy);
00279     changed = 0;
00280     for (i = 2; i < fs->clusters+2; i++)
00281         if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
00282         !get_owner(fs, i)) {
00283         if (!fs->fat[fs->fat[i].value].prev--)
00284             die("Internal error: prev going below zero");
00285         set_fat(fs,i,-1);
00286         changed = 1;
00287         VfatPrint("Broke cycle at cluster %lu in free chain.\n",i);
00288         break;
00289         }
00290     }
00291     while (changed);
00292     files = reclaimed = 0;
00293     for (i = 2; i < fs->clusters+2; i++)
00294     if (get_owner(fs,i) == &dummy && !fs->fat[i].prev) {
00295         DIR_ENT de;
00296         loff_t offset;
00297         files++;
00298         offset = alloc_rootdir_entry(fs,&de,"FSCK%04dREC");
00299         de.start = CT_LE_W(i&0xffff);
00300         if (fs->fat_bits == 32)
00301         de.starthi = CT_LE_W(i>>16);
00302         for (walk = i; walk > 0 && walk != -1;
00303          walk = next_cluster(fs,walk)) {
00304         de.size = CT_LE_L(CF_LE_L(de.size)+fs->cluster_size);
00305         reclaimed++;
00306         }
00307         fs_write(offset,sizeof(DIR_ENT),&de);
00308     }
00309     if (reclaimed)
00310     VfatPrint("Reclaimed %d unused cluster%s (%d bytes) in %d chain%s.\n",
00311       reclaimed,reclaimed == 1 ? "" : "s",reclaimed*fs->cluster_size,files,
00312       files == 1 ? "" : "s");
00313 }
00314 
00315 
00316 unsigned long update_free(DOS_FS *fs)
00317 {
00318     unsigned long i;
00319     unsigned long free = 0;
00320     int do_set = 0;
00321 
00322     for (i = 2; i < fs->clusters+2; i++)
00323     if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
00324         ++free;
00325 
00326     if (!fs->fsinfo_start)
00327     return free;
00328 
00329     if (FsCheckFlags & FSCHECK_VERBOSE)
00330     VfatPrint("Checking free cluster summary.\n");
00331     if (fs->free_clusters >= 0) {
00332     if (free != fs->free_clusters) {
00333         VfatPrint( "Free cluster summary wrong (%ld vs. really %ld)\n",
00334             fs->free_clusters,free);
00335         if (FsCheckFlags & FSCHECK_INTERACTIVE)
00336         VfatPrint( "1) Correct\n2) Don't correct\n" );
00337         else VfatPrint( "  Auto-correcting.\n" );
00338         if (!(FsCheckFlags & FSCHECK_INTERACTIVE) || get_key("12","?") == '1')
00339         do_set = 1;
00340     }
00341     }
00342     else {
00343     VfatPrint( "Free cluster summary uninitialized (should be %ld)\n", free );
00344     if (FsCheckFlags & FSCHECK_INTERACTIVE)
00345         VfatPrint( "1) Set it\n2) Leave it uninitialized\n" );
00346     else VfatPrint( "  Auto-setting.\n" );
00347     if (!(FsCheckFlags & FSCHECK_INTERACTIVE) || get_key("12","?") == '1')
00348         do_set = 1;
00349     }
00350 
00351     if (do_set) {
00352     fs->free_clusters = free;
00353     free = CT_LE_L(free);
00354     fs_write(fs->fsinfo_start+offsetof(struct info_sector,free_clusters),
00355          sizeof(free),&free);
00356     }
00357 
00358     return free;
00359 }
00360 
00361 /* Local Variables: */
00362 /* tab-width: 8     */
00363 /* End:             */

Generated on Sat May 26 2012 04:17:57 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.