static int vdrive_command_scratch(vdrive_t *vdrive, BYTE *name, int length) { int status, rc; BYTE *slot; cbmdos_cmd_parse_t cmd_parse; /* XXX * Wrong name parser -- s0:file1,0:file2 means scratch * those 2 files. (It's similar to the copy command.) */ cmd_parse.cmd = name; cmd_parse.cmdlength = length; cmd_parse.readmode = 0; rc = cbmdos_command_parse(&cmd_parse); if (rc != SERIAL_OK) { status = CBMDOS_IPE_NO_NAME; } else if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) { status = CBMDOS_IPE_WRITE_PROTECT_ON; } else { /*#ifdef DEBUG_DRIVE*/ log_debug("remove name='%s', len=%d (%d), type= %d.", cmd_parse.parsecmd, cmd_parse.parselength, length, cmd_parse.filetype); /*#endif*/ vdrive->deleted_files = 0; /* Since vdrive_dir_remove_slot() uses * vdrive_dir_find_first_slot() too, we cannot find the * matching files by simply repeating * vdrive_dir find_next_slot() calls alone; we have to re-call * vdrive_dir_find_first_slot() each time... EP 1996/04/07 */ vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd, cmd_parse.parselength, 0); while ((slot = vdrive_dir_find_next_slot(vdrive))) { vdrive_dir_remove_slot(vdrive, slot); vdrive->deleted_files++; vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd, cmd_parse.parselength, 0); } if (vdrive->deleted_files) status = CBMDOS_IPE_DELETED; else status = CBMDOS_IPE_NOT_FOUND; vdrive_command_set_error(vdrive, status, 1, 0); } lib_free(cmd_parse.parsecmd); return status; }
/* CMD style subdir support (using DIR filetype) */ static int vdrive_command_chdir(vdrive_t *vdrive, BYTE *name, int length) { int status, rc; BYTE *slot, buffer[256]; cbmdos_cmd_parse_t cmd_parse; cmd_parse.cmd = name; cmd_parse.cmdlength = length; cmd_parse.readmode = 0; rc = cbmdos_command_parse(&cmd_parse); if (rc != SERIAL_OK) { status = CBMDOS_IPE_NO_NAME; } else { /*#ifdef DEBUG_DRIVE*/ log_debug("chdir name='%s', len=%d (%d), type= %d.", cmd_parse.parsecmd, cmd_parse.parselength, length, cmd_parse.filetype); /*#endif*/ vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd, cmd_parse.parselength, CBMDOS_FT_DIR); slot = vdrive_dir_find_next_slot(vdrive); if (slot) { slot = &vdrive->Dir_buffer[vdrive->SlotNumber * 32]; rc = vdrive_read_sector(vdrive, buffer, slot[SLOT_FIRST_TRACK], slot[SLOT_FIRST_SECTOR]); if (rc > 0) { return rc; } if (rc < 0) { return CBMDOS_IPE_NOT_READY; } vdrive->Header_Track = slot[SLOT_FIRST_TRACK]; vdrive->Header_Sector = slot[SLOT_FIRST_SECTOR]; vdrive->Dir_Track = buffer[0]; vdrive->Dir_Sector = buffer[1]; status = CBMDOS_IPE_OK; } else { status = CBMDOS_IPE_PATH_NOT_FOUND; } vdrive_command_set_error(vdrive, status, 0, 0); } lib_free(cmd_parse.parsecmd); return status; }
int vdrive_iec_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse_ext) { bufferinfo_t *p = &(vdrive->buffers[secondary]); BYTE *slot; /* Current directory entry */ int rc, status = SERIAL_OK; /* FIXME: This should probably be set to zero */ cbmdos_cmd_parse_t cmd_parse_stat; cbmdos_cmd_parse_t *cmd_parse; BYTE name_stat[17]; unsigned int opentype; if (cmd_parse_ext != NULL) { cmd_parse = cmd_parse_ext; memset(name_stat, 0, sizeof(name_stat)); strncpy((char *)name_stat, cmd_parse->parsecmd, sizeof(name_stat) - 1); name = name_stat; length = (unsigned int)strlen((char *)name); secondary = cmd_parse->secondary; } else { cmd_parse = &cmd_parse_stat; } if (cmd_parse_ext == NULL && (!name || !*name) && p->mode != BUFFER_COMMAND_CHANNEL) { return SERIAL_NO_DEVICE; } /* No floppy in drive? */ if (vdrive->image == NULL && p->mode != BUFFER_COMMAND_CHANNEL && secondary != 15 && *name != '#') { vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); log_message(vdrive_iec_log, "Drive not ready."); return SERIAL_ERROR; } #ifdef DEBUG_DRIVE log_debug("VDRIVE#%i: OPEN: Name '%s' (%d) on ch %d.", vdrive->unit, name, length, secondary); #endif /* * If channel is command channel, name will be used as write. Return only * status of last write ... */ if (p->mode == BUFFER_COMMAND_CHANNEL) { unsigned int n; for (n = 0; n < length; n++) { status = vdrive_iec_write(vdrive, name[n], secondary); } if (length) { p->readmode = CBMDOS_FAM_WRITE; } else { p->readmode = CBMDOS_FAM_READ; } return status; } /* * Clear error flag */ vdrive_command_set_error(vdrive, CBMDOS_IPE_OK, 0, 0); /* * In use ? */ if (p->mode != BUFFER_NOT_IN_USE) { #ifdef DEBUG_DRIVE log_debug("Cannot open channel %d. Mode is %d.", secondary, p->mode); #endif vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_CHANNEL, 0, 0); return SERIAL_ERROR; } if (cmd_parse_ext == NULL) { cmd_parse->cmd = name; cmd_parse->cmdlength = length; cmd_parse->secondary = secondary; /* make sure this is zero, since it isn't set below */ cmd_parse->recordlength = 0; cmd_parse->drive = -1; rc = cbmdos_command_parse(cmd_parse); if (rc != CBMDOS_IPE_OK) { status = SERIAL_ERROR; goto out; } #ifdef DEBUG_DRIVE log_debug("Raw file name: `%s', length: %i.", name, length); log_debug("Parsed file name: `%s', reallength: %i. drive: %i", cmd_parse->parsecmd, cmd_parse->parselength, cmd_parse->drive); #endif if (cmd_parse->drive != -1) { /* a drive number was specified in the filename */ if ((vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) || (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8250) || (vdrive->image_format == VDRIVE_IMAGE_FORMAT_2040)) { /* FIXME: dual disk drives not supported */ if (cmd_parse->drive == 0) { /* FIXME: use drive 0 */ } else if (cmd_parse->drive == 1) { /* FIXME: use drive 1 */ /* since some software gets confused when it sees the same disk in both drives, we bail out with an error instead. */ log_warning(LOG_DEFAULT, "second drive of dual disk drive is not supported"); vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); status = SERIAL_ERROR; goto out; } else { /* FIXME: what exactly does the drive do if drivenumber is > 1, look up the file on both drives perhaps ? */ } } else { /* single disk drives seem to ignore the drive number, *except* if it is 1, which will result in an error. */ if (cmd_parse->drive == 1) { vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); status = SERIAL_ERROR; goto out; } } } } /* Limit file name to 16 chars. */ if (cmd_parse->parselength > 16) { cmd_parse->parselength = 16; } /* * Internal buffer ? */ if (*name == '#') { vdrive_alloc_buffer(p, BUFFER_MEMORY_BUFFER); /* the pointer is actually 1 on the real drives. */ /* this probably relates to the B-R and B-W commands. */ /* 1541 firmware: $cb84 - open channel, $cc0f bp = 1 */ p->bufptr = 1; /* we need a length to support the original B-R and B-W commands. */ p->length = 256; status = SERIAL_OK; goto out; } /* Clear update flag */ p->needsupdate = 0; /* * Directory read * A little-known feature of the 1541: open 1,8,2,"$" (or even 1,8,1). * It gives you the BAM+DIR as a sequential file, containing the data * just as it appears on disk. -Olaf Seibert */ if (*name == '$') { p->readmode = CBMDOS_FAM_READ; status = iec_open_read_directory(vdrive, secondary, cmd_parse); goto out; } /* * Check that there is room on directory. */ if (cmd_parse->readmode == CBMDOS_FAM_READ || cmd_parse->readmode == CBMDOS_FAM_APPEND) { opentype = cmd_parse->filetype; } else { opentype = CBMDOS_FT_DEL; } vdrive_dir_find_first_slot(vdrive, cmd_parse->parsecmd, cmd_parse->parselength, opentype, &p->dir); /* * Find the first non-DEL entry in the directory (if it exists). */ do { slot = vdrive_dir_find_next_slot(&p->dir); } while (slot && ((slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_DEL)); p->readmode = cmd_parse->readmode; p->slot = slot; /* Call REL function if we are creating OR opening one */ if (cmd_parse->filetype == CBMDOS_FT_REL || ( slot && (slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_REL)) { /* Make sure the record length of the opening command is the same as the record length in the directory slot, if not DOS ERROR 50 */ if (slot && cmd_parse->recordlength > 0 && slot[SLOT_RECORD_LENGTH] != cmd_parse->recordlength) { vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0); status = SERIAL_ERROR; goto out; } /* At this point the record lengths are the same (or will be), so set them equal. */ if (slot) { cmd_parse->recordlength = slot[SLOT_RECORD_LENGTH]; } status = vdrive_rel_open(vdrive, secondary, cmd_parse, name); goto out; } if (cmd_parse->readmode == CBMDOS_FAM_READ) { status = iec_open_read(vdrive, secondary); } else { status = iec_open_write(vdrive, secondary, cmd_parse, name); } out: lib_free(cmd_parse->parsecmd); return status; }
/* CBM style sub partition support (using CBM filetype) on 1581 dos command "/dirname" enters a partition, "i" will go back to root FIXME: this works only for .d81 */ static int vdrive_command_chpart(vdrive_t *vdrive, BYTE *name, int length) { int status, rc; int ts,ss,te,len; BYTE *slot, buffer[256]; cbmdos_cmd_parse_t cmd_parse; cmd_parse.cmd = name; cmd_parse.cmdlength = length; cmd_parse.readmode = 0; rc = cbmdos_command_parse(&cmd_parse); if (rc != SERIAL_OK) { status = CBMDOS_IPE_NO_NAME; } else { /*#ifdef DEBUG_DRIVE*/ log_debug("chpart name='%s', len=%d (%d), type= %d.", cmd_parse.parsecmd, cmd_parse.parselength, length, cmd_parse.filetype); /*#endif*/ vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd, cmd_parse.parselength, CBMDOS_FT_CBM); slot = vdrive_dir_find_next_slot(vdrive); status = CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */ if (slot) { slot = &vdrive->Dir_buffer[vdrive->SlotNumber * 32]; /* In order to use a partition as a sub-directory, it must adhere to the following four rules: 1. It must start on sector 0 2. It's size must be in multiples of 40 sectors (which means the last sector is 39) 3. It must be a minimum of 120 sectors long (3 tracks) 4. It must not start on or cross track 40 */ ts = slot[SLOT_FIRST_TRACK]; ss = slot[SLOT_FIRST_SECTOR]; len = slot[SLOT_NR_BLOCKS] + (slot[SLOT_NR_BLOCKS + 1] * 256); if ((ss == 0) && ((len % 40) == 0) && (len >= 120) && (ts != 40)) { te = ts + (len / 40); if (((ts < 40) && (te >= 40)) || (te >= (int)vdrive->num_tracks)) { return CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */ } /* read the first BAM sector to get the DIR start The BAM track for the sub-directory exists on the first track of the partition, and has the same layout as the disk BAM on track 40. */ rc = vdrive_read_sector(vdrive, buffer, ts, 0); if (rc > 0) { return rc; } if (rc < 0) { return CBMDOS_IPE_NOT_READY; } /* more sanity checks */ if ((buffer[0] < ts) || (buffer[1] > 39)) { return CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */ } /*#ifdef DEBUG_DRIVE*/ log_debug("Partition Trk %d Sec %d - Trk %d len: %d", ts, ss, te, len); /*#endif*/ /* setup BAM location */ vdrive->Header_Track = ts; vdrive->Header_Sector = 0; vdrive->Bam_Track = ts; vdrive->Bam_Sector = 0; /* set area for active partition */ vdrive->Part_Start = ts; vdrive->Part_End = te; /* start of directory */ vdrive->Dir_Track = buffer[0]; vdrive->Dir_Sector = buffer[1]; status = CBMDOS_IPE_OK; } } } vdrive_command_set_error(vdrive, status, 0, 0); lib_free(cmd_parse.parsecmd); return status; }
static int vdrive_command_rename(vdrive_t *vdrive, BYTE *dest, int length) { BYTE *src; BYTE *slot; int status = CBMDOS_IPE_OK, rc; cbmdos_cmd_parse_t cmd_parse_dst, cmd_parse_src; if (!dest || !(src = memchr((char *)++dest, '=', length)) ) { return CBMDOS_IPE_SYNTAX; } *src++ = 0; #ifdef DEBUG_DRIVE log_debug("RENAME: dest= '%s', orig= '%s'.", dest, src); #endif cmd_parse_dst.cmd = dest; cmd_parse_dst.cmdlength = (unsigned int)strlen((char *)dest); cmd_parse_dst.readmode = CBMDOS_FAM_READ; rc = cbmdos_command_parse(&cmd_parse_dst); if (rc == FLOPPY_ERROR) { status = CBMDOS_IPE_SYNTAX; goto out1; } cmd_parse_src.cmd = src; cmd_parse_src.cmdlength = (unsigned int)strlen((char *)src); cmd_parse_src.readmode = CBMDOS_FAM_READ; rc = cbmdos_command_parse(&cmd_parse_src); if (rc == FLOPPY_ERROR) { status = CBMDOS_IPE_SYNTAX; goto out2; } if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) { status = CBMDOS_IPE_WRITE_PROTECT_ON; goto out2; } /* Check if the destination name is already in use. */ vdrive_dir_find_first_slot(vdrive, cmd_parse_dst.parsecmd, cmd_parse_dst.parselength, cmd_parse_dst.filetype); slot = vdrive_dir_find_next_slot(vdrive); if (slot) { status = CBMDOS_IPE_FILE_EXISTS; goto out2; } /* Find the file to rename. */ vdrive_dir_find_first_slot(vdrive, cmd_parse_src.parsecmd, cmd_parse_src.parselength, cmd_parse_src.filetype); slot = vdrive_dir_find_next_slot(vdrive); if (!slot) { status = CBMDOS_IPE_NOT_FOUND; goto out2; } /* Now we can replace the old file name... */ /* We write directly to the Dir_buffer. */ slot = &vdrive->Dir_buffer[vdrive->SlotNumber * 32]; memset(slot + SLOT_NAME_OFFSET, 0xa0, 16); memcpy(slot + SLOT_NAME_OFFSET, cmd_parse_dst.parsecmd, cmd_parse_dst.parselength); /* FIXME: is this right? */ if (cmd_parse_dst.filetype) slot[SLOT_TYPE_OFFSET] = cmd_parse_dst.filetype; /* Update the directory. */ if (vdrive_write_sector(vdrive, vdrive->Dir_buffer, vdrive->Curr_track, vdrive->Curr_sector) < 0) status = CBMDOS_IPE_WRITE_ERROR_VER; out2: lib_free(cmd_parse_src.parsecmd); out1: lib_free(cmd_parse_dst.parsecmd); return status; }