1 // This file is part of Deark.
2 // Copyright (C) 2020 Jason Summers
3 // See the file COPYING for terms of use.
6 // LoadDskF/SaveDskF/SKF OS/2 disk image
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_fat
);
11 DE_DECLARE_MODULE(de_module_loaddskf
);
13 #define MAX_NESTING_LEVEL 16
23 i64 fn_base_len
, fn_ext_len
;
26 de_ucstring
*short_fn
;
28 struct de_timestamp mod_time
;
37 i64 pending_lfn_bytesused
;
38 #define LFN_CHARS_PER_FRAGMENT 13
39 #define LFN_MAX_FRAGMENTS 20
40 u8 pending_lfn
[LFN_CHARS_PER_FRAGMENT
*2*LFN_MAX_FRAGMENTS
];
43 typedef struct localctx_struct
{
44 de_encoding input_encoding
;
45 u8 opt_check_root_dir
;
48 // TODO: Decide how to handle different variants of FAT.
49 #define FAT_SUBFMT_UNKNOWN 0
50 #define FAT_SUBFMT_PC 1
51 #define FAT_SUBFMT_ATARIST 2
54 #define FAT_PLATFORM_UNKNOWN 0
55 #define FAT_PLATFORM_PC 1
56 #define FAT_PLATFORM_ATARIST 2
59 u8 num_fat_bits
; // 12, 16, or 32. 0 if unknown.
60 u8 has_atarist_checksum
;
62 i64 sectors_per_cluster
;
63 i64 bytes_per_cluster
;
65 i64 data_region_sector
;
67 i64 num_data_region_clusters
;
70 i64 num_sectors_per_fat
;
71 i64 max_root_dir_entries16
;
73 i64 num_cluster_identifiers
;
74 struct de_strarray
*curpath
;
77 u32
*fat_nextcluster
; // array[num_fat_entries]
78 u8
*cluster_used_flags
; // array[num_fat_entries]
79 u8
*cluster_used_flags_saved
; // array[num_fat_entries] (or NULL)
80 dbuf
*ea_data
; // NULL if not available
83 static void fat_save_cluster_use_flags(deark
*c
, lctx
*d
)
85 if(!d
->cluster_used_flags
) return;
86 if(!d
->cluster_used_flags_saved
) {
87 d
->cluster_used_flags_saved
= de_malloc(c
, d
->num_fat_entries
);
89 de_memcpy(d
->cluster_used_flags_saved
, d
->cluster_used_flags
,
90 (size_t)d
->num_fat_entries
);
93 static void fat_restore_cluster_use_flags(deark
*c
, lctx
*d
)
95 if(!d
->cluster_used_flags_saved
|| !d
->cluster_used_flags
) return;
96 de_memcpy(d
->cluster_used_flags
, d
->cluster_used_flags_saved
,
97 (size_t)d
->num_fat_entries
);
100 static i64
sectornum_to_offset(deark
*c
, lctx
*d
, i64 secnum
)
102 return secnum
* d
->bytes_per_sector
;
105 static int is_good_clusternum(lctx
*d
, i64 cnum
)
108 if(cnum
>= d
->num_cluster_identifiers
) return 0;
112 static i64
clusternum_to_offset(deark
*c
, lctx
*d
, i64 cnum
)
114 return d
->data_region_pos
+ (cnum
-2) * d
->bytes_per_cluster
;
117 static void dbg_timestamp(deark
*c
, struct de_timestamp
*ts
, const char *name
)
119 char timestamp_buf
[64];
121 de_timestamp_to_string(ts
, timestamp_buf
, sizeof(timestamp_buf
), 0);
122 de_dbg(c
, "%s: %s", name
, timestamp_buf
);
125 static i64
get_unpadded_len(const u8
*s
, i64 len1
)
130 // Stop at NUL, I guess.
131 for(i
=0; i
<len1
; i
++) {
138 for(i
=len
; i
>0; i
--) {
146 static int extract_file_lowlevel(deark
*c
, lctx
*d
, struct member_data
*md
, dbuf
*outf
)
150 i64 nbytes_remaining
;
152 cur_cluster
= md
->first_cluster
;
154 nbytes_remaining
= 0;
157 nbytes_remaining
= md
->filesize
;
164 if(nbytes_remaining
<= 0) break;
165 if(!is_good_clusternum(d
, cur_cluster
)) break;
166 if(d
->cluster_used_flags
[cur_cluster
]) break;
167 d
->cluster_used_flags
[cur_cluster
] = 1;
168 if(c
->debug_level
>=3) de_dbg3(c
, "cluster: %d", (int)cur_cluster
);
169 dpos
= clusternum_to_offset(c
, d
, cur_cluster
);
170 nbytes_to_copy
= de_min_int(d
->bytes_per_cluster
, nbytes_remaining
);
171 dbuf_copy(c
->infile
, dpos
, nbytes_to_copy
, outf
);
172 nbytes_remaining
-= nbytes_to_copy
;
173 cur_cluster
= (i64
)d
->fat_nextcluster
[cur_cluster
];
176 if(nbytes_remaining
>0) {
185 static void do_extract_file(deark
*c
, lctx
*d
, struct member_data
*md
)
189 de_ucstring
*fullfn
= NULL
;
192 if(md
->filesize
> d
->num_data_region_clusters
* d
->bytes_per_cluster
) {
193 de_err(c
, "%s: Bad file size", ucstring_getpsz_d(md
->short_fn
));
198 fi
= de_finfo_create(c
);
199 fullfn
= ucstring_create(c
);
200 de_strarray_make_path(d
->curpath
, fullfn
, DE_MPFLAG_NOTRAILINGSLASH
);
201 de_finfo_set_name_from_ucstring(c
, fi
, fullfn
, DE_SNFLAG_FULLPATH
);
202 fi
->original_filename_flag
= 1;
204 fi
->is_directory
= 1;
206 else if(md
->is_volume_label
) {
207 fi
->is_volume_label
= 1;
209 if(md
->mod_time
.is_valid
) {
210 fi
->timestamp
[DE_TIMESTAMPIDX_MODIFY
] = md
->mod_time
;
213 outf
= dbuf_create_output_file(c
, NULL
, fi
, 0);
215 if(!extract_file_lowlevel(c
, d
, md
, outf
)) {
216 de_err(c
, "%s: File extraction failed", ucstring_getpsz_d(md
->short_fn
));
222 ucstring_destroy(fullfn
);
223 de_finfo_destroy(c
, fi
);
226 static void do_subdir(deark
*c
, lctx
*d
, struct member_data
*md
, int nesting_level
);
228 static void do_vfat_entry(deark
*c
, lctx
*d
, struct dirctx
*dctx
, i64 pos1
, u8 seq_num_raw
)
232 int is_first_entry
= 0;
235 if(seq_num_raw
==0xe5) {
236 de_dbg(c
, "[deleted VFAT entry]");
241 de_dbg(c
, "seq number: 0x%02x", (UI
)seq_num_raw
);
243 seq_num
= seq_num_raw
& 0xbf;
245 if(seq_num
<1 || seq_num
>LFN_MAX_FRAGMENTS
) {
246 de_warn(c
, "Bad VFAT sequence number (%u)", (UI
)seq_num
);
251 if(seq_num_raw
& 0x40) {
253 de_zeromem(dctx
->pending_lfn
, sizeof(dctx
->pending_lfn
));
254 dctx
->first_seq_num
= seq_num
;
258 if(!dctx
->lfn_valid
|| (seq_num
+1 != dctx
->prev_seq_num
)) {
259 de_dbg(c
, "[stray VFAT entry]");
264 dctx
->prev_seq_num
= seq_num
;
266 startpos_in_lfn
= LFN_CHARS_PER_FRAGMENT
*2*((i64
)seq_num
-1);
268 de_read(&dctx
->pending_lfn
[startpos_in_lfn
+ 0], pos1
+ 1, 10); // 5 chars
269 fn_cksum
= de_getbyte(pos1
+13);
270 de_read(&dctx
->pending_lfn
[startpos_in_lfn
+10], pos1
+14, 12); // 6 more chars
271 de_read(&dctx
->pending_lfn
[startpos_in_lfn
+22], pos1
+28, 4); // 2 more chars
272 de_dbg(c
, "filename checksum (reported): 0x%02x", (UI
)fn_cksum
);
273 if(!is_first_entry
) {
274 if(fn_cksum
!= dctx
->name_cksum
) {
275 de_dbg(c
, "[inconsistent VFAT checksums]");
279 dctx
->name_cksum
= fn_cksum
;
285 static void vfat_cksum_update(const u8
*buf
, size_t buflen
, u8
*cksum
)
289 for(i
=0; i
<buflen
; i
++) {
290 *cksum
= (((*cksum
) & 1) << 7) + ((*cksum
) >> 1) + buf
[i
];
294 // If the long file name seems valid, sets it in md->long_fn for later use.
295 static void handle_vfat_lfn(deark
*c
, lctx
*d
, struct dirctx
*dctx
,
296 struct member_data
*md
)
299 i64 max_len_in_ucs2_chars
;
300 i64 len_in_ucs2_chars
= 0;
303 if(!dctx
->lfn_valid
) goto done
;
304 if(dctx
->prev_seq_num
!= 1) goto done
;
305 if(md
->long_fn
) goto done
;
307 vfat_cksum_update(md
->fn_base
, 8, &cksum_calc
);
308 vfat_cksum_update(md
->fn_ext
, 3, &cksum_calc
);
309 de_dbg(c
, "filename checksum (calculated): 0x%02x", (UI
)cksum_calc
);
310 if(cksum_calc
!= dctx
->name_cksum
) goto done
;
312 max_len_in_ucs2_chars
= LFN_CHARS_PER_FRAGMENT
* (i64
)dctx
->first_seq_num
;
313 if(max_len_in_ucs2_chars
> (i64
)(sizeof(dctx
->pending_lfn
)/2)) goto done
;
314 for(i
=0; i
<max_len_in_ucs2_chars
; i
++) {
315 if(dctx
->pending_lfn
[i
*2]==0x00 && dctx
->pending_lfn
[i
*2+1]==0x00) break;
316 if(dctx
->pending_lfn
[i
*2]==0xff && dctx
->pending_lfn
[i
*2+1]==0xff) break;
320 md
->long_fn
= ucstring_create(c
);
321 ucstring_append_bytes(md
->long_fn
, dctx
->pending_lfn
, len_in_ucs2_chars
*2,
322 0, DE_ENCODING_UTF16LE
);
323 de_dbg(c
, "long filename: \"%s\"", ucstring_getpsz_d(md
->long_fn
));
329 // Reads from md->fn_base* and md->fn_ext*, writes to md->short_fn
330 static void decode_short_filename(deark
*c
, lctx
*d
, struct member_data
*md
)
332 if(md
->fn_base_len
>0) {
333 ucstring_append_bytes(md
->short_fn
, md
->fn_base
, md
->fn_base_len
, 0, d
->input_encoding
);
336 ucstring_append_char(md
->short_fn
, '_');
338 if(md
->fn_ext_len
>0) {
339 ucstring_append_char(md
->short_fn
, '.');
340 ucstring_append_bytes(md
->short_fn
, md
->fn_ext
, md
->fn_ext_len
, 0, d
->input_encoding
);
344 static void decode_volume_label_name(deark
*c
, lctx
*d
, struct member_data
*md
)
346 if(md
->fn_ext_len
>0) {
347 ucstring_append_bytes(md
->short_fn
, md
->fn_base
, 8, 0, d
->input_encoding
);
348 ucstring_append_bytes(md
->short_fn
, md
->fn_ext
, md
->fn_ext_len
, 0, d
->input_encoding
);
351 ucstring_append_bytes(md
->short_fn
, md
->fn_base
, md
->fn_base_len
, 0, d
->input_encoding
);
355 // md is that of the file whose EA data is being requested.
356 // Uses md->ea_handle.
357 static void do_fat_eadata_item(deark
*c
, lctx
*d
, struct member_data
*md
)
359 de_module_params
*mparams
= NULL
;
361 if(!d
->ea_data
) goto done
;
362 if(md
->ea_handle
==0) goto done
;
363 mparams
= de_malloc(c
, sizeof(de_module_params
));
364 mparams
->in_params
.input_encoding
= d
->input_encoding
;
365 mparams
->in_params
.flags
= 0x1;
366 mparams
->in_params
.uint1
= (u32
)md
->ea_handle
;
367 de_dbg(c
, "reading OS/2 extended attributes");
369 // TODO: Better filenames for icons that may be extracted.
370 // The ea_data module will use the filename contained in the EA data stream,
371 // but it would be better to use the "fullfn" that will be constructed in
372 // do_extract_file(). Some refactoring will be needed.
373 de_run_module_by_id_on_slice(c
, "ea_data", mparams
, d
->ea_data
, 0, d
->ea_data
->len
);
374 de_dbg_indent(c
, -1);
380 // md is that of the "EA DATA" file itself.
381 static void do_fat_eadata(deark
*c
, lctx
*d
, struct member_data
*md
)
385 if(d
->ea_data
) goto done
;
386 d
->ea_data
= dbuf_create_membuf(c
, 0, 0);
387 dbuf_set_length_limit(d
->ea_data
, c
->infile
->len
);
388 ret
= extract_file_lowlevel(c
, d
, md
, d
->ea_data
);
390 dbuf_close(d
->ea_data
);
394 de_dbg(c
, "[read EA data, len=%"I64_FMT
"]", d
->ea_data
->len
);
399 // Returns 0 if this is the end-of-directory marker.
400 static int do_dir_entry(deark
*c
, lctx
*d
, struct dirctx
*dctx
,
401 i64 pos1
, int nesting_level
, int scanmode
)
407 int need_curpath_pop
= 0;
408 de_ucstring
*descr
= NULL
;
409 struct member_data
*md
= NULL
;
411 md
= de_malloc(c
, sizeof(struct member_data
));
413 de_dbg(c
, "dir entry at %"I64_FMT
, pos1
);
416 de_read(md
->fn_base
, pos1
+0, 8);
417 de_read(md
->fn_ext
, pos1
+8, 3);
418 firstbyte
= md
->fn_base
[0];
420 if(firstbyte
==0x00) {
421 de_dbg(c
, "[end of dir marker]");
426 md
->attribs
= (UI
)de_getbyte(pos1
+11);
427 descr
= ucstring_create(c
);
428 de_describe_dos_attribs(c
, md
->attribs
, descr
, 0x1);
429 de_dbg(c
, "attribs: 0x%02x (%s)", md
->attribs
, ucstring_getpsz_d(descr
));
430 if((md
->attribs
& 0x3f)==0x0f) {
431 do_vfat_entry(c
, d
, dctx
, pos1
, firstbyte
);
435 if((md
->attribs
& 0x18) == 0x00) {
438 else if((md
->attribs
& 0x18) == 0x08) {
439 md
->is_volume_label
= 1;
441 else if((md
->attribs
& 0x18) == 0x10) {
445 de_warn(c
, "Invalid directory entry");
451 if(dctx
->lfn_valid
) {
452 handle_vfat_lfn(c
, d
, dctx
, md
);
456 if(firstbyte
==0xe5) {
457 de_dbg(c
, "[deleted]");
459 md
->fn_base
[0] = '?';
461 else if(firstbyte
==0x05) {
462 md
->fn_base
[0] = 0xe5;
465 md
->fn_base_len
= get_unpadded_len(md
->fn_base
, 8);
466 md
->fn_ext_len
= get_unpadded_len(md
->fn_ext
, 3);
468 if(md
->is_subdir
&& md
->fn_base_len
>=1 && md
->fn_base
[0]=='.') {
469 // special "." and ".." dirs
473 md
->short_fn
= ucstring_create(c
);
474 if(md
->is_volume_label
) {
475 decode_volume_label_name(c
, d
, md
);
478 decode_short_filename(c
, d
, md
);
481 de_dbg(c
, "filename: \"%s\"", ucstring_getpsz_d(md
->short_fn
));
483 if(ucstring_isnonempty(md
->long_fn
)) {
484 de_strarray_push(d
->curpath
, md
->long_fn
);
487 de_strarray_push(d
->curpath
, md
->short_fn
);
489 need_curpath_pop
= 1;
491 if(!scanmode
&& d
->num_fat_bits
<32) {
492 md
->ea_handle
= (UI
)de_getu16le(pos1
+20);
494 de_dbg(c
, "EA handle (if OS/2): %u", md
->ea_handle
);
498 dtime
= de_getu16le(pos1
+22);
499 ddate
= de_getu16le(pos1
+24);
500 de_dos_datetime_to_timestamp(&md
->mod_time
, ddate
, dtime
);
501 dbg_timestamp(c
, &md
->mod_time
, "mod time");
503 // TODO: This is wrong for FAT32.
504 md
->first_cluster
= de_getu16le(pos1
+26);
505 de_dbg(c
, "first cluster: %"I64_FMT
, md
->first_cluster
);
507 md
->filesize
= de_getu32le(pos1
+28);
508 de_dbg(c
, "file size: %"I64_FMT
, md
->filesize
);
509 if(md
->is_volume_label
) md
->filesize
= 0;
511 // (Done reading dir entry)
513 if(is_deleted
) goto done
;
516 if(!md
->is_subdir
&& !md
->is_special
&& (md
->attribs
&0x04) &&
517 md
->fn_base_len
==7 && md
->fn_ext_len
==3 &&
518 !de_memcmp(md
->fn_base
, "EA DATA", 7) &&
519 !de_memcmp(md
->fn_ext
, " SF", 3) )
521 do_fat_eadata(c
, d
, md
);
524 de_dbg2(c
, "[scan mode - not extracting]");
528 if(md
->ea_handle
!=0 && d
->ea_data
) {
529 do_fat_eadata_item(c
, d
, md
);
532 if(!md
->is_subdir
&& !md
->is_special
) {
533 do_extract_file(c
, d
, md
);
535 else if(md
->is_subdir
&& !md
->is_special
) {
536 do_extract_file(c
, d
, md
);
537 do_subdir(c
, d
, md
, nesting_level
+1);
541 ucstring_destroy(descr
);
543 ucstring_destroy(md
->short_fn
);
544 ucstring_destroy(md
->long_fn
);
546 if(need_curpath_pop
) {
547 de_strarray_pop(d
->curpath
);
549 de_dbg_indent(c
, -1);
553 // Process a contiguous block of directory entries
554 // Returns 0 if an end-of-dir marker was found.
555 static int do_dir_entries(deark
*c
, lctx
*d
, struct dirctx
*dctx
,
556 i64 pos1
, i64 len
, int nesting_level
, int scanmode
)
562 num_entries
= len
/32;
563 de_dbg(c
, "num entries: %"I64_FMT
, num_entries
);
565 for(i
=0; i
<num_entries
; i
++) {
566 if(!do_dir_entry(c
, d
, dctx
, pos1
+32*i
, nesting_level
, scanmode
)) {
569 dctx
->dir_entry_count
++;
577 static void destroy_dirctx(deark
*c
, struct dirctx
*dctx
)
583 static void do_subdir(deark
*c
, lctx
*d
, struct member_data
*md
, int nesting_level
)
585 int saved_indent_level
;
588 struct dirctx
*dctx
= NULL
;
590 de_dbg_indent_save(c
, &saved_indent_level
);
592 if(nesting_level
>= MAX_NESTING_LEVEL
) {
593 de_err(c
, "Directories nested too deeply");
597 dctx
= de_malloc(c
, sizeof(struct dirctx
));
599 cur_cluster_num
= md
->first_cluster
;
600 if(!is_good_clusternum(d
, cur_cluster_num
)) {
601 de_err(c
, "Bad subdirectory entry");
604 cur_cluster_pos
= clusternum_to_offset(c
, d
, cur_cluster_num
);
605 de_dbg(c
, "subdir starting at %"I64_FMT
, cur_cluster_pos
);
609 if(!is_good_clusternum(d
, cur_cluster_num
)) {
612 cur_cluster_pos
= clusternum_to_offset(c
, d
, cur_cluster_num
);
613 de_dbg(c
, "[subdir cluster %"I64_FMT
" at %"I64_FMT
"]", cur_cluster_num
, cur_cluster_pos
);
615 if(d
->cluster_used_flags
[cur_cluster_num
]) {
618 d
->cluster_used_flags
[cur_cluster_num
] = 1;
620 if(!do_dir_entries(c
, d
, dctx
, cur_cluster_pos
, d
->bytes_per_cluster
, nesting_level
, 0)) {
624 cur_cluster_num
= d
->fat_nextcluster
[cur_cluster_num
];
628 destroy_dirctx(c
, dctx
);
629 de_dbg_indent_restore(c
, saved_indent_level
);
632 static void do_root_dir(deark
*c
, lctx
*d
)
635 struct dirctx
*dctx
= NULL
;
637 dctx
= de_malloc(c
, sizeof(struct dirctx
));
638 pos1
= sectornum_to_offset(c
, d
, d
->root_dir_sector
);
639 de_dbg(c
, "dir at %"I64_FMT
, pos1
);
641 if(pos1
<d
->bytes_per_sector
) goto done
;
642 if(d
->prescan_root_dir
) {
643 de_dbg(c
, "[scanning root dir]");
644 // This feature causes us to intentionally read some clusters more than once,
645 // so we have to work around our protections against doing that.
646 fat_save_cluster_use_flags(c
, d
);
648 (void)do_dir_entries(c
, d
, dctx
, pos1
, d
->max_root_dir_entries16
* 32, 0, 1);
649 de_dbg_indent(c
, -1);
650 fat_restore_cluster_use_flags(c
, d
);
651 de_dbg(c
, "[done scanning root dir]");
653 (void)do_dir_entries(c
, d
, dctx
, pos1
, d
->max_root_dir_entries16
* 32, 0, 0);
655 destroy_dirctx(c
, dctx
);
656 de_dbg_indent(c
, -1);
659 static int root_dir_seems_valid(deark
*c
, lctx
*d
)
662 i64 max_entries_to_check
;
667 if(d
->num_fat_bits
==32) return 1;
669 if(d
->max_root_dir_entries16
<=0) return 0;
670 pos1
= sectornum_to_offset(c
, d
, d
->root_dir_sector
);
671 if(pos1
+ d
->max_root_dir_entries16
* 32 > c
->infile
->len
) {
675 max_entries_to_check
= de_max_int(d
->max_root_dir_entries16
, 10);
676 for(i
=0; i
<max_entries_to_check
; i
++) {
681 entrypos
= pos1
+ 32*i
;
682 firstbyte
= de_getbyte(entrypos
);
683 if(firstbyte
==0x00) break;
684 if(firstbyte
==0xe5) continue; // Don't validate deleted entries
686 attribs
= de_getbyte(entrypos
+11);
690 else if((attribs
& 0x3f) == 0x0f) {
693 else if((attribs
& 0x18)==0x18) {
694 errcount
++; // dir + vol.label not valid
697 // TODO: It's really lame to only validate the attribs field, when there's
698 // so much more we could be doing. But it's a hard problem. We don't want
699 // to be too sensitive to minor errors.
702 if(errcount
>1 || (errcount
==1 && entrycount
<=1)) {
708 static void do_atarist_boot_checksum(deark
*c
, lctx
*d
, i64 pos1
)
712 ck
= de_calccrc_oneshot(c
->infile
, pos1
, 512, DE_CRCOBJ_SUM_U16BE
);
714 de_dbg(c
, "Atari ST checksum: 0x%04x", ck
);
716 d
->has_atarist_checksum
= 1;
720 static void do_oem_name(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
722 struct de_stringreaderdata
*srd
;
725 srd
= dbuf_read_string(c
->infile
, pos
, len
, len
, 0, DE_ENCODING_ASCII
);
727 // Require printable ASCII.
728 for(i
=0; i
<len
; i
++) {
729 if(srd
->sz
[i
]<32 || srd
->sz
[i
]>126) {
734 de_dbg(c
, "OEM name: \"%s\"", ucstring_getpsz_d(srd
->str
));
737 de_destroy_stringreaderdata(c
, srd
);
740 static int do_boot_sector(deark
*c
, lctx
*d
, i64 pos1
)
743 i64 num_data_region_sectors
;
744 i64 num_root_dir_sectors
;
745 i64 num_sectors_per_fat16
;
746 i64 num_sectors_per_fat32
= 0;
748 i64 num_sectors32
= 0;
749 i64 num_sectors_per_track
;
751 i64 num_sectors_per_cylinder
;
752 i64 num_cylinders
= 0;
759 de_dbg(c
, "boot sector at %"I64_FMT
, pos1
);
762 // BIOS parameter block
763 jmpinstrlen
= (d
->subfmt
==FAT_SUBFMT_ATARIST
)?2:3;
764 de_dbg(c
, "jump instr: %s",
765 de_render_hexbytes_from_dbuf(c
->infile
, pos1
, jmpinstrlen
, tmpbuf
, sizeof(tmpbuf
)));
767 if(d
->subfmt
==FAT_SUBFMT_ATARIST
) {
768 do_oem_name(c
, d
, pos1
+2, 6);
769 de_dbg(c
, "serial num: %s",
770 de_render_hexbytes_from_dbuf(c
->infile
, pos1
+8, 3, tmpbuf
, sizeof(tmpbuf
)));
773 do_oem_name(c
, d
, pos1
+3, 8);
777 d
->bytes_per_sector
= de_getu16le_p(&pos
);
778 de_dbg(c
, "bytes per sector: %d", (int)d
->bytes_per_sector
);
779 d
->sectors_per_cluster
= (i64
)de_getbyte_p(&pos
);
780 de_dbg(c
, "sectors per cluster: %d", (int)d
->sectors_per_cluster
);
781 d
->num_rsvd_sectors
= de_getu16le_p(&pos
);
783 de_dbg(c
, "reserved sectors: %d", (int)d
->num_rsvd_sectors
);
784 if(d
->num_rsvd_sectors
==0) {
785 // This happens on some Atari ST disks. Don't know why.
786 d
->num_rsvd_sectors
= 1;
789 d
->num_fats
= (i64
)de_getbyte_p(&pos
);
790 de_dbg(c
, "number of FATs: %d", (int)d
->num_fats
);
792 // This is expected to be 0 for FAT32.
793 d
->max_root_dir_entries16
= de_getu16le_p(&pos
);
794 de_dbg(c
, "max number of root dir entries (if FAT12/16): %d", (int)d
->max_root_dir_entries16
);
796 num_sectors16
= de_getu16le_p(&pos
);
797 de_dbg(c
, "number of sectors (old 16-bit field): %d", (int)num_sectors16
);
798 b
= de_getbyte_p(&pos
);
799 de_dbg(c
, "media descriptor: 0x%02x", (UI
)b
);
800 num_sectors_per_fat16
= de_getu16le_p(&pos
);
801 de_dbg(c
, "sectors per FAT (if FAT12/16): %d", (int)num_sectors_per_fat16
);
803 num_sectors_per_track
= de_getu16le_p(&pos
);
804 de_dbg(c
, "sectors per track: %d", (int)num_sectors_per_track
);
805 num_heads
= de_getu16le_p(&pos
);
806 de_dbg(c
, "number of heads: %d", (int)num_heads
);
809 de_read(cksum_sig
, pos
, 2);
810 de_dbg(c
, "boot sector signature: %s",
811 de_render_hexbytes_from_mem(cksum_sig
, 2, tmpbuf
, sizeof(tmpbuf
)));
813 do_atarist_boot_checksum(c
, d
, pos1
);
814 if(d
->has_atarist_checksum
) {
815 d
->platform
= FAT_PLATFORM_ATARIST
;
816 de_dbg(c
, "[This is probably a bootable Atari ST disk.]");
818 else if(cksum_sig
[0]==0x55 && cksum_sig
[1]==0xaa) {
819 d
->platform
= FAT_PLATFORM_PC
;
820 de_dbg(c
, "[Disk has PC-compatible boot code.]");
823 if(num_sectors16
==0) {
824 num_sectors32
= de_getu32le(pos1
+32);
825 de_dbg(c
, "num sectors (new 32-bit field): %"I64_FMT
, num_sectors32
);
828 if(num_sectors_per_fat16
==0) {
829 num_sectors_per_fat32
= de_getu32le(pos1
+36);
830 de_dbg(c
, "sectors per FAT (if FAT32): %u", (UI
)num_sectors_per_fat32
);
833 if(num_sectors_per_fat16
==0) {
834 d
->num_sectors_per_fat
= num_sectors_per_fat32
;
837 d
->num_sectors_per_fat
= num_sectors_per_fat16
;
840 if(num_sectors16
==0) {
841 d
->num_sectors
= num_sectors32
;
844 d
->num_sectors
= num_sectors16
;
847 num_sectors_per_cylinder
= num_heads
* num_sectors_per_track
;
848 if(num_sectors_per_cylinder
> 0) {
849 num_cylinders
= de_pad_to_n(d
->num_sectors
, num_sectors_per_cylinder
) / num_sectors_per_cylinder
;
851 de_dbg(c
, "number of cylinders (calculated): %"I64_FMT
, num_cylinders
);
853 if(d
->sectors_per_cluster
<1) goto done
;
854 if(d
->bytes_per_sector
<32) goto done
;
855 d
->bytes_per_cluster
= d
->bytes_per_sector
* d
->sectors_per_cluster
;
856 d
->root_dir_sector
= d
->num_rsvd_sectors
+ d
->num_sectors_per_fat
* d
->num_fats
;
857 de_dbg(c
, "root dir pos (calculated): %"I64_FMT
" (sector %"I64_FMT
")",
858 sectornum_to_offset(c
, d
, d
->root_dir_sector
), d
->root_dir_sector
);
860 // num_root_dir_sectors is expected to be 0 for FAT32.
861 num_root_dir_sectors
= (d
->max_root_dir_entries16
*32 + d
->bytes_per_sector
- 1)/d
->bytes_per_sector
;
863 num_data_region_sectors
= d
->num_sectors
- (d
->root_dir_sector
+ num_root_dir_sectors
);
864 if(num_data_region_sectors
<0) goto done
;
865 d
->num_data_region_clusters
= num_data_region_sectors
/ d
->sectors_per_cluster
;
866 de_dbg(c
, "number of clusters (calculated): %"I64_FMT
, d
->num_data_region_clusters
);
868 d
->data_region_sector
= d
->root_dir_sector
+ num_root_dir_sectors
;
869 d
->data_region_pos
= d
->data_region_sector
* d
->bytes_per_sector
;
870 de_dbg(c
, "data region pos (calculated): %"I64_FMT
" (sector %"I64_FMT
")", d
->data_region_pos
,
871 d
->data_region_sector
);
873 // (The first cluster is numbered "2".)
874 d
->num_cluster_identifiers
= d
->num_data_region_clusters
+ 2;
876 if(d
->num_data_region_clusters
< 4085) {
877 d
->num_fat_bits
= 12;
879 else if(d
->num_data_region_clusters
< 65525) {
880 d
->num_fat_bits
= 16;
883 d
->num_fat_bits
= 32;
886 de_dbg(c
, "bits per cluster id (calculated): %u", (UI
)d
->num_fat_bits
);
892 de_err(c
, "Invalid or unsupported boot sector");
894 de_dbg_indent(c
, -1);
898 static int do_read_fat(deark
*c
, lctx
*d
)
902 i64 fat_idx_to_read
= 0;
906 pos1
= sectornum_to_offset(c
, d
, d
->num_rsvd_sectors
+ fat_idx_to_read
*d
->num_sectors_per_fat
);
907 de_dbg(c
, "FAT#%d at %"I64_FMT
, (int)fat_idx_to_read
, pos1
);
910 if(d
->num_cluster_identifiers
> (i64
)(DE_MAX_SANE_OBJECT_SIZE
/sizeof(u32
))) goto done
;
911 d
->num_fat_entries
= d
->num_cluster_identifiers
;
912 d
->fat_nextcluster
= de_mallocarray(c
, d
->num_fat_entries
, sizeof(u32
));
913 d
->cluster_used_flags
= de_malloc(c
, d
->num_fat_entries
);
916 if(d
->num_fat_bits
==12) {
917 for(i
=0; i
<d
->num_fat_entries
+1; i
+=2) {
920 val
= (UI
)dbuf_getint_ext(c
->infile
, pos
, 3, 1, 0);
922 if(i
< d
->num_fat_entries
) {
923 d
->fat_nextcluster
[i
] = (u32
)(val
& 0xfff);
925 if(i
+1 < d
->num_fat_entries
) {
926 d
->fat_nextcluster
[i
+1] = (u32
)(val
>> 12);
930 else if(d
->num_fat_bits
==16) {
931 for(i
=0; i
<d
->num_fat_entries
; i
++) {
932 d
->fat_nextcluster
[i
] = (u32
)de_getu16le_p(&pos
);
936 de_err(c
, "This type of FAT is not supported");
940 if(c
->debug_level
>=3) {
941 for(i
=0; i
<d
->num_fat_entries
; i
++) {
942 de_dbg3(c
, "fat[%"I64_FMT
"]: %"I64_FMT
, i
, (i64
)d
->fat_nextcluster
[i
]);
948 de_dbg_indent(c
, -1);
952 static void de_run_fat(deark
*c
, de_module_params
*mparams
)
956 int got_root_dir
= 0;
957 de_encoding default_encoding
= DE_ENCODING_CP437_G
;
961 // 0x1 = No valid FAT directory structure found
962 mparams
->out_params
.flags
= 0;
965 d
= de_malloc(c
, sizeof(lctx
));
967 d
->prescan_root_dir
= (u8
)de_get_ext_option_bool(c
, "fat:scanroot", 1);
968 d
->opt_check_root_dir
= (u8
)de_get_ext_option_bool(c
, "fat:checkroot", 1);
969 s
= de_get_ext_option(c
, "fat:subfmt");
971 if(!de_strcmp(s
, "pc")) {
972 d
->subfmt_req
= FAT_SUBFMT_PC
;
974 else if(!de_strcmp(s
, "atarist")) {
975 d
->subfmt_req
= FAT_SUBFMT_ATARIST
;
978 d
->subfmt
= d
->subfmt_req
;
979 if(d
->subfmt
==FAT_SUBFMT_ATARIST
) {
980 default_encoding
= DE_ENCODING_ATARIST
;
983 d
->input_encoding
= de_get_input_encoding(c
, mparams
, default_encoding
);
986 if(!do_boot_sector(c
, d
, 0)) goto done
;
987 if(d
->num_fat_bits
==0) goto done
;
989 switch(d
->platform
) {
990 case FAT_PLATFORM_PC
:
991 de_declare_fmtf(c
, "FAT%d - PC", d
->num_fat_bits
);
993 case FAT_PLATFORM_ATARIST
:
994 de_declare_fmtf(c
, "FAT%d - Atari ST", d
->num_fat_bits
);
997 de_declare_fmtf(c
, "FAT%d - Unknown platform", d
->num_fat_bits
);
1001 if(!do_read_fat(c
, d
)) goto done
;
1003 if(d
->opt_check_root_dir
) {
1004 if(!root_dir_seems_valid(c
, d
)) {
1005 de_warn(c
, "This file does not appear to contain a valid FAT "
1006 "directory structure. (\"-opt fat:checkroot=0\" to try anyway)");
1011 d
->curpath
= de_strarray_create(c
, MAX_NESTING_LEVEL
+10);
1017 // Inform the parent module that we failed to do anything.
1019 mparams
->out_params
.flags
|= 0x1;
1024 de_free(c
, d
->fat_nextcluster
);
1025 de_free(c
, d
->cluster_used_flags
);
1026 de_free(c
, d
->cluster_used_flags_saved
);
1027 if(d
->curpath
) de_strarray_destroy(d
->curpath
);
1028 if(d
->ea_data
) dbuf_close(d
->ea_data
);
1033 static int de_identify_fat(deark
*c
)
1035 i64 bytes_per_sector
;
1036 i64 max_root_dir_entries
;
1037 i64 num_rsvd_sectors
;
1041 u8 sectors_per_cluster
;
1046 // TODO: This needs a lot of work.
1047 // It's good enough for most FAT12 floppy disk images.
1049 de_read(b
, 0, sizeof(b
));
1050 bytes_per_sector
= de_getu16le_direct(&b
[11]);
1051 sectors_per_cluster
= b
[13];
1052 num_rsvd_sectors
= de_getu16le_direct(&b
[14]);
1054 max_root_dir_entries
= de_getu16le_direct(&b
[17]);
1055 media_descr
= b
[21];
1057 if(bytes_per_sector
!=512) return 0;
1058 switch(sectors_per_cluster
) {
1059 case 1: case 2: case 4: case 8:
1060 case 16: case 32: case 64: case 128:
1065 if(num_fats
!=1 && num_fats
!=2) return 0;
1066 if(media_descr
<0xe5 && media_descr
!=0) return 0; // Media descriptor
1069 if(b
[0]==0xeb && b
[2]==0x90) confidence
+= 2;
1070 else if(b
[0]==0xe9) confidence
+= 1;
1071 else if(b
[0]==0x60) confidence
+= 1;
1072 has_pc_sig
= (de_getu16be(510)==0x55aa);
1073 if(has_pc_sig
) confidence
+= 2;
1074 if(num_fats
==2) confidence
+= 1;
1075 if(media_descr
>=0xe5) confidence
+= 1;
1076 if(num_rsvd_sectors
==1) confidence
+= 1;
1077 if(max_root_dir_entries
==112 || max_root_dir_entries
==224) confidence
+= 2;
1079 has_ext
= de_input_file_has_ext(c
, "ima") ||
1080 de_input_file_has_ext(c
, "img") ||
1081 de_input_file_has_ext(c
, "st");
1083 if(confidence
>=6) return (has_ext
?100:80);
1084 else if(confidence
>=4) return (has_ext
?60:9);
1088 static void de_help_fat(deark
*c
)
1090 de_msg(c
, "-opt fat:checkroot=0 : Read the directory structure, even if it "
1092 de_msg(c
, "-opt fat:scanroot=0 : Do not scan the root directory to look for "
1096 void de_module_fat(deark
*c
, struct deark_module_info
*mi
)
1099 mi
->desc
= "FAT disk image";
1100 mi
->run_fn
= de_run_fat
;
1101 mi
->identify_fn
= de_identify_fat
;
1102 mi
->help_fn
= de_help_fat
;
1105 ///////////////////////// LoadDskF/SaveDskF format (OS/2-centric)
1111 u32 checksum_reported
;
1114 i64 expected_dcmpr_size
; // 0 if unknown
1115 i64 padded_size
; // 0 if unknown
1116 struct de_crcobj
*crco
;
1119 // Get, report, and compare calculated checksum
1120 static void loaddskf_finish_checksum(deark
*c
, struct skf_ctx
*d
)
1122 d
->checksum_calc
= de_crcobj_getval(d
->crco
);
1123 de_dbg(c
, "checksum (calculated): 0x%08x", (UI
)d
->checksum_calc
);
1124 if(d
->checksum_calc
!= d
->checksum_reported
) {
1125 de_warn(c
, "Checksum mismatch (reported 0x%08x, calculated 0x%08x). "
1126 "Something may have gone wrong.", (UI
)d
->checksum_reported
,
1127 (UI
)d
->checksum_calc
);
1131 static void loaddskf_calc_checksum_noncmpr(deark
*c
, struct skf_ctx
*d
)
1133 i64 nbytes_to_checksum
;
1135 nbytes_to_checksum
= c
->infile
->len
- d
->hdr_size
;
1136 if(d
->expected_dcmpr_size
&& d
->expected_dcmpr_size
< nbytes_to_checksum
) {
1137 nbytes_to_checksum
= d
->expected_dcmpr_size
;
1140 de_crcobj_addslice(d
->crco
, c
->infile
, d
->hdr_size
, nbytes_to_checksum
);
1143 static void loaddskf_pad_ima_file(deark
*c
, struct skf_ctx
*d
, dbuf
*outf
)
1145 i64 num_padding_bytes
;
1149 if(d
->padded_size
<=0) goto done
;
1150 num_padding_bytes
= d
->padded_size
- outf
->len
;
1151 if(num_padding_bytes
<=0) goto done
;
1152 de_dbg(c
, "[adding padding]");
1154 // TODO: Does it matter what we pad with? Possibilities include 0x00, 0xe5, 0xf6.
1155 padding_value
= 0x00;
1156 dbuf_write_run(outf
, padding_value
, num_padding_bytes
);
1161 static void loaddskf_convert_noncmpr_to_ima(deark
*c
, struct skf_ctx
*d
)
1165 outf
= dbuf_create_output_file(c
, "ima", NULL
, 0);
1166 de_dbg(c
, "[copying]");
1167 dbuf_copy(c
->infile
, d
->hdr_size
, c
->infile
->len
- d
->hdr_size
, outf
);
1168 loaddskf_pad_ima_file(c
, d
, outf
);
1172 static void loaddskf_decode_as_fat(deark
*c
, struct skf_ctx
*d
)
1176 dlen
= de_max_int(c
->infile
->len
- d
->hdr_size
, d
->padded_size
);
1177 de_dbg(c
, "decoding as FAT, pos=%"I64_FMT
", len=%"I64_FMT
, d
->hdr_size
, dlen
);
1178 if(dlen
<=0) goto done
;
1180 de_dbg_indent(c
, 1);
1181 de_run_module_by_id_on_slice(c
, "fat", NULL
, c
->infile
, d
->hdr_size
, dlen
);
1182 de_dbg_indent(c
, -1);
1187 static void loaddskf_decompress(deark
*c
, struct skf_ctx
*d
)
1189 struct de_dfilter_in_params dcmpri
;
1190 struct de_dfilter_out_params dcmpro
;
1191 struct de_dfilter_results dres
;
1195 outf
= dbuf_create_output_file(c
, "ima", NULL
, 0);
1196 dbuf_enable_wbuffer(outf
);
1199 outf
= dbuf_create_output_file(c
, "unc.dsk", NULL
, 0);
1200 dbuf_enable_wbuffer(outf
);
1201 dbuf_write(outf
, (const u8
*)"\xaa\x59", 2);
1202 dbuf_copy(c
->infile
, 2, d
->hdr_size
-2, outf
);
1205 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
1206 dcmpri
.f
= c
->infile
;
1207 dcmpri
.pos
= d
->hdr_size
;
1208 dcmpri
.len
= c
->infile
->len
- dcmpri
.pos
;
1211 dbuf_set_writelistener(outf
, de_writelistener_for_crc
, (void*)d
->crco
);
1213 de_dbg(c
, "[decompressing]");
1214 fmtutil_ibmlzw_codectype1(c
, &dcmpri
, &dcmpro
, &dres
, NULL
);
1215 dbuf_flush(dcmpro
.f
);
1217 de_err(c
, "Decompression failed: %s", de_dfilter_get_errmsg(c
, &dres
));
1221 d
->checksum_calc
= de_crcobj_getval(d
->crco
);
1222 loaddskf_finish_checksum(c
, d
);
1225 loaddskf_pad_ima_file(c
, d
, outf
);
1227 // TODO: If !d->to_raw, maybe we should still ensure it decompressed to
1228 // the expected size.
1234 static int loaddskf_read_header(deark
*c
, struct skf_ctx
*d
)
1236 i64 bytes_per_sector
;
1237 i64 num_sectors_per_track
;
1240 i64 num_sectors_in_image
;
1243 de_dbg(c
, "header");
1244 de_dbg_indent(c
, 1);
1246 bytes_per_sector
= de_getu16le(4);
1247 de_dbg(c
, "bytes per sector: %u", (UI
)bytes_per_sector
);
1248 d
->checksum_reported
= (u32
)de_getu32le(20); // TODO: What is this?
1249 de_dbg(c
, "checksum (reported): 0x%08x", (UI
)d
->checksum_reported
);
1250 num_cylinders
= de_getu16le(24);
1251 de_dbg(c
, "cylinders: %u", (UI
)num_cylinders
);
1252 num_heads
= de_getu16le(26);
1253 de_dbg(c
, "number of heads: %u", (UI
)num_heads
);
1254 num_sectors_per_track
= de_getu16le(28);
1255 de_dbg(c
, "sectors per track: %u", (UI
)num_sectors_per_track
);
1256 num_sectors_in_image
= de_getu16le(34);
1257 de_dbg(c
, "num sectors in image: %u", (UI
)num_sectors_in_image
);
1259 d
->hdr_size
= de_getu16le(38);
1260 if(d
->hdr_size
==0) d
->hdr_size
= 512;
1261 de_dbg(c
, "header size: %"I64_FMT
, d
->hdr_size
);
1262 if(d
->hdr_size
<40 || d
->hdr_size
>c
->infile
->len
) {
1268 if(num_cylinders
<20 || num_cylinders
>200 ||
1269 num_heads
<1 || num_heads
>2 ||
1270 num_sectors_per_track
<8 || num_sectors_per_track
>200 ||
1271 bytes_per_sector
<128 || bytes_per_sector
>2048)
1273 de_warn(c
, "Unexpected disk geometry. Something may have failed.");
1277 d
->expected_dcmpr_size
= num_sectors_in_image
* bytes_per_sector
;
1278 d
->padded_size
= num_cylinders
* num_heads
* num_sectors_per_track
* bytes_per_sector
;
1279 de_dbg(c
, "expected uncmpr image size: %"I64_FMT
", padded=%"I64_FMT
,
1280 d
->expected_dcmpr_size
, d
->padded_size
);
1286 de_err(c
, "Failed to parse LoadDskF file");
1288 de_dbg_indent(c
, -1);
1292 static void de_run_loaddskf(deark
*c
, de_module_params
*mparams
)
1294 struct skf_ctx
*d
= NULL
;
1295 const char *subfmt_name
;
1298 d
= de_malloc(c
, sizeof(struct skf_ctx
));
1299 d
->to_raw
= de_get_ext_option_bool(c
, "loaddskf:toraw", 0);
1300 d
->crco
= de_crcobj_create(c
, DE_CRCOBJ_SUM_U16LE
);
1302 sig
= (UI
)de_getu16be(0);
1305 subfmt_name
= "old";
1308 subfmt_name
= "new";
1312 subfmt_name
= "new, compressed";
1314 d
->is_compressed
= 1;
1317 de_err(c
, "Not a LoadDskF file");
1321 de_declare_fmtf(c
, "LoadDskF (%s)", subfmt_name
);
1322 if(!loaddskf_read_header(c
, d
)) goto done
;
1323 if(d
->is_compressed
) {
1324 loaddskf_decompress(c
, d
);
1327 loaddskf_calc_checksum_noncmpr(c
, d
);
1328 loaddskf_finish_checksum(c
, d
);
1330 loaddskf_convert_noncmpr_to_ima(c
, d
);
1333 loaddskf_decode_as_fat(c
, d
);
1339 de_crcobj_destroy(d
->crco
);
1344 static int de_identify_loaddskf(deark
*c
)
1348 sig
= (UI
)de_getu16be(0);
1349 if(sig
==0xaa58 || sig
==0xaa59 || sig
==0xaa5a) {
1350 if((UI
)de_getu16be(2)==0xf000) {
1358 static void de_help_loaddskf(deark
*c
)
1360 de_msg(c
, "-opt loaddskf:toraw : Convert to raw FAT/IMA format");
1363 void de_module_loaddskf(deark
*c
, struct deark_module_info
*mi
)
1365 mi
->id
= "loaddskf";
1366 mi
->desc
= "LoadDskF/SaveDskF disk image";
1367 mi
->run_fn
= de_run_loaddskf
;
1368 mi
->identify_fn
= de_identify_loaddskf
;
1369 mi
->help_fn
= de_help_loaddskf
;