e5a5504232fa2e8daf14b33e20c901113046cf05
1 /* fat.c - Read/write access to the FAT */
3 /* Written 1993 by Werner Almesberger */
5 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
6 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
15 //#pragma warning(disable: 4018)
17 static void get_fat(FAT_ENTRY
*entry
,void *fat
,unsigned long cluster
,DOS_FS
*fs
)
21 switch(fs
->fat_bits
) {
23 ptr
= &((unsigned char *) fat
)[cluster
*3/2];
24 entry
->value
= 0xfff & (cluster
& 1 ? (ptr
[0] >> 4) | (ptr
[1] << 4) :
25 (ptr
[0] | ptr
[1] << 8));
28 entry
->value
= CF_LE_W(((unsigned short *) fat
)[cluster
]);
31 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
32 * are not part of the cluster number. So we cut them off. */
34 unsigned long e
= CF_LE_L(((unsigned int *) fat
)[cluster
]);
35 entry
->value
= e
& 0xfffffff;
36 entry
->reserved
= e
>> 28;
40 die("Bad FAT entry size: %d bits.",fs
->fat_bits
);
46 void read_fat(DOS_FS
*fs
)
50 void *first
,*second
,*use
;
51 int first_ok
,second_ok
;
53 eff_size
= ((fs
->clusters
+2)*fs
->fat_bits
+7)/8;
54 // TMN: Must round up to disk-sector boundary. For now, assume 512-byte disk.
56 eff_size
+= 512 - (eff_size
% 512);
58 first
= vfalloc(eff_size
);
59 fs_read(fs
->fat_start
,eff_size
,first
);
62 second
= vfalloc(eff_size
);
63 fs_read(fs
->fat_start
+fs
->fat_size
,eff_size
,second
);
67 if (second
&& memcmp(first
,second
,eff_size
) != 0) {
68 FAT_ENTRY first_media
, second_media
;
69 memset (&first_media
, 0, sizeof (first_media
));
70 memset (&second_media
, 0, sizeof (second_media
));
71 get_fat(&first_media
,first
,0,fs
);
72 get_fat(&second_media
,second
,0,fs
);
73 first_ok
= (first_media
.value
& FAT_EXTD(fs
)) == FAT_EXTD(fs
);
74 second_ok
= (second_media
.value
& FAT_EXTD(fs
)) == FAT_EXTD(fs
);
75 if (first_ok
&& !second_ok
) {
76 VfatPrint("FATs differ - using first FAT.\n");
77 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
79 if (!first_ok
&& second_ok
) {
80 VfatPrint("FATs differ - using second FAT.\n");
81 fs_write(fs
->fat_start
,eff_size
,use
= second
);
83 if (first_ok
&& second_ok
) {
84 if (FsCheckFlags
& FSCHECK_INTERACTIVE
) {
85 VfatPrint("FATs differ but appear to be intact. Use which FAT ?\n"
86 "1) Use first FAT\n2) Use second FAT\n");
87 if (get_key("12","?") == '1')
88 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
89 else fs_write(fs
->fat_start
,eff_size
,use
= second
);
92 VfatPrint("FATs differ but appear to be intact. Using first "
94 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
97 if (!first_ok
&& !second_ok
) {
98 VfatPrint("Both FATs appear to be corrupt. Giving up.\n");
102 fs
->fat
= qalloc(&FsCheckMemQueue
,sizeof(FAT_ENTRY
)*(fs
->clusters
+2));
103 for (i
= 2; i
< fs
->clusters
+2; i
++) get_fat(&fs
->fat
[i
],use
,i
,fs
);
104 for (i
= 2; i
< fs
->clusters
+2; i
++)
105 if (fs
->fat
[i
].value
>= fs
->clusters
+2 &&
106 (fs
->fat
[i
].value
< FAT_MIN_BAD(fs
))) {
107 VfatPrint("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
108 i
-2,fs
->fat
[i
].value
,fs
->clusters
+2-1);
117 void set_fat(DOS_FS
*fs
,unsigned long cluster
,unsigned long new)
119 unsigned char data
[4];
125 else if ((long)new == -2)
127 switch( fs
->fat_bits
) {
129 offs
= fs
->fat_start
+cluster
*3/2;
131 data
[0] = ((new & 0xf) << 4) | (fs
->fat
[cluster
-1].value
>> 8);
135 data
[0] = new & 0xff;
136 data
[1] = (new >> 8) | (cluster
== fs
->clusters
-1 ? 0 :
137 (0xff & fs
->fat
[cluster
+1].value
) << 4);
142 offs
= fs
->fat_start
+cluster
*2;
143 *(unsigned short *) data
= CT_LE_W(new);
147 offs
= fs
->fat_start
+cluster
*4;
148 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
149 * are not part of the cluster number. So we never touch them. */
150 *(unsigned long *) data
= CT_LE_L( (new & 0xfffffff) |
151 (fs
->fat
[cluster
].reserved
<< 28) );
155 die("Bad FAT entry size: %d bits.",fs
->fat_bits
);
157 fs
->fat
[cluster
].value
= new;
158 fs_write(offs
,size
,&data
);
159 fs_write(offs
+fs
->fat_size
,size
,&data
);
163 int bad_cluster(DOS_FS
*fs
,unsigned long cluster
)
165 return FAT_IS_BAD(fs
,fs
->fat
[cluster
].value
);
169 unsigned long next_cluster(DOS_FS
*fs
,unsigned long cluster
)
173 value
= fs
->fat
[cluster
].value
;
174 if (FAT_IS_BAD(fs
,value
))
175 die("Internal error: next_cluster on bad cluster");
176 return FAT_IS_EOF(fs
,value
) ? -1 : value
;
180 loff_t
cluster_start(DOS_FS
*fs
,unsigned long cluster
)
182 return fs
->data_start
+((loff_t
)cluster
-2)*fs
->cluster_size
;
186 void set_owner(DOS_FS
*fs
,unsigned long cluster
,DOS_FILE
*owner
)
188 if (owner
&& fs
->fat
[cluster
].owner
)
189 die("Internal error: attempt to change file owner");
190 fs
->fat
[cluster
].owner
= owner
;
194 DOS_FILE
*get_owner(DOS_FS
*fs
,unsigned long cluster
)
196 return fs
->fat
[cluster
].owner
;
200 void fix_bad(DOS_FS
*fs
)
204 if (FsCheckFlags
& FSCHECK_VERBOSE
)
205 VfatPrint("Checking for bad clusters.\n");
206 for (i
= 2; i
< fs
->clusters
+2; i
++)
207 if (!get_owner(fs
,i
) && !FAT_IS_BAD(fs
,fs
->fat
[i
].value
))
208 if (!fs_test(cluster_start(fs
,i
),fs
->cluster_size
)) {
209 VfatPrint("Cluster %lu is unreadable.\n",i
);
215 void reclaim_free(DOS_FS
*fs
)
220 if (FsCheckFlags
& FSCHECK_VERBOSE
)
221 VfatPrint("Checking for unused clusters.\n");
223 for (i
= 2; i
< fs
->clusters
+2; i
++)
224 if (!get_owner(fs
,i
) && fs
->fat
[i
].value
&&
225 !FAT_IS_BAD(fs
,fs
->fat
[i
].value
)) {
230 VfatPrint("Reclaimed %d unused cluster%s (%d bytes).\n",reclaimed
,
231 reclaimed
== 1 ? "" : "s",reclaimed
*fs
->cluster_size
);
235 static void tag_free(DOS_FS
*fs
,DOS_FILE
*ptr
)
239 unsigned long i
,walk
;
241 for (i
= 2; i
< fs
->clusters
+2; i
++)
242 if (fs
->fat
[i
].value
&& !FAT_IS_BAD(fs
,fs
->fat
[i
].value
) &&
243 !get_owner(fs
,i
) && !fs
->fat
[i
].prev
) {
245 for (walk
= i
; walk
> 0 && walk
!= -1;
246 walk
= next_cluster(fs
,walk
)) {
247 if (!(owner
= get_owner(fs
,walk
))) set_owner(fs
,walk
,ptr
);
248 else if (owner
!= ptr
)
249 die("Internal error: free chain collides with file");
260 void reclaim_file(DOS_FS
*fs
)
263 int reclaimed
,files
,changed
;
264 unsigned long i
,next
,walk
;
266 if (FsCheckFlags
& FSCHECK_VERBOSE
)
267 VfatPrint("Reclaiming unconnected clusters.\n");
268 for (i
= 2; i
< fs
->clusters
+2; i
++) fs
->fat
[i
].prev
= 0;
269 for (i
= 2; i
< fs
->clusters
+2; i
++) {
270 next
= fs
->fat
[i
].value
;
271 if (!get_owner(fs
,i
) && next
&& next
< fs
->clusters
+2) {
272 if (get_owner(fs
,next
) || !fs
->fat
[next
].value
||
273 FAT_IS_BAD(fs
,fs
->fat
[next
].value
)) set_fat(fs
,i
,-1);
274 else fs
->fat
[next
].prev
++;
280 for (i
= 2; i
< fs
->clusters
+2; i
++)
281 if (fs
->fat
[i
].value
&& !FAT_IS_BAD(fs
,fs
->fat
[i
].value
) &&
283 if (!fs
->fat
[fs
->fat
[i
].value
].prev
--)
284 die("Internal error: prev going below zero");
287 VfatPrint("Broke cycle at cluster %lu in free chain.\n",i
);
292 files
= reclaimed
= 0;
293 for (i
= 2; i
< fs
->clusters
+2; i
++)
294 if (get_owner(fs
,i
) == &dummy
&& !fs
->fat
[i
].prev
) {
298 offset
= alloc_rootdir_entry(fs
,&de
,"FSCK%04dREC");
299 de
.start
= CT_LE_W(i
&0xffff);
300 if (fs
->fat_bits
== 32)
301 de
.starthi
= CT_LE_W(i
>>16);
302 for (walk
= i
; walk
> 0 && walk
!= -1;
303 walk
= next_cluster(fs
,walk
)) {
304 de
.size
= CT_LE_L(CF_LE_L(de
.size
)+fs
->cluster_size
);
307 fs_write(offset
,sizeof(DIR_ENT
),&de
);
310 VfatPrint("Reclaimed %d unused cluster%s (%d bytes) in %d chain%s.\n",
311 reclaimed
,reclaimed
== 1 ? "" : "s",reclaimed
*fs
->cluster_size
,files
,
312 files
== 1 ? "" : "s");
316 unsigned long update_free(DOS_FS
*fs
)
319 unsigned long free
= 0;
322 for (i
= 2; i
< fs
->clusters
+2; i
++)
323 if (!get_owner(fs
,i
) && !FAT_IS_BAD(fs
,fs
->fat
[i
].value
))
326 if (!fs
->fsinfo_start
)
329 if (FsCheckFlags
& FSCHECK_VERBOSE
)
330 VfatPrint("Checking free cluster summary.\n");
331 if (fs
->free_clusters
>= 0) {
332 if (free
!= fs
->free_clusters
) {
333 VfatPrint( "Free cluster summary wrong (%ld vs. really %ld)\n",
334 fs
->free_clusters
,free
);
335 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
336 VfatPrint( "1) Correct\n2) Don't correct\n" );
337 else VfatPrint( " Auto-correcting.\n" );
338 if (!(FsCheckFlags
& FSCHECK_INTERACTIVE
) || get_key("12","?") == '1')
343 VfatPrint( "Free cluster summary uninitialized (should be %ld)\n", free
);
344 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
345 VfatPrint( "1) Set it\n2) Leave it uninitialized\n" );
346 else VfatPrint( " Auto-setting.\n" );
347 if (!(FsCheckFlags
& FSCHECK_INTERACTIVE
) || get_key("12","?") == '1')
352 fs
->free_clusters
= free
;
353 free
= CT_LE_L(free
);
354 fs_write(fs
->fsinfo_start
+offsetof(struct info_sector
,free_clusters
),
361 /* Local Variables: */