1 | //--------------------------------------------------------------
|
---|
2 | //File name: apa.c
|
---|
3 | //--------------------------------------------------------------
|
---|
4 | #include <thbase.h>
|
---|
5 | #include <sysclib.h>
|
---|
6 | #include <cdvdman.h>
|
---|
7 | #include <iomanX.h>
|
---|
8 | #include <sysmem.h>
|
---|
9 |
|
---|
10 | #include "ps2_hdd.h"
|
---|
11 | #include "hdd.h"
|
---|
12 | #include "hdl.h"
|
---|
13 | #include "apa.h"
|
---|
14 |
|
---|
15 | #define AUTO_DELETE_EMPTY
|
---|
16 |
|
---|
17 | #define _MB * (1024 * 1024) /* really ugly :-) */
|
---|
18 |
|
---|
19 | typedef struct ps2_partition_run_type
|
---|
20 | {
|
---|
21 | unsigned long sector;
|
---|
22 | u_long size_in_mb;
|
---|
23 | } ps2_partition_run_t;
|
---|
24 |
|
---|
25 | //Remove this line, and uncomment the next line, to reactivate 'apa_check'
|
---|
26 | //static int apa_check(const apa_partition_table_t *table);
|
---|
27 |
|
---|
28 | //--------------------------------------------------------------
|
---|
29 | u_long apa_partition_checksum(const ps2_partition_header_t *part)
|
---|
30 | {
|
---|
31 | const u_long *p = (const u_long*)part;
|
---|
32 | register u_long i;
|
---|
33 | u_long sum = 0;
|
---|
34 | for(i=1; i<256; ++i)
|
---|
35 | sum += get_u32(p + i);
|
---|
36 | return sum;
|
---|
37 | }
|
---|
38 | //------------------------------
|
---|
39 | //endfunc apa_partition_checksum
|
---|
40 | //--------------------------------------------------------------
|
---|
41 | static apa_partition_table_t* apa_ptable_alloc(void)
|
---|
42 | {
|
---|
43 | apa_partition_table_t *table = AllocSysMemory(0, sizeof (apa_partition_table_t), NULL);
|
---|
44 | if(table != NULL)
|
---|
45 | memset(table, 0, sizeof (apa_partition_table_t));
|
---|
46 | return table;
|
---|
47 | }
|
---|
48 | //------------------------------
|
---|
49 | //endfunc apa_ptable_alloc
|
---|
50 | //--------------------------------------------------------------
|
---|
51 | void apa_ptable_free(apa_partition_table_t *table)
|
---|
52 | {
|
---|
53 | if (table != NULL){
|
---|
54 | if (table->chunks_map != NULL)
|
---|
55 | FreeSysMemory(table->chunks_map);
|
---|
56 | if (table->parts != NULL)
|
---|
57 | FreeSysMemory(table->parts);
|
---|
58 | FreeSysMemory(table);
|
---|
59 | }
|
---|
60 | }
|
---|
61 | //------------------------------
|
---|
62 | //endfunc apa_ptable_free
|
---|
63 | //--------------------------------------------------------------
|
---|
64 | static int apa_part_add (apa_partition_table_t *table, const ps2_partition_header_t *part, int existing, int linked)
|
---|
65 | {
|
---|
66 | if (table->part_count == table->part_alloc_){ /* grow buffer */
|
---|
67 | u_long bytes = (table->part_alloc_ + 16) * sizeof (apa_partition_t);
|
---|
68 | apa_partition_t *tmp = AllocSysMemory(0, bytes, NULL);
|
---|
69 | if(tmp != NULL)
|
---|
70 | {
|
---|
71 | memset(tmp, 0, bytes);
|
---|
72 | if (table->parts != NULL) /* copy existing */
|
---|
73 | memcpy(tmp, table->parts, table->part_count * sizeof (apa_partition_t));
|
---|
74 | FreeSysMemory(table->parts);
|
---|
75 | table->parts = tmp;
|
---|
76 | table->part_alloc_ += 16;
|
---|
77 | }
|
---|
78 | else return -2;
|
---|
79 | }
|
---|
80 |
|
---|
81 | memcpy(&table->parts[table->part_count].header, part, sizeof (ps2_partition_header_t));
|
---|
82 | table->parts[table->part_count].existing = existing;
|
---|
83 | table->parts[table->part_count].modified = !existing;
|
---|
84 | table->parts[table->part_count].linked = linked;
|
---|
85 | ++table->part_count;
|
---|
86 |
|
---|
87 | return 0;
|
---|
88 | }
|
---|
89 | //------------------------------
|
---|
90 | //endfunc apa_part_add
|
---|
91 | //--------------------------------------------------------------
|
---|
92 | /* //Remove this line and a similar one below to reactivate 'apa_setup_statistics'
|
---|
93 | static int apa_setup_statistics(apa_partition_table_t *table)
|
---|
94 | {
|
---|
95 | u_long i;
|
---|
96 | char *map;
|
---|
97 |
|
---|
98 | table->total_chunks = table->device_size_in_mb / 128;
|
---|
99 | map = AllocSysMemory(0, table->total_chunks * sizeof (char), NULL);
|
---|
100 | if(map != NULL)
|
---|
101 | {
|
---|
102 | for(i=0; i<table->total_chunks; ++i)
|
---|
103 | map [i] = MAP_AVAIL;
|
---|
104 |
|
---|
105 | // build occupided/available space map
|
---|
106 | table->allocated_chunks = 0;
|
---|
107 | table->free_chunks = table->total_chunks;
|
---|
108 | for(i=0; i<table->part_count; ++i)
|
---|
109 | {
|
---|
110 | const ps2_partition_header_t *part = &table->parts [i].header;
|
---|
111 | u_long part_no = get_u32(&part->start) / ((128 _MB) / 512);
|
---|
112 | u_long num_parts = get_u32(&part->length) / ((128 _MB) / 512);
|
---|
113 |
|
---|
114 | // "alloc" num_parts starting at part_no
|
---|
115 | while (num_parts)
|
---|
116 | {
|
---|
117 | if(map[part_no] == MAP_AVAIL)
|
---|
118 | map[part_no] = get_u32(&part->main) == 0 ? MAP_MAIN : MAP_SUB;
|
---|
119 | else
|
---|
120 | map[part_no] = MAP_COLL; // collision
|
---|
121 | ++part_no;
|
---|
122 | --num_parts;
|
---|
123 | ++table->allocated_chunks;
|
---|
124 | --table->free_chunks;
|
---|
125 | }
|
---|
126 | }
|
---|
127 |
|
---|
128 | if(table->chunks_map != NULL)
|
---|
129 | FreeSysMemory(table->chunks_map);
|
---|
130 | table->chunks_map = map;
|
---|
131 |
|
---|
132 | return 0;
|
---|
133 | }
|
---|
134 | else return -2;
|
---|
135 | }
|
---|
136 | */ //Remove this line and a similar one below to reactivate 'apa_setup_statistics'
|
---|
137 | //------------------------------
|
---|
138 | //endfunc apa_setup_statistics
|
---|
139 | //--------------------------------------------------------------
|
---|
140 | int apa_ptable_read_ex ( hio_t *hio, apa_partition_table_t **table)
|
---|
141 | {
|
---|
142 | u_long size_in_kb;
|
---|
143 | int result = hio->stat(hio, &size_in_kb);
|
---|
144 | if(result == 0){
|
---|
145 | u_long total_sectors;
|
---|
146 | // limit HDD size to 128GB - 1KB; that is: exclude the last 128MB chunk
|
---|
147 | //if (size_in_kb > 128 * 1024 * 1024 - 1)
|
---|
148 | // size_in_kb = 128 * 1024 * 1024 - 1;
|
---|
149 |
|
---|
150 | total_sectors = size_in_kb * 2; /* 1KB = 2 sectors of 512 bytes, each */
|
---|
151 |
|
---|
152 | *table = apa_ptable_alloc();
|
---|
153 | if(*table != NULL){
|
---|
154 | u_long sector = 0;
|
---|
155 | do {
|
---|
156 | u_long bytes;
|
---|
157 | ps2_partition_header_t part;
|
---|
158 | result = hio->read(hio, sector, sizeof(part) / 512, &part, &bytes);
|
---|
159 | if(result == 0){
|
---|
160 | if(bytes == sizeof(part) &&
|
---|
161 | get_u32(&part.checksum) == apa_partition_checksum(&part) &&
|
---|
162 | memcmp(part.magic, PS2_PARTITION_MAGIC, 4) == 0)
|
---|
163 | {
|
---|
164 | if(get_u32(&part.start) < total_sectors &&
|
---|
165 | get_u32(&part.start) + get_u32(&part.length) < total_sectors)
|
---|
166 | {
|
---|
167 | if((get_u16(&part.flags)==0x0000) && (get_u16(&part.type) ==0x1337))
|
---|
168 | result = apa_part_add(*table, &part, 1, 1);
|
---|
169 | if(result == 0)
|
---|
170 | sector = get_u32(&part.next);
|
---|
171 | } else { /* partition behind end-of-HDD */
|
---|
172 | result = 7; /* data behind end-of-HDD */
|
---|
173 | break;
|
---|
174 | }
|
---|
175 | } else
|
---|
176 | result = 1;
|
---|
177 | }
|
---|
178 | /* TODO: check whether next partition is not loaded already --
|
---|
179 | * do not deadlock; that is a quick-and-dirty hack */
|
---|
180 | if ((*table)->part_count > 10000)
|
---|
181 | result = 7;
|
---|
182 | } while (result == 0 && sector != 0);
|
---|
183 |
|
---|
184 | if (result == 0){
|
---|
185 | (*table)->device_size_in_mb = size_in_kb / 1024;
|
---|
186 | //NB: uncommenting the next lines requires changes elsewhere too
|
---|
187 | //result = apa_setup_statistics (*table);
|
---|
188 | //if (result == 0)
|
---|
189 | //result = apa_check (*table);
|
---|
190 | }
|
---|
191 |
|
---|
192 | if (result != 0){
|
---|
193 | result = 20000+(*table)->part_count;
|
---|
194 | apa_ptable_free (*table);
|
---|
195 | }
|
---|
196 | }
|
---|
197 | else result = -2;
|
---|
198 | }
|
---|
199 | return result;
|
---|
200 | }
|
---|
201 | //------------------------------
|
---|
202 | //endfunc apa_ptable_read_ex
|
---|
203 | //--------------------------------------------------------------
|
---|
204 | /* //Remove this line and a similar one below to reactivate 'apa_check'
|
---|
205 | static int apa_check (const apa_partition_table_t *table) {
|
---|
206 |
|
---|
207 | u_long i, j, k;
|
---|
208 |
|
---|
209 | const u_long total_sectors = table->device_size_in_mb * 1024 * 2;
|
---|
210 |
|
---|
211 | for (i=0; i<table->part_count; ++i)
|
---|
212 | {
|
---|
213 | const ps2_partition_header_t *part = &table->parts [i].header;
|
---|
214 | if (get_u32 (&part->checksum) != apa_partition_checksum (part))
|
---|
215 | return 7; // bad checksum
|
---|
216 |
|
---|
217 | if (get_u32 (&part->start) < total_sectors &&
|
---|
218 | get_u32 (&part->start) + get_u32 (&part->length) <= total_sectors)
|
---|
219 | ;
|
---|
220 | else
|
---|
221 | {
|
---|
222 | return 7; // data behind end-of-HDD
|
---|
223 | }
|
---|
224 |
|
---|
225 | if ((get_u32 (&part->length) % ((128 _MB) / 512)) != 0)
|
---|
226 | return 7; // partition size not multiple to 128MB
|
---|
227 |
|
---|
228 | if ((get_u32 (&part->start) % get_u32 (&part->length)) != 0)
|
---|
229 | return 7; // partition start not multiple on partition size
|
---|
230 |
|
---|
231 | if (get_u32 (&part->main) == 0 &&
|
---|
232 | get_u16 (&part->flags) == 0 &&
|
---|
233 | get_u32 (&part->start) != 0)
|
---|
234 | { // check sub-partitions
|
---|
235 | u_long count = 0;
|
---|
236 | for (j=0; j<table->part_count; ++j)
|
---|
237 | {
|
---|
238 | const ps2_partition_header_t *part2 = &table->parts [j].header;
|
---|
239 | if (get_u32 (&part2->main) == get_u32 (&part->start))
|
---|
240 | { // sub-partition of current main partition
|
---|
241 | int found;
|
---|
242 | if (get_u16 (&part2->flags) != PS2_PART_FLAG_SUB)
|
---|
243 | return 7;
|
---|
244 |
|
---|
245 | found = 0;
|
---|
246 | for (k=0; k<get_u32 (&part->nsub); ++k)
|
---|
247 | if (get_u32 (&part->subs [k].start) == get_u32 (&part2->start))
|
---|
248 | { // in list
|
---|
249 | if (get_u32 (&part->subs [k].length) != get_u32 (&part2->length))
|
---|
250 | return 7;
|
---|
251 | found = 1;
|
---|
252 | break;
|
---|
253 | }
|
---|
254 | if (!found)
|
---|
255 | return 7; // not found in the list
|
---|
256 |
|
---|
257 | ++count;
|
---|
258 | }
|
---|
259 | }
|
---|
260 | if (count != get_u32 (&part->nsub))
|
---|
261 | return 7; // wrong number of sub-partitions
|
---|
262 | }
|
---|
263 | }
|
---|
264 |
|
---|
265 | // verify double-linked list
|
---|
266 | for (i=0; i<table->part_count; ++i)
|
---|
267 | {
|
---|
268 | apa_partition_t *prev = table->parts + (i > 0 ? i - 1 : table->part_count - 1);
|
---|
269 | apa_partition_t *curr = table->parts + i;
|
---|
270 | apa_partition_t *next = table->parts + (i + 1 < table->part_count ? i + 1 : 0);
|
---|
271 | if (get_u32 (&curr->header.prev) != get_u32 (&prev->header.start) ||
|
---|
272 | get_u32 (&curr->header.next) != get_u32 (&next->header.start))
|
---|
273 | return 7; // bad links
|
---|
274 | }
|
---|
275 |
|
---|
276 | return 0;
|
---|
277 | }
|
---|
278 | */ //Remove this line and a similar one above to reactivate 'apa_check'
|
---|
279 | //------------------------------
|
---|
280 | //endfunc apa_check
|
---|
281 | //--------------------------------------------------------------
|
---|
282 | u_long get_u32 (const void *buffer)
|
---|
283 | {
|
---|
284 | const u_char *p = buffer;
|
---|
285 | return ((((u_long) p[3]) << 24) |
|
---|
286 | (((u_long) p[2]) << 16) |
|
---|
287 | (((u_long) p[1]) << 8) |
|
---|
288 | (((u_long) p[0]) << 0));
|
---|
289 | }
|
---|
290 | //------------------------------
|
---|
291 | //endfunc get_u32
|
---|
292 | //--------------------------------------------------------------
|
---|
293 | void set_u32 (void *buffer, u_long val)
|
---|
294 | {
|
---|
295 | u_char *p = buffer;
|
---|
296 | p [3] = (u_char) (val >> 24);
|
---|
297 | p [2] = (u_char) (val >> 16);
|
---|
298 | p [1] = (u_char) (val >> 8);
|
---|
299 | p [0] = (u_char) (val >> 0);
|
---|
300 | }
|
---|
301 | //------------------------------
|
---|
302 | //endfunc set_u32
|
---|
303 | //--------------------------------------------------------------
|
---|
304 | u_short get_u16 (const void *buffer)
|
---|
305 | {
|
---|
306 | const u_char *p = buffer;
|
---|
307 | return ((((u_short) p[1]) << 8) |
|
---|
308 | (((u_short) p[0]) << 0));
|
---|
309 | }
|
---|
310 | //------------------------------
|
---|
311 | //endfunc get_u16
|
---|
312 | //--------------------------------------------------------------
|
---|
313 | void set_u16 (void *buffer, u_short val)
|
---|
314 | {
|
---|
315 | u_char *p = buffer;
|
---|
316 | p [1] = (u_char) (val >> 8);
|
---|
317 | p [0] = (u_char) (val >> 0);
|
---|
318 | }
|
---|
319 | //------------------------------
|
---|
320 | //endfunc set_u16
|
---|
321 | //--------------------------------------------------------------
|
---|
322 | //End of file: apa.c
|
---|
323 | //--------------------------------------------------------------
|
---|