//-------------------------------------------------------------- //File name: apa.c //-------------------------------------------------------------- #include #include #include #include #include #include "ps2_hdd.h" #include "hdd.h" #include "hdl.h" #include "apa.h" #define AUTO_DELETE_EMPTY #define _MB * (1024 * 1024) /* really ugly :-) */ typedef struct ps2_partition_run_type { unsigned long sector; u_long size_in_mb; } ps2_partition_run_t; //Remove this line, and uncomment the next line, to reactivate 'apa_check' //static int apa_check(const apa_partition_table_t *table); //-------------------------------------------------------------- u_long apa_partition_checksum(const ps2_partition_header_t *part) { const u_long *p = (const u_long*)part; register u_long i; u_long sum = 0; for(i=1; i<256; ++i) sum += get_u32(p + i); return sum; } //------------------------------ //endfunc apa_partition_checksum //-------------------------------------------------------------- static apa_partition_table_t* apa_ptable_alloc(void) { apa_partition_table_t *table = AllocSysMemory(0, sizeof (apa_partition_table_t), NULL); if(table != NULL) memset(table, 0, sizeof (apa_partition_table_t)); return table; } //------------------------------ //endfunc apa_ptable_alloc //-------------------------------------------------------------- void apa_ptable_free(apa_partition_table_t *table) { if (table != NULL){ if (table->chunks_map != NULL) FreeSysMemory(table->chunks_map); if (table->parts != NULL) FreeSysMemory(table->parts); FreeSysMemory(table); } } //------------------------------ //endfunc apa_ptable_free //-------------------------------------------------------------- static int apa_part_add (apa_partition_table_t *table, const ps2_partition_header_t *part, int existing, int linked) { if (table->part_count == table->part_alloc_){ /* grow buffer */ u_long bytes = (table->part_alloc_ + 16) * sizeof (apa_partition_t); apa_partition_t *tmp = AllocSysMemory(0, bytes, NULL); if(tmp != NULL) { memset(tmp, 0, bytes); if (table->parts != NULL) /* copy existing */ memcpy(tmp, table->parts, table->part_count * sizeof (apa_partition_t)); FreeSysMemory(table->parts); table->parts = tmp; table->part_alloc_ += 16; } else return -2; } memcpy(&table->parts[table->part_count].header, part, sizeof (ps2_partition_header_t)); table->parts[table->part_count].existing = existing; table->parts[table->part_count].modified = !existing; table->parts[table->part_count].linked = linked; ++table->part_count; return 0; } //------------------------------ //endfunc apa_part_add //-------------------------------------------------------------- /* //Remove this line and a similar one below to reactivate 'apa_setup_statistics' static int apa_setup_statistics(apa_partition_table_t *table) { u_long i; char *map; table->total_chunks = table->device_size_in_mb / 128; map = AllocSysMemory(0, table->total_chunks * sizeof (char), NULL); if(map != NULL) { for(i=0; itotal_chunks; ++i) map [i] = MAP_AVAIL; // build occupided/available space map table->allocated_chunks = 0; table->free_chunks = table->total_chunks; for(i=0; ipart_count; ++i) { const ps2_partition_header_t *part = &table->parts [i].header; u_long part_no = get_u32(&part->start) / ((128 _MB) / 512); u_long num_parts = get_u32(&part->length) / ((128 _MB) / 512); // "alloc" num_parts starting at part_no while (num_parts) { if(map[part_no] == MAP_AVAIL) map[part_no] = get_u32(&part->main) == 0 ? MAP_MAIN : MAP_SUB; else map[part_no] = MAP_COLL; // collision ++part_no; --num_parts; ++table->allocated_chunks; --table->free_chunks; } } if(table->chunks_map != NULL) FreeSysMemory(table->chunks_map); table->chunks_map = map; return 0; } else return -2; } */ //Remove this line and a similar one below to reactivate 'apa_setup_statistics' //------------------------------ //endfunc apa_setup_statistics //-------------------------------------------------------------- int apa_ptable_read_ex ( hio_t *hio, apa_partition_table_t **table) { u_long size_in_kb; int result = hio->stat(hio, &size_in_kb); if(result == 0){ u_long total_sectors; // limit HDD size to 128GB - 1KB; that is: exclude the last 128MB chunk //if (size_in_kb > 128 * 1024 * 1024 - 1) // size_in_kb = 128 * 1024 * 1024 - 1; total_sectors = size_in_kb * 2; /* 1KB = 2 sectors of 512 bytes, each */ *table = apa_ptable_alloc(); if(*table != NULL){ u_long sector = 0; do { u_long bytes; ps2_partition_header_t part; result = hio->read(hio, sector, sizeof(part) / 512, &part, &bytes); if(result == 0){ if(bytes == sizeof(part) && get_u32(&part.checksum) == apa_partition_checksum(&part) && memcmp(part.magic, PS2_PARTITION_MAGIC, 4) == 0) { if(get_u32(&part.start) < total_sectors && get_u32(&part.start) + get_u32(&part.length) < total_sectors) { if((get_u16(&part.flags)==0x0000) && (get_u16(&part.type) ==0x1337)) result = apa_part_add(*table, &part, 1, 1); if(result == 0) sector = get_u32(&part.next); } else { /* partition behind end-of-HDD */ result = 7; /* data behind end-of-HDD */ break; } } else result = 1; } /* TODO: check whether next partition is not loaded already -- * do not deadlock; that is a quick-and-dirty hack */ if ((*table)->part_count > 10000) result = 7; } while (result == 0 && sector != 0); if (result == 0){ (*table)->device_size_in_mb = size_in_kb / 1024; //NB: uncommenting the next lines requires changes elsewhere too //result = apa_setup_statistics (*table); //if (result == 0) //result = apa_check (*table); } if (result != 0){ result = 20000+(*table)->part_count; apa_ptable_free (*table); } } else result = -2; } return result; } //------------------------------ //endfunc apa_ptable_read_ex //-------------------------------------------------------------- /* //Remove this line and a similar one below to reactivate 'apa_check' static int apa_check (const apa_partition_table_t *table) { u_long i, j, k; const u_long total_sectors = table->device_size_in_mb * 1024 * 2; for (i=0; ipart_count; ++i) { const ps2_partition_header_t *part = &table->parts [i].header; if (get_u32 (&part->checksum) != apa_partition_checksum (part)) return 7; // bad checksum if (get_u32 (&part->start) < total_sectors && get_u32 (&part->start) + get_u32 (&part->length) <= total_sectors) ; else { return 7; // data behind end-of-HDD } if ((get_u32 (&part->length) % ((128 _MB) / 512)) != 0) return 7; // partition size not multiple to 128MB if ((get_u32 (&part->start) % get_u32 (&part->length)) != 0) return 7; // partition start not multiple on partition size if (get_u32 (&part->main) == 0 && get_u16 (&part->flags) == 0 && get_u32 (&part->start) != 0) { // check sub-partitions u_long count = 0; for (j=0; jpart_count; ++j) { const ps2_partition_header_t *part2 = &table->parts [j].header; if (get_u32 (&part2->main) == get_u32 (&part->start)) { // sub-partition of current main partition int found; if (get_u16 (&part2->flags) != PS2_PART_FLAG_SUB) return 7; found = 0; for (k=0; knsub); ++k) if (get_u32 (&part->subs [k].start) == get_u32 (&part2->start)) { // in list if (get_u32 (&part->subs [k].length) != get_u32 (&part2->length)) return 7; found = 1; break; } if (!found) return 7; // not found in the list ++count; } } if (count != get_u32 (&part->nsub)) return 7; // wrong number of sub-partitions } } // verify double-linked list for (i=0; ipart_count; ++i) { apa_partition_t *prev = table->parts + (i > 0 ? i - 1 : table->part_count - 1); apa_partition_t *curr = table->parts + i; apa_partition_t *next = table->parts + (i + 1 < table->part_count ? i + 1 : 0); if (get_u32 (&curr->header.prev) != get_u32 (&prev->header.start) || get_u32 (&curr->header.next) != get_u32 (&next->header.start)) return 7; // bad links } return 0; } */ //Remove this line and a similar one above to reactivate 'apa_check' //------------------------------ //endfunc apa_check //-------------------------------------------------------------- u_long get_u32 (const void *buffer) { const u_char *p = buffer; return ((((u_long) p[3]) << 24) | (((u_long) p[2]) << 16) | (((u_long) p[1]) << 8) | (((u_long) p[0]) << 0)); } //------------------------------ //endfunc get_u32 //-------------------------------------------------------------- void set_u32 (void *buffer, u_long val) { u_char *p = buffer; p [3] = (u_char) (val >> 24); p [2] = (u_char) (val >> 16); p [1] = (u_char) (val >> 8); p [0] = (u_char) (val >> 0); } //------------------------------ //endfunc set_u32 //-------------------------------------------------------------- u_short get_u16 (const void *buffer) { const u_char *p = buffer; return ((((u_short) p[1]) << 8) | (((u_short) p[0]) << 0)); } //------------------------------ //endfunc get_u16 //-------------------------------------------------------------- void set_u16 (void *buffer, u_short val) { u_char *p = buffer; p [1] = (u_char) (val >> 8); p [0] = (u_char) (val >> 0); } //------------------------------ //endfunc set_u16 //-------------------------------------------------------------- //End of file: apa.c //--------------------------------------------------------------