1975a12ad3db9f05b534bf3c39e89585b40c1de8
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> */
20 #pragma warning(disable: 4018)
22 static void get_fat(FAT_ENTRY
*entry
,void *fat
,unsigned long cluster
,DOS_FS
*fs
)
26 switch(fs
->fat_bits
) {
28 ptr
= &((unsigned char *) fat
)[cluster
*3/2];
29 entry
->value
= 0xfff & (cluster
& 1 ? (ptr
[0] >> 4) | (ptr
[1] << 4) :
30 (ptr
[0] | ptr
[1] << 8));
33 entry
->value
= CF_LE_W(((unsigned short *) fat
)[cluster
]);
36 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
37 * are not part of the cluster number. So we cut them off. */
39 unsigned long e
= CF_LE_L(((unsigned int *) fat
)[cluster
]);
40 entry
->value
= e
& 0xfffffff;
41 entry
->reserved
= e
>> 28;
45 die("Bad FAT entry size: %d bits.",fs
->fat_bits
);
51 void read_fat(DOS_FS
*fs
)
55 void *first
,*second
,*use
;
56 int first_ok
,second_ok
;
58 eff_size
= ((fs
->clusters
+2)*fs
->fat_bits
+7)/8;
59 // TMN: Must round up to disk-sector boundary. For now, assume 512-byte disk.
61 eff_size
+= 512 - (eff_size
% 512);
63 first
= alloc(eff_size
);
64 fs_read(fs
->fat_start
,eff_size
,first
);
67 second
= alloc(eff_size
);
68 fs_read(fs
->fat_start
+fs
->fat_size
,eff_size
,second
);
72 if (second
&& memcmp(first
,second
,eff_size
) != 0) {
73 FAT_ENTRY first_media
, second_media
;
74 get_fat(&first_media
,first
,0,fs
);
75 get_fat(&second_media
,second
,0,fs
);
76 first_ok
= (first_media
.value
& FAT_EXTD(fs
)) == FAT_EXTD(fs
);
77 second_ok
= (second_media
.value
& FAT_EXTD(fs
)) == FAT_EXTD(fs
);
78 if (first_ok
&& !second_ok
) {
79 printf("FATs differ - using first FAT.\n");
80 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
82 if (!first_ok
&& second_ok
) {
83 printf("FATs differ - using second FAT.\n");
84 fs_write(fs
->fat_start
,eff_size
,use
= second
);
86 if (first_ok
&& second_ok
) {
88 printf("FATs differ but appear to be intact. Use which FAT ?\n"
89 "1) Use first FAT\n2) Use second FAT\n");
90 if (get_key("12","?") == '1')
91 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
92 else fs_write(fs
->fat_start
,eff_size
,use
= second
);
95 printf("FATs differ but appear to be intact. Using first "
97 fs_write(fs
->fat_start
+fs
->fat_size
,eff_size
,use
= first
);
100 if (!first_ok
&& !second_ok
) {
101 printf("Both FATs appear to be corrupt. Giving up.\n");
105 fs
->fat
= qalloc(&mem_queue
,sizeof(FAT_ENTRY
)*(fs
->clusters
+2));
106 for (i
= 2; i
< fs
->clusters
+2; i
++) get_fat(&fs
->fat
[i
],use
,i
,fs
);
107 for (i
= 2; i
< fs
->clusters
+2; i
++)
108 if (fs
->fat
[i
].value
>= fs
->clusters
+2 &&
109 (fs
->fat
[i
].value
< FAT_MIN_BAD(fs
))) {
110 printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
111 i
-2,fs
->fat
[i
].value
,fs
->clusters
+2-1);
120 void set_fat(DOS_FS
*fs
,unsigned long cluster
,unsigned long new)
122 unsigned char data
[4];
128 else if ((long)new == -2)
130 switch( fs
->fat_bits
) {
132 offs
= fs
->fat_start
+cluster
*3/2;
134 data
[0] = ((new & 0xf) << 4) | (fs
->fat
[cluster
-1].value
>> 8);
138 data
[0] = new & 0xff;
139 data
[1] = (new >> 8) | (cluster
== fs
->clusters
-1 ? 0 :
140 (0xff & fs
->fat
[cluster
+1].value
) << 4);
145 offs
= fs
->fat_start
+cluster
*2;
146 *(unsigned short *) data
= CT_LE_W(new);
150 offs
= fs
->fat_start
+cluster
*4;
151 /* According to M$, the high 4 bits of a FAT32 entry are reserved and
152 * are not part of the cluster number. So we never touch them. */
153 *(unsigned long *) data
= CT_LE_L( (new & 0xfffffff) |
154 (fs
->fat
[cluster
].reserved
<< 28) );
158 die("Bad FAT entry size: %d bits.",fs
->fat_bits
);
160 fs
->fat
[cluster
].value
= new;
161 fs_write(offs
,size
,&data
);
162 fs_write(offs
+fs
->fat_size
,size
,&data
);
166 int bad_cluster(DOS_FS
*fs
,unsigned long cluster
)
168 return FAT_IS_BAD(fs
,fs
->fat
[cluster
].value
);
172 unsigned long next_cluster(DOS_FS
*fs
,unsigned long cluster
)
176 value
= fs
->fat
[cluster
].value
;
177 if (FAT_IS_BAD(fs
,value
))
178 die("Internal error: next_cluster on bad cluster");
179 return FAT_IS_EOF(fs
,value
) ? -1 : value
;
183 loff_t
cluster_start(DOS_FS
*fs
,unsigned long cluster
)
185 return fs
->data_start
+((loff_t
)cluster
-2)*fs
->cluster_size
;
189 void set_owner(DOS_FS
*fs
,unsigned long cluster
,DOS_FILE
*owner
)
191 if (owner
&& fs
->fat
[cluster
].owner
)
192 die("Internal error: attempt to change file owner");
193 fs
->fat
[cluster
].owner
= owner
;
197 DOS_FILE
*get_owner(DOS_FS
*fs
,unsigned long cluster
)
199 return fs
->fat
[cluster
].owner
;
203 void fix_bad(DOS_FS
*fs
)
208 printf("Checking for bad clusters.\n");
209 for (i
= 2; i
< fs
->clusters
+2; i
++)
210 if (!get_owner(fs
,i
) && !FAT_IS_BAD(fs
,fs
->fat
[i
].value
))
211 if (!fs_test(cluster_start(fs
,i
),fs
->cluster_size
)) {
212 printf("Cluster %lu is unreadable.\n",i
);
218 void reclaim_free(DOS_FS
*fs
)
224 printf("Checking for unused clusters.\n");
226 for (i
= 2; i
< fs
->clusters
+2; i
++)
227 if (!get_owner(fs
,i
) && fs
->fat
[i
].value
&&
228 !FAT_IS_BAD(fs
,fs
->fat
[i
].value
)) {
233 printf("Reclaimed %d unused cluster%s (%d bytes).\n",reclaimed
,
234 reclaimed
== 1 ? "" : "s",reclaimed
*fs
->cluster_size
);
238 static void tag_free(DOS_FS
*fs
,DOS_FILE
*ptr
)
242 unsigned long i
,walk
;
244 for (i
= 2; i
< fs
->clusters
+2; i
++)
245 if (fs
->fat
[i
].value
&& !FAT_IS_BAD(fs
,fs
->fat
[i
].value
) &&
246 !get_owner(fs
,i
) && !fs
->fat
[i
].prev
) {
248 for (walk
= i
; walk
> 0 && walk
!= -1;
249 walk
= next_cluster(fs
,walk
)) {
250 if (!(owner
= get_owner(fs
,walk
))) set_owner(fs
,walk
,ptr
);
251 else if (owner
!= ptr
)
252 die("Internal error: free chain collides with file");
263 void reclaim_file(DOS_FS
*fs
)
266 int reclaimed
,files
,changed
;
267 unsigned long i
,next
,walk
;
270 printf("Reclaiming unconnected clusters.\n");
271 for (i
= 2; i
< fs
->clusters
+2; i
++) fs
->fat
[i
].prev
= 0;
272 for (i
= 2; i
< fs
->clusters
+2; i
++) {
273 next
= fs
->fat
[i
].value
;
274 if (!get_owner(fs
,i
) && next
&& next
< fs
->clusters
+2) {
275 if (get_owner(fs
,next
) || !fs
->fat
[next
].value
||
276 FAT_IS_BAD(fs
,fs
->fat
[next
].value
)) set_fat(fs
,i
,-1);
277 else fs
->fat
[next
].prev
++;
283 for (i
= 2; i
< fs
->clusters
+2; i
++)
284 if (fs
->fat
[i
].value
&& !FAT_IS_BAD(fs
,fs
->fat
[i
].value
) &&
286 if (!fs
->fat
[fs
->fat
[i
].value
].prev
--)
287 die("Internal error: prev going below zero");
290 printf("Broke cycle at cluster %lu in free chain.\n",i
);
295 files
= reclaimed
= 0;
296 for (i
= 2; i
< fs
->clusters
+2; i
++)
297 if (get_owner(fs
,i
) == &dummy
&& !fs
->fat
[i
].prev
) {
301 offset
= alloc_rootdir_entry(fs
,&de
,"FSCK%04dREC");
302 de
.start
= CT_LE_W(i
&0xffff);
303 if (fs
->fat_bits
== 32)
304 de
.starthi
= CT_LE_W(i
>>16);
305 for (walk
= i
; walk
> 0 && walk
!= -1;
306 walk
= next_cluster(fs
,walk
)) {
307 de
.size
= CT_LE_L(CF_LE_L(de
.size
)+fs
->cluster_size
);
310 fs_write(offset
,sizeof(DIR_ENT
),&de
);
313 printf("Reclaimed %d unused cluster%s (%d bytes) in %d chain%s.\n",
314 reclaimed
,reclaimed
== 1 ? "" : "s",reclaimed
*fs
->cluster_size
,files
,
315 files
== 1 ? "" : "s");
319 unsigned long update_free(DOS_FS
*fs
)
322 unsigned long free
= 0;
325 for (i
= 2; i
< fs
->clusters
+2; i
++)
326 if (!get_owner(fs
,i
) && !FAT_IS_BAD(fs
,fs
->fat
[i
].value
))
329 if (!fs
->fsinfo_start
)
333 printf("Checking free cluster summary.\n");
334 if (fs
->free_clusters
>= 0) {
335 if (free
!= fs
->free_clusters
) {
336 printf( "Free cluster summary wrong (%ld vs. really %ld)\n",
337 fs
->free_clusters
,free
);
339 printf( "1) Correct\n2) Don't correct\n" );
340 else printf( " Auto-correcting.\n" );
341 if (!interactive
|| get_key("12","?") == '1')
346 printf( "Free cluster summary uninitialized (should be %ld)\n", free
);
348 printf( "1) Set it\n2) Leave it uninitialized\n" );
349 else printf( " Auto-setting.\n" );
350 if (!interactive
|| get_key("12","?") == '1')
355 fs
->free_clusters
= free
;
356 free
= CT_LE_L(free
);
357 fs_write(fs
->fsinfo_start
+offsetof(struct info_sector
,free_clusters
),
364 /* Local Variables: */