Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
int vdrive_dir_first_directory(vdrive_t *vdrive, const char *name,
                               int length, int filetype, bufferinfo_t *p)
{
    BYTE *l;

    if (length) {
        if (*name == '$') {
            ++name;
            --length;
        }
        if (*name == ':') {
            ++name;
            --length;
        }
    }
    if (!*name || length < 1) {
        name = "*\0";
        length = 1;
    }

    filetype = vdrive_dir_filetype(name, length);
    vdrive_dir_find_first_slot(vdrive, name, length, filetype, &p->dir);

    /*
     * Start Address, Line Link and Line number 0
     */

    l = p->buffer;

    *l++ = 1;
    *l++ = 4;

    *l++ = 1;
    *l++ = 1;

    *l++ = 0;
    *l++ = 0;

    l[25] = 0;

    *l++ = (BYTE)0x12;          /* Reverse on */
    *l++ = '"';

    memcpy(l, &p->dir.buffer[vdrive->bam_name], 16);
    vdrive_dir_no_a0_pads(l, 16);
    l += 16;
    *l++ = '"';
    *l++ = ' ';
    memcpy(l, &p->dir.buffer[vdrive->bam_id], 5);
    vdrive_dir_no_a0_pads(l, 5);

    p->bufptr = 32;

    return vdrive_dir_next_directory(vdrive, p);
}
Exemplo n.º 3
0
/*
    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;
}
Exemplo n.º 4
0
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);
    }
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
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 (vdrive_read_sector(vdrive, 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, &p->dir);
        e = vdrive_dir_find_next_slot(&p->dir);

        /* 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(&p->dir.buffer[p->dir.slot * 32 + 2],
               p->slot + 2, 30);

        /* Write the sector. */
        vdrive_write_sector(vdrive, p->dir.buffer, p->dir.track, p->dir.sector);
    }

    return SERIAL_OK;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
/*
    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;
}
Exemplo n.º 9
0
/*
    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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
int vdrive_dir_create_directory(vdrive_t *vdrive, const char *name,
                                int length, int filetype, BYTE *outputptr)
{
    BYTE *l, *p;
    BYTE *origptr = outputptr;
    int blocks, i;

    if (length) {
        if (*name == '$') {
            ++name;
            --length;
        }
        if (*name == ':') {
            ++name;
            --length;
        }
    }
    if (!*name || length < 1) {
        name = "*\0";
        length = 1;
    }

    /*
     * Start Address, Line Link and Line number 0
     */

    l = outputptr;
    *l++ = 1;
    *l++ = 4;

    l += 2;                     /* Leave space for Next Line Link */
    *l++ = 0;
    *l++ = 0;

    *l++ = (BYTE)0x12;          /* Reverse on */

    *l++ = '"';

    memcpy(l, &vdrive->bam[vdrive->bam_name], 16);
    vdrive_dir_no_a0_pads(l, 16);
    l += 16;
    *l++ = '"';
    *l++ = ' ';
    memcpy(l, &vdrive->bam[vdrive->bam_id], 5);
    vdrive_dir_no_a0_pads(l, 5);
    l += 5;
    *l++ = 0;

    /*
     * Pointer to the next line
     */

    outputptr[2] = 1;
    outputptr[3] = 1;
    outputptr = l;

    /*
     * Now, list files that match the pattern.
     * Wildcards can be used too.
     */

    vdrive_dir_find_first_slot(vdrive, name, length, filetype);

    while ((p = vdrive_dir_find_next_slot(vdrive))) {
        BYTE *tl;

        /* Check whether the directory exceeds the malloced memory.  We make
           sure there is enough space for two lines because we also have to
           add the final ``...BLOCKS FREE'' line.  */
        if ((l - origptr) >= DIR_MAXBUF - 64) {
            log_error(vdrive_dir_log, "Directory too long: giving up.");
            return -1;
        }

        if (p[SLOT_TYPE_OFFSET]) {

            tl = l;
            l += 2;

            /*
             * Length and spaces
             */
            blocks = p[SLOT_NR_BLOCKS] + p[SLOT_NR_BLOCKS + 1] * 256;
            SET_LO_HI(l, blocks);

            if (blocks < 10)
                *l++ = ' ';
            if (blocks < 100)
                *l++ = ' ';
            /*
             * Filename
             */

            *l++ = ' ';
            *l++ = '"';

            memcpy(l, &p[SLOT_NAME_OFFSET], 16);

            for (i = 0; (i < 16) && (p[SLOT_NAME_OFFSET + i] != 0xa0);)
                i++;

            vdrive_dir_no_a0_pads(l, 16);

            l[16] = ' ';
            l[i] = '"';
            l += 17;

            /*
             * Type + End
             * There are 3 spaces or < and 2 spaces after the filetype.
             * Well, not exactly - the whole directory entry is 32 byte long
             * (including nullbyte).
             * Depending on the file size, there are more or less spaces
             */

            sprintf((char *)l, "%c%s%c%c",
                    (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_CLOSED ? ' ' : '*'),
                    cbmdos_filetype_get(p[SLOT_TYPE_OFFSET] & 0x07),
                    (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_LOCKED ? '<' : ' '),
                    0);
            l += 5;
            i = (int)(l - tl);

            while (i < 31) {
                *l++ = ' ';
                i++;
            }
            *l++ = '\0';

            /*
             * New address
             */

            outputptr[0] = 1;
            outputptr[1] = 1;
            outputptr = l;
        }
    }

    blocks = vdrive_bam_free_block_count(vdrive);

    *l++ = 0;
    *l++ = 0;
    SET_LO_HI(l, blocks);
    memcpy(l, "BLOCKS FREE.", 12);
    l += 12;
    memset(l, ' ', 13);
    l += 13;
    *l++ = (char) 0;

    /* Line Address */
    outputptr[0] = 1;
    outputptr[1] = 1;

    /*
     * end
     */
    *l++ = (char) 0;
    *l++ = (char) 0;
    *l   = (char) 0;

    return (int)(l - origptr);
}