diff options
Diffstat (limited to 'src/tools/imgtool/modules/prodos.cpp')
-rw-r--r-- | src/tools/imgtool/modules/prodos.cpp | 2267 |
1 files changed, 0 insertions, 2267 deletions
diff --git a/src/tools/imgtool/modules/prodos.cpp b/src/tools/imgtool/modules/prodos.cpp deleted file mode 100644 index 6db41ae529b..00000000000 --- a/src/tools/imgtool/modules/prodos.cpp +++ /dev/null @@ -1,2267 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet -/**************************************************************************** - - prodos.cpp - - Apple II ProDOS disk images - -***************************************************************************** - - Notes: - - ProDOS disks are split into 512 byte blocks. - - ProDOS directory structure: - - Offset Length Description - ------ ------ ----------- - 0 2 ??? - 2 2 Next block (0 if end) - 4 39 Directory Entry - 43 39 Directory Entry - ... - 472 39 Directory Entry - 511 1 ??? - - - ProDOS directory entry structure: - - Offset Length Description - ------ ------ ----------- - 0 1 Storage type (bits 7-4) - 10 - Seedling File (1 block) - 20 - Sapling File (2-256 blocks) - 30 - Tree File (257-32768 blocks) - 40 - Pascal Areas on ProFile HDs (???) - 50 - GS/OS Extended File (data and rsrc fork) - E0 - Subdirectory Header - F0 - Volume Header - 1 15 File name (NUL padded) - 16 1 File type - 17 2 Key pointer - 19 2 Blocks used - 21 3 File size - 24 4 Creation date - 28 1 ProDOS version that created the file - 29 1 Minimum ProDOS version needed to read the file - 30 1 Access byte - 31 2 Auxilary file type - 33 4 Last modified date - 37 2 Header pointer - - - In "seedling files", the key pointer points to a single block that is the - whole file. In "sapling files", the key pointer points to an index block - that contains 256 2-byte index pointers that point to the actual blocks of - the files. These 2-byte values are not contiguous; the low order byte is - in the first half of the block, and the high order byte is in the second - half of the block. In "tree files", the key pointer points to an index - block of index blocks. - - ProDOS dates are 32-bit little endian values - - bits 0- 4 Day - bits 5- 8 Month (0-11) - bits 9-15 Year (0-49 is 2000-2049, 50-99 is 1950-1999) - bits 16-21 Minute - bits 24-28 Hour - - - ProDOS directory and volume headers have this information: - - Offset Length Description - ------ ------ ----------- - 31 1 Length of the entry; generally is 39 - 32 1 Number of entries per block; generally is 13 - 33 2 Active entry count in directory - 35 2 Volume bitmap block number - 37 2 Total blocks on volume - - GS/OS Extended Files (storage type $5) point to an extended key block that - contains information about the two forks. The first half of the extended - key block contains info about the data form, and the second half the - resource fork. Both sides have the following format: - - Offset Length Description - ------ ------ ----------- - 0 1 Storage type (bits 3-0, unlike the directory entry) - 1 2 Key pointer - 3 2 Blocks used - 5 3 File size - 8 1 Size of secondary info #1 (must be 18 to be valid) - 9 1 Secondary info #1 type (1=FInfo 2=xFInfo) - 10 16 FInfo or xFInfo - 26 1 Size of secondary info #2 (must be 18 to be valid) - 27 1 Secondary info #2 type (1=FInfo 2=xFInfo) - 28 16 FInfo or xFInfo - - FInfo format: - - Offset Length Description - ------ ------ ----------- - 0 4 File type - 4 4 File creator - 8 2 Finder flags - 10 2 X Coordinate - 12 2 Y Coordinate - 14 2 Finder folder - - xFInfo format: - - Offset Length Description - ------ ------ ----------- - 0 2 Icon ID - 2 6 Reserved - 8 1 Script Code - 9 1 Extended flags - 10 2 Comment ID - 12 4 Put Away Directory - - - For more info, consult ProDOS technical note #25 - (http://web.pdx.edu/~heiss/technotes/pdos/tn.pdos.25.html) - -*****************************************************************************/ - -#include "imgtool.h" -#include "formats/imageutl.h" -#include "formats/ap2_dsk.h" -#include "formats/ap_dsk35.h" -#include "iflopimg.h" -#include "macutil.h" - -#define ROOTDIR_BLOCK 2 -#define BLOCK_SIZE 512 - -struct prodos_diskinfo -{ - imgtoolerr_t (*load_block)(imgtool::image &image, int block, void *buffer); - imgtoolerr_t (*save_block)(imgtool::image &image, int block, const void *buffer); - uint8_t dirent_size; - uint8_t dirents_per_block; - uint16_t volume_bitmap_block; - uint16_t total_blocks; -}; - -struct prodos_direnum -{ - uint32_t block; - uint32_t index; - uint8_t block_data[BLOCK_SIZE]; -}; - -struct prodos_dirent -{ - char filename[16]; - uint8_t storage_type; - uint16_t extkey_pointer; - uint16_t key_pointer[2]; - uint32_t filesize[2]; - int depth[2]; - uint32_t lastmodified_time; - uint32_t creation_time; - - /* FInfo */ - uint32_t file_type; - uint32_t file_creator; - uint16_t finder_flags; - uint16_t coord_x; - uint16_t coord_y; - uint16_t finder_folder; - - /* xFInfo */ - uint16_t icon_id; - uint8_t script_code; - uint8_t extended_flags; - uint16_t comment_id; - uint32_t putaway_directory; -}; - -enum creation_policy_t -{ - CREATE_NONE, - CREATE_FILE, - CREATE_DIR -}; - - - -static imgtool::datetime prodos_crack_time(uint32_t prodos_time) -{ - util::arbitrary_datetime dt; - dt.second = 0; - dt.minute = ((prodos_time >> 16) & 0x3F); - dt.hour = ((prodos_time >> 24) & 0x1F); - dt.day_of_month = ((prodos_time >> 0) & 0x1F); - dt.month = ((prodos_time >> 5) & 0x0F) + 1; - dt.year = ((prodos_time >> 9) & 0x7F) + 1900; - if (dt.year <= 1949) - dt.year += 100; - - return imgtool::datetime(imgtool::datetime::datetime_type::LOCAL, dt); -} - - - -static uint32_t prodos_setup_time(time_t ansi_time) -{ - struct tm t; - uint32_t result = 0; - - t = *localtime(&ansi_time); - if ((t.tm_year >= 100) && (t.tm_year <= 149)) - t.tm_year -= 100; - - result |= (((uint32_t) t.tm_min) & 0x003F) << 16; - result |= (((uint32_t) t.tm_hour) & 0x001F) << 24; - result |= (((uint32_t) t.tm_mday) & 0x001F) << 0; - result |= (((uint32_t) t.tm_mon) & 0x000F) << 5; - result |= (((uint32_t) t.tm_year) & 0x007F) << 9; - return result; -} - - - -static uint32_t prodos_time_now(void) -{ - time_t now; - time(&now); - return prodos_setup_time(now); -} - - - -static int is_file_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)) - || ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_normalfile_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x10) && (storage_type <= 0x3F)); -} - - - -static int is_extendedfile_storagetype(uint8_t storage_type) -{ - return ((storage_type >= 0x50) && (storage_type <= 0x5F)); -} - - - -static int is_dir_storagetype(uint8_t storage_type) -{ - return (storage_type >= 0xE0) && (storage_type <= 0xEF); -} - - - -static prodos_diskinfo *get_prodos_info(imgtool::image &image) -{ - prodos_diskinfo *info; - info = (prodos_diskinfo *) imgtool_floppy_extrabytes(image); - return info; -} - - - -/* ----------------------------------------------------------------------- */ - -static void prodos_find_block_525(imgtool::image &image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector1, uint32_t *sector2) -{ - static const uint8_t skewing[] = - { - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, - 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F - }; - - block *= 2; - - *track = block / APPLE2_SECTOR_COUNT; - *head = 0; - *sector1 = skewing[block % APPLE2_SECTOR_COUNT + 0]; - *sector2 = skewing[block % APPLE2_SECTOR_COUNT + 1]; -} - - - -static imgtoolerr_t prodos_load_block_525(imgtool::image &image, - int block, void *buffer) -{ - floperr_t ferr; - uint32_t track, head, sector1, sector2; - - prodos_find_block_525(image, block, &track, &head, §or1, §or2); - - /* read first sector */ - ferr = floppy_read_sector(imgtool_floppy(image), head, track, - sector1, 0, ((uint8_t *) buffer) + 0, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - /* read second sector */ - ferr = floppy_read_sector(imgtool_floppy(image), head, track, - sector2, 0, ((uint8_t *) buffer) + 256, 256); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_save_block_525(imgtool::image &image, - int block, const void *buffer) -{ - floperr_t ferr; - uint32_t track, head, sector1, sector2; - - prodos_find_block_525(image, block, &track, &head, §or1, §or2); - - /* read first sector */ - ferr = floppy_write_sector(imgtool_floppy(image), head, track, - sector1, 0, ((const uint8_t *) buffer) + 0, 256, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - /* read second sector */ - ferr = floppy_write_sector(imgtool_floppy(image), head, track, - sector2, 0, ((const uint8_t *) buffer) + 256, 256, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_setprocs_525(imgtool::image &image) -{ - prodos_diskinfo *info; - info = get_prodos_info(image); - info->load_block = prodos_load_block_525; - info->save_block = prodos_save_block_525; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_find_block_35(imgtool::image &image, int block, - uint32_t *track, uint32_t *head, uint32_t *sector) -{ - int sides = 2; - - *track = 0; - while(block >= (apple35_sectors_per_track(imgtool_floppy(image), *track) * sides)) - { - block -= (apple35_sectors_per_track(imgtool_floppy(image), (*track)++) * sides); - if (*track >= 80) - return IMGTOOLERR_SEEKERROR; - } - - *head = block / apple35_sectors_per_track(imgtool_floppy(image), *track); - *sector = block % apple35_sectors_per_track(imgtool_floppy(image), *track); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_load_block_35(imgtool::image &image, - int block, void *buffer) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = prodos_find_block_35(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512); - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_save_block_35(imgtool::image &image, - int block, const void *buffer) -{ - imgtoolerr_t err; - floperr_t ferr; - uint32_t track, head, sector; - - err = prodos_find_block_35(image, block, &track, &head, §or); - if (err) - return err; - - ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, 512, 0); /* TODO: pass ddam argument from imgtool */ - if (ferr) - return imgtool_floppy_error(ferr); - - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_setprocs_35(imgtool::image &image) -{ - prodos_diskinfo *info; - info = get_prodos_info(image); - info->load_block = prodos_load_block_35; - info->save_block = prodos_save_block_35; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_load_block(imgtool::image &image, - int block, void *buffer) -{ - prodos_diskinfo *diskinfo; - diskinfo = get_prodos_info(image); - return diskinfo->load_block(image, block, buffer); -} - - - -static imgtoolerr_t prodos_save_block(imgtool::image &image, - int block, const void *buffer) -{ - prodos_diskinfo *diskinfo; - diskinfo = get_prodos_info(image); - return diskinfo->save_block(image, block, buffer); -} - - - -static imgtoolerr_t prodos_clear_block(imgtool::image &image, int block) -{ - uint8_t buffer[BLOCK_SIZE]; - memset(buffer, 0, sizeof(buffer)); - return prodos_save_block(image, block, buffer); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_diskimage_open(imgtool::image &image) -{ - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - prodos_diskinfo *di; - const uint8_t *ent; - - di = get_prodos_info(image); - - /* specify defaults */ - di->dirent_size = 39; - di->dirents_per_block = 13; - - /* load the first block, hoping that the volume header is first */ - err = prodos_load_block(image, ROOTDIR_BLOCK, buffer); - if (err) - return err; - - ent = &buffer[4]; - - /* did we find the volume header? */ - if ((ent[0] & 0xF0) == 0xF0) - { - di->dirent_size = pick_integer_le(ent, 31, 1); - di->dirents_per_block = pick_integer_le(ent, 32, 1); - di->volume_bitmap_block = pick_integer_le(ent, 35, 2); - di->total_blocks = pick_integer_le(ent, 37, 2); - } - - /* sanity check these values */ - if (di->dirent_size < 39) - return IMGTOOLERR_CORRUPTIMAGE; - if (di->dirents_per_block * di->dirent_size >= BLOCK_SIZE) - return IMGTOOLERR_CORRUPTIMAGE; - if (di->volume_bitmap_block >= di->total_blocks) - return IMGTOOLERR_CORRUPTIMAGE; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_open_525(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - prodos_setprocs_525(image); - return prodos_diskimage_open(image); -} - - - -static imgtoolerr_t prodos_diskimage_open_35(imgtool::image &image, imgtool::stream::ptr &&dummy) -{ - prodos_setprocs_35(image); - return prodos_diskimage_open(image); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_load_volume_bitmap(imgtool::image &image, uint8_t **bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t *alloc_bitmap; - uint32_t bitmap_blocks, i; - - di = get_prodos_info(image); - - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - alloc_bitmap = (uint8_t*)malloc(bitmap_blocks * BLOCK_SIZE); - if (!alloc_bitmap) - { - err = IMGTOOLERR_OUTOFMEMORY; - goto done; - } - - for (i = 0; i < bitmap_blocks; i++) - { - err = prodos_load_block(image, di->volume_bitmap_block + i, - &alloc_bitmap[i * BLOCK_SIZE]); - if (err) - goto done; - } - - err = IMGTOOLERR_SUCCESS; - -done: - if (err && alloc_bitmap) - { - free(alloc_bitmap); - alloc_bitmap = NULL; - } - *bitmap = alloc_bitmap; - return err; -} - - - -static imgtoolerr_t prodos_save_volume_bitmap(imgtool::image &image, const uint8_t *bitmap) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint32_t bitmap_blocks, i; - - di = get_prodos_info(image); - - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - for (i = 0; i < bitmap_blocks; i++) - { - err = prodos_save_block(image, di->volume_bitmap_block + i, - &bitmap[i * BLOCK_SIZE]); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static void prodos_set_volume_bitmap_bit(uint8_t *buffer, uint16_t block, int value) -{ - uint8_t mask; - buffer += block / 8; - mask = 1 << (7 - (block % 8)); - if (value) - *buffer |= mask; - else - *buffer &= ~mask; -} - - - -static int prodos_get_volume_bitmap_bit(const uint8_t *buffer, uint16_t block) -{ - uint8_t mask; - buffer += block / 8; - mask = 1 << (7 - (block % 8)); - return (*buffer & mask) ? 1 : 0; -} - - - -static imgtoolerr_t prodos_alloc_block(imgtool::image &image, uint8_t *bitmap, - uint16_t *block) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - prodos_diskinfo *di; - uint16_t bitmap_blocks, i; - uint8_t *alloc_bitmap = NULL; - - di = get_prodos_info(image); - *block = 0; - bitmap_blocks = (di->total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - if (!bitmap) - { - err = prodos_load_volume_bitmap(image, &alloc_bitmap); - if (err) - goto done; - bitmap = alloc_bitmap; - } - - for (i = (di->volume_bitmap_block + bitmap_blocks); i < di->total_blocks; i++) - { - if (!prodos_get_volume_bitmap_bit(bitmap, i)) - { - prodos_set_volume_bitmap_bit(bitmap, i, 1); - *block = i; - break; - } - } - - if (*block > 0) - { - if (alloc_bitmap) - { - err = prodos_save_volume_bitmap(image, bitmap); - if (err) - goto done; - } - } - else - { - err = IMGTOOLERR_NOSPACE; - } - -done: - if (err) - *block = 0; - if (alloc_bitmap) - free(alloc_bitmap); - return err; -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_diskimage_create(imgtool::image &image, util::option_resolution *opts) -{ - imgtoolerr_t err; - uint32_t heads, tracks, sectors, sector_bytes; - uint32_t dirent_size, volume_bitmap_block, i; - uint32_t volume_bitmap_block_count, total_blocks; - uint8_t buffer[BLOCK_SIZE]; - - heads = opts->lookup_int('H'); - tracks = opts->lookup_int('T'); - sectors = opts->lookup_int('S'); - sector_bytes = opts->lookup_int('L'); - - dirent_size = 39; - volume_bitmap_block = 6; - total_blocks = tracks * heads * sectors * sector_bytes / BLOCK_SIZE; - volume_bitmap_block_count = (total_blocks + (BLOCK_SIZE * 8) - 1) / (BLOCK_SIZE * 8); - - /* prepare initial dir block */ - memset(buffer, 0, sizeof(buffer)); - place_integer_le(buffer, 4 + 0, 1, 0xF0); - place_integer_le(buffer, 4 + 31, 1, dirent_size); - place_integer_le(buffer, 4 + 32, 1, BLOCK_SIZE / dirent_size); - place_integer_le(buffer, 4 + 35, 2, volume_bitmap_block); - place_integer_le(buffer, 4 + 37, 2, total_blocks); - - err = prodos_save_block(image, ROOTDIR_BLOCK, buffer); - if (err) - return err; - - /* setup volume bitmap */ - memset(buffer, 0, sizeof(buffer)); - for (i = 0; i < (volume_bitmap_block + volume_bitmap_block_count); i++) - prodos_set_volume_bitmap_bit(buffer, i, 1); - prodos_save_block(image, volume_bitmap_block, buffer); - - /* and finally open the image */ - return prodos_diskimage_open(image); -} - - - -static imgtoolerr_t prodos_diskimage_create_525(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - prodos_setprocs_525(image); - return prodos_diskimage_create(image, opts); -} - - - -static imgtoolerr_t prodos_diskimage_create_35(imgtool::image &image, imgtool::stream::ptr &&dummy, util::option_resolution *opts) -{ - prodos_setprocs_35(image); - return prodos_diskimage_create(image, opts); -} - - - -/* ----------------------------------------------------------------------- */ - -static imgtoolerr_t prodos_enum_seek(imgtool::image &image, - prodos_direnum *appleenum, uint32_t block, uint32_t index) -{ - imgtoolerr_t err; - uint8_t buffer[BLOCK_SIZE]; - - if (appleenum->block != block) - { - if (block != 0) - { - err = prodos_load_block(image, block, buffer); - if (err) - return err; - memcpy(appleenum->block_data, buffer, sizeof(buffer)); - } - appleenum->block = block; - } - - appleenum->index = index; - return IMGTOOLERR_SUCCESS; -} - - - -static uint8_t *next_info_block(uint8_t *buffer, size_t *position) -{ - size_t side = *position & 0x100; - size_t subpos = *position & 0x0FF; - uint8_t *result; - - if (subpos < 8) - { - subpos = 8; - *position = side + subpos; - } - - while((buffer[side + subpos] == 0x00) || (subpos + buffer[side + subpos] > 0x100)) - { - if (side) - return NULL; - - side = 0x100; - subpos = 8; - } - - result = &buffer[side + subpos]; - subpos += *result; - *position = side + subpos; - return result; -} - - - -static uint8_t *alloc_info_block(uint8_t *buffer, size_t block_size, uint8_t block_type) -{ - size_t position = 0; - size_t side; - size_t subpos; - uint8_t *result; - - while(next_info_block(buffer, &position)) - ; - - side = position & 0x100; - subpos = position & 0x0FF; - - if ((subpos + block_size) > 0x100) - return NULL; - - result = &buffer[side + subpos]; - *(result++) = (uint8_t) block_size; - *(result++) = block_type; - memset(result, 0, block_size - 2); - return result; -} - - - -static imgtoolerr_t prodos_get_next_dirent(imgtool::image &image, - prodos_direnum *appleenum, prodos_dirent &ent) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - size_t finfo_offset; - uint32_t next_block, next_index; - uint32_t offset; - uint8_t buffer[BLOCK_SIZE]; - const uint8_t *info_ptr; - int fork_num; - - di = get_prodos_info(image); - memset(&ent, 0, sizeof(ent)); - - /* have we hit the end of the file? */ - if (appleenum->block == 0) - return IMGTOOLERR_SUCCESS; - - /* populate the resulting dirent */ - offset = appleenum->index * di->dirent_size + 4; - ent.storage_type = appleenum->block_data[offset + 0]; - memcpy(ent.filename, &appleenum->block_data[offset + 1], 15); - ent.filename[15] = '\0'; - ent.creation_time = pick_integer_le(appleenum->block_data, offset + 24, 4); - ent.lastmodified_time = pick_integer_le(appleenum->block_data, offset + 33, 4); - ent.file_type = 0x3F3F3F3F; - ent.file_creator = 0x3F3F3F3F; - ent.finder_flags = 0; - ent.coord_x = 0; - ent.coord_y = 0; - ent.finder_folder = 0; - ent.icon_id = 0; - ent.script_code = 0; - ent.extended_flags = 0; - ent.comment_id = 0; - ent.putaway_directory = 0; - - if (is_extendedfile_storagetype(ent.storage_type)) - { - /* this is a ProDOS extended file; we need to get the extended info - * block */ - ent.extkey_pointer = pick_integer_le(appleenum->block_data, offset + 17, 2); - - err = prodos_load_block(image, ent.extkey_pointer, buffer); - if (err) - return err; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - ent.key_pointer[fork_num] = pick_integer_le(buffer, 1 + (fork_num * 256), 2); - ent.filesize[fork_num] = pick_integer_le(buffer, 5 + (fork_num * 256), 3); - ent.depth[fork_num] = buffer[fork_num * 256] & 0x0F; - } - - finfo_offset = 0; - while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL) - { - if (*(info_ptr++) == 18) - { - switch(*(info_ptr++)) - { - case 1: /* FInfo */ - ent.file_type = pick_integer_be(info_ptr, 0, 4); - ent.file_creator = pick_integer_be(info_ptr, 4, 4); - ent.finder_flags = pick_integer_be(info_ptr, 8, 2); - ent.coord_x = pick_integer_be(info_ptr, 10, 2); - ent.coord_y = pick_integer_be(info_ptr, 12, 2); - ent.finder_folder = pick_integer_be(info_ptr, 14, 4); - break; - - case 2: /* xFInfo */ - ent.icon_id = pick_integer_be(info_ptr, 0, 2); - ent.script_code = pick_integer_be(info_ptr, 8, 1); - ent.extended_flags = pick_integer_be(info_ptr, 9, 1); - ent.comment_id = pick_integer_be(info_ptr, 10, 2); - ent.putaway_directory = pick_integer_be(info_ptr, 12, 4); - break; - } - } - } - } - else - { - /* normal ProDOS files have all of the info right here */ - ent.key_pointer[0] = pick_integer_le(appleenum->block_data, offset + 17, 2); - ent.filesize[0] = pick_integer_le(appleenum->block_data, offset + 21, 3); - ent.depth[0] = ent.storage_type >> 4; - } - - /* identify next entry */ - next_block = appleenum->block; - next_index = appleenum->index + 1; - if (next_index >= di->dirents_per_block) - { - next_block = pick_integer_le(appleenum->block_data, 2, 2); - next_index = 0; - } - - /* seek next block */ - err = prodos_enum_seek(image, appleenum, next_block, next_index); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -/* changes a normal file to a ProDOS extended file */ -static imgtoolerr_t prodos_promote_file(imgtool::image &image, uint8_t *bitmap, prodos_dirent *ent) -{ - imgtoolerr_t err; - uint16_t new_block; - uint8_t buffer[BLOCK_SIZE]; - - assert(is_normalfile_storagetype(ent->storage_type)); - - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - - /* create raw extended info block */ - memset(buffer, 0, sizeof(buffer)); - err = prodos_save_block(image, new_block, buffer); - if (err) - return err; - - ent->storage_type = (ent->storage_type & 0x0F) | 0x50; - ent->extkey_pointer = new_block; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_put_dirent(imgtool::image &image, - prodos_direnum *appleenum, prodos_dirent *ent) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint32_t offset; - size_t finfo_offset; - uint8_t buffer[BLOCK_SIZE]; - int fork_num; - int needs_finfo = false; - int needs_xfinfo = false; - uint8_t *info_ptr; - uint8_t *finfo; - uint8_t *xfinfo; - - di = get_prodos_info(image); - offset = appleenum->index * di->dirent_size + 4; - - /* determine whether we need FInfo and/or xFInfo */ - if (is_normalfile_storagetype(ent->storage_type)) - { - needs_finfo = (ent->file_type != 0x3F3F3F3F) || - (ent->file_creator != 0x3F3F3F3F) || - (ent->finder_flags != 0) || - (ent->coord_x != 0) || - (ent->coord_y != 0) || - (ent->finder_folder != 0); - - needs_xfinfo = (ent->icon_id != 0) || - (ent->script_code != 0) || - (ent->extended_flags != 0) || - (ent->comment_id != 0) || - (ent->putaway_directory != 0); - } - - /* do we need to promote this file to an extended file? */ - if (!is_extendedfile_storagetype(ent->storage_type) - && (needs_finfo || needs_xfinfo)) - { - err = prodos_promote_file(image, NULL, ent); - if (err) - return err; - } - - /* write out the storage type, filename, creation and lastmodified times */ - appleenum->block_data[offset + 0] = ent->storage_type; - memcpy(&appleenum->block_data[offset + 1], ent->filename, 15); - place_integer_le(appleenum->block_data, offset + 24, 4, ent->creation_time); - place_integer_le(appleenum->block_data, offset + 33, 4, ent->lastmodified_time); - - if (is_extendedfile_storagetype(ent->storage_type)) - { - /* ProDOS extended file */ - err = prodos_load_block(image, ent->extkey_pointer, buffer); - if (err) - return err; - - finfo = NULL; - xfinfo = NULL; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - place_integer_le(buffer, 1 + (fork_num * 256), 2, ent->key_pointer[fork_num]); - place_integer_le(buffer, 5 + (fork_num * 256), 3, ent->filesize[fork_num]); - buffer[fork_num * 256] = ent->depth[fork_num]; - } - - finfo_offset = 0; - while((info_ptr = next_info_block(buffer, &finfo_offset)) != NULL) - { - if (*(info_ptr++) == 18) - { - switch(*(info_ptr++)) - { - case 1: /* FInfo */ - finfo = info_ptr; - break; - - case 2: /* xFInfo */ - xfinfo = info_ptr; - break; - } - } - } - - /* allocate the finfo and/or xinfo blocks, if we need them */ - if (needs_finfo && !finfo) - finfo = alloc_info_block(buffer, 18, 1); - if (needs_xfinfo && !xfinfo) - xfinfo = alloc_info_block(buffer, 18, 2); - - if (finfo) - { - place_integer_be(finfo, 0, 4, ent->file_type); - place_integer_be(finfo, 4, 4, ent->file_creator); - place_integer_be(finfo, 8, 2, ent->finder_flags); - place_integer_be(finfo, 10, 2, ent->coord_x); - place_integer_be(finfo, 12, 2, ent->coord_y); - place_integer_be(finfo, 14, 4, ent->finder_folder); - } - - if (xfinfo) - { - place_integer_be(xfinfo, 0, 2, ent->icon_id); - place_integer_be(xfinfo, 8, 1, ent->script_code); - place_integer_be(xfinfo, 9, 1, ent->extended_flags); - place_integer_be(xfinfo, 10, 2, ent->comment_id); - place_integer_be(xfinfo, 12, 4, ent->putaway_directory); - } - - err = prodos_save_block(image, ent->extkey_pointer, buffer); - if (err) - return err; - - place_integer_le(appleenum->block_data, offset + 17, 2, ent->extkey_pointer); - place_integer_le(appleenum->block_data, offset + 21, 3, BLOCK_SIZE); - } - else - { - /* normal file */ - place_integer_le(appleenum->block_data, offset + 17, 2, ent->key_pointer[0]); - place_integer_le(appleenum->block_data, offset + 21, 3, ent->filesize[0]); - } - - err = prodos_save_block(image, appleenum->block, appleenum->block_data); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_lookup_path(imgtool::image &image, const char *path, - creation_policy_t create, prodos_direnum *direnum, prodos_dirent *ent) -{ - imgtoolerr_t err; - prodos_direnum my_direnum; - uint32_t block = ROOTDIR_BLOCK; - const char *old_path; - uint16_t this_block; - uint32_t this_index; - uint16_t free_block = 0; - uint32_t free_index = 0; - uint16_t new_file_block; - uint8_t buffer[BLOCK_SIZE]; - - if (!direnum) - direnum = &my_direnum; - - while(*path) - { - memset(direnum, 0, sizeof(*direnum)); - err = prodos_enum_seek(image, direnum, block, 0); - if (err) - goto done; - - do - { - this_block = direnum->block; - this_index = direnum->index; - - err = prodos_get_next_dirent(image, direnum, *ent); - if (err) - goto done; - - /* if we need to create a file entry and this is free, track it */ - if (create && this_block && !free_block && !ent->storage_type) - { - free_block = this_block; - free_index = this_index; - } - } - while(direnum->block && (strcmp(path, ent->filename) || ( - !is_file_storagetype(ent->storage_type) && - !is_dir_storagetype(ent->storage_type)))); - - old_path = path; - path += strlen(path) + 1; - if (*path) - { - /* we have found part of the path; we are not finished yet */ - if (!is_dir_storagetype(ent->storage_type)) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - block = ent->key_pointer[0]; - } - else if (!direnum->block) - { - /* did not find file; maybe we need to create it */ - if (create == CREATE_NONE) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - /* do we need to expand the directory? */ - if (!free_block) - { - if (this_block == 0) - { - err = IMGTOOLERR_CORRUPTFILE; - goto done; - } - - err = prodos_load_block(image, this_block, buffer); - if (err) - goto done; - - /* allocate a block */ - err = prodos_alloc_block(image, NULL, &free_block); - if (err) - goto done; - - /* clear out this new block */ - err = prodos_clear_block(image, free_block); - if (err) - goto done; - - /* save this link */ - place_integer_le(buffer, 2, 2, free_block); - err = prodos_save_block(image, this_block, buffer); - if (err) - goto done; - - free_index = 0; - } - - /* seek back to the free space */ - err = prodos_enum_seek(image, direnum, free_block, free_index); - if (err) - goto done; - - new_file_block = 0; - if (create == CREATE_DIR) - { - /* if we are creating a directory, we need to create a new block */ - err = prodos_alloc_block(image, NULL, &new_file_block); - if (err) - goto done; - - err = prodos_clear_block(image, new_file_block); - if (err) - goto done; - } - - /* prepare the dirent */ - memset(ent, 0, sizeof(*ent)); - ent->storage_type = (create == CREATE_DIR) ? 0xe0 : 0x10; - ent->creation_time = ent->lastmodified_time = prodos_time_now(); - ent->key_pointer[0] = new_file_block; - ent->file_type = 0x3F3F3F3F; - ent->file_creator = 0x3F3F3F3F; - strncpy(ent->filename, old_path, ARRAY_LENGTH(ent->filename)); - - /* and place it */ - err = prodos_put_dirent(image, direnum, ent); - if (err) - goto done; - - this_block = free_block; - this_index = free_index; - } - else - { - /* we've found the file; seek that dirent */ - err = prodos_enum_seek(image, direnum, this_block, this_index); - if (err) - goto done; - } - } - - err = IMGTOOLERR_SUCCESS; -done: - return err; -} - - - -static imgtoolerr_t prodos_fill_file(imgtool::image &image, uint8_t *bitmap, - uint16_t key_block, int key_block_allocated, - int depth, uint32_t blockcount, uint32_t block_index) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int dirty; - int sub_block_allocated; - uint16_t i, sub_block, new_sub_block; - uint8_t buffer[BLOCK_SIZE]; - - di = get_prodos_info(image); - - if (key_block_allocated) - { - /* we are on a recently allocated key block; start fresh */ - memset(buffer, 0, sizeof(buffer)); - dirty = true; - } - else - { - /* this is a preexisting key block */ - err = prodos_load_block(image, key_block, buffer); - if (err) - return err; - dirty = false; - } - - for (i = 0; i < 256; i++) - { - sub_block_allocated = false; - - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block += buffer[i + 0]; - - new_sub_block = sub_block; - if ((block_index < blockcount) && (sub_block == 0)) - { - err = prodos_alloc_block(image, bitmap, &new_sub_block); - if (err) - return err; - sub_block_allocated = true; - } - else if ((block_index >= blockcount) && (sub_block != 0)) - { - new_sub_block = 0; - if (sub_block < di->total_blocks) - prodos_set_volume_bitmap_bit(bitmap, sub_block, 0); - } - - /* did we change the block? */ - if (new_sub_block != sub_block) - { - dirty = true; - buffer[i + 0] = new_sub_block >> 0; - buffer[i + 256] = new_sub_block >> 8; - if (sub_block == 0) - sub_block = new_sub_block; - } - - /* call recursive function */ - if (depth > 2) - { - err = prodos_fill_file(image, bitmap, sub_block, sub_block_allocated, depth - 1, blockcount, block_index); - if (err) - return err; - } - - /* increment index */ - block_index += 1 << ((depth - 2) * 8); - } - - /* if we changed anything, then save the block */ - if (dirty) - { - err = prodos_save_block(image, key_block, buffer); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_set_file_block_count(imgtool::image &image, prodos_direnum *direnum, - prodos_dirent *ent, uint8_t *bitmap, int fork_num, uint32_t new_blockcount) -{ - imgtoolerr_t err; - int depth, new_depth, i; - uint16_t new_block, block; - uint8_t buffer[BLOCK_SIZE]; - uint16_t key_pointer; - - if (fork_num && (new_blockcount > 0) && !is_extendedfile_storagetype(ent->storage_type)) - { - /* need to change a normal file to an extended file */ - err = prodos_promote_file(image, bitmap, ent); - if (err) - return err; - } - - key_pointer = ent->key_pointer[fork_num]; - depth = ent->depth[fork_num]; - - /* determine the new tree depth */ - if (new_blockcount <= 1) - new_depth = 1; - else if (new_blockcount <= 256) - new_depth = 2; - else - new_depth = 3; - - /* are we zero length, and do we have to create a block? */ - if ((new_blockcount >= 1) && (key_pointer == 0)) - { - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - key_pointer = new_block; - } - - /* do we have to grow the tree? */ - while(new_depth > depth) - { - err = prodos_alloc_block(image, bitmap, &new_block); - if (err) - return err; - - /* create this new key block, with a link to the previous one */ - memset(buffer, 0, sizeof(buffer)); - buffer[0] = (uint8_t) (key_pointer >> 0); - buffer[256] = (uint8_t) (key_pointer >> 8); - err = prodos_save_block(image, new_block, buffer); - if (err) - return err; - - depth++; - key_pointer = new_block; - } - - /* do we have to shrink the tree? */ - while(new_depth < depth) - { - err = prodos_load_block(image, key_pointer, buffer); - if (err) - return err; - - for (i = 1; i < 256; i++) - { - block = buffer[i + 256]; - block <<= 8; - block |= buffer[i + 0]; - - if (block > 0) - { - if (depth > 2) - { - /* remove this block's children */ - err = prodos_fill_file(image, bitmap, block, false, depth - 1, 0, 0); - if (err) - return err; - } - - /* and remove this block */ - prodos_set_volume_bitmap_bit(bitmap, block, 0); - } - } - - /* remove this key block */ - prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0); - - /* set the new key pointer */ - block = buffer[256]; - block <<= 8; - block |= buffer[0]; - key_pointer = block; - - depth--; - } - - if (new_blockcount > 0) - { - /* fill out the file tree */ - err = prodos_fill_file(image, bitmap, key_pointer, false, depth, new_blockcount, 0); - if (err) - return err; - } - else if (key_pointer != 0) - { - /* we are now zero length, and don't need a key pointer */ - prodos_set_volume_bitmap_bit(bitmap, key_pointer, 0); - key_pointer = 0; - } - - /* change the depth if we are not an extended file */ - if (is_normalfile_storagetype(ent->storage_type)) - { - ent->storage_type &= ~0xF0; - ent->storage_type |= depth * 0x10; - } - - ent->key_pointer[fork_num] = key_pointer; - ent->depth[fork_num] = depth; - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_set_file_size(imgtool::image &image, prodos_direnum *direnum, - prodos_dirent *ent, int fork_num, uint32_t new_size) -{ - imgtoolerr_t err = IMGTOOLERR_SUCCESS; - uint32_t blockcount, new_blockcount; - uint8_t *bitmap = NULL; - - if (ent->filesize[fork_num] != new_size) - { - blockcount = (ent->filesize[fork_num] + BLOCK_SIZE - 1) / BLOCK_SIZE; - new_blockcount = (new_size + BLOCK_SIZE - 1) / BLOCK_SIZE; - - /* do we need to change the block chain? */ - if (new_blockcount != blockcount) - { - err = prodos_load_volume_bitmap(image, &bitmap); - if (err) - goto done; - - err = prodos_set_file_block_count(image, direnum, ent, bitmap, fork_num, new_blockcount); - if (err) - goto done; - - err = prodos_save_volume_bitmap(image, bitmap); - if (err) - goto done; - } - - ent->filesize[fork_num] = new_size; - err = prodos_put_dirent(image, direnum, ent); - if (err) - goto done; - } - -done: - if (bitmap) - free(bitmap); - return err; -} - - - -static uint32_t prodos_get_storagetype_maxfilesize(uint8_t storage_type) -{ - uint32_t max_filesize = 0; - switch(storage_type & 0xF0) - { - case 0x10: - max_filesize = BLOCK_SIZE * 1; - break; - case 0x20: - max_filesize = BLOCK_SIZE * 256; - break; - case 0x30: - case 0x50: - max_filesize = BLOCK_SIZE * 32768; - break; - } - return max_filesize; -} - - - -static imgtoolerr_t prodos_diskimage_beginenum(imgtool::directory &enumeration, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - prodos_direnum *appleenum; - prodos_dirent ent; - uint16_t block = ROOTDIR_BLOCK; - - appleenum = (prodos_direnum *) enumeration.extra_bytes(); - - /* find subdirectory, if appropriate */ - if (*path) - { - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - block = ent.key_pointer[0]; - } - - /* seek initial block */ - err = prodos_enum_seek(image, appleenum, block, 0); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_nextenum(imgtool::directory &enumeration, imgtool_dirent &ent) -{ - imgtoolerr_t err; - imgtool::image &image(enumeration.image()); - prodos_direnum *appleenum; - prodos_dirent pd_ent; - uint32_t max_filesize; - - appleenum = (prodos_direnum *) enumeration.extra_bytes(); - - do - { - err = prodos_get_next_dirent(image, appleenum, pd_ent); - if (err) - return err; - } - while(appleenum->block - && !is_file_storagetype(pd_ent.storage_type) - && !is_dir_storagetype(pd_ent.storage_type)); - - /* end of file? */ - if (pd_ent.storage_type == 0x00) - { - ent.eof = 1; - return IMGTOOLERR_SUCCESS; - } - - strcpy(ent.filename, pd_ent.filename); - ent.directory = is_dir_storagetype(pd_ent.storage_type); - ent.creation_time = prodos_crack_time(pd_ent.creation_time); - ent.lastmodified_time = prodos_crack_time(pd_ent.lastmodified_time); - - if (!ent.directory) - { - ent.filesize = pd_ent.filesize[0]; - - max_filesize = prodos_get_storagetype_maxfilesize(pd_ent.storage_type); - if (ent.filesize > max_filesize) - { - ent.corrupt = 1; - ent.filesize = max_filesize; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_read_file_tree(imgtool::image &image, uint32_t *filesize, - uint32_t block, int nest_level, imgtool::stream &destf) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t buffer[BLOCK_SIZE]; - uint16_t sub_block; - size_t bytes_to_write; - int i; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - if (nest_level > 0) - { - /* this is an index block */ - for (i = 0; i < 256; i++) - { - /* retrieve the block pointer; the two bytes are on either half - * of the block */ - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - if (sub_block != 0) - { - err = prodos_read_file_tree(image, filesize, sub_block, nest_level - 1, destf); - if (err) - return err; - } - } - } - else - { - /* this is a leaf block */ - bytes_to_write = std::min(size_t(*filesize), sizeof(buffer)); - destf.write(buffer, bytes_to_write); - *filesize -= bytes_to_write; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_write_file_tree(imgtool::image &image, uint32_t *filesize, - uint32_t block, int nest_level, imgtool::stream &sourcef) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - uint8_t buffer[BLOCK_SIZE]; - uint16_t sub_block; - size_t bytes_to_read; - int i; - - /* nothing more to read? bail */ - if (*filesize == 0) - return IMGTOOLERR_SUCCESS; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - if (nest_level > 0) - { - for (i = 0; i < 256; i++) - { - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - if (sub_block != 0) - { - err = prodos_write_file_tree(image, filesize, sub_block, nest_level - 1, sourcef); - if (err) - return err; - } - } - } - else - { - /* this is a leaf block */ - bytes_to_read = std::min(size_t(*filesize), sizeof(buffer)); - sourcef.read(buffer, bytes_to_read); - *filesize -= bytes_to_read; - - err = prodos_save_block(image, block, buffer); - if (err) - return err; - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_freespace(imgtool::partition &partition, uint64_t *size) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_diskinfo *di; - uint8_t *bitmap = NULL; - uint16_t i; - - di = get_prodos_info(image); - *size = 0; - - err = prodos_load_volume_bitmap(image, &bitmap); - if (err) - goto done; - - for (i = 0; i < di->total_blocks; i++) - { - if (!prodos_get_volume_bitmap_bit(bitmap, i)) - *size += BLOCK_SIZE; - } - -done: - if (bitmap) - free(bitmap); - return err; -} - - - -static imgtoolerr_t prodos_diskimage_readfile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &destf) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - uint16_t key_pointer; - int nest_level; - mac_fork_t fork_num; - - err = prodos_lookup_path(image, filename, CREATE_NONE, NULL, &ent); - if (err) - return err; - - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - key_pointer = ent.key_pointer[fork_num]; - nest_level = ent.depth[fork_num] - 1; - - if (key_pointer != 0) - { - err = prodos_read_file_tree(image, &ent.filesize[fork_num], key_pointer, - nest_level, destf); - if (err) - return err; - } - - /* have we not actually received the correct amount of bytes? if not, fill in the rest */ - if (ent.filesize[fork_num] > 0) - destf.fill(0, ent.filesize[fork_num]); - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_writefile(imgtool::partition &partition, const char *filename, const char *fork, imgtool::stream &sourcef, util::option_resolution *opts) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - uint64_t file_size; - mac_fork_t fork_num; - - file_size = sourcef.size(); - - err = prodos_lookup_path(image, filename, CREATE_FILE, &direnum, &ent); - if (err) - return err; - - /* only work on files */ - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - err = mac_identify_fork(fork, &fork_num); - if (err) - return err; - - /* set the file size */ - err = prodos_set_file_size(image, &direnum, &ent, fork_num, file_size); - if (err) - return err; - - err = prodos_write_file_tree(image, &ent.filesize[fork_num], ent.key_pointer[fork_num], - ent.depth[fork_num] - 1, sourcef); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_deletefile(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - /* only work on files */ - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - /* empty out both forks */ - err = prodos_set_file_size(image, &direnum, &ent, 0, 0); - if (err) - return err; - err = prodos_set_file_size(image, &direnum, &ent, 1, 0); - if (err) - return err; - - memset(&ent, 0, sizeof(ent)); - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_listforks(imgtool::partition &partition, const char *path, std::vector<imgtool::fork_entry> &forks) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - if (is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - // specify data fork - forks.emplace_back(ent.filesize[0], imgtool::fork_entry::type_t::DATA); - - if (is_extendedfile_storagetype(ent.storage_type)) - { - // specify the resource fork - forks.emplace_back(ent.filesize[1], imgtool::fork_entry::type_t::RESOURCE); - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_createdir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - - err = prodos_lookup_path(image, path, CREATE_DIR, &direnum, &ent); - if (err) - return err; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - return IMGTOOLERR_FILENOTFOUND; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_free_directory(imgtool::image &image, uint8_t *volume_bitmap, uint16_t key_pointer) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - uint16_t next_block; - uint32_t offset; - uint8_t buffer[BLOCK_SIZE]; - - di = get_prodos_info(image); - - if (key_pointer != 0) - { - err = prodos_load_block(image, key_pointer, buffer); - if (err) - return err; - - for (i = 0; i < di->dirents_per_block; i++) - { - offset = i * di->dirent_size + 4; - - if (is_file_storagetype(buffer[offset]) || is_file_storagetype(buffer[offset])) - return IMGTOOLERR_DIRNOTEMPTY; - } - - next_block = pick_integer_le(buffer, 2, 2); - - err = prodos_free_directory(image, volume_bitmap, next_block); - if (err) - return err; - - prodos_set_volume_bitmap_bit(volume_bitmap, key_pointer, 0); - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_deletedir(imgtool::partition &partition, const char *path) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - uint8_t *volume_bitmap = NULL; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - goto done; - - /* only work on directories */ - if (!is_dir_storagetype(ent.storage_type)) - { - err = IMGTOOLERR_FILENOTFOUND; - goto done; - } - - err = prodos_load_volume_bitmap(image, &volume_bitmap); - if (err) - goto done; - - err = prodos_free_directory(image, volume_bitmap, ent.key_pointer[0]); - if (err) - goto done; - - err = prodos_save_volume_bitmap(image, volume_bitmap); - if (err) - goto done; - - memset(&ent, 0, sizeof(ent)); - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - goto done; - -done: - if (volume_bitmap) - free(volume_bitmap); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_get_file_tree(imgtool::image &image, imgtool_chainent *chain, size_t chain_size, - size_t *chain_pos, uint16_t block, uint8_t total_depth, uint8_t cur_depth) -{ - imgtoolerr_t err; - prodos_diskinfo *di; - int i; - uint16_t sub_block; - uint8_t buffer[BLOCK_SIZE]; - - if (block == 0) - return IMGTOOLERR_SUCCESS; - if (*chain_pos >= chain_size) - return IMGTOOLERR_SUCCESS; - - /* check bounds */ - di = get_prodos_info(image); - if (block >= di->total_blocks) - return IMGTOOLERR_CORRUPTFILE; - - chain[*chain_pos].level = cur_depth; - chain[*chain_pos].block = block; - (*chain_pos)++; - - /* must we recurse into the tree? */ - if (cur_depth < total_depth) - { - err = prodos_load_block(image, block, buffer); - if (err) - return err; - - for (i = 0; i < 256; i++) - { - sub_block = buffer[i + 256]; - sub_block <<= 8; - sub_block |= buffer[i + 0]; - - err = prodos_get_file_tree(image, chain, chain_size, chain_pos, sub_block, total_depth, cur_depth + 1); - if (err) - return err; - } - } - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_getattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - int i; - - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - values[i].i = ent.file_type; - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - values[i].i = ent.file_creator; - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - values[i].i = ent.finder_flags; - break; - case IMGTOOLATTR_INT_MAC_COORDX: - values[i].i = ent.coord_x; - break; - case IMGTOOLATTR_INT_MAC_COORDY: - values[i].i = ent.coord_y; - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - values[i].i = ent.finder_folder; - break; - case IMGTOOLATTR_INT_MAC_ICONID: - values[i].i = ent.icon_id; - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - values[i].i = ent.script_code; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - values[i].i = ent.extended_flags; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - values[i].i = ent.comment_id; - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - values[i].i = ent.putaway_directory; - break; - - case IMGTOOLATTR_TIME_CREATED: - values[i].t = prodos_crack_time(ent.creation_time).to_time_t(); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - values[i].t = prodos_crack_time(ent.lastmodified_time).to_time_t(); - break; - } - } - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_setattrs(imgtool::partition &partition, const char *path, const uint32_t *attrs, const imgtool_attribute *values) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - prodos_direnum direnum; - int i; - - err = prodos_lookup_path(image, path, CREATE_NONE, &direnum, &ent); - if (err) - return err; - - for (i = 0; attrs[i]; i++) - { - switch(attrs[i]) - { - case IMGTOOLATTR_INT_MAC_TYPE: - ent.file_type = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_CREATOR: - ent.file_creator = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_FINDERFLAGS: - ent.finder_flags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COORDX: - ent.coord_x = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COORDY: - ent.coord_y = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_FINDERFOLDER: - ent.finder_folder = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_ICONID: - ent.icon_id = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_SCRIPTCODE: - ent.script_code = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: - ent.extended_flags = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_COMMENTID: - ent.comment_id = values[i].i; - break; - case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: - ent.putaway_directory = values[i].i; - break; - - case IMGTOOLATTR_TIME_CREATED: - ent.creation_time = prodos_setup_time(values[i].t); - break; - case IMGTOOLATTR_TIME_LASTMODIFIED: - ent.lastmodified_time = prodos_setup_time(values[i].t); - break; - } - } - - err = prodos_put_dirent(image, &direnum, &ent); - if (err) - return err; - - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_suggesttransfer(imgtool::partition &partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - mac_filecategory_t file_category = MAC_FILECATEGORY_DATA; - - if (path) - { - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - file_category = is_extendedfile_storagetype(ent.storage_type) - ? MAC_FILECATEGORY_FORKED : MAC_FILECATEGORY_DATA; - } - - mac_suggest_transfer(file_category, suggestions, suggestions_length); - return IMGTOOLERR_SUCCESS; -} - - - -static imgtoolerr_t prodos_diskimage_getchain(imgtool::partition &partition, const char *path, imgtool_chainent *chain, size_t chain_size) -{ - imgtoolerr_t err; - imgtool::image &image(partition.image()); - prodos_dirent ent; - size_t chain_pos = 0; - int fork_num; - - err = prodos_lookup_path(image, path, CREATE_NONE, NULL, &ent); - if (err) - return err; - - switch(ent.storage_type & 0xF0) - { - case 0x10: - case 0x20: - case 0x30: - /* normal ProDOS file */ - err = prodos_get_file_tree(image, chain, chain_size, &chain_pos, - ent.key_pointer[0], ent.depth[0] - 1, 0); - if (err) - return err; - break; - - case 0x50: - /* extended ProDOS file */ - chain[chain_pos].level = 0; - chain[chain_pos].block = ent.extkey_pointer; - chain_pos++; - - for (fork_num = 0; fork_num <= 1; fork_num++) - { - if (ent.key_pointer[fork_num]) - { - err = prodos_get_file_tree(image, chain, chain_size, &chain_pos, - ent.key_pointer[fork_num], ent.depth[fork_num] - 1, 1); - if (err) - return err; - } - } - break; - - case 0xE0: - /* directory */ - return IMGTOOLERR_UNIMPLEMENTED; - - default: - return IMGTOOLERR_UNEXPECTED; - } - - return IMGTOOLERR_SUCCESS; -} - - - -static void generic_prodos_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR: info->i = 1; break; - case IMGTOOLINFO_INT_OPEN_IS_STRICT: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME: info->i = 1; break; - case IMGTOOLINFO_INT_WRITING_UNTESTED: info->i = 1; break; - case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(prodos_diskinfo); break; - case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(prodos_direnum); break; - case IMGTOOLINFO_INT_PATH_SEPARATOR: info->i = '/'; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "ProDOS format"); break; - case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break; - case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break; - case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = prodos_diskimage_beginenum; break; - case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = prodos_diskimage_nextenum; break; - case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = prodos_diskimage_freespace; break; - case IMGTOOLINFO_PTR_READ_FILE: info->read_file = prodos_diskimage_readfile; break; - case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = prodos_diskimage_writefile; break; - case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = prodos_diskimage_deletefile; break; - case IMGTOOLINFO_PTR_LIST_FORKS: info->list_forks = prodos_diskimage_listforks; break; - case IMGTOOLINFO_PTR_CREATE_DIR: info->create_dir = prodos_diskimage_createdir; break; - case IMGTOOLINFO_PTR_DELETE_DIR: info->delete_dir = prodos_diskimage_deletedir; break; - case IMGTOOLINFO_PTR_GET_ATTRS: info->get_attrs = prodos_diskimage_getattrs; break; - case IMGTOOLINFO_PTR_SET_ATTRS: info->set_attrs = prodos_diskimage_setattrs; break; - case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = prodos_diskimage_suggesttransfer; break; - case IMGTOOLINFO_PTR_GET_CHAIN: info->get_chain = prodos_diskimage_getchain; break; - } -} - - - -void prodos_525_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_525"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_525; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_525; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple2; break; - - default: generic_prodos_get_info(imgclass, state, info); break; - } -} - - - -void prodos_35_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "prodos_35"); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = prodos_diskimage_create_35; break; - case IMGTOOLINFO_PTR_FLOPPY_OPEN: info->open = prodos_diskimage_open_35; break; - case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_apple35_iigs; break; - - default: generic_prodos_get_info(imgclass, state, info); break; - } -} |