New "ea_data" module
[deark.git] / modules / fat.c
blob01e9d63dd2fd7f1efa84243f37317af7b63c5894
1 // This file is part of Deark.
2 // Copyright (C) 2020 Jason Summers
3 // See the file COPYING for terms of use.
5 // FAT disk image
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_fat);
10 DE_DECLARE_MODULE(de_module_loaddskf);
11 DE_DECLARE_MODULE(de_module_ea_data);
13 #define MAX_NESTING_LEVEL 16
15 struct member_data {
16 u8 fn_base[8];
17 u8 fn_ext[3];
18 u8 is_subdir;
19 u8 is_special;
20 UI attribs;
21 UI ea_handle;
22 i64 fn_base_len, fn_ext_len;
23 i64 filesize;
24 i64 first_cluster;
25 de_ucstring *short_fn;
26 de_ucstring *long_fn;
27 struct de_timestamp mod_time;
30 struct dirctx {
31 u8 lfn_valid;
32 u8 first_seq_num;
33 u8 prev_seq_num;
34 u8 name_cksum;
35 i64 dir_entry_count;
36 i64 pending_lfn_bytesused;
37 #define LFN_CHARS_PER_FRAGMENT 13
38 #define LFN_MAX_FRAGMENTS 20
39 u8 pending_lfn[LFN_CHARS_PER_FRAGMENT*2*LFN_MAX_FRAGMENTS];
42 typedef struct localctx_struct {
43 de_encoding input_encoding;
44 int opt_check_rootdir;
46 // TODO: Decide how to handle different variants of FAT.
47 #define FAT_SUBFMT_UNKNOWN 0
48 #define FAT_SUBFMT_PC 1
49 #define FAT_SUBFMT_ATARIST 2
50 int subfmt_req;
51 int subfmt;
52 #define FAT_PLATFORM_UNKNOWN 0
53 #define FAT_PLATFORM_PC 1
54 #define FAT_PLATFORM_ATARIST 2
55 int platform;
57 u8 num_fat_bits; // 12, 16, or 32. 0 if unknown.
58 u8 has_atarist_checksum;
59 i64 bytes_per_sector;
60 i64 sectors_per_cluster;
61 i64 bytes_per_cluster;
62 i64 num_sectors;
63 i64 data_region_sector;
64 i64 data_region_pos;
65 i64 num_data_region_clusters;
66 i64 num_rsvd_sectors;
67 i64 num_fats;
68 i64 num_sectors_per_fat;
69 i64 max_root_dir_entries16;
70 i64 root_dir_sector;
71 i64 num_cluster_identifiers;
72 struct de_strarray *curpath;
74 i64 num_fat_entries;
75 u32 *fat_nextcluster; // array[num_fat_entries]
76 u8 *cluster_used_flags; // array[num_fat_entries]
77 } lctx;
79 static i64 sectornum_to_offset(deark *c, lctx *d, i64 secnum)
81 return secnum * d->bytes_per_sector;
84 static int is_good_clusternum(lctx *d, i64 cnum)
86 if(cnum<2) return 0;
87 if(cnum >= d->num_cluster_identifiers) return 0;
88 return 1;
91 static i64 clusternum_to_offset(deark *c, lctx *d, i64 cnum)
93 return d->data_region_pos + (cnum-2) * d->bytes_per_cluster;
96 static void dbg_timestamp(deark *c, struct de_timestamp *ts, const char *name)
98 char timestamp_buf[64];
100 de_timestamp_to_string(ts, timestamp_buf, sizeof(timestamp_buf), 0);
101 de_dbg(c, "%s: %s", name, timestamp_buf);
104 static i64 get_unpadded_len(const u8 *s, i64 len1)
106 i64 i;
107 i64 len = len1;
109 // Stop at NUL, I guess.
110 for(i=0; i<len1; i++) {
111 if(s[i]==0x00) {
112 len = i;
113 break;
117 for(i=len; i>0; i--) {
118 if(s[i-1]!=' ') {
119 return i;
122 return 0;
125 static void do_extract_file(deark *c, lctx *d, struct member_data *md)
127 dbuf *outf = NULL;
128 de_finfo *fi = NULL;
129 de_ucstring *fullfn = NULL;
130 i64 cur_cluster;
131 i64 nbytes_remaining;
133 if(!md->is_subdir) {
134 if(md->filesize > d->num_data_region_clusters * d->bytes_per_cluster) {
135 de_err(c, "%s: Bad file size", ucstring_getpsz_d(md->short_fn));
136 goto done;
140 fi = de_finfo_create(c);
141 fullfn = ucstring_create(c);
142 de_strarray_make_path(d->curpath, fullfn, DE_MPFLAG_NOTRAILINGSLASH);
143 de_finfo_set_name_from_ucstring(c, fi, fullfn, DE_SNFLAG_FULLPATH);
144 fi->original_filename_flag = 1;
145 if(md->is_subdir) {
146 fi->is_directory = 1;
148 if(md->mod_time.is_valid) {
149 fi->timestamp[DE_TIMESTAMPIDX_MODIFY] = md->mod_time;
152 outf = dbuf_create_output_file(c, NULL, fi, 0);
154 cur_cluster = md->first_cluster;
155 if(md->is_subdir) {
156 nbytes_remaining = 0;
158 else {
159 nbytes_remaining = md->filesize;
162 while(1) {
163 i64 dpos;
164 i64 nbytes_to_copy;
166 if(nbytes_remaining <= 0) break;
167 if(!is_good_clusternum(d, cur_cluster)) break;
168 if(d->cluster_used_flags[cur_cluster]) break;
169 d->cluster_used_flags[cur_cluster] = 1;
170 if(c->debug_level>=3) de_dbg3(c, "cluster: %d", (int)cur_cluster);
171 dpos = clusternum_to_offset(c, d, cur_cluster);
172 nbytes_to_copy = de_min_int(d->bytes_per_cluster, nbytes_remaining);
173 dbuf_copy(c->infile, dpos, nbytes_to_copy, outf);
174 nbytes_remaining -= nbytes_to_copy;
175 cur_cluster = (i64)d->fat_nextcluster[cur_cluster];
178 if(nbytes_remaining>0) {
179 de_err(c, "%s: File extraction failed", ucstring_getpsz_d(md->short_fn));
180 goto done;
183 done:
184 dbuf_close(outf);
185 ucstring_destroy(fullfn);
186 de_finfo_destroy(c, fi);
189 static void do_subdir(deark *c, lctx *d, struct member_data *md, int nesting_level);
191 static void do_vfat_entry(deark *c, lctx *d, struct dirctx *dctx, i64 pos1, u8 seq_num_raw)
193 u8 seq_num;
194 u8 fn_cksum;
195 int is_first_entry = 0;
196 i64 startpos_in_lfn;
198 if(seq_num_raw==0xe5) {
199 de_dbg(c, "[deleted VFAT entry]");
200 dctx->lfn_valid = 0;
201 goto done;
204 de_dbg(c, "seq number: 0x%02x", (UI)seq_num_raw);
206 seq_num = seq_num_raw & 0xbf;
208 if(seq_num<1 || seq_num>LFN_MAX_FRAGMENTS) {
209 de_warn(c, "Bad VFAT sequence number (%u)", (UI)seq_num);
210 dctx->lfn_valid = 0;
211 goto done;
214 if(seq_num_raw & 0x40) {
215 is_first_entry = 1;
216 de_zeromem(dctx->pending_lfn, sizeof(dctx->pending_lfn));
217 dctx->first_seq_num = seq_num;
218 dctx->lfn_valid = 1;
220 else {
221 if(!dctx->lfn_valid || (seq_num+1 != dctx->prev_seq_num)) {
222 de_dbg(c, "[stray VFAT entry]");
223 dctx->lfn_valid = 0;
224 goto done;
227 dctx->prev_seq_num = seq_num;
229 startpos_in_lfn = LFN_CHARS_PER_FRAGMENT*2*((i64)seq_num-1);
231 de_read(&dctx->pending_lfn[startpos_in_lfn+ 0], pos1+ 1, 10); // 5 chars
232 fn_cksum = de_getbyte(pos1+13);
233 de_read(&dctx->pending_lfn[startpos_in_lfn+10], pos1+14, 12); // 6 more chars
234 de_read(&dctx->pending_lfn[startpos_in_lfn+22], pos1+28, 4); // 2 more chars
235 de_dbg(c, "filename checksum (reported): 0x%02x", (UI)fn_cksum);
236 if(!is_first_entry) {
237 if(fn_cksum != dctx->name_cksum) {
238 de_dbg(c, "[inconsistent VFAT checksums]");
239 dctx->lfn_valid = 0;
242 dctx->name_cksum = fn_cksum;
244 done:
248 static void vfat_cksum_update(const u8 *buf, size_t buflen, u8 *cksum)
250 size_t i;
252 for(i=0; i<buflen; i++) {
253 *cksum = (((*cksum) & 1) << 7) + ((*cksum) >> 1) + buf[i];
257 // If the long file name seems valid, sets it in md->long_fn for later use.
258 static void handle_vfat_lfn(deark *c, lctx *d, struct dirctx *dctx,
259 struct member_data *md)
261 u8 cksum_calc = 0;
262 i64 max_len_in_ucs2_chars;
263 i64 len_in_ucs2_chars = 0;
264 i64 i;
266 if(!dctx->lfn_valid) goto done;
267 if(dctx->prev_seq_num != 1) goto done;
268 if(md->long_fn) goto done;
270 vfat_cksum_update(md->fn_base, 8, &cksum_calc);
271 vfat_cksum_update(md->fn_ext, 3, &cksum_calc);
272 de_dbg(c, "filename checksum (calculated): 0x%02x", (UI)cksum_calc);
273 if(cksum_calc != dctx->name_cksum) goto done;
275 max_len_in_ucs2_chars = LFN_CHARS_PER_FRAGMENT * (i64)dctx->first_seq_num;
276 if(max_len_in_ucs2_chars > (i64)(sizeof(dctx->pending_lfn)/2)) goto done;
277 for(i=0; i<max_len_in_ucs2_chars; i++) {
278 if(dctx->pending_lfn[i*2]==0x00 && dctx->pending_lfn[i*2+1]==0x00) break;
279 if(dctx->pending_lfn[i*2]==0xff && dctx->pending_lfn[i*2+1]==0xff) break;
280 len_in_ucs2_chars++;
283 md->long_fn = ucstring_create(c);
284 ucstring_append_bytes(md->long_fn, dctx->pending_lfn, len_in_ucs2_chars*2,
285 0, DE_ENCODING_UTF16LE);
286 de_dbg(c, "long filename: \"%s\"", ucstring_getpsz_d(md->long_fn));
288 done:
292 // Reads from md->fn_base* and md->fn_ext*, writes to md->short_fn
293 static void decode_short_filename(deark *c, lctx *d, struct member_data *md)
295 if(md->fn_base_len>0) {
296 ucstring_append_bytes(md->short_fn, md->fn_base, md->fn_base_len, 0, d->input_encoding);
298 else {
299 ucstring_append_char(md->short_fn, '_');
301 if(md->fn_ext_len>0) {
302 ucstring_append_char(md->short_fn, '.');
303 ucstring_append_bytes(md->short_fn, md->fn_ext, md->fn_ext_len, 0, d->input_encoding);
307 static void decode_volume_label_name(deark *c, lctx *d, struct member_data *md)
309 if(md->fn_ext_len>0) {
310 ucstring_append_bytes(md->short_fn, md->fn_base, 8, 0, d->input_encoding);
311 ucstring_append_bytes(md->short_fn, md->fn_ext, md->fn_ext_len, 0, d->input_encoding);
313 else {
314 ucstring_append_bytes(md->short_fn, md->fn_base, md->fn_base_len, 0, d->input_encoding);
318 // Returns 0 if this is the end-of-directory marker.
319 static int do_dir_entry(deark *c, lctx *d, struct dirctx *dctx,
320 i64 pos1, int nesting_level)
322 u8 firstbyte;
323 i64 ddate, dtime;
324 int retval = 0;
325 int is_deleted = 0;
326 int is_volume_label = 0;
327 int need_curpath_pop = 0;
328 de_ucstring *descr = NULL;
329 struct member_data *md = NULL;
331 md = de_malloc(c, sizeof(struct member_data));
333 de_dbg(c, "dir entry at %"I64_FMT, pos1);
334 de_dbg_indent(c, 1);
336 de_read(md->fn_base, pos1+0, 8);
337 de_read(md->fn_ext, pos1+8, 3);
338 firstbyte = md->fn_base[0];
340 if(firstbyte==0x00) {
341 de_dbg(c, "[end of dir marker]");
342 goto done;
344 retval = 1;
346 md->attribs = (UI)de_getbyte(pos1+11);
347 descr = ucstring_create(c);
348 de_describe_dos_attribs(c, md->attribs, descr, 0x1);
349 de_dbg(c, "attribs: 0x%02x (%s)", md->attribs, ucstring_getpsz_d(descr));
350 if((md->attribs & 0x3f)==0x0f) {
351 do_vfat_entry(c, d, dctx, pos1, firstbyte);
352 goto done;
355 if((md->attribs & 0x18) == 0x00) {
356 ; // Normal file
358 else if((md->attribs & 0x18) == 0x08) {
359 is_volume_label = 1;
360 md->is_special = 1;
362 else if((md->attribs & 0x18) == 0x10) {
363 md->is_subdir = 1;
365 else {
366 de_warn(c, "Invalid directory entry");
367 md->is_special = 1;
368 dctx->lfn_valid = 0;
369 goto done;
372 if(dctx->lfn_valid) {
373 handle_vfat_lfn(c, d, dctx, md);
374 dctx->lfn_valid = 0;
377 if(firstbyte==0xe5) {
378 de_dbg(c, "[deleted]");
379 is_deleted = 1;
380 md->fn_base[0] = '?';
382 else if(firstbyte==0x05) {
383 md->fn_base[0] = 0xe5;
386 md->fn_base_len = get_unpadded_len(md->fn_base, 8);
387 md->fn_ext_len = get_unpadded_len(md->fn_ext, 3);
389 if(md->is_subdir && md->fn_base_len>=1 && md->fn_base[0]=='.') {
390 // special "." and ".." dirs
391 md->is_special = 1;
394 md->short_fn = ucstring_create(c);
395 if(is_volume_label) {
396 decode_volume_label_name(c, d, md);
398 else {
399 decode_short_filename(c, d, md);
402 de_dbg(c, "filename: \"%s\"", ucstring_getpsz_d(md->short_fn));
404 if(ucstring_isnonempty(md->long_fn)) {
405 de_strarray_push(d->curpath, md->long_fn);
407 else {
408 de_strarray_push(d->curpath, md->short_fn);
410 need_curpath_pop = 1;
412 if(d->num_fat_bits<32) {
413 md->ea_handle = (UI)de_getu16le(pos1+20);
414 if(md->ea_handle) {
415 de_dbg(c, "EA handle (if OS/2): %u", md->ea_handle);
419 dtime = de_getu16le(pos1+22);
420 ddate = de_getu16le(pos1+24);
421 de_dos_datetime_to_timestamp(&md->mod_time, ddate, dtime);
422 dbg_timestamp(c, &md->mod_time, "mod time");
424 // TODO: This is wrong for FAT32.
425 md->first_cluster = de_getu16le(pos1+26);
426 de_dbg(c, "first cluster: %"I64_FMT, md->first_cluster);
428 md->filesize = de_getu32le(pos1+28);
429 de_dbg(c, "file size: %"I64_FMT, md->filesize);
431 if(!is_deleted && !md->is_subdir && !md->is_special) {
432 do_extract_file(c, d, md);
434 else if(!is_deleted && md->is_subdir && !md->is_special) {
435 do_extract_file(c, d, md);
436 do_subdir(c, d, md, nesting_level+1);
439 done:
440 ucstring_destroy(descr);
441 if(md) {
442 ucstring_destroy(md->short_fn);
443 ucstring_destroy(md->long_fn);
445 if(need_curpath_pop) {
446 de_strarray_pop(d->curpath);
448 de_dbg_indent(c, -1);
449 return retval;
452 // Process a contiguous block of directory entries
453 // Returns 0 if an end-of-dir marker was found.
454 static int do_dir_entries(deark *c, lctx *d, struct dirctx *dctx,
455 i64 pos1, i64 len, int nesting_level)
457 i64 num_entries;
458 i64 i;
459 int retval = 0;
461 num_entries = len/32;
462 de_dbg(c, "num entries: %"I64_FMT, num_entries);
464 for(i=0; i<num_entries; i++) {
465 if(!do_dir_entry(c, d, dctx, pos1+32*i, nesting_level)) {
466 goto done;
468 dctx->dir_entry_count++;
471 retval = 1;
472 done:
473 return retval;
476 static void destroy_dirctx(deark *c, struct dirctx *dctx)
478 if(!dctx) return;
479 de_free(c, dctx);
482 static void do_subdir(deark *c, lctx *d, struct member_data *md, int nesting_level)
484 int saved_indent_level;
485 i64 cur_cluster_num;
486 i64 cur_cluster_pos;
487 struct dirctx *dctx = NULL;
489 de_dbg_indent_save(c, &saved_indent_level);
491 if(nesting_level >= MAX_NESTING_LEVEL) {
492 de_err(c, "Directories nested too deeply");
493 goto done;
496 dctx = de_malloc(c, sizeof(struct dirctx));
498 cur_cluster_num = md->first_cluster;
499 if(!is_good_clusternum(d, cur_cluster_num)) {
500 de_err(c, "Bad subdirectory entry");
501 goto done;
503 cur_cluster_pos = clusternum_to_offset(c, d, cur_cluster_num);
504 de_dbg(c, "subdir starting at %"I64_FMT, cur_cluster_pos);
505 de_dbg_indent(c, 1);
507 while(1) {
508 if(!is_good_clusternum(d, cur_cluster_num)) {
509 break;
511 cur_cluster_pos = clusternum_to_offset(c, d, cur_cluster_num);
512 de_dbg(c, "[subdir cluster %"I64_FMT" at %"I64_FMT"]", cur_cluster_num, cur_cluster_pos);
514 if(d->cluster_used_flags[cur_cluster_num]) {
515 goto done;
517 d->cluster_used_flags[cur_cluster_num] = 1;
519 if(!do_dir_entries(c, d, dctx, cur_cluster_pos, d->bytes_per_cluster, nesting_level)) {
520 break;
523 cur_cluster_num = d->fat_nextcluster[cur_cluster_num];
526 done:
527 destroy_dirctx(c, dctx);
528 de_dbg_indent_restore(c, saved_indent_level);
531 static void do_root_dir(deark *c, lctx *d)
533 i64 pos1;
534 struct dirctx *dctx = NULL;
536 dctx = de_malloc(c, sizeof(struct dirctx));
537 pos1 = sectornum_to_offset(c, d, d->root_dir_sector);
538 de_dbg(c, "dir at %"I64_FMT, pos1);
539 de_dbg_indent(c, 1);
540 if(pos1<d->bytes_per_sector) goto done;
541 (void)do_dir_entries(c, d, dctx, pos1, d->max_root_dir_entries16 * 32, 0);
542 done:
543 destroy_dirctx(c, dctx);
544 de_dbg_indent(c, -1);
547 static int root_dir_seems_valid(deark *c, lctx *d)
549 i64 pos1;
550 i64 max_entries_to_check;
551 i64 i;
552 i64 entrycount = 0;
553 i64 errcount = 0;
555 if(d->num_fat_bits==32) return 1;
557 if(d->max_root_dir_entries16<=0) return 0;
558 pos1 = sectornum_to_offset(c, d, d->root_dir_sector);
559 if(pos1 + d->max_root_dir_entries16 * 32 > c->infile->len) {
560 return 0;
563 max_entries_to_check = de_max_int(d->max_root_dir_entries16, 10);
564 for(i=0; i<max_entries_to_check; i++) {
565 i64 entrypos;
566 u8 firstbyte;
567 u8 attribs;
569 entrypos = pos1 + 32*i;
570 firstbyte = de_getbyte(entrypos);
571 if(firstbyte==0x00) break;
572 if(firstbyte==0xe5) continue; // Don't validate deleted entries
573 entrycount++;
574 attribs = de_getbyte(entrypos+11);
575 if(attribs & 0xc0) {
576 errcount++;
578 else if((attribs & 0x3f) == 0x0f) {
579 ; // LFN; OK
581 else if((attribs & 0x18)==0x18) {
582 errcount++; // dir + vol.label not valid
585 // TODO: It's really lame to only validate the attribs field, when there's
586 // so much more we could be doing. But it's a hard problem. We don't want
587 // to be too sensitive to minor errors.
590 if(errcount>1 || (errcount==1 && entrycount<=1)) {
591 return 0;
593 return 1;
596 static void do_atarist_boot_checksum(deark *c, lctx *d, i64 pos1)
598 i64 i;
599 UI ck = 0;
601 for(i=0; i<256; i++) {
602 ck += (UI)de_getu16be(pos1+i*2);
603 ck &= 0xffff;
606 de_dbg(c, "Atari ST checksum: 0x%04x", ck);
607 if(ck==0x1234) {
608 d->has_atarist_checksum = 1;
612 static void do_oem_name(deark *c, lctx *d, i64 pos, i64 len)
614 struct de_stringreaderdata *srd;
615 i64 i;
617 srd = dbuf_read_string(c->infile, pos, len, len, 0, DE_ENCODING_ASCII);
619 // Require printable ASCII.
620 for(i=0; i<len; i++) {
621 if(srd->sz[i]<32 || srd->sz[i]>126) {
622 goto done;
626 de_dbg(c, "OEM name: \"%s\"", ucstring_getpsz_d(srd->str));
628 done:
629 de_destroy_stringreaderdata(c, srd);
632 static int do_boot_sector(deark *c, lctx *d, i64 pos1)
634 i64 pos;
635 i64 num_data_region_sectors;
636 i64 num_root_dir_sectors;
637 i64 num_sectors_per_fat16;
638 i64 num_sectors_per_fat32 = 0;
639 i64 num_sectors16;
640 i64 num_sectors32 = 0;
641 i64 num_sectors_per_track;
642 i64 num_heads;
643 i64 jmpinstrlen;
644 u8 b;
645 u8 cksum_sig[2];
646 int retval = 0;
648 de_dbg(c, "boot sector at %"I64_FMT, pos1);
649 de_dbg_indent(c, 1);
651 // BIOS parameter block
652 jmpinstrlen = (d->subfmt==FAT_SUBFMT_ATARIST)?2:3;
653 de_dbg_hexdump(c, c->infile, pos1, jmpinstrlen, jmpinstrlen, "jump instr", 0);
655 if(d->subfmt==FAT_SUBFMT_ATARIST) {
656 do_oem_name(c, d, pos1+2, 6);
657 de_dbg_hexdump(c, c->infile, pos1+8, 3, 3, "serial num", 0);
659 else {
660 do_oem_name(c, d, pos1+3, 8);
663 pos = pos1+11;
664 d->bytes_per_sector = de_getu16le_p(&pos);
665 de_dbg(c, "bytes per sector: %d", (int)d->bytes_per_sector);
666 d->sectors_per_cluster = (i64)de_getbyte_p(&pos);
667 de_dbg(c, "sectors per cluster: %d", (int)d->sectors_per_cluster);
668 d->num_rsvd_sectors = de_getu16le_p(&pos);
670 de_dbg(c, "reserved sectors: %d", (int)d->num_rsvd_sectors);
671 if(d->num_rsvd_sectors==0) {
672 // This happens on some Atari ST disks. Don't know why.
673 d->num_rsvd_sectors = 1;
676 d->num_fats = (i64)de_getbyte_p(&pos);
677 de_dbg(c, "number of FATs: %d", (int)d->num_fats);
679 // This is expected to be 0 for FAT32.
680 d->max_root_dir_entries16 = de_getu16le_p(&pos);
681 de_dbg(c, "max number of root dir entries (if FAT12/16): %d", (int)d->max_root_dir_entries16);
683 num_sectors16 = de_getu16le_p(&pos);
684 de_dbg(c, "number of sectors (old 16-bit field): %d", (int)num_sectors16);
685 b = de_getbyte_p(&pos);
686 de_dbg(c, "media descriptor: 0x%02x", (UI)b);
687 num_sectors_per_fat16 = de_getu16le_p(&pos);
688 de_dbg(c, "sectors per FAT (if FAT12/16): %d", (int)num_sectors_per_fat16);
690 num_sectors_per_track = de_getu16le_p(&pos);
691 de_dbg(c, "sectors per track: %d", (int)num_sectors_per_track);
692 num_heads = de_getu16le_p(&pos);
693 de_dbg(c, "number of heads: %d", (int)num_heads);
695 pos = pos1+0x1fe;
696 de_read(cksum_sig, pos, 2);
697 de_dbg(c, "boot sector signature: 0x%02x 0x%02x", (UI)cksum_sig[0], (UI)cksum_sig[1]);
699 do_atarist_boot_checksum(c, d, pos1);
700 if(d->has_atarist_checksum) {
701 d->platform = FAT_PLATFORM_ATARIST;
702 de_dbg(c, "[This is probably a bootable Atari ST disk.]");
704 else if(cksum_sig[0]==0x55 && cksum_sig[1]==0xaa) {
705 d->platform = FAT_PLATFORM_PC;
706 de_dbg(c, "[Disk has PC-compatible boot code.]");
709 if(num_sectors16==0) {
710 num_sectors32 = de_getu32le(pos1+32);
711 de_dbg(c, "num sectors (new 32-bit field): %"I64_FMT, num_sectors32);
714 if(num_sectors_per_fat16==0) {
715 num_sectors_per_fat32 = de_getu32le(pos1+36);
716 de_dbg(c, "sectors per FAT (if FAT32): %u", (UI)num_sectors_per_fat32);
719 if(num_sectors_per_fat16==0) {
720 d->num_sectors_per_fat = num_sectors_per_fat32;
722 else {
723 d->num_sectors_per_fat = num_sectors_per_fat16;
726 if(num_sectors16==0) {
727 d->num_sectors = num_sectors32;
729 else {
730 d->num_sectors = num_sectors16;
733 if(d->sectors_per_cluster<1) goto done;
734 if(d->bytes_per_sector<32) goto done;
735 d->bytes_per_cluster = d->bytes_per_sector * d->sectors_per_cluster;
736 d->root_dir_sector = d->num_rsvd_sectors + d->num_sectors_per_fat * d->num_fats;
737 de_dbg(c, "root dir pos (calculated): %"I64_FMT" (sector %"I64_FMT")",
738 sectornum_to_offset(c, d, d->root_dir_sector), d->root_dir_sector);
740 // num_root_dir_sectors is expected to be 0 for FAT32.
741 num_root_dir_sectors = (d->max_root_dir_entries16*32 + d->bytes_per_sector - 1)/d->bytes_per_sector;
743 num_data_region_sectors = d->num_sectors - (d->root_dir_sector + num_root_dir_sectors);
744 if(num_data_region_sectors<0) goto done;
745 d->num_data_region_clusters = num_data_region_sectors / d->sectors_per_cluster;
746 de_dbg(c, "num clusters (calculated): %"I64_FMT, d->num_data_region_clusters);
748 d->data_region_sector = d->root_dir_sector + num_root_dir_sectors;
749 d->data_region_pos = d->data_region_sector * d->bytes_per_sector;
750 de_dbg(c, "data region pos (calculated): %"I64_FMT" (sector %"I64_FMT")", d->data_region_pos,
751 d->data_region_sector);
753 // (The first cluster is numbered "2".)
754 d->num_cluster_identifiers = d->num_data_region_clusters + 2;
756 if(d->num_data_region_clusters < 4085) {
757 d->num_fat_bits = 12;
759 else if(d->num_data_region_clusters < 65525) {
760 d->num_fat_bits = 16;
762 else {
763 d->num_fat_bits = 32;
766 de_dbg(c, "bits per cluster id: %u", (UI)d->num_fat_bits);
768 retval = 1;
770 done:
771 if(!retval) {
772 de_err(c, "Invalid or unsupported boot sector");
774 de_dbg_indent(c, -1);
775 return retval;
778 static int do_read_fat(deark *c, lctx *d)
780 i64 pos1;
781 i64 pos;
782 i64 fat_idx_to_read = 0;
783 int retval = 0;
784 i64 i;
786 pos1 = sectornum_to_offset(c, d, d->num_rsvd_sectors + fat_idx_to_read*d->num_sectors_per_fat);
787 de_dbg(c, "FAT#%d at %"I64_FMT, (int)fat_idx_to_read, pos1);
788 de_dbg_indent(c, 1);
790 if(d->num_cluster_identifiers > (i64)(DE_MAX_SANE_OBJECT_SIZE/sizeof(u32))) goto done;
791 d->num_fat_entries = d->num_cluster_identifiers;
792 d->fat_nextcluster = de_mallocarray(c, d->num_fat_entries, sizeof(u32));
793 d->cluster_used_flags = de_malloc(c, d->num_fat_entries);
795 pos = pos1;
796 if(d->num_fat_bits==12) {
797 for(i=0; i<d->num_fat_entries+1; i+=2) {
798 UI val;
800 val = (UI)dbuf_getint_ext(c->infile, pos, 3, 1, 0);
801 pos += 3;
802 if(i < d->num_fat_entries) {
803 d->fat_nextcluster[i] = (u32)(val & 0xfff);
805 if(i+1 < d->num_fat_entries) {
806 d->fat_nextcluster[i+1] = (u32)(val >> 12);
810 else if(d->num_fat_bits==16) {
811 for(i=0; i<d->num_fat_entries; i++) {
812 d->fat_nextcluster[i] = (u32)de_getu16le_p(&pos);
815 else {
816 de_err(c, "This type of FAT is not supported");
817 goto done;
820 if(c->debug_level>=3) {
821 for(i=0; i<d->num_fat_entries; i++) {
822 de_dbg3(c, "fat[%"I64_FMT"]: %"I64_FMT, i, (i64)d->fat_nextcluster[i]);
826 retval = 1;
827 done:
828 de_dbg_indent(c, -1);
829 return retval;
832 static void de_run_fat(deark *c, de_module_params *mparams)
834 lctx *d = NULL;
835 const char *s;
836 int got_root_dir = 0;
837 de_encoding default_encoding = DE_ENCODING_CP437_G;
839 if(mparams) {
840 // out_params.flags:
841 // 0x1 = No valid FAT directory structure found
842 mparams->out_params.flags = 0;
845 d = de_malloc(c, sizeof(lctx));
847 d->opt_check_rootdir = de_get_ext_option_bool(c, "fat:checkroot", 1);
848 s = de_get_ext_option(c, "fat:subfmt");
849 if(s) {
850 if(!de_strcmp(s, "pc")) {
851 d->subfmt_req = FAT_SUBFMT_PC;
853 else if(!de_strcmp(s, "atarist")) {
854 d->subfmt_req = FAT_SUBFMT_ATARIST;
857 d->subfmt = d->subfmt_req;
858 if(d->subfmt==FAT_SUBFMT_ATARIST) {
859 default_encoding = DE_ENCODING_ATARIST;
862 d->input_encoding = de_get_input_encoding(c, mparams, default_encoding);
864 // TODO: Detect MBR?
865 if(!do_boot_sector(c, d, 0)) goto done;
866 if(d->num_fat_bits==0) goto done;
868 switch(d->platform) {
869 case FAT_PLATFORM_PC:
870 de_declare_fmtf(c, "FAT%d - PC", d->num_fat_bits);
871 break;
872 case FAT_PLATFORM_ATARIST:
873 de_declare_fmtf(c, "FAT%d - Atari ST", d->num_fat_bits);
874 break;
875 default:
876 de_declare_fmtf(c, "FAT%d - Unknown platform", d->num_fat_bits);
877 break;
880 if(!do_read_fat(c, d)) goto done;
882 if(d->opt_check_rootdir) {
883 if(!root_dir_seems_valid(c, d)) {
884 de_warn(c, "This file does not appear to contain a valid FAT "
885 "directory structure. (\"-opt fat:checkroot=0\" to try anyway)");
886 goto done;
890 d->curpath = de_strarray_create(c, MAX_NESTING_LEVEL+10);
891 got_root_dir = 1;
892 do_root_dir(c, d);
894 done:
895 if(!got_root_dir) {
896 // Inform the parent module that we failed to do anything.
897 if(mparams) {
898 mparams->out_params.flags |= 0x1;
902 if(d) {
903 de_free(c, d->fat_nextcluster);
904 de_free(c, d->cluster_used_flags);
905 if(d->curpath) de_strarray_destroy(d->curpath);
906 de_free(c, d);
910 static int de_identify_fat(deark *c)
912 i64 bytes_per_sector;
913 i64 max_root_dir_entries;
914 i64 num_rsvd_sectors;
915 int confidence = 0;
916 int has_pc_sig;
917 int has_ext;
918 u8 sectors_per_cluster;
919 u8 num_fats;
920 u8 media_descr;
921 u8 b[32];
923 // TODO: This needs a lot of work.
924 // It's good enough for most FAT12 floppy disk images.
926 de_read(b, 0, sizeof(b));
927 bytes_per_sector = de_getu16le_direct(&b[11]);
928 sectors_per_cluster = b[13];
929 num_rsvd_sectors = de_getu16le_direct(&b[14]);
930 num_fats = b[16];
931 max_root_dir_entries = de_getu16le_direct(&b[17]);
932 media_descr = b[21];
934 if(bytes_per_sector!=512) return 0;
935 switch(sectors_per_cluster) {
936 case 1: case 2: case 4: case 8:
937 case 16: case 32: case 64: case 128:
938 break;
939 default:
940 return 0;
942 if(num_fats!=1 && num_fats!=2) return 0;
943 if(media_descr<0xe5 && media_descr!=0) return 0; // Media descriptor
945 confidence = 1;
946 if(b[0]==0xeb && b[2]==0x90) confidence += 2;
947 else if(b[0]==0xe9) confidence += 1;
948 else if(b[0]==0x60) confidence += 1;
949 has_pc_sig = (de_getu16be(510)==0x55aa);
950 if(has_pc_sig) confidence += 2;
951 if(num_fats==2) confidence += 1;
952 if(media_descr>=0xe5) confidence += 1;
953 if(num_rsvd_sectors==1) confidence += 1;
954 if(max_root_dir_entries==112 || max_root_dir_entries==224) confidence += 2;
956 has_ext = de_input_file_has_ext(c, "ima") ||
957 de_input_file_has_ext(c, "img") ||
958 de_input_file_has_ext(c, "st");
960 if(confidence>=6) return (has_ext?100:80);
961 else if(confidence>=4) return (has_ext?60:9);
962 else return 0;
965 static void de_help_fat(deark *c)
967 de_msg(c, "-opt fat:checkroot=0 : Read the directory structure, even if it "
968 "seems invalid");
971 void de_module_fat(deark *c, struct deark_module_info *mi)
973 mi->id = "fat";
974 mi->desc = "FAT disk image";
975 mi->run_fn = de_run_fat;
976 mi->identify_fn = de_identify_fat;
977 mi->help_fn = de_help_fat;
980 ///////////////////////// LoadDskF/SaveDskF format (OS/2-centric)
982 // We barely support this format, but if it's uncompressed, we'll try to skip
983 // past the header, and pretend it's FAT.
985 struct skf_ctx {
986 int new_fmt;
987 i64 hdr_size;
990 static void loaddskf_decode_as_fat(deark *c, struct skf_ctx *d)
992 i64 dlen = c->infile->len - d->hdr_size;
994 de_dbg(c, "decoding as FAT, pos=%"I64_FMT", len=%"I64_FMT, d->hdr_size, dlen);
995 if(dlen<=0) goto done;
997 de_dbg_indent(c, 1);
998 de_run_module_by_id_on_slice(c, "fat", NULL, c->infile, d->hdr_size, dlen);
999 de_dbg_indent(c, -1);
1000 done:
1004 static int loaddskf_read_header(deark *c, struct skf_ctx *d)
1006 int retval = 0;
1008 d->hdr_size = de_getu16le(38);
1009 de_dbg(c, "header size: %"I64_FMT, d->hdr_size);
1010 if((UI)de_getu16be(d->hdr_size + 510) != 0x55aa) {
1011 goto done;
1013 retval = 1;
1015 done:
1016 if(!retval) {
1017 de_err(c, "Failed to parse LoadDskF file");
1019 return retval;
1022 static void de_run_loaddskf(deark *c, de_module_params *mparams)
1024 struct skf_ctx *d = NULL;
1025 UI sig;
1027 d = de_malloc(c, sizeof(struct skf_ctx));
1028 sig = (UI)de_getu16be(0);
1029 switch(sig) {
1030 case 0xaa58:
1031 break;
1032 case 0xaa59:
1033 d->new_fmt = 1;
1034 break;
1035 case 0xaa5a:
1036 de_err(c, "Compressed LoadDskF files are not supported");
1037 goto done;
1038 default:
1039 de_err(c, "Not a LoadDskF file");
1040 goto done;
1043 if(!loaddskf_read_header(c, d)) goto done;
1044 loaddskf_decode_as_fat(c, d);
1046 done:
1047 de_free(c, d);
1050 static int de_identify_loaddskf(deark *c)
1052 UI sig;
1054 sig = (UI)de_getu16be(0);
1055 if(sig==0xaa58 || sig==0xaa59 || sig==0xaa5a) {
1056 if((UI)de_getu16be(2)==0xf000) {
1057 return 100;
1059 return 9;
1061 return 0;
1064 void de_module_loaddskf(deark *c, struct deark_module_info *mi)
1066 mi->id = "loaddskf";
1067 mi->desc = "LoadDskF/SaveDskF disk image";
1068 mi->run_fn = de_run_loaddskf;
1069 mi->identify_fn = de_identify_loaddskf;
1072 //---------------------- "EA DATA. SF"
1074 struct eadata_ctx {
1075 de_encoding input_encoding;
1076 i64 bytes_per_cluster;
1079 static int eadata_is_ea_sector_at_offset(deark *c, struct eadata_ctx *d, i64 pos, int strictmode)
1081 u8 b;
1083 if((UI)de_getu16be(pos)!=0x4541) return 0;
1084 if(strictmode) {
1085 if((UI)de_getu32be(pos+4)!=0) return 0;
1086 b = de_getbyte(pos+8);
1087 if(b<32) return 0;
1088 if((UI)de_getu32be(pos+22)!=0) return 0;
1090 return 1;
1093 static void eadata_do_ea_data(deark *c, struct eadata_ctx *d, i64 pos1, i64 *pbytes_consumed)
1095 i64 pos = pos1;
1096 i64 ealen;
1097 int saved_indent_level;
1099 *pbytes_consumed = 0;
1100 de_dbg_indent_save(c, &saved_indent_level);
1101 de_dbg(c, "EA data at %"I64_FMT, pos1);
1102 de_dbg_indent(c, 1);
1104 ealen = de_getu16le_p(&pos);
1105 *pbytes_consumed = ealen;
1106 de_dbg(c, "data len: %"I64_FMT, ealen);
1108 de_dbg_hexdump(c, c->infile, pos, ealen-2, 256, NULL, 0x1);
1110 de_dbg_indent_restore(c, saved_indent_level);
1113 static void eadata_do_ea_sector_by_offset(deark *c, struct eadata_ctx *d, i64 pos1,
1114 i64 *pbytes_consumed1)
1116 i64 n;
1117 i64 pos;
1118 i64 bytes_consumed2 = 0;
1119 de_ucstring *fn = NULL;
1120 int saved_indent_level;
1122 de_dbg_indent_save(c, &saved_indent_level);
1124 if(!eadata_is_ea_sector_at_offset(c, d, pos1, 0)) {
1125 de_err(c, "EA sector not found at %"I64_FMT, pos1);
1126 goto done;
1129 de_dbg(c, "EA sector at %"I64_FMT, pos1);
1130 de_dbg_indent(c, 1);
1131 pos = pos1+2;
1132 n = de_getu16le_p(&pos);
1133 de_dbg(c, "sector number (consistency check): %u", (UI)n);
1135 pos += 4;
1137 fn = ucstring_create(c);
1138 dbuf_read_to_ucstring(c->infile, pos, 12, fn, DE_CONVFLAG_STOP_AT_NUL, d->input_encoding);
1139 de_dbg(c, "file name: \"%s\"", ucstring_getpsz_d(fn));
1140 pos += 12;
1142 pos += 2;
1143 pos += 4;
1145 eadata_do_ea_data(c, d, pos, &bytes_consumed2);
1146 pos += bytes_consumed2;
1148 if(pbytes_consumed1) {
1149 *pbytes_consumed1 = pos - pos1;
1152 done:
1153 ucstring_destroy(fn);
1154 de_dbg_indent_restore(c, saved_indent_level);
1157 static int eadata_id_to_offset(deark *c, struct eadata_ctx *d, UI id, i64 *poffset)
1159 int retval = 0;
1160 UI a_idx;
1161 UI a_val;
1162 UI b_val;
1163 i64 cluster_num;
1165 *poffset = 0;
1167 a_idx = id>>7;
1168 if(a_idx>=240) goto done;
1169 a_val = (UI)de_getu16le(32+2*(i64)a_idx);
1170 b_val = (UI)de_getu16le(512+2*(i64)id);
1171 if(b_val==0xffff) goto done;
1173 cluster_num = (i64)b_val + (i64)a_val;
1174 *poffset = d->bytes_per_cluster * cluster_num;
1176 if(eadata_is_ea_sector_at_offset(c, d, *poffset, 0)) {
1177 retval = 1;
1180 done:
1181 return retval;
1184 static void eadata_scan_file(deark *c, struct eadata_ctx *d)
1186 i64 pos = 1024;
1188 while(pos < c->infile->len) {
1189 if(eadata_is_ea_sector_at_offset(c, d, pos, 1)) {
1190 i64 bytes_consumed;
1192 eadata_do_ea_sector_by_offset(c, d, pos, &bytes_consumed);
1194 if(bytes_consumed<1) bytes_consumed = 1;
1195 pos = de_pad_to_n(pos+bytes_consumed, 512);
1197 else {
1198 pos += 512;
1203 static void de_run_eadata(deark *c, de_module_params *mparams)
1205 int ret;
1206 UI ea_id = 0;
1207 i64 pos;
1208 const char *s;
1210 de_declare_fmt(c, "OS/2 extended attributes data");
1212 struct eadata_ctx *d = de_malloc(c, sizeof(struct eadata_ctx));
1213 s = de_get_ext_option(c, "ea_data:handle");
1214 if(s) {
1215 ea_id = (UI)de_atoi(s);
1217 d->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_CP437);
1218 d->bytes_per_cluster = 512;
1220 if(ea_id==0) {
1221 eadata_scan_file(c, d);
1223 else {
1224 ret = eadata_id_to_offset(c, d, ea_id, &pos);
1225 if(!ret) goto done;
1226 eadata_do_ea_sector_by_offset(c, d, pos, NULL);
1229 done:
1230 de_free(c, d);
1233 static int de_identify_eadata(deark *c)
1235 if(de_getu16be(0)!=0x4544) return 0;
1236 if(de_input_file_has_ext(c, " sf")) return 100;
1237 if(dbuf_is_all_zeroes(c->infile, 2, 30)) {
1238 return 20;
1240 return 0;
1243 static void de_help_eadata(deark *c)
1245 de_msg(c, "-opt ea_data:handle=<n> : Decode only EA handle/pointer <n>");
1248 void de_module_ea_data(deark *c, struct deark_module_info *mi)
1250 mi->id = "ea_data";
1251 mi->desc = "EA DATA (OS/2 extended attributes)";
1252 mi->run_fn = de_run_eadata;
1253 mi->identify_fn = de_identify_eadata;
1254 mi->help_fn = de_help_eadata;