/* FIXME: partition support */ int vdrive_bam_alloc_first_free_sector(vdrive_t *vdrive, unsigned int *track, unsigned int *sector) { unsigned int s, d, max_tracks; int t; max_tracks = vdrive_calculate_disk_half(vdrive); for (d = 0; d <= max_tracks; d++) { int max_sector; t = vdrive->Bam_Track - d; #ifdef DEBUG_DRIVE log_error(LOG_ERR, "Allocate first free sector on track %d.", t); #endif if (d && t >= 1) { max_sector = vdrive_get_max_sectors(vdrive, t); for (s = 0; s < (unsigned int)max_sector; s++) { if (vdrive_bam_allocate_sector(vdrive, t, s)) { *track = t; *sector = s; #ifdef DEBUG_DRIVE log_error(LOG_ERR, "Allocate first free sector: %d,%d.", t, s); #endif return 0; } } } t = vdrive->Bam_Track + d; #ifdef DEBUG_DRIVE log_error(LOG_ERR, "Allocate first free sector on track %d.", t); #endif if (t <= (int)(vdrive->num_tracks)) { max_sector = vdrive_get_max_sectors(vdrive, t); if (d) { s = 0; } else if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) { s = 64; /* after root directory */ } else { s = max_sector; /* skip bam track */ } for (; s < (unsigned int)max_sector; s++) { if (vdrive_bam_allocate_sector(vdrive, t, s)) { *track = t; *sector = s; #ifdef DEBUG_DRIVE log_error(LOG_ERR, "Allocate first free sector: %d,%d.", t, s); #endif return 0; } } } } return -1; }
static int vdrive_bam_alloc_up(vdrive_t *vdrive, unsigned int *track, unsigned int *sector) { unsigned int max_sector, t, s; for (t = *track; t <= vdrive->num_tracks; t++) { max_sector = vdrive_get_max_sectors(vdrive, t); for (s = 0; s < max_sector; s++) { if (vdrive_bam_allocate_sector(vdrive, t, s)) { *track = t; *sector = s; return 0; } } } return -1; }
BYTE *vdrive_dir_find_next_slot(vdrive_dir_context_t *dir) { static BYTE return_slot[32]; vdrive_t *vdrive = dir->vdrive; #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot start (t:%d/s:%d) #%d", dir->track, dir->sector, dir->slot); #endif /* * Loop all directory blocks starting from track 18, sector 1 (1541). */ do { /* * Load next(first) directory block ? */ dir->slot++; if (dir->slot >= 8) { int status; /* end of current directory? */ if (dir->buffer[0] == 0) { break; } dir->slot = 0; dir->track = (unsigned int)dir->buffer[0]; dir->sector = (unsigned int)dir->buffer[1]; status = vdrive_read_sector(vdrive, dir->buffer, dir->track, dir->sector); if (status != 0) { return NULL; /* error */ } } if (vdrive_dir_name_match(&dir->buffer[dir->slot * 32], dir->find_nslot, dir->find_length, dir->find_type)) { memcpy(return_slot, &dir->buffer[dir->slot * 32], 32); return return_slot; } } while (1); #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot (t:%d/s:%d) #%d", dir->track, dir->sector, dir->slot); #endif /* * If length < 0, create new directory-entry if possible */ if (dir->find_length < 0) { int i, sector; BYTE *dirbuf; sector = dir->sector + vdrive_dir_get_interleave(vdrive->image_format); for (i = 0; i < vdrive_get_max_sectors(vdrive, dir->track); i++) { dirbuf = find_next_directory_sector(dir, dir->track, sector); if (dirbuf != NULL) { return dirbuf; } sector++; if (sector >= vdrive_get_max_sectors(vdrive, dir->track)) { sector = 0; } } } return NULL; }
/* FIXME: partition support */ int vdrive_bam_alloc_next_free_sector(vdrive_t *vdrive, unsigned int *track, unsigned int *sector) { unsigned int max_sector, i, t, s; if (*track == vdrive->Bam_Track) { if (vdrive->image_format != VDRIVE_IMAGE_FORMAT_4000 || *sector < 64) { return -1; } } /* Calculate the next sector for the current interleave */ s = *sector + vdrive_bam_get_interleave(vdrive->image_format); t = *track; max_sector = vdrive_get_max_sectors(vdrive, t); if (s >= max_sector) { s -= max_sector; if (s != 0) { s--; } } /* Look for a sector on the same track */ for (i = 0; i < max_sector; i++) { if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000 && *track == vdrive->Bam_Track && s < 64) { s = 64; } if (vdrive_bam_allocate_sector(vdrive, t, s)) { *track = t; *sector = s; return 0; } s++; if (s >= max_sector) { s = 0; } } if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000 && *track == vdrive->Bam_Track) { (*track)++; } /* Look for a sector on a close track */ *sector = 0; if (*track < vdrive->Dir_Track) { if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) { return 0; } *track = vdrive->Dir_Track - 1; if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) { return 0; } *track = vdrive->Dir_Track + 1; if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) { return 0; } } else { if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) { return 0; } *track = vdrive->Dir_Track + 1; if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) { return 0; } *track = vdrive->Dir_Track - 1; if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) { return 0; } } return -1; }
/* 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; }
BYTE *vdrive_dir_find_next_slot(vdrive_t *vdrive) { static BYTE return_slot[32]; #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot start (t:%d/s:%d) #%d", vdrive->Curr_track, vdrive->Curr_sector, vdrive->SlotNumber); #endif /* * Loop all directory blocks starting from track 18, sector 1 (1541). */ do { /* * Load next(first) directory block ? */ vdrive->SlotNumber++; if (vdrive->SlotNumber >= 8) { int status; /* end of current directory? */ if (vdrive->Dir_buffer[0] == 0) { break; } vdrive->SlotNumber = 0; vdrive->Curr_track = (int)vdrive->Dir_buffer[0]; vdrive->Curr_sector = (int)vdrive->Dir_buffer[1]; status = disk_image_read_sector(vdrive->image, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector); if (status != 0) { return NULL; /* error */ } } if (vdrive_dir_name_match(&vdrive->Dir_buffer[vdrive->SlotNumber * 32], vdrive->find_nslot, vdrive->find_length, vdrive->find_type)) { memcpy(return_slot, &vdrive->Dir_buffer[vdrive->SlotNumber * 32], 32); return return_slot; } } while (1); #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot (t:%d/s:%d) #%d", vdrive->Curr_track, vdrive->Curr_sector, vdrive->SlotNumber); #endif /* * If length < 0, create new directory-entry if possible */ if (vdrive->find_length < 0) { int i, sector; BYTE *dirbuf; sector = vdrive->Curr_sector + vdrive_dir_get_interleave(vdrive->image_format); for (i = 0; i < vdrive_get_max_sectors(vdrive, vdrive->Curr_track); i++) { dirbuf = find_next_directory_sector(vdrive, vdrive->Curr_track, sector); if (dirbuf != NULL) { return dirbuf; } sector++; if (sector >= vdrive_get_max_sectors(vdrive, vdrive->Curr_track)) { sector = 0; } } } return NULL; }