1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_apm
);
11 struct partition_info
{
12 i64 partition_startsec
;
13 i64 partition_startpos
;
14 i64 partition_size_in_secs
;
15 i64 partition_size_in_bytes
;
16 unsigned int partition_status
;
18 struct de_stringreaderdata
*ptype
;
21 typedef struct localctx_struct
{
26 static void destroy_partition_info(deark
*c
, struct partition_info
*pi
)
29 ucstring_destroy(pi
->pname
);
30 de_destroy_stringreaderdata(c
, pi
->ptype
);
34 static void do_extract_partition(deark
*c
, lctx
*d
, struct partition_info
*pi
)
37 const char *ext
= "partition";
39 int use_pname_in_name
= 1;
40 int use_ptype_in_name
= 1;
41 de_ucstring
*outfname
= NULL
;
43 if(pi
->partition_startpos
>= c
->infile
->len
) goto done
;
44 len_to_extract
= pi
->partition_size_in_bytes
;
45 if(pi
->partition_startpos
+ len_to_extract
> c
->infile
->len
) {
46 de_warn(c
, "Partition at %"I64_FMT
" goes beyond end of file", pi
->partition_startpos
);
47 len_to_extract
= c
->infile
->len
- pi
->partition_startpos
;
50 fi
= de_finfo_create(c
);
51 outfname
= ucstring_create(c
);
53 if(!de_strcmp(pi
->ptype
->sz
, "Apple_partition_map")) {
55 use_pname_in_name
= 0;
57 else if(!de_strcmp(pi
->ptype
->sz
, "Apple_HFS")) {
58 unsigned int sig
= (unsigned int)de_getu16be(pi
->partition_startpos
+1024);
59 if(sig
==0x4244) { // "BD"
61 use_ptype_in_name
= 0;
63 else if(sig
==0x482b) { // "H+"
65 use_ptype_in_name
= 0;
67 else if(sig
==0x4858) { // "HX"
69 use_ptype_in_name
= 0;
73 if(use_pname_in_name
&& ucstring_isnonempty(pi
->pname
)) {
74 ucstring_append_ucstring(outfname
, pi
->pname
);
76 if(use_ptype_in_name
&& ucstring_isnonempty(pi
->ptype
->str
)) {
78 ucstring_append_sz(outfname
, ".", DE_ENCODING_LATIN1
);
80 ucstring_append_ucstring(outfname
, pi
->ptype
->str
);
83 de_finfo_set_name_from_ucstring(c
, fi
, outfname
, 0);
86 dbuf_create_file_from_slice(c
->infile
, pi
->partition_startpos
,
87 len_to_extract
, ext
, fi
, 0);
90 de_finfo_destroy(c
, fi
);
91 ucstring_destroy(outfname
);
94 static int do_entry_at_sector(deark
*c
, lctx
*d
, i64 secnum
)
96 i64 pos
= secnum
*d
->secsize
;
99 int saved_indent_level
;
100 struct partition_info
*pi
= NULL
;
102 de_dbg_indent_save(c
, &saved_indent_level
);
104 if(dbuf_memcmp(c
->infile
, pos
, "PM", 2)) {
105 de_err(c
, "Partition map entry not found at %"I64_FMT
, pos
);
109 pi
= de_malloc(c
, sizeof(struct partition_info
));
111 de_dbg(c
, "partition map entry at %"I64_FMT
, pos
);
115 npartitions
= de_getu32be_p(&pos
);
116 de_dbg(c
, "total number of partitions: %d", (int)npartitions
);
118 d
->npartitions
= npartitions
;
122 pi
->partition_startsec
= de_getu32be_p(&pos
);
123 pi
->partition_startpos
= pi
->partition_startsec
* d
->secsize
;
124 de_dbg(c
, "starting sector of partition: %"I64_FMT
" (offset %"I64_FMT
")",
125 pi
->partition_startsec
, pi
->partition_startpos
);
127 pi
->partition_size_in_secs
= de_getu32be_p(&pos
);
128 pi
->partition_size_in_bytes
= pi
->partition_size_in_secs
* d
->secsize
;
129 de_dbg(c
, "partition size: %"I64_FMT
" sectors (%"I64_FMT
" bytes)",
130 pi
->partition_size_in_secs
, pi
->partition_size_in_bytes
);
132 pi
->pname
= ucstring_create(c
);
133 dbuf_read_to_ucstring(c
->infile
, pos
, 32, pi
->pname
, DE_CONVFLAG_STOP_AT_NUL
,
135 de_dbg(c
, "partition name: \"%s\"", ucstring_getpsz(pi
->pname
));
138 pi
->ptype
= dbuf_read_string(c
->infile
, pos
, 32, 32, DE_CONVFLAG_STOP_AT_NUL
,
140 de_dbg(c
, "partition type: \"%s\"", ucstring_getpsz(pi
->ptype
->str
));
143 pi
->partition_status
= (unsigned int)de_getu32be_p(&pos
);
144 de_dbg(c
, "status: 0x%08x", (unsigned int)pi
->partition_status
);
146 // TODO: More fields here
148 do_extract_partition(c
, d
, pi
);
151 if(pi
) destroy_partition_info(c
, pi
);
152 de_dbg_indent_restore(c
, saved_indent_level
);
156 static void de_run_apm(deark
*c
, de_module_params
*mparams
)
162 d
= de_malloc(c
, sizeof(lctx
));
166 // Read the first map entry (should set d->npartitions)
167 ret
= do_entry_at_sector(c
, d
, 1);
170 // Read the rest of the entries
171 for(i
=1; i
<d
->npartitions
; i
++) {
172 ret
= do_entry_at_sector(c
, d
, 1+i
);
180 static int de_identify_apm(deark
*c
)
185 if(dbuf_memcmp(c
->infile
, 512+i
*512, "PM\x00\x00", 4))
191 void de_module_apm(deark
*c
, struct deark_module_info
*mi
)
194 mi
->desc
= "Apple Partition Map";
195 mi
->run_fn
= de_run_apm
;
196 mi
->identify_fn
= de_identify_apm
;