diff --git a/targetutil/geos-apple/convert.c b/targetutil/geos-apple/convert.c new file mode 100644 index 000000000..cafccca99 --- /dev/null +++ b/targetutil/geos-apple/convert.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include + +dhandle_t dhandle; + +struct dir_entry_t { + struct { + unsigned name_length :4; + unsigned storage_type :4; + } storage_length; + char file_name[15]; + unsigned char file_type; + unsigned key_pointer; + unsigned blocks_used; + unsigned char size[3]; + unsigned long creation; + unsigned char version; + unsigned char min_version; + unsigned char access; + unsigned aux_type; + unsigned long last_mod; + unsigned header_pointer; +}* dir_entry; + +union { + unsigned char bytes[512]; + struct { + unsigned prev_block; + unsigned next_block; + unsigned char entries[1]; + } content; +} dir_block; + +union { + unsigned char bytes[512]; + struct { + unsigned char addr_lo[254]; + unsigned char size_lo[2]; + unsigned char addr_hi[254]; + unsigned char size_hi[2]; + } content; +} index_block; + +union { + unsigned char bytes[512]; + struct { + unsigned char info_block[256]; + unsigned char vlir_records[128]; + struct dir_entry_t dir_entry; + } content; +} header_block; + + +static void err_exit(char *operation) +{ + fprintf(stderr, "%s - err:%02x - %s", + operation, (int)_oserror, _stroserror(_oserror)); + getchar(); + exit(EXIT_FAILURE); +} + + +static unsigned get_dir_entry(char* p_name) +{ + char* d_name; + char* f_name; + size_t f_namelen; + DIR* dir; + struct dirent* dirent; + unsigned cur_addr; + unsigned char entry_length; + unsigned char entries_per_block; + unsigned char cur_entry; + + /* Split path name into directory name and file name */ + f_name = strrchr(p_name, '/'); + if (f_name) { + d_name = p_name; + *f_name++ = '\0'; + } else { + d_name = "."; + f_name = p_name; + } + f_namelen = strlen(f_name); + + /* Start with high level functions to get handling + of relative path and current drive for free */ + dir = opendir(d_name); + if (!dir) { + err_exit("opendir"); + } + dirent = readdir(dir); + if (!dirent) { + err_exit("readdir"); + } + + /* Field header_pointer directly follows field last_mod */ + cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1); + + /* DEV_NUM is set to the drive accessed above */ + dhandle = dio_open(*(driveid_t*)0xBF30); + if (!dhandle) { + err_exit("dio_open"); + } + + if (dio_read(dhandle, cur_addr, &dir_block)) { + err_exit("dio_read.1"); + } + + /* Get directory entry infos from directory header */ + entry_length = dir_block.bytes[0x23]; + entries_per_block = dir_block.bytes[0x24]; + + /* Skip directory header entry */ + cur_entry = 1; + + do { + + /* Search for next active directory entry */ + do { + + /* Check if next directory block is necessary */ + if (cur_entry == entries_per_block) { + + /* Check if another directory block is present */ + cur_addr = dir_block.content.next_block; + if (!cur_addr) { + _mappederrno(0x46); + err_exit("dio_read.2"); + } + + /* Read next directory block */ + if (dio_read(dhandle, cur_addr, &dir_block)) { + err_exit("dio_read.3"); + } + + /* Start with first entry in next block */ + cur_entry = 0; + } + + /* Compute pointer to current entry */ + dir_entry = (struct dir_entry_t*)(dir_block.content.entries + + cur_entry * entry_length); + + /* Switch to next entry */ + ++cur_entry; + } while (!dir_entry->storage_length.storage_type); + + } while (dir_entry->storage_length.name_length != f_namelen || + strncasecmp(dir_entry->file_name, f_name, f_namelen)); + + return cur_addr; +} + + +int main(int argc, char* argv[]) +{ + char input[80]; + char* p_name; + unsigned dir_addr; + unsigned header_addr; + + if (argc > 1) { + p_name = argv[1]; + } else { + printf("Apple GEOS Convert\nPathname:"); + p_name = gets(input); + } + + dir_addr = get_dir_entry(p_name); + + if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) { + err_exit("dio_read.4"); + } + + header_addr = index_block.content.addr_lo[0] | + index_block.content.addr_hi[0] << 8; + + if (dio_read(dhandle, header_addr, &header_block)) { + err_exit("dio_read.5"); + } + + dir_entry->storage_length = header_block.content.dir_entry.storage_length; + memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15); + dir_entry->file_type = header_block.content.dir_entry.file_type; + memcpy(dir_entry->size, header_block.content.dir_entry.size, 3); + dir_entry->creation = header_block.content.dir_entry.creation; + dir_entry->version = header_block.content.dir_entry.version; + dir_entry->min_version = header_block.content.dir_entry.min_version; + dir_entry->aux_type = header_addr; + dir_entry->last_mod = header_block.content.dir_entry.last_mod; + + memmove(&index_block.content.addr_lo[0], + &index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1); + memmove(&index_block.content.addr_hi[0], + &index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1); + + index_block.content.size_lo[1] = dir_entry->size[0]; + index_block.content.size_hi[1] = dir_entry->size[1]; + index_block.content.size_lo[0] = dir_entry->size[2]; + index_block.content.size_hi[0] = 0; + + if (dio_write(dhandle, dir_addr, &dir_block)) { + err_exit("dio_write.1"); + } + + if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) { + err_exit("dio_write.2"); + } + + if (dio_close(dhandle)) { + err_exit("dio_close"); + } + + return EXIT_SUCCESS; +} \ No newline at end of file