Exemple #1
0
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);
}
Exemple #2
0
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;
}
Exemple #3
0
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, &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;
    }

    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;
}
Exemple #4
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;
}
Exemple #5
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) {
        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);
    }
}
Exemple #6
0
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);
        }
    }
}
Exemple #7
0
/* 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;
}
Exemple #8
0
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
		}
	}
}
Exemple #9
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);
    }
}
Exemple #10
0
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;
}
Exemple #11
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
	}
}
Exemple #12
0
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;
}
Exemple #13
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;
}
Exemple #14
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;
}
Exemple #16
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;
}
Exemple #17
0
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;
}
Exemple #18
0
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;
}
Exemple #19
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;
}