int vdrive_write_sector(vdrive_t *vdrive, const BYTE *buf, unsigned int track, unsigned int sector) { disk_addr_t dadr; dadr.track = track; dadr.sector = sector; return disk_image_write_sector(vdrive->image, buf, &dadr); }
static void vdrive_rel_commit(vdrive_t *vdrive, bufferinfo_t *p) { /* Check for writes here to commit the buffers. */ if (p->needsupdate & DIRTY_SECTOR) { /* Write the sector */ disk_image_write_sector(vdrive->image, p->buffer, p->track, p->sector); /* Clear flag for next sector */ p->needsupdate &= ~(DIRTY_SECTOR); } return; }
static int wd1770_sector_write(unsigned int dnr, unsigned int track, unsigned int sector) { BYTE sector_data[256]; int rc; wd1770_conv_phy2log(dnr, &track, §or); wd1770_buffer_get(dnr, sector_data, sizeof(sector_data)); #ifdef WD_DEBUG log_debug("WRITE T%i S%i",track,sector); #endif rc = disk_image_write_sector(wd1770[dnr].image, sector_data, track, sector); if (rc < 0) { log_error(wd1770_log, "Cannot write T:%d S:%d to disk image.", track, sector); return -1; } sector++; wd1770_buffer_get(dnr, sector_data, sizeof(sector_data)); #ifdef WD_DEBUG log_debug("WRITE T%i S%i",track,sector); #endif rc = disk_image_write_sector(wd1770[dnr].image, sector_data, track, sector); if (rc < 0) { log_error(wd1770_log, "Cannot write T:%d S:%d to disk image.", track, sector); return -1; } return 0; }
static void vdrive_rel_flush_sidesectors(vdrive_t *vdrive, bufferinfo_t *p) { unsigned int i, j, o, side; /* Write super side sector if it is dirty and if it is not imaginary */ if (p->super_side_sector_needsupdate && p->super_side_sector_track) { /* Write the super side sector */ disk_image_write_sector(vdrive->image, p->super_side_sector, p->super_side_sector_track, p->super_side_sector_sector); /* Clear flag for super side sector */ p->super_side_sector_needsupdate = 0; } /* find the number of side sector groups */ for (side = 0; p->super_side_sector[OFFSET_SUPER_POINTER + side * 2] != 0 ; side++ ); o = 0; for (j = 0; j < side ; j++ ) { for (i = 0; i < SIDE_SECTORS_MAX; i++) { if ( p->side_sector_needsupdate[o] && p->side_sector_track[o]) { /* Write the super side sector */ disk_image_write_sector(vdrive->image, &(p->side_sector[o*256]), p->side_sector_track[o], p->side_sector_sector[o]); /* Clear flag for super side sector */ p->side_sector_needsupdate[o] = 0; } o++; } } return; }
/* Hack... otherwise you get internal compiler errors when optimizing on gcc2.7.2 on RISC OS */ static void gcr_data_writeback2(BYTE *buffer, BYTE *offset, unsigned int track, unsigned int sector, drive_t *drive) { int rc; gcr_convert_GCR_to_sector(buffer, offset, drive->GCR_track_start_ptr, drive->GCR_current_track_size); if (buffer[0] != 0x7) { log_error(drive->log, "Could not find data block id of T:%d S:%d.", track, sector); } else { rc = disk_image_write_sector(drive->image, buffer + 1, track, sector); if (rc < 0) log_error(drive->log, "Could not update T:%d S:%d.", track, sector); } }
static void drive_extend_disk_image(drive_t *drive) { int rc; unsigned int track, sector; BYTE buffer[256]; drive->image->tracks = EXT_TRACKS_1541; memset(buffer, 0, 256); for (track = NUM_TRACKS_1541 + 1; track <= EXT_TRACKS_1541; track++) { for (sector = 0; sector < disk_image_sector_per_track(DISK_IMAGE_TYPE_D64, track); sector++) { rc = disk_image_write_sector(drive->image, buffer, track, sector); if (rc < 0) log_error(drive->log, "Could not update T:%d S:%d.", track, sector); } } }
/* Returns NULL if the allocation failed. */ static BYTE *find_next_directory_sector(vdrive_t *vdrive, unsigned int track, unsigned int sector) { if (vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, track, sector)) { vdrive->Dir_buffer[0] = track; vdrive->Dir_buffer[1] = sector; disk_image_write_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); #ifdef DEBUG_DRIVE log_debug("Found (%d %d) TR = %d SE = %d.", track, sector, vdrive->Curr_track, vdrive->Curr_sector); #endif vdrive->SlotNumber = 0; memset(vdrive->Dir_buffer, 0, 256); vdrive->Dir_buffer[1] = 0xff; vdrive->Curr_sector = sector; return vdrive->Dir_buffer; } return NULL; }
static void drive_extend_disk_image(drive_t *drive) { int rc; unsigned int track, sector; BYTE buffer[256]; drive->image->tracks = EXT_TRACKS_1541; memset(buffer, 0, 256); for (track = NUM_TRACKS_1541 + 1; track <= EXT_TRACKS_1541; track++) { for (sector = 0; sector < disk_image_sector_per_track(DISK_IMAGE_TYPE_D64, track); sector++) { rc = disk_image_write_sector(drive->image, buffer, track, sector); #ifdef CELL_DEBUG if (rc < 0) printf("ERROR: Could not update T:%d S:%d.\n", track, sector); #endif } } }
void vdrive_dir_remove_slot(vdrive_t *vdrive, BYTE *slot) { unsigned int tmp; int t, s; /* Find slot. */ for (tmp = 0; (tmp < 16) && slot[SLOT_NAME_OFFSET + tmp] != 0xa0; tmp++); vdrive_dir_find_first_slot(vdrive, (char *)&slot[SLOT_NAME_OFFSET], tmp, slot[SLOT_TYPE_OFFSET] & 0x07); /* If slot found, remove. */ if (vdrive_dir_find_next_slot(vdrive)) { /* Free all sector this file is using. */ t = (int) vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_FIRST_TRACK]; s = (int) vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_FIRST_SECTOR]; vdrive_dir_free_chain(vdrive, t, s); /* Free side sectors. */ t = (int) vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_SIDE_TRACK]; s = (int) vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_SIDE_SECTOR]; vdrive_dir_free_chain(vdrive, t, s); /* Update bam */ vdrive_bam_write_bam(vdrive); /* Update directory entry */ vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_TYPE_OFFSET] = 0; disk_image_write_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); } }
int vdrive_iec_update_dirent(vdrive_t *vdrive, unsigned int channel) { bufferinfo_t *p = &(vdrive->buffers[channel]); /* Update directory information - no error checks, everything should be safe at this point. */ vdrive->Curr_track = p->dir_track; vdrive->Curr_sector = p->dir_sector; vdrive->SlotNumber = p->dir_slot; /* Read in the track/sector where the directory entry lies. */ disk_image_read_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); /* Copy over our new slot. */ memcpy(&(vdrive->Dir_buffer[vdrive->SlotNumber * 32 + 2]), p->slot + 2, 30); /* Write it back. */ disk_image_write_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); return 0; }
/* Hack... otherwise you get internal compiler errors when optimizing on gcc2.7.2 on RISC OS */ static void gcr_data_writeback2(BYTE *buffer, BYTE *offset, unsigned int track, unsigned int sector, drive_t *drive) { int rc; gcr_convert_GCR_to_sector(buffer, offset, drive->GCR_track_start_ptr, drive->GCR_current_track_size); if (buffer[0] != 0x7) { #ifdef CELL_DEBUG printf("ERROR: Could not find data block id of T:%d S:%d.\n", track, sector); #endif } else { rc = disk_image_write_sector(drive->image, buffer + 1, track, sector); #ifdef CELL_DEBUG if (rc < 0) printf("ERROR: Could not update T:%d S:%d.\n", track, sector); #endif } }
static int iec_write_sequential(vdrive_t *vdrive, bufferinfo_t *bi, int length) { unsigned int t_new, s_new; int retval; BYTE *buf = bi->buffer; BYTE *slot = bi->slot; /* * First block of a file ? */ if (bi->track == 0) { /* allocate the first sector */ retval = vdrive_bam_alloc_first_free_sector(vdrive, vdrive->bam, &t_new, &s_new); if (retval < 0) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return -1; } /* remember track and sector */ bi->track = t_new; bi->sector = s_new; /* use update flag to indicate replace mode */ if (bi->needsupdate) { /* save and replace */ slot[SLOT_REPLACE_TRACK] = t_new; slot[SLOT_REPLACE_SECTOR] = s_new; } else { /* new file */ slot[SLOT_FIRST_TRACK] = t_new; slot[SLOT_FIRST_SECTOR] = s_new; } /* reset block counter */ slot[SLOT_NR_BLOCKS] = 0; slot[SLOT_NR_BLOCKS + 1] = 0; } if (length == WRITE_BLOCK) { /* * Write current sector and allocate next */ t_new = bi->track; s_new = bi->sector; retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, &t_new, &s_new); if (retval < 0) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return -1; } buf[0] = t_new; buf[1] = s_new; disk_image_write_sector(vdrive->image, buf, bi->track, bi->sector); bi->track = t_new; bi->sector = s_new; } else { /* * Write last block */ buf[0] = 0; buf[1] = length - 1; disk_image_write_sector(vdrive->image, buf, bi->track, bi->sector); } /* Increment block count. */ if (!(++slot[SLOT_NR_BLOCKS])) ++slot[SLOT_NR_BLOCKS + 1]; return 0; }
static int vdrive_rel_add_sector(vdrive_t *vdrive, unsigned int secondary, unsigned int *track, unsigned int *sector) { bufferinfo_t *p = &(vdrive->buffers[secondary]); unsigned int i, j, k, l, m, side, o; unsigned int t_new, s_new, t_super, s_super, current; int retval; BYTE *slot = p->slot; /* Find the total blocks this REL file uses. */ i = slot[SLOT_NR_BLOCKS] + (slot[SLOT_NR_BLOCKS + 1] << 8); /* Compare it with the maximum for the particular disk image. */ if (i >= vdrive_rel_blocks_max(vdrive)) { /* If we are equal or over, report error 52 */ vdrive_command_set_error(vdrive, CBMDOS_IPE_TOOLARGE, 0, 0); return 1; } /* find the number of side sector groups */ o = OFFSET_SUPER_POINTER; for (side = 0; side < SIDE_SUPER_MAX && p->super_side_sector[o] != 0 ; side++, o+=2 ); /* If the file isn't new, find the last record */ if ( side ) { side--; /* Find last side sector; guaranteed find. */ o = 256 * ( side * SIDE_SECTORS_MAX ) + OFFSET_NEXT_TRACK; for (i = 0; i < SIDE_SECTORS_MAX; i++, o+=256 ) { if (p->side_sector[o] == 0) break; } /* obtain the last byte of the sector according to the index */ j = ( p->side_sector[256 * ( i + side * SIDE_SECTORS_MAX) + OFFSET_NEXT_SECTOR ] + 1 - OFFSET_POINTER ) / 2; /* Get the track and sector of the last REL block */ o = 256 * ( i + side * SIDE_SECTORS_MAX) + OFFSET_POINTER + 2 * (j-1); *track = p->side_sector[o]; *sector = p->side_sector[o + 1]; /* Find a new sector */ retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, track, sector); } else { /* New REL file, get ready to create... */ i = 0; j = 0; *track = 0; *sector = 0; /* Find the first new sector */ retval = vdrive_bam_alloc_first_free_sector(vdrive, vdrive->bam, track, sector); } /* Leave if no space left */ if (retval < 0) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return 1; } /* Check if this side sector is full or if we need on in general. */ if ( j == SIDE_INDEX_MAX || j == 0 ) { /* Allocate a new sector for the new side sector. */ t_new = *track; s_new = *sector; retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, &t_new, &s_new); /* If no space, leave with no changes */ if (retval < 0) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return 1; } /* We will adjust the side sector later, but atleast we know we have a place to make adjustments. */ } /* setup for later */ k = 0; m = p->slot[SLOT_RECORD_LENGTH]; /* remember old current record, we will need it for later. */ current = p->record + 1; /* If this is a unallocated file... */ if ( j == 0 ) { /* Update slot information if this is our first side sector. */ p->slot[SLOT_FIRST_TRACK] = *track; p->slot[SLOT_FIRST_SECTOR] = *sector; /* Update the super side sector */ p->super_side_sector[OFFSET_NEXT_TRACK] = t_new; p->super_side_sector[OFFSET_NEXT_SECTOR] = s_new; p->super_side_sector[OFFSET_SUPER_254] = 254; p->super_side_sector[OFFSET_SUPER_POINTER] = t_new; p->super_side_sector[OFFSET_SUPER_POINTER+1] = s_new; p->super_side_sector_needsupdate = 1; t_super = t_new; s_super = s_new; /* Does this image require a real super side sector? */ if (vdrive_rel_has_super(vdrive)) { retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, &t_super, &s_super); /* If no space, leave with no changes */ if (retval < 0) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return 1; } p->super_side_sector_track = t_super; p->super_side_sector_sector = s_super; } else { /* No super side sector required for this image */ p->super_side_sector_track = 0; p->super_side_sector_sector = 0; } p->slot[SLOT_SIDE_TRACK] = t_super; p->slot[SLOT_SIDE_SECTOR] = s_super; /* set up first data block */ p->track_next = *track; p->sector_next = *sector; /* Update the directory entry */ vdrive_iec_update_dirent(vdrive, secondary); } else { /* Existing... */ /* Move to last sector, use position command - this will flush any dirty buffers too. */ vdrive_rel_position(vdrive, secondary, p->record_max & 255, p->record_max >> 8, 1); /* Modify this sector to connect to the next one. */ /* We won't use the pointer in this sector for the last used byte as it could very well be wrong. The 1541/71/81 had a tendency to mess the last sector when making REL files by expanding in small chunks. This generally would happen when a new side sector was created. I can generate a case where this bug happens, but I can't seem to figure out why - yet. */ p->buffer[OFFSET_NEXT_TRACK] = p->track_next = *track; p->buffer[OFFSET_NEXT_SECTOR] = p->sector_next = *sector; /* Fill the new records up with the default 0xff 0x00 ... */ o = p->bufptr + m; while (o < 256) { if (k==0) p->buffer[o] = 0xff; else p->buffer[o] = 0x00; k = ( k + 1 ) % m; /* increment the maximum records each time we complete a full record. */ if (k==0) p->record_max++; o++; } /* flag the current sector as dirty - the other functions will update it. */ p->needsupdate = DIRTY_SECTOR; } /* Fill new sector with maximum records */ o = 2; while (o < 256) { if (k==0) p->buffer_next[o] = 0xff; else p->buffer_next[o] = 0x00; k = ( k + 1 ) % m; /* increment the maximum records each time we complete a full record. */ if (k==0) p->record_max++; o++; } /* set as last sector in REL file */ p->buffer_next[OFFSET_NEXT_TRACK] = 0; /* Update the last byte based on how much of the last record we filled. */ p->buffer_next[OFFSET_NEXT_SECTOR] = 255 - k; /* update the "next" buffer to disk, we don't have a dirty flag for it. */ disk_image_write_sector(vdrive->image, p->buffer_next, p->track_next, p->sector_next); /* If this is the first side sector being made */ if ( j == 0 ) { /* Build some of the structure */ p->side_sector[OFFSET_NEXT_TRACK] = 0; p->side_sector[OFFSET_RECORD_LEN] = m; p->side_sector[OFFSET_SIDE_SECTOR] = t_new; p->side_sector[OFFSET_SIDE_SECTOR + 1] = s_new; p->side_sector_track[0] = t_new; p->side_sector_sector[0] = s_new; /* Follow through with the "else" of the next if */ } /* If this side sector is full... */ if ( j == SIDE_INDEX_MAX ) { /* Update previous side sector */ o = ( i + side * SIDE_SECTORS_MAX); /* dirty the side sector. */ p->side_sector_needsupdate[ o ] = 1; o *= 256; /* Update the link. */ p->side_sector[o + OFFSET_NEXT_TRACK] = t_new; p->side_sector[o + OFFSET_NEXT_SECTOR] = s_new; /* Is this the last side sector of a group in a super side sector? */ if ( i == SIDE_SECTORS_MAX - 1 ) { /* Yes, create a new group. */ /* correct side reference. */ side++; /* reallocate memory for another side sector group */ o = SIDE_SECTORS_MAX * 256; p->side_sector = lib_realloc(p->side_sector, ( side + 1 ) * o ); /* clear out new portion, the function may not do this */ memset(&(p->side_sector[side * o]), 0, o); /* Also reallocate and clear out new sections of track and sectors locations and dirty flag of each side sector */ o = ( side + 1 ) * SIDE_SECTORS_MAX; p->side_sector_track = lib_realloc(p->side_sector_track, o); p->side_sector_sector = lib_realloc(p->side_sector_sector, o); p->side_sector_needsupdate = lib_realloc(p->side_sector_needsupdate, o); o = side * SIDE_SECTORS_MAX; memset(&(p->side_sector_track[o]), 0, SIDE_SECTORS_MAX); memset(&(p->side_sector_sector[o]), 0, SIDE_SECTORS_MAX); memset(&(p->side_sector_needsupdate[o]), 0, SIDE_SECTORS_MAX); /* Create first side sector of new group */ o *=256; p->side_sector[o + OFFSET_SIDE_SECTOR ] = t_new; p->side_sector[o + OFFSET_SIDE_SECTOR + 1] = s_new; p->side_sector[o + OFFSET_SECTOR_NUM] = 0; /* Adjust the super side sector */ o = OFFSET_SUPER_POINTER + side * 2; p->super_side_sector[o] = t_new; p->super_side_sector[o+1] = s_new; p->super_side_sector_needsupdate = 1; /* Set up reference to the first side sector. */ o = ( side * SIDE_SECTORS_MAX); } else { /* Nope, update old group. */ /* Update side sector indices. */ l = o = 256 * ( side * SIDE_SECTORS_MAX ); for (k=0; k<=i; k++, o+=256) { p->side_sector[o + OFFSET_SIDE_SECTOR + ( i + 1 ) * 2 ] = t_new; p->side_sector[o + OFFSET_SIDE_SECTOR + ( i + 1 ) * 2 + 1] = s_new; } /* Update the new sector */ p->side_sector[o + OFFSET_SECTOR_NUM] = i+1; /* Copy side sector track and sectors from first side sector. */ for ( k=0;k<SIDE_SECTORS_MAX * 2;k++ ) { p->side_sector[o + OFFSET_SIDE_SECTOR + k ] = p->side_sector[l + OFFSET_SIDE_SECTOR + k ]; } o = ( side * SIDE_SECTORS_MAX ); /* Mark all of other side sectors as dirty. */ for ( k=0; k<=i; k++, o++) { p->side_sector_needsupdate[o] = 1; } /* Set up the reference to the new side sector. */ o = ( (i+1) + side * SIDE_SECTORS_MAX); } /* dirty the side sector. */ p->side_sector_needsupdate[ o ] = 1; /* update the internal references. */ p->side_sector_track[ o ] = t_new; p->side_sector_sector[ o ] = s_new; /* Update the side sector contents. */ o *= 256; p->side_sector[o + OFFSET_NEXT_TRACK] = 0; p->side_sector[o + OFFSET_NEXT_SECTOR] = OFFSET_POINTER + 1; p->side_sector[o + OFFSET_RECORD_LEN] = m; p->side_sector[o + OFFSET_POINTER] = *track; p->side_sector[o + OFFSET_POINTER + 1] = *sector; } else { /* Update last side sector with new data. */ o = ( i + side * SIDE_SECTORS_MAX ); /* set sector dirty. */ p->side_sector_needsupdate[ o ] = 1; /* update last byte used. */ o *= 256; p->side_sector[ o + OFFSET_NEXT_SECTOR ] = OFFSET_POINTER + 2 * j + 1; o+= OFFSET_POINTER + 2 * j; /* update track and sector of data. */ p->side_sector[o] = *track; p->side_sector[o + 1] = *sector; } /* Move back to original record - it may not even exist. */ vdrive_rel_position(vdrive, secondary, current & 255, current >> 8, 1); /* everything is okay. */ return 0; }
static int iec_open_write(vdrive_t *vdrive, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse, const BYTE *name) { bufferinfo_t *p = &(vdrive->buffers[secondary]); unsigned int track, sector; BYTE *slot = p->slot, *e; if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) { vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0); return SERIAL_ERROR; } /* set flag for overwrite mode */ p->needsupdate = 0; if (slot) { /* file exists */ if (*name == '@') { /* replace mode: we don't want the dirent updated at all until close */ /* allocate buffers */ vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL); p->bufptr = 2; /* Create our own slot, since the one passed is static */ p->slot = lib_calloc(1, 32); /* Copy the static on to the new one. */ memcpy(p->slot, slot, 32); slot = p->slot; /* set flag for replace mode */ p->needsupdate = 1; /* find a new track and sector when writing */ p->track = p->sector = 0; } else { if (p->readmode == CBMDOS_FAM_APPEND) { /* append mode */ /* allocate buffers */ vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL); /* Create our own slot, since the one passed is static */ p->slot = lib_calloc(1, 32); /* Copy the static on to the new one. */ memcpy(p->slot, slot, 32); slot = p->slot; /* set file unclosed */ p->slot[SLOT_TYPE_OFFSET] &= 0x7f; /* get the starting track and sector */ p->track = track = slot[SLOT_FIRST_TRACK]; p->sector = sector = slot[SLOT_FIRST_SECTOR]; /* update block count as we find the end of the file */ /* the real drives actually don't do this, so each time you append to a file, the block count increases by 1. I think it is safer to correct the block count. */ slot[SLOT_NR_BLOCKS] = 255; slot[SLOT_NR_BLOCKS + 1] = 255; /* scan to the end of the file */ while (track) { p->track = track; p->sector = sector; if (disk_image_read_sector(vdrive->image, p->buffer, p->track, p->sector)) { /* couldn't read sector, report error and leave */ vdrive_free_buffer(p); vdrive_command_set_error(vdrive, CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR, p->track, p->sector); return SERIAL_ERROR; } /* setup next link */ track = p->buffer[0]; sector = p->buffer[1]; /* Increment block count. */ if (!(++slot[SLOT_NR_BLOCKS])) ++slot[SLOT_NR_BLOCKS + 1]; } /* compensate if the dir link is 0 (rare possibility) */ if (!p->track) { /* Our loop didn't even execute once, set the block size to 0 */ slot[SLOT_NR_BLOCKS] = 0; slot[SLOT_NR_BLOCKS + 1] = 0; /* set buffer pointer to 2 */ sector = 1; } /* set the buffer pointer */ p->bufptr = sector + 1; } else { /* can't overwrite an existing file */ vdrive_iec_close(vdrive, secondary); vdrive_command_set_error(vdrive, CBMDOS_IPE_FILE_EXISTS, 0, 0); return SERIAL_ERROR; } } } else { /* new file... */ /* create a slot based on the opening name */ vdrive_dir_create_slot(p, cmd_parse->parsecmd, cmd_parse->parselength, cmd_parse->filetype); /* Write the directory entry to disk as an UNCLOSED file. */ vdrive_dir_find_first_slot(vdrive, NULL, -1, 0); e = vdrive_dir_find_next_slot(vdrive); /* If there is not space for the slot, disk is full */ if (!e) { vdrive_free_buffer(p); vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return SERIAL_ERROR; } /* find a new track and sector when writing */ p->track = p->sector = 0; } if (!p->needsupdate) { /* copy the slot information into the sector. */ memcpy(&vdrive->Dir_buffer[vdrive->SlotNumber * 32 + 2], p->slot + 2, 30); /* Write the sector. */ disk_image_write_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); } /* Remember the directory information for close. */ p->dir_track = vdrive->Curr_track; p->dir_sector = vdrive->Curr_sector; p->dir_slot = vdrive->SlotNumber; return SERIAL_OK; }
static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) { BYTE major_version, minor_version; snapshot_module_t *m; char snap_module_name[10]; WORD word; char *filename = NULL; char *request_str; int len = 0; FILE *fp; BYTE sector_data[0x100]; disk_addr_t dadr; int rc; drive_t *drive; drive = drive_context[dnr]->drive; sprintf(snap_module_name, "NOIMAGE%i", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); if (m != NULL) { file_system_detach_disk(dnr + 8); snapshot_module_close(m); return 0; } sprintf(snap_module_name, "IMAGE%i", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); if (m == NULL) { return 0; } if (major_version > IMAGE_SNAP_MAJOR || minor_version > IMAGE_SNAP_MINOR) { log_error(drive_snapshot_log, "Snapshot module version (%d.%d) newer than %d.%d.", major_version, minor_version, IMAGE_SNAP_MAJOR, IMAGE_SNAP_MINOR); } if (SMR_W(m, &word) < 0) { snapshot_module_close(m); return -1; } switch (word) { case 1581: len = D81_FILE_SIZE; break; case 8050: len = D80_FILE_SIZE; break; case 8250: len = D82_FILE_SIZE; break; default: log_error(drive_snapshot_log, "Snapshot of disk image unknown (type %d)", (int)word); snapshot_module_close(m); return -1; } /* create temporary file of the right size */ fp = archdep_mkstemp_fd(&filename, MODE_WRITE); if (fp == NULL) { log_error(drive_snapshot_log, "Could not create temporary file!"); snapshot_module_close(m); return -1; } /* blow up the file to needed size */ if (fseek(fp, len - 1, SEEK_SET) < 0 || (fputc(0, fp) == EOF)) { log_error(drive_snapshot_log, "Could not create large temporary file"); fclose(fp); lib_free(filename); snapshot_module_close(m); return -1; } fclose(fp); lib_free(filename); if (file_system_attach_disk(dnr + 8, filename) < 0) { log_error(drive_snapshot_log, "Invalid Disk Image"); lib_free(filename); snapshot_module_close(m); return -1; } request_str = lib_msprintf("Disk image unit #%d imported from snapshot", dnr + 8); zfile_close_action(filename, ZFILE_REQUEST, request_str); lib_free(request_str); /* we use the return code to step through the tracks. So we do not need any geometry info. */ SMR_BA(m, sector_data, 0x100); for (dadr.track = 1;; dadr.track++) { rc = 0; for (dadr.sector = 0;; dadr.sector++) { rc = disk_image_write_sector(drive->image, sector_data, &dadr); if (rc == 0) { SMR_BA(m, sector_data, 0x100); } else { break; } } if (dadr.sector == 0) { break; } } vdrive_bam_reread_bam(dnr + 8); snapshot_module_close(m); m = NULL; return 0; }
static BYTE fdc_do_job_(unsigned int fnum, int buf, unsigned int drv, BYTE job, BYTE *header) { #endif unsigned int dnr; BYTE rc; int ret; int i; disk_addr_t dadr; BYTE *base; BYTE sector_data[256]; BYTE disk_id[2]; drive_t *drive; dadr.track = header[2]; dadr.sector = header[3]; /* determine drive/disk image to use */ if (drv < fdc[fnum].num_drives) { dnr = fnum + drv; } else { /* drive 1 on a single disk drive */ return FDC_ERR_SYNC; } rc = 0; base = &(fdc[fnum].buffer[(buf + 1) << 8]); #ifdef FDC_DEBUG log_message(fdc_log, "do job %02x, buffer %d ($%04x): d%d t%d s%d, " "image=%p, type=%04d", job, buf, (buf + 1) << 8, dnr, dadr.track, dadr.sector, fdc[dnr].image, fdc[dnr].image ? fdc[dnr].image->type : 0); #endif if (fdc[dnr].image == NULL && job != 0xd0) { #ifdef FDC_DEBUG log_message(fdc_log, "dnr=%d, image=NULL -> no disk!", dnr); #endif return FDC_ERR_SYNC; } file_system_bam_get_disk_id(dnr + 8, disk_id); switch (job) { case 0x80: /* read */ if (header[0] != disk_id[0] || header[1] != disk_id[1]) { rc = FDC_ERR_ID; break; } ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, "Cannot read T:%d S:%d from disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DRIVE; } else { memcpy(base, sector_data, 256); rc = FDC_ERR_OK; } break; case 0x90: /* write */ if (header[0] != disk_id[0] || header[1] != disk_id[1]) { rc = FDC_ERR_ID; break; } if (fdc[dnr].image->read_only) { rc = FDC_ERR_WPROT; break; } memcpy(sector_data, base, 256); ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, "Could not update T:%d S:%d on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DRIVE; } else { rc = FDC_ERR_OK; } break; case 0xA0: /* verify */ if (header[0] != disk_id[0] || header[1] != disk_id[1]) { rc = FDC_ERR_ID; break; } ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, "Cannot read T:%d S:%d from disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DRIVE; } else { rc = FDC_ERR_OK; for (i = 0; i < 256; i++) { if (fnum) { if (sector_data[i] != base[i]) { rc = FDC_ERR_VERIFY; } } else { if (sector_data[i] != base[i]) { rc = FDC_ERR_VERIFY; } } } } break; case 0xB0: /* seek - move to track and read ID(?) */ header[0] = disk_id[0]; header[1] = disk_id[1]; /* header[2] = fdc[dnr].last_track; */ dadr.track = header[2]; header[3] = 1; rc = FDC_ERR_OK; break; case 0xC0: /* bump (to track 0 and back to 18?) */ dadr.track = 1; if (DOS_IS_20(fdc[fnum].drive_type)) { header[2] = 18; } rc = FDC_ERR_OK; break; case 0xD0: /* jump to buffer - but we do not emulate FDC CPU */ #ifdef FDC_DEBUG log_message(fdc_log, "exec buffer %d ($%04x): %02x %02x %02x %02x %02x", buf, (buf + 1) << 8, base[0], base[1], base[2], base[3] ); #endif if (DOS_IS_40(fdc[fnum].drive_type) || DOS_IS_30(fdc[fnum].drive_type)) { if (!memcmp(fdc[fnum].iprom + 0x12f8, &fdc[fnum].buffer[0x100], 0x100)) { fdc[fnum].fdc_state = FDC_RESET2; return 0; } } if (DOS_IS_80(fdc[fnum].drive_type)) { static const BYTE jumpseq[] = { 0x78, 0x6c, 0xfc, 0xff }; if (!memcmp(jumpseq, &fdc[fnum].buffer[0x100], 4)) { fdc[fnum].fdc_state = FDC_RESET0; return 0; } } rc = FDC_ERR_DRIVE; break; case 0xE0: /* execute when drive/head ready. We do not emulate FDC CPU, but we handle the case when a disk is formatted */ /* we have to check for standard format code that is copied to buffers 0-3 */ if (DOS_IS_80(fdc[fnum].drive_type)) { rc = fdc_do_format_D80(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); } else if (DOS_IS_40(fdc[fnum].drive_type) || DOS_IS_30(fdc[fnum].drive_type)) { rc = fdc_do_format_D40(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); } else if (DOS_IS_20(fdc[fnum].drive_type)) { rc = fdc_do_format_D20(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); } else { rc = FDC_ERR_DRIVE; } break; case 0xF0: if (header[0] != disk_id[0] || header[1] != disk_id[1]) { rc = FDC_ERR_ID; break; } /* try to read block header from disk */ rc = FDC_ERR_OK; break; } drive = drive_context[dnr]->drive; drive->current_half_track = 2 * dadr.track; fdc[dnr].last_track = dadr.track; fdc[dnr].last_sector = dadr.sector; return rc; }
static BYTE fdc_do_format_D80(fdc_t *fdc, unsigned int fnum, unsigned int dnr, unsigned int track, unsigned int sector, int buf, BYTE *header) { int i; int ret; BYTE rc = 0; disk_addr_t dadr; BYTE sector_data[256]; if (!memcmp(fdc[fnum].iprom, &fdc[fnum].buffer[0x100], 0x300)) { unsigned int ntracks, nsectors = 0; /* detected format code */ #ifdef FDC_DEBUG log_message(fdc_log, "format code: "); log_message(fdc_log, " track for zones side 0: %d %d %d %d", fdc[fnum].buffer[0xb0], fdc[fnum].buffer[0xb1], fdc[fnum].buffer[0xb2], fdc[fnum].buffer[0xb3]); log_message(fdc_log, " track for zones side 1: %d %d %d %d", fdc[fnum].buffer[0xb4], fdc[fnum].buffer[0xb5], fdc[fnum].buffer[0xb6], fdc[fnum].buffer[0xb7]); log_message(fdc_log, " secs per track: %d %d %d %d", fdc[fnum].buffer[0x99], fdc[fnum].buffer[0x9a], fdc[fnum].buffer[0x9b], fdc[fnum].buffer[0x9c]); log_message(fdc_log, " vars: 870=%d 873=%d 875=%d", fdc[fnum].buffer[0x470], fdc[fnum].buffer[0x473], fdc[fnum].buffer[0x475]); log_message(fdc_log, " track=%d, sector=%d", track, sector); log_message(fdc_log, " id=%02x,%02x (%c%c)", header[0], header[1], header[0], header[1]); log_message(fdc_log, " sides=%d", fdc[fnum].buffer[0xac]); #endif if (fdc[dnr].image->read_only) { rc = FDC_ERR_WPROT; return rc; } ntracks = (fdc[fnum].buffer[0xac] > 1) ? 154 : 77; memset(sector_data, 0, 256); for (ret = 0, dadr.track = 1; ret == 0 && dadr.track <= ntracks; dadr.track++) { if (dadr.track < 78) { for (i = 3; i >= 0; i--) { if (dadr.track < fdc[fnum].buffer[0xb0 + i]) { nsectors = fdc[fnum].buffer[0x99 + i]; break; } } } else { for (i = 3; i >= 0; i--) { if (dadr.track < fdc[fnum].buffer[0xb4 + i]) { nsectors = fdc[fnum].buffer[0x99 + i]; break; } } } for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, "Could not update T:%d S:%d on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DCHECK; break; } } } file_system_bam_set_disk_id(dnr + 8, header); } if (!rc) { rc = FDC_ERR_OK; } return rc; }
static BYTE fdc_do_format_D40(fdc_t *fdc, unsigned int fnum, unsigned int dnr, unsigned int track, unsigned int sector, int buf, BYTE *header) { int i; int ret; BYTE rc = 0; disk_addr_t dadr; BYTE sector_data[256]; if (!memcmp(fdc[fnum].iprom + 0x1000, &fdc[fnum].buffer[0x100], 0x200)) { static const unsigned int sectorchangeat[4] = { 0, 17, 24, 30 }; unsigned int ntracks, nsectors = 0; #ifdef FDC_DEBUG log_message(fdc_log, "format code: "); log_message(fdc_log, " secs per track: %d %d %d %d", fdc[fnum].buffer[0x99], fdc[fnum].buffer[0x9a], fdc[fnum].buffer[0x9b], fdc[fnum].buffer[0x9c]); log_message(fdc_log, " track=%d, sector=%d", track, sector); log_message(fdc_log, " id=%02x,%02x (%c%c)", header[0], header[1], header[0], header[1]); #endif if (fdc[dnr].image->read_only) { rc = FDC_ERR_WPROT; return rc; } ntracks = 35; memset(sector_data, 0, 256); for (ret = 0, dadr.track = 1; ret == 0 && dadr.track <= ntracks; dadr.track++) { for (i = 3; i >= 0; i--) { if (dadr.track > sectorchangeat[i]) { nsectors = fdc[fnum].buffer[0x99 + 3 - i]; break; } } #ifdef FDC_DEBUG log_message(fdc_log, " track %d, -> %d sectors", dadr.track, nsectors); #endif for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, "Could not update T:%d S:%d on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DCHECK; break; } } } file_system_bam_set_disk_id(dnr + 8, header); } if (!rc) { rc = FDC_ERR_OK; } return rc; }
static int vdrive_rel_open_new(vdrive_t *vdrive, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse, const BYTE *name) { bufferinfo_t *p = &(vdrive->buffers[secondary]); BYTE *slot; /* Allocate a directory slot */ vdrive_dir_find_first_slot(vdrive, NULL, -1, 0); slot = vdrive_dir_find_next_slot(vdrive); /* If we can't get one the directory is full - disk full */ if (!slot) { vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0); return 1; } /* Create our own slot */ p->slot = lib_calloc(1, 32); /* Populate it */ memset(p->slot + SLOT_NAME_OFFSET, 0xa0, 16); memcpy(p->slot + SLOT_NAME_OFFSET, cmd_parse->parsecmd, cmd_parse->parselength); #ifdef DEBUG_DRIVE log_debug("DIR: Created dir slot. Name (%d) '%s'\n", cmd_parse->parsecmd, cmd_parse->parselength); #endif p->slot[SLOT_TYPE_OFFSET] = cmd_parse->filetype | 0x80; /* closed */ p->slot[SLOT_RECORD_LENGTH] = cmd_parse->recordlength; /* Store in buffer */ memcpy(&(vdrive->Dir_buffer[vdrive->SlotNumber * 32 + 2]), p->slot + 2, 30); #ifdef DEBUG_DRIVE log_debug("DEBUG: write DIR slot (%d %d).", vdrive->Curr_track, vdrive->Curr_sector); #endif /* Write the sector */ disk_image_write_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); /* Allocate memory for super side sector */ p->super_side_sector = lib_malloc(256); /* clear out block */ memset(p->super_side_sector, 0, 256); /* build valid super side sector block */ p->super_side_sector[OFFSET_SUPER_254] = 254; p->super_side_sector_track = 0; p->super_side_sector_sector = 0; /* Clear dirty flag */ p->super_side_sector_needsupdate = 0; /* allocate memory for side sectors */ p->side_sector = lib_malloc(SIDE_SECTORS_MAX * 256); memset(p->side_sector, 0, SIDE_SECTORS_MAX * 256); /* Also clear out track and sectors locations and dirty flag of each side sector */ p->side_sector_track = lib_malloc(SIDE_SECTORS_MAX); p->side_sector_sector = lib_malloc(SIDE_SECTORS_MAX); p->side_sector_needsupdate = lib_malloc(SIDE_SECTORS_MAX); memset(p->side_sector_track, 0, SIDE_SECTORS_MAX); memset(p->side_sector_sector, 0, SIDE_SECTORS_MAX); memset(p->side_sector_needsupdate, 0, SIDE_SECTORS_MAX); /* Remember the directory information incase our REL file grows. */ p->dir_track = vdrive->Curr_track; p->dir_sector = vdrive->Curr_sector; p->dir_slot = vdrive->SlotNumber; /* Everything okay */ return 0; }