static int iec_close_sequential(vdrive_t *vdrive, unsigned int secondary) { bufferinfo_t *p = &(vdrive->buffers[secondary]); unsigned int track = 0, sector = 0; if (p->readmode & (CBMDOS_FAM_WRITE | CBMDOS_FAM_APPEND)) { /* * Flush bytes and write slot to directory */ 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; } #ifdef DEBUG_DRIVE log_debug("DEBUG: flush."); #endif /* Flush remained of file */ iec_write_sequential(vdrive, p, p->bufptr); /* Set the file as closed */ p->slot[SLOT_TYPE_OFFSET] |= 0x80; /* Closed */ /* is this a save and replace? */ if (p->needsupdate) { /* remember the original track and sector */ track = p->slot[SLOT_FIRST_TRACK]; sector = p->slot[SLOT_FIRST_SECTOR]; /* move over the replacement track and sector */ p->slot[SLOT_FIRST_TRACK] = p->slot[SLOT_REPLACE_TRACK]; p->slot[SLOT_FIRST_SECTOR] = p->slot[SLOT_REPLACE_SECTOR]; /* set replacement track and sector to 0 */ p->slot[SLOT_REPLACE_TRACK] = 0; p->slot[SLOT_REPLACE_SECTOR] = 0; } /* Update the directory entry (block count, closed) */ vdrive_iec_update_dirent(vdrive, secondary); /* if we have a track and sector saved */ if (track) { /* remove the original file */ vdrive_dir_free_chain(vdrive, track, sector); } /* Update BAM */ vdrive_bam_write_bam(vdrive); /* Free up the slot */ lib_free(p->slot); } /* Release buffers */ vdrive_free_buffer(p); return SERIAL_OK; }
static int vdrive_rel_grow(vdrive_t *vdrive, unsigned int secondary, unsigned int records) { bufferinfo_t *p = &(vdrive->buffers[secondary]); unsigned int track, sector; unsigned int i, j, k, l = 0; /* Add a sector to the rel file until we meet the required records. */ while ( records >= p->record_max ) { l = vdrive_rel_add_sector(vdrive, secondary, &track, §or); if (l) break; } /* Flush the side sectors, since they have changed */ vdrive_rel_flush_sidesectors(vdrive, p); /* Update the BAM. */ vdrive_bam_write_bam(vdrive); /* Update block count on file expansions. */ /* Find the total blocks this REL file uses. */ k = p->slot[SLOT_NR_BLOCKS] + (p->slot[SLOT_NR_BLOCKS + 1] << 8); /* determine the block count of the data */ i = p->record_max * p->slot[SLOT_RECORD_LENGTH]; j = i / 254; if (i % 254) j++; /* determine the block count of the side sectors */ i = j / SIDE_INDEX_MAX; if (j % SIDE_INDEX_MAX) i++; /* Add another block for a super side sector */ if (p->super_side_sector_track) i++; /* Sum them up */ i = i + j; /* Compare with the current */ if (i != k) { /* Convert to high/low */ p->slot[SLOT_NR_BLOCKS] = i % 256; p->slot[SLOT_NR_BLOCKS + 1] = i / 256; /* Update the directory entry (block count) */ vdrive_iec_update_dirent(vdrive, secondary); } return l; }
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); } }
void vdrive_dir_remove_slot(vdrive_dir_context_t *dir) { int t, s; vdrive_t *vdrive = dir->vdrive; /* Free all sector this file is using. */ t = (int) dir->buffer[dir->slot * 32 + SLOT_FIRST_TRACK]; s = (int) dir->buffer[dir->slot * 32 + SLOT_FIRST_SECTOR]; vdrive_dir_free_chain(vdrive, t, s); /* Free side sectors. */ t = (int) dir->buffer[dir->slot * 32 + SLOT_SIDE_TRACK]; s = (int) dir->buffer[dir->slot * 32 + SLOT_SIDE_SECTOR]; vdrive_dir_free_chain(vdrive, t, s); /* Update bam */ vdrive_bam_write_bam(vdrive); /* Update directory entry */ dir->buffer[dir->slot * 32 + SLOT_TYPE_OFFSET] = 0; vdrive_write_sector(vdrive, dir->buffer, dir->track, dir->sector); }
/* FIXME: partition support */ int vdrive_command_format(vdrive_t *vdrive, const char *disk_name) { BYTE tmp[256]; int status; char *name, *comma; BYTE id[2]; if (!disk_name) return CBMDOS_IPE_SYNTAX; if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) return CBMDOS_IPE_WRITE_PROTECT_ON; if (vdrive->image->device == DISK_IMAGE_DEVICE_FS) { if (disk_image_fsimage_fd_get(vdrive->image) == NULL) return CBMDOS_IPE_NOT_READY; } comma = strchr(disk_name, ','); if (comma != NULL) { if (comma != disk_name) { name = lib_malloc(comma - disk_name + 1); memcpy(name, disk_name, comma - disk_name); name[comma - disk_name] = '\0'; } else { name = lib_stralloc(" "); } if (comma[1] != '\0') { id[0] = comma[1]; if (comma[2] != '\0') { id[1] = comma[2]; } else { id[1] = ' '; } } else { id[1] = id[0] = ' '; } } else { name = lib_stralloc(disk_name); id[1] = id[0] = ' '; } /* Make the first dir-entry. */ memset(tmp, 0, 256); tmp[1] = 255; if (vdrive_write_sector(vdrive, tmp, vdrive->Dir_Track, vdrive->Dir_Sector) < 0) { lib_free(name); return CBMDOS_IPE_WRITE_ERROR_VER; } vdrive_bam_create_empty_bam(vdrive, name, id); vdrive_bam_write_bam(vdrive); /* Validate is called to clear the BAM. */ status = vdrive_command_validate(vdrive); lib_free(name); return status; }
/* FIXME: partition support */ int vdrive_command_validate(vdrive_t *vdrive) { unsigned int t, s; int status, max_sector; BYTE *b, oldbam[BAM_MAXSIZE]; status = vdrive_command_initialize(vdrive); if (status != CBMDOS_IPE_OK) return status; if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) return CBMDOS_IPE_WRITE_PROTECT_ON; memcpy(oldbam, vdrive->bam, vdrive->bam_size); vdrive_bam_clear_all(vdrive->image_format, vdrive->bam); for (t = 1; t <= vdrive->num_tracks; t++) { max_sector = vdrive_get_max_sectors(vdrive, t); for (s = 0; s < (unsigned int)max_sector; s++) { vdrive_bam_free_sector(vdrive->image_format, vdrive->bam, t, s); } } /* First, map out the header (BAM) and the directory, themselves. */ status = vdrive_bam_allocate_chain(vdrive, vdrive->Bam_Track, vdrive->Bam_Sector); if (status != CBMDOS_IPE_OK) { memcpy(vdrive->bam, oldbam, vdrive->bam_size); return status; } switch (vdrive->image_format) { case VDRIVE_IMAGE_FORMAT_1571: /* Map the opposite side of the directory cylinder. */ max_sector = vdrive_get_max_sectors(vdrive, 53); for (s = 0; s < (unsigned int)max_sector; s++) { vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 53, s); } break; case VDRIVE_IMAGE_FORMAT_1581: /* Map the BAM sectors. */ vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, vdrive->Bam_Track, vdrive->Bam_Sector + 1); vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, vdrive->Bam_Track, vdrive->Bam_Sector + 2); break; case VDRIVE_IMAGE_FORMAT_4000: /* Map the boot sector. */ vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 1, 0); /* Map the BAM sectors. */ for (s = 2; s < 34; s++) vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 1, s); break; } vdrive_dir_find_first_slot(vdrive, "*", 1, 0); while ((b = vdrive_dir_find_next_slot(vdrive))) { char *filetype = (char *) &vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_TYPE_OFFSET]; if (*filetype & CBMDOS_FT_CLOSED) { status = vdrive_bam_allocate_chain(vdrive, b[SLOT_FIRST_TRACK], b[SLOT_FIRST_SECTOR]); if (status != CBMDOS_IPE_OK) { memcpy(vdrive->bam, oldbam, vdrive->bam_size); return status; } /* The real drive always validates side sectors even if the file type is not REL. */ status = vdrive_bam_allocate_chain(vdrive, b[SLOT_SIDE_TRACK], b[SLOT_SIDE_SECTOR]); if (status != CBMDOS_IPE_OK) { memcpy(vdrive->bam, oldbam, vdrive->bam_size); return status; } } else { /* Delete an unclosed file. */ *filetype = CBMDOS_FT_DEL; if (vdrive_write_sector(vdrive, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector) < 0) return CBMDOS_IPE_WRITE_ERROR_VER; } } /* Write back BAM only if validate was successful. */ vdrive_bam_write_bam(vdrive); return status; }