Example #1
0
/*
   read first dir buffer into Dir_buffer
*/
void vdrive_dir_find_first_slot(vdrive_t *vdrive, const char *name,
                                int length, unsigned int type)
{
    if (length > 0) {
        BYTE *nslot;

        nslot = cbmdos_dir_slot_create(name, length);
        memcpy(vdrive->find_nslot, nslot, CBMDOS_SLOT_NAME_LENGTH);
        lib_free(nslot);
    }

    vdrive->find_length = length;
    vdrive->find_type = type;

    vdrive->Curr_track = vdrive->Header_Track;
    vdrive->Curr_sector = vdrive->Header_Sector;
    vdrive->SlotNumber = 7;

    disk_image_read_sector(vdrive->image, vdrive->Dir_buffer,
                           vdrive->Curr_track, vdrive->Curr_sector);

    vdrive->Dir_buffer[0] = vdrive->Dir_Track;
    vdrive->Dir_buffer[1] = vdrive->Dir_Sector;

#ifdef DEBUG_DRIVE
    log_debug("DIR: vdrive_dir_find_first_slot (curr t:%d/s:%d dir t:%d/s:%d)", 
              vdrive->Curr_track, vdrive->Curr_sector,
              vdrive->Dir_Track, vdrive->Dir_Sector
             );
#endif
}
Example #2
0
/* This is where logical sectors are turned to physical. Not yet, but soon. */
int vdrive_read_sector(vdrive_t *vdrive, BYTE *buf, unsigned int track, unsigned int sector)
{
    disk_addr_t dadr;
    dadr.track = track;
    dadr.sector = sector;
    return disk_image_read_sector(vdrive->image, buf, &dadr);
}
static int drive_snapshot_write_image_module(snapshot_t *s, unsigned int dnr)
{
    char snap_module_name[10];
    snapshot_module_t *m;
    BYTE sector_data[0x100];
    WORD word;
    disk_addr_t dadr;
    int rc;
    drive_t *drive;

    drive = drive_context[dnr]->drive;

    if (drive->image == NULL) {
        sprintf(snap_module_name, "NOIMAGE%i", dnr);
    } else {
        sprintf(snap_module_name, "IMAGE%i", dnr);
    }

    m = snapshot_module_create(s, snap_module_name, IMAGE_SNAP_MAJOR,
                               IMAGE_SNAP_MINOR);
    if (m == NULL) {
        return -1;
    }

    if (drive->image == NULL) {
        if (snapshot_module_close(m) < 0) {
            return -1;
        }

        return 0;
    }

    word = drive->image->type;
    SMW_W(m, word);

    /* we use the return code to step through the tracks. So we do not
       need any geometry info. */
    for (dadr.track = 1;; dadr.track++) {
        rc = 0;
        for (dadr.sector = 0;; dadr.sector++) {
            rc = disk_image_read_sector(drive->image, sector_data, &dadr);
            if (rc == 0) {
                SMW_BA(m, sector_data, 0x100);
            } else {
                break;
            }
        }
        if (dadr.sector == 0) {
            break;
        }
    }

    if (snapshot_module_close(m) < 0) {
        return -1;
    }
    return 0;
}
Example #4
0
void vdrive_rel_listen(vdrive_t *vdrive, unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);

    if (p->needsupdate & WRITTEN_RECORD) {
	    /* Fill the rest of the currently written record. */
	    vdrive_rel_fillrecord(vdrive, secondary);

	    /* set up the buffer pointer to the next record */
	    p->bufptr = p->record_next;
	    /* add the record length to the next record pointer */
	    p->record_next += p->side_sector[OFFSET_RECORD_LEN];
	    /* calculate the maximum length (for read, for write we should use
	       record_next - 1 */
	    p->length = p->record_next - 1;
	    /* increment the record reference */
	    p->record++;
	    /* Find the length of the record starting from the end until no zeros
	       are found */
	    if ( p->length < 256) {
		    /* If the maximum length of the record is in this sector, just
		       check for where the zeros end */
		    for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
	    }
	    else {
		    int status=1;

		    /* Get the next sector */
		    /* If it doesn't exist, we will use the max length calculated above */
		    if (p->buffer[0] != 0) {
			    /* Read in the sector if it has not been buffered */
			    if (p->buffer[0] != p->track_next || p->buffer[1] != p->sector_next) {
				    status = disk_image_read_sector(vdrive->image, p->buffer_next, p->buffer[0],
						    p->buffer[1]);
			    }
			    else {
				    status = 0;
			    }
		    }
		    /* If all is good, calculate the length now */
		    if (!status) {
			    /* update references, if the sector read in */
			    p->track_next = p->buffer[0];
			    p->sector_next = p->buffer[1];
			    /* Start looking in the buffered sector */
			    for (;p->length >= 256 && p->buffer_next[p->length-256+2] == 0 ; p->length-- );
			    /* If we crossed into the current sector, look there too */
			    if (p->length<256) {
				    for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
			    }
		    }

	    }
	    //log_debug("Forced from write to position %d, 0 on channel %d.", p->record, secondary);
    }
}
Example #5
0
static int wd1770_sector_read(unsigned int dnr, unsigned int track,
                              unsigned int sector)
{
    BYTE sector_data[256];
    int rc;

    wd1770_conv_phy2log(dnr, &track, &sector);

#ifdef WD_DEBUG
    log_debug("READ T%i S%i",track,sector);
#endif

    rc = disk_image_read_sector(wd1770[dnr].image, sector_data, track, sector);

    if (rc < 0) {
        log_error(wd1770_log,
                  "Cannot read T:%d S:%d from disk image.", track, sector);
        return -1;
    }

    wd1770_buffer_put(dnr, sector_data, sizeof(sector_data));

    sector++;

#ifdef WD_DEBUG
    log_debug("READ T%i S%i",track,sector);
#endif

    rc = disk_image_read_sector(wd1770[dnr].image, sector_data, track, sector);

    if (rc < 0) {
        log_error(wd1770_log,
                  "Cannot read T:%d S:%d from disk image.", track, sector);
        return -1;
    }

    wd1770_buffer_put(dnr, sector_data, sizeof(sector_data));

    return 0;
}
Example #6
0
static int iec_read_sequential(vdrive_t *vdrive, BYTE *data,
                               unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    int status;
    unsigned int track, sector;

    if (p->readmode != CBMDOS_FAM_READ) {
        *data = 0xc7;
        return SERIAL_ERROR;
    }

    *data = p->buffer[p->bufptr];
    if (p->length != 0) {
        if (p->bufptr == p->length) {
            p->bufptr = 0xff;
        } 
    }
    p->bufptr = (p->bufptr + 1) & 0xff;
    if (p->bufptr) {
        return SERIAL_OK;
    }
    if (p->length) {
        p->readmode = CBMDOS_FAM_EOF;
        return SERIAL_EOF;
    }

    switch (p->mode) {
    case BUFFER_SEQUENTIAL:

        track = (unsigned int)p->buffer[0];
        sector = (unsigned int)p->buffer[1];

        status = disk_image_read_sector(vdrive->image, p->buffer,
                                                track, sector);
        p->length = p->buffer[0] ? 0 : p->buffer[1];
        vdrive_set_last_read(track, sector, p->buffer);

        if (status == 0) {
            p->bufptr = 2;
        } else {
            p->readmode = CBMDOS_FAM_EOF;
        }
        break;
    case BUFFER_DIRECTORY_READ:
        p->length = vdrive_dir_next_directory(vdrive, p);
        p->bufptr = 0;
        break;
    }
    return SERIAL_OK;
}
Example #7
0
void vdrive_dir_free_chain(vdrive_t *vdrive, int t, int s)
{
    BYTE buf[256];

    while (t) {
        /* Check for illegal track or sector.  */
        if (disk_image_check_sector(vdrive->image, t, s) < 0)
            break;

        /* Check if this sector is really allocated.  */
        if (!vdrive_bam_free_sector(vdrive->image_format, vdrive->bam, t, s))
            break;

        /* FIXME: This seems to be redundant.  AB19981124  */
        vdrive_bam_free_sector(vdrive->image_format, vdrive->bam, t, s);
        disk_image_read_sector(vdrive->image, buf, t, s);
        t = (int)buf[0];
        s = (int)buf[1];
    }
}
Example #8
0
static int iec_open_read_sequential(vdrive_t *vdrive, unsigned int secondary,
                                     unsigned int track, unsigned int sector)
{
    int status;
    bufferinfo_t *p = &(vdrive->buffers[secondary]);

    vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL);
    p->bufptr = 2;

    status = disk_image_read_sector(vdrive->image, p->buffer, track, sector);
    p->length = p->buffer[0] ? 0 : p->buffer[1];

    vdrive_set_last_read(track, sector, p->buffer);

    if (status != 0) {
        vdrive_iec_close(vdrive, secondary);
        return SERIAL_ERROR;
    }
    return SERIAL_OK;
}
Example #9
0
static int setID(unsigned int dnr)
{
	BYTE buffer[256];
	int rc;
	drive_t *drive;

	drive = drive_context[dnr]->drive;

	if (!(drive->image))
		return -1;

	rc = disk_image_read_sector(drive->image, buffer, 18, 0);
	if (rc >= 0)
	{
		drive->diskID1 = buffer[0xa2];
		drive->diskID2 = buffer[0xa3];
	}

	return rc;
}
Example #10
0
void vdrive_dir_find_first_slot(vdrive_t *vdrive, const char *name,
                                int length, unsigned int type)
{
    if (length > 0) {
        BYTE *nslot;

        nslot = cbmdos_dir_slot_create(name, length);
        memcpy(vdrive->find_nslot, nslot, CBMDOS_SLOT_NAME_LENGTH);
        lib_free(nslot);
    }

    vdrive->find_length = length;
    vdrive->find_type = type;

    vdrive->Curr_track = vdrive->Dir_Track;
    vdrive->Curr_sector = vdrive->Dir_Sector;
    vdrive->SlotNumber = 0;
    vdrive->SlotNumber--;

    disk_image_read_sector(vdrive->image, vdrive->Dir_buffer,
                           vdrive->Dir_Track, vdrive->Dir_Sector);
}
Example #11
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;
}
Example #12
0
static void drive_image_read_d64_d71(drive_t *drive)
{
	BYTE buffer[260], chksum;
	int i;
	unsigned int track, sector;

	if (!(drive->image))
		return;

	buffer[258] = buffer[259] = 0;

	/* Since the D64/D71 format does not provide the actual track sizes or
	   speed zones, we set them to standard values.  */
	if ((drive->image->type == DISK_IMAGE_TYPE_D64
				|| drive->image->type == DISK_IMAGE_TYPE_D67
				|| drive->image->type == DISK_IMAGE_TYPE_X64)
			&& (drive->type == DRIVE_TYPE_1541
				|| drive->type == DRIVE_TYPE_1541II
				|| drive->type == DRIVE_TYPE_1551
				|| drive->type == DRIVE_TYPE_1570
				|| drive->type == DRIVE_TYPE_2031)) {
		drive_image_init_track_size_d64(drive);
	}
	if (drive->image->type == DISK_IMAGE_TYPE_D71
			|| drive->type == DRIVE_TYPE_1571
			|| drive->type == DRIVE_TYPE_1571CR
			|| drive->type == DRIVE_TYPE_2031) {
		drive_image_init_track_size_d71(drive);
	}

	drive_set_half_track(drive->current_half_track, drive);

	for (track = 1; track <= drive->image->tracks; track++) {
		BYTE *ptr;
		unsigned int max_sector = 0;

		ptr = drive->gcr->data + GCR_OFFSET(track);
		max_sector = disk_image_sector_per_track(drive->image->type,
				track);
		/* Clear track to avoid read errors.  */
		memset(ptr, 0x55, NUM_MAX_BYTES_TRACK);

		for (sector = 0; sector < max_sector; sector++)
		{
			int rc;
			ptr = drive->gcr->data + sector_offset(track, sector,
					max_sector, drive);

			rc = disk_image_read_sector(drive->image, buffer + 1, track,
					sector);

#ifdef CELL_DEBUG
			if (rc < 0) {
				printf("ERROR: Cannot read T:%d S:%d from disk image.\n", track, sector);
				continue;
			}
#endif

			if (rc == 21) {
				ptr = drive->gcr->data + GCR_OFFSET(track);
				memset(ptr, 0x00, NUM_MAX_BYTES_TRACK);
				break;
			}

			buffer[0] = (rc == 22) ? 0xff : 0x07;

			chksum = buffer[1];
			for (i = 2; i < 257; i++)
				chksum ^= buffer[i];
			buffer[257] = (rc == 23) ? chksum ^ 0xff : chksum;
			gcr_convert_sector_to_GCR(buffer, ptr, track, sector,
					drive->diskID1, drive->diskID2,
					(BYTE)(rc));
		}
	}
}
Example #13
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;
}
Example #14
0
BYTE *vdrive_dir_find_next_slot(vdrive_t *vdrive)
{
    static BYTE return_slot[32];

#ifdef DEBUG_DRIVE
    log_debug("DIR: vdrive_dir_find_next_slot start (t:%d/s:%d) #%d", vdrive->Curr_track, vdrive->Curr_sector, vdrive->SlotNumber);
#endif
    /*
     * Loop all directory blocks starting from track 18, sector 1 (1541).
     */

    do {
        /*
         * Load next(first) directory block ?
         */

        vdrive->SlotNumber++;

        if (vdrive->SlotNumber >= 8) {
            int status;

            /* end of current directory? */
            if (vdrive->Dir_buffer[0] == 0) {
                break;
            }

            vdrive->SlotNumber = 0;
            vdrive->Curr_track  = (int)vdrive->Dir_buffer[0];
            vdrive->Curr_sector = (int)vdrive->Dir_buffer[1];

            status = disk_image_read_sector(vdrive->image, vdrive->Dir_buffer,
                                            vdrive->Curr_track,
                                            vdrive->Curr_sector);
            if (status != 0) {
                return NULL; /* error */
            }
        }
        if (vdrive_dir_name_match(&vdrive->Dir_buffer[vdrive->SlotNumber * 32],
                                  vdrive->find_nslot, vdrive->find_length,
                                  vdrive->find_type)) {
            memcpy(return_slot, &vdrive->Dir_buffer[vdrive->SlotNumber * 32], 32);
            return return_slot;
        }
    } while (1);

#ifdef DEBUG_DRIVE
    log_debug("DIR: vdrive_dir_find_next_slot (t:%d/s:%d) #%d", vdrive->Curr_track, vdrive->Curr_sector, vdrive->SlotNumber);
#endif

    /*
     * If length < 0, create new directory-entry if possible
     */
    if (vdrive->find_length < 0) {
        int i, sector;
        BYTE *dirbuf;

        sector = vdrive->Curr_sector + vdrive_dir_get_interleave(vdrive->image_format);

        for (i = 0; i < vdrive_get_max_sectors(vdrive, vdrive->Curr_track); i++) {

            dirbuf = find_next_directory_sector(vdrive, vdrive->Curr_track, sector);
            if (dirbuf != NULL) {
                return dirbuf;
            }

            sector++;
            if (sector >= vdrive_get_max_sectors(vdrive, vdrive->Curr_track)) {
                sector = 0;
            }
        }
    }
    return NULL;
}
Example #15
0
int vdrive_rel_read(vdrive_t *vdrive, BYTE *data, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	/* Check if we are past the end of the REL file. */
	if (p->record >= p->record_max)
	{
		*data = 0x0d;
		vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0);
		return SERIAL_EOF;
	}

	/*
	 * Read next block if needed
	 */
	if (p->buffer[0]) {
		if (p->bufptr >= 256) {
			int status = 0;
			unsigned int track, sector;

			track = (unsigned int)p->buffer[0];
			sector = (unsigned int)p->buffer[1];

			/* Commit the buffers. */
			vdrive_rel_commit(vdrive, p);

			/* Check to see if the next record is in the buffered sector */
			if (p->track_next == track && p->sector_next == sector) {
				/* Swap the two buffers */
				BYTE *tmp;
				tmp = p->buffer;
				p->buffer = p->buffer_next;
				p->buffer_next = tmp;
				p->track_next = p->track;
				p->sector_next = p->sector;
				p->track = track;
				p->sector = sector;
				status = 0;
			} else if (p->track!=track || p->sector != sector ) {
				/* load in the sector to memory */
				status = disk_image_read_sector(vdrive->image, p->buffer, track, sector);
			}

			if (status == 0)
			{
				p->track = track;
				p->sector = sector;
				p->bufptr = p->bufptr - 254;
				p->length = p->length - 254;
				p->record_next = p->record_next - 254;
				/* keep buffered sector where ever it is */
				/* we won't read in the next sector unless we have to */
			}
			else
			{
				#ifdef CELL_DEBUG
				printf("ERROR: Cannot read track %i sector %i.\n", track, sector);
				#endif
				*data = 0xc7;
				return SERIAL_EOF;
			}
		}
	} else {
		if (p->bufptr >= (unsigned int)( p->buffer[1] + 2 ))
		{
			/* check to see if we have the pointer overflow problem here. */
			if (p->record_next > p->length)
			{
				*data = 0x0d;
#ifdef DEBUG_DRIVE
				if (p->mode == BUFFER_COMMAND_CHANNEL)
					log_error(vdrive_rel_log,
							"Disk read  %d [%02d %02d] data %02x (%c).",
							p->mode, 0, 0, *data, (isprint(*data)
								? *data : '.'));
#endif
				vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0);
				return SERIAL_EOF;
			}
			else {
				/* Yes, just rotate though to this buffer. */
				if (p->bufptr>=256) {
					p->bufptr = p->bufptr - 254;
					p->length = p->length - 254;
					p->record_next = p->record_next - 254;
				}
			}
		}
	}

	*data = p->buffer[p->bufptr];
	p->bufptr++;

	if (p->bufptr > p->length) {
		/* set up the buffer pointer to the next record */
		p->bufptr = p->record_next;
		/* add the record length to the next record pointer */
		p->record_next += p->side_sector[OFFSET_RECORD_LEN];
		/* calculate the maximum length (for read, for write we should use
		   record_next - 1 */
		p->length = p->record_next - 1;
		/* increment the record reference */
		p->record++;
		/* Exit if we have hit the end of the REL data. */
		if (p->record >= p->record_max) {
			return SERIAL_EOF;
		}
		/* Find the length of the record starting from the end until no zeros
		   are found */
		if ( p->length < 256) {
			/* If the maximum length of the record is in this sector, just
			   check for where the zeros end */
			for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
		}
		else {
			int status=1;

			/* Get the next sector */
			/* If it doesn't exist, we will use the max length calculated above */
			if (p->buffer[0] != 0) {
				/* Read in the sector if it has not been buffered */
				if (p->buffer[0] != p->track_next || p->buffer[1] != p->sector_next) {
					status = disk_image_read_sector(vdrive->image, p->buffer_next, p->buffer[0],
							p->buffer[1]);
				}
				else {
					status = 0;
				}
			}
			/* If all is good, calculate the length now */
			if (!status) {
				/* update references, if the sector read in */
				p->track_next = p->buffer[0];
				p->sector_next = p->buffer[1];
				/* Start looking in the buffered sector */
				for (;p->length >= 256 && p->buffer_next[p->length-256+2] == 0 ; p->length-- );
				/* If we crossed into the current sector, look there too */
				if (p->length<256) {
					for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
				}
			}

		}
		//log_debug("Forced from read to position %d, 0 on channel %d.", p->record, secondary);

		return SERIAL_EOF;
	}

	return SERIAL_OK;
}
Example #16
0
image_contents_t *diskcontents_block_read(vdrive_t *vdrive)
{
    image_contents_t *contents;
    BYTE buffer[256];
    int retval;
    image_contents_file_list_t *lp;

    machine_drive_flush();

    if (vdrive == NULL)
        return NULL;

    retval = vdrive_bam_read_bam(vdrive);

    if (retval < 0) {
        vdrive_internal_close_disk_image(vdrive);
        return NULL;
    }

    contents = image_contents_new();

    memcpy(contents->name, vdrive->bam + vdrive->bam_name,
           IMAGE_CONTENTS_NAME_LEN);
    contents->name[IMAGE_CONTENTS_NAME_LEN] = 0;

    memcpy(contents->id, vdrive->bam + vdrive->bam_id, IMAGE_CONTENTS_ID_LEN);
    contents->id[IMAGE_CONTENTS_ID_LEN] = 0;

    contents->blocks_free = (int)vdrive_bam_free_block_count(vdrive);

    vdrive->Curr_track = vdrive->Dir_Track;
    vdrive->Curr_sector = vdrive->Dir_Sector;

    lp = NULL;
    contents->file_list = NULL;

    circular_check_init();

    while (1) {
        BYTE *p;
        int j;

        retval = disk_image_read_sector(vdrive->image, buffer,
                                        vdrive->Curr_track,
                                        vdrive->Curr_sector);

        if (retval != 0
            || circular_check(vdrive->Curr_track, vdrive->Curr_sector)) {
            /*image_contents_destroy(contents);*/
            vdrive_internal_close_disk_image(vdrive);
            return contents/*NULL*/;
        }

        for (p = buffer, j = 0; j < 8; j++, p += 32)
            if (p[SLOT_TYPE_OFFSET] != 0) {
                image_contents_file_list_t *new_list;
                int i;

                new_list = lib_malloc(sizeof(image_contents_file_list_t));
                new_list->size = ((int)p[SLOT_NR_BLOCKS]
                                  + ((int)p[SLOT_NR_BLOCKS + 1] << 8));

                for (i = 0; i < IMAGE_CONTENTS_FILE_NAME_LEN; i++)
                        new_list->name[i] = p[SLOT_NAME_OFFSET + i];

                new_list->name[IMAGE_CONTENTS_FILE_NAME_LEN] = 0;

                new_list->name[i] = 0;

                sprintf((char *)new_list->type, "%c%s%c",
                        (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_CLOSED ? ' ' : '*'),
                        cbmdos_filetype_get(p[SLOT_TYPE_OFFSET] & 0x07),
                        (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_LOCKED ? '<' : ' '));

                new_list->next = NULL;

                if (lp == NULL) {
                    new_list->prev = NULL;
                    contents->file_list = new_list;
                    lp = contents->file_list;
                } else {
                    new_list->prev = lp;
                    lp->next = new_list;
                    lp = new_list;
                }
            }

        if (buffer[0] == 0)
            break;

        vdrive->Curr_track = (int)buffer[0];
        vdrive->Curr_sector = (int)buffer[1];
    }

    vdrive_internal_close_disk_image(vdrive);
    return contents;
}
Example #17
0
File: fdc.c Project: AreaScout/vice
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;
}
Example #18
0
int vdrive_rel_position(vdrive_t *vdrive, unsigned int secondary,
                        unsigned int rec_lo, unsigned int rec_hi,
                        unsigned int position)
{
	unsigned int record, rec_start, rec_len;
	unsigned int track, sector;
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	/* find the record length from the first side sector */
	rec_len = p->slot[SLOT_RECORD_LENGTH];

	/* position 0 and 1 are the same - the first */
	position = (position == 0) ? 0 : position - 1;

	/* generate error 51 if we point to a position greater than the record
	   length */
	if (position >= rec_len)
	{
		#ifdef CELL_DEBUG
		printf("ERROR: Position larger than record!?\n");
		#endif
		return 51;
	}

	/* generate a 16 bit value for the record from the two 8-bit values */
	record = rec_lo + (rec_hi << 8);
	/* record 0 and 1 are the same - the first */
	record = (record == 0) ? 0 : record - 1;

	p->record = record;
	/* if the record is greater then the maximum, return error 50, but
	   remember the record for growth */
	if (record >= p->record_max) {
		if (record > 0) {
			return CBMDOS_IPE_NO_RECORD;
		} else {
			/* If the REL has just been created, report OK on record #1. */
			return CBMDOS_IPE_OK;
		}
	}

	/* Fill the rest of the currently written record. */
	vdrive_rel_fillrecord(vdrive, secondary);

	//log_debug("Requested position %d, %d on channel %d.", record, position, secondary);

	/* locate the track, sector and sector offset of record */
	vdrive_rel_track_sector(vdrive, secondary, record, &track, &sector, &rec_start);

	/* Check to see if the next record is in the buffered sector */
	if (p->track_next == track && p->sector_next == sector) {
		BYTE *tmp;

		/* Commit the buffers. */
		vdrive_rel_commit(vdrive, p);

		/* Swap the two buffers */
		tmp = p->buffer;
		p->buffer = p->buffer_next;
		p->buffer_next = tmp;
		p->track_next = p->track;
		p->sector_next = p->sector;
		p->track = track;
		p->sector = sector;
	} else if (p->track != track || p->sector != sector ) {
		/* Commit the buffers. */
		vdrive_rel_commit(vdrive, p);

		/* load in the sector to memory */
		if (disk_image_read_sector(vdrive->image, p->buffer, track, sector) != 0)
		{
			#ifdef CELL_DEBUG
			printf("ERROR: Cannot read track %i sector %i.\n", track, sector);
			#endif
			return 66;
		}
		p->track=track;
		p->sector=sector;
		/* keep buffered sector where ever it is */
		/* we won't read in the next sector unless we have to */
	}

	/* set the buffer pointer */
	p->bufptr = rec_start + 2 + position;
	/* compute the next pointer record */
	p->record_next = p->bufptr - position + rec_len;

	/* set the maximum record length */
	p->length = p->record_next - 1;

	/* It appears that all Commodore drives have the same problems handling
	   REL files when it comes to using the position option of the record
	   command.  Normally when a record is selected, the drive firmware
	   scan from the end of the record to the beginning for when a non-NULL
	   byte is found.  When it finds it, this is considered the end of a
	   record (for a read).  The problem is: what happens when you position
	   the read pointer past this end point?  An overflow occurs in the
	   read of course!  Since the calculated record length is much larger
	   than it should be (but less than 256) the drive can read up to a
	   whole block of data    from the subsequent records.  Although this is
	   a bug (from my point of view), we have to try to emulate it.  Apon
	   analyzing the 1541 code (the 1571 and 1581 have the same behavior),
	   at $e170 (the subroutine for searching for the non-NULL is at $e1b5)
	   the    overflow may not occur under one specific instance.  This is
	   when the start of the record is in one block and the selected
	   position places it in another block.  In this case, only a length of
	   1 byte is set as the record length.  In all other cases, the length
	   is set to 255 - position. */

	/* Find the length of the record starting from the end until no zeros
	   are found */
	if ( p->length < 256) {
		/* If the maximum length of the record is in this sector, just
		   check for where the zeros end */
		for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );

		/* Compensate for overflow length bug, set maximum length based on
		   the position requested */
		if (p->bufptr > p->length && position > 0) {
			p->length = p->bufptr + 254 - position;
		}
	}
	else {
		int status=1;

		/* Get the next sector */
		/* If it doesn't exist, we will use the max length calculated above */
		if (p->buffer[0] != 0) {
			/* Read in the sector if it has not been buffered */
			if (p->buffer[0] != p->track_next || p->buffer[1] != p->sector_next)
			{
				status = disk_image_read_sector(vdrive->image, p->buffer_next, p->buffer[0],
						p->buffer[1]);
			}
			else {
				status = 0;
			}
		}
		/* If all is good, calculate the length now */
		if (!status) {
			/* update references, if the sector read in */
			p->track_next = p->buffer[0];
			p->sector_next = p->buffer[1];
			/* Start looking in the buffered sector */
			for (;p->length >= 256 && p->length >= p->bufptr && p->buffer_next[p->length-256+2] == 0 ; p->length-- );

			/* If we crossed into the current sector, look there too, but
			   only if the position places us in the current sector.
			   Otherwise, the length will be 1 at this point. */
			if (p->length < 256 && p->bufptr < 256) {
				for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );

				/* Compensate for overflow length bug, set maximum length
				   based on the position requested */
				if (p->bufptr > p->length && position > 0 ) {
					p->length = p->bufptr + 254 - position;
				}
			}
		}
	}

	return CBMDOS_IPE_OK;

}
Example #19
0
static unsigned int vdrive_rel_record_max(vdrive_t *vdrive, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	unsigned int i, j, k, l, side, o;
	unsigned int track, sector;

	/* The original 1541 documentation states that there can only be 720
	   (6*120) records in a REL file - this is incorrect.  It is actually
	   blocks.  The side sectors point to each block in the REL file.  It is
	   up to the drive to determine the where the buffer pointer should be
	   when the record changes. */

	/* To find the maximum records we have to check the last block of the REL
	   file.  The last block is referenced in the last side sector group by
	   the OFFSET_NEXT_SECTOR byte.  The next sector pointer after this one
	   should be zero - we will check anyways to make sure.  Once the last
	   block is found, we can move to that sector and check the used bytes
	   there. */

	/* The maximum REL file size for a 1541/1571 is 700 blocks, although it
	   is documented to be 720.  The 1581 is limited to 3000 blocks,
	   although it is documented to be 90720 (126*6*120).  You think they
	   would have allowed it to be atleast the maximum amount of disk
	   space. */

	/* 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 );

	/* check if this is a NEW rel file - no data in super side sector. */
	if (!side) {
		/* return a maximum of 0. */
		return 0;
	}

	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 block */
	j--;
	o = 256 * ( i + side * SIDE_SECTORS_MAX ) + OFFSET_POINTER + 2 * j;
	track = p->side_sector[o];
	sector = p->side_sector[o + 1];

	/* read it in */
	if (disk_image_read_sector(vdrive->image, p->buffer, track, sector) != 0)
	{
		#ifdef CELL_DEBUG
		printf("ERROR: Cannot read relative file data sector.\n");
		#endif
		vdrive_command_set_error(vdrive,  CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR, track, sector);
		return 0;
	}

	/* calculate the total bytes based on the number of super side, side
	   sectors, and last byte index */
	k = ( ( side * SIDE_SECTORS_MAX + i ) * SIDE_INDEX_MAX + j )
		* 254 + p->buffer[OFFSET_NEXT_SECTOR] - 1;

	/* divide by the record length, and get the maximum records */
	l = k / p->slot[SLOT_RECORD_LENGTH];

	return l;
}
Example #20
0
static int vdrive_rel_open_existing(vdrive_t *vdrive, unsigned int secondary)
{
	unsigned int track, sector, side, i, j, o;
	bufferinfo_t *p = &(vdrive->buffers[secondary]);
	BYTE *slot;

	slot = p->slot;

	/* 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);

	/* read super side sector, if it exists */

	track = p->slot[SLOT_SIDE_TRACK];
	sector = p->slot[SLOT_SIDE_SECTOR];

	/* Allocate memory for super side sector */
	p->super_side_sector = lib_malloc(256);

	if (disk_image_read_sector(vdrive->image, p->super_side_sector, track, sector) != 0)
	{
#ifdef CELL_DEBUG
		printf("ERROR: Cannot read side sector.\n");
#endif
		lib_free((char *)p->super_side_sector);
		return -1;
	}

	/* check to see if this is a super side sector.  If not, create an
	   imaginary one so we don't have to change all our code. */
	if (p->super_side_sector[OFFSET_SUPER_254] != 254) {
		/* clear out block */
		memset(p->super_side_sector, 0, 256);
		/* build valid super side sector block */
		p->super_side_sector[OFFSET_NEXT_TRACK] = track;
		p->super_side_sector[OFFSET_NEXT_SECTOR] = sector;
		p->super_side_sector[OFFSET_SUPER_254] = 254;
		p->super_side_sector[OFFSET_SUPER_POINTER] = track;
		p->super_side_sector[OFFSET_SUPER_POINTER+1] = sector;
		/* set track and sector to 0, i.e. no update */
		p->super_side_sector_track = 0;
		p->super_side_sector_sector = 0;
	}
	else {
		/* set track and sector */
		p->super_side_sector_track = track;
		p->super_side_sector_sector = sector;
	}
	/* Clear dirty flag */
	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++ );

	/* allocate memory for side sectors */
	p->side_sector = lib_malloc(side * SIDE_SECTORS_MAX * 256);
	memset(p->side_sector, 0, side * 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 * SIDE_SECTORS_MAX);
	p->side_sector_sector = lib_malloc(side * SIDE_SECTORS_MAX);
	p->side_sector_needsupdate = lib_malloc(side * SIDE_SECTORS_MAX);
	memset(p->side_sector_track, 0, side * SIDE_SECTORS_MAX);
	memset(p->side_sector_sector, 0, side * SIDE_SECTORS_MAX);
	memset(p->side_sector_needsupdate, 0, side * SIDE_SECTORS_MAX);

	for (j = 0; j < side ; j++ )
	{
		track = p->super_side_sector[OFFSET_SUPER_POINTER + j * 2];
		sector = p->super_side_sector[OFFSET_SUPER_POINTER + j * 2 + 1];

		for (i = 0; i < SIDE_SECTORS_MAX; i++)
		{
			o = i + j * SIDE_SECTORS_MAX;
			/* Save the track and sector of each side sector so we can also write
			   and update REL files. */
			p->side_sector_track[o] = track;
			p->side_sector_sector[o] = sector;

			o*=256;

			if (disk_image_read_sector(vdrive->image, &(p->side_sector[o]), track, sector) != 0)
			{
				#ifdef CELL_DEBUG
				printf("ERROR: Cannot read side sector.\n");
				#endif
				return -1;
			}
			if (p->side_sector[o + OFFSET_SECTOR_NUM] != i)
			{
				#ifdef CELL_DEBUG
				printf("ERROR: Side sector number do not match.\n");
				#endif
				return -1;
			}

			track = p->side_sector[o + OFFSET_NEXT_TRACK];
			sector = p->side_sector[o + OFFSET_NEXT_SECTOR];

			if (track == 0)
				break;
		}
	}

	/* 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;

	return 0;
}
Example #21
0
int vdrive_rel_write(vdrive_t *vdrive, BYTE data, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	if (vdrive->image->read_only)
	{
		vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
		return SERIAL_ERROR;
	}

	/* Check if we need to grow the REL file. */
	if (p->record >= p->record_max)
	{
		if (vdrive_rel_grow(vdrive, secondary, p->record) < 0)
			return SERIAL_OK; /* Couldn't grow it, error generated in function. */
	}

	/*
	 * Read next block if needed
	 */
	if (p->buffer[0]) {
		if (p->bufptr >= 256) {
			int status = 0;
			unsigned int track, sector;

			track = (unsigned int)p->buffer[0];
			sector = (unsigned int)p->buffer[1];

			/* Commit the buffers. */
			vdrive_rel_commit(vdrive, p);

			/* Check to see if the next record is in the buffered sector */
			if (p->track_next == track && p->sector_next == sector) {
				/* Swap the two buffers */
				BYTE *tmp;
				tmp = p->buffer;
				p->buffer = p->buffer_next;
				p->buffer_next = tmp;
				p->track_next = p->track;
				p->sector_next = p->sector;
				p->track = track;
				p->sector = sector;
				status = 0;
			} else if (p->track!=track || p->sector != sector ) {
				/* load in the sector to memory */
				status = disk_image_read_sector(vdrive->image, p->buffer, track, sector);
			}

			if (status == 0) {
				p->track = track;
				p->sector = sector;
				p->bufptr = p->bufptr - 254;
				p->length = p->length - 254;
				p->record_next = p->record_next - 254;
				/* keep buffered sector where ever it is */
				/* we won't read in the next sector unless we have to */
			}
			else
			{
#ifdef CELL_DEBUG
				printf("ERROR: Cannot read track %i sector %i.\n", track, sector);
#endif
				return SERIAL_EOF;
			}
		}
	} else {
		if (p->bufptr >= (unsigned int)( p->buffer[1] + 2 ) ) {
#ifdef DEBUG_DRIVE
			if (p->mode == BUFFER_COMMAND_CHANNEL)
				log_error(vdrive_rel_log,
						"Disk read  %d [%02d %02d] data %02x (%c).",
						p->mode, 0, 0, data, (isprint(data)
							? data : '.'));
#endif
			if (vdrive_rel_grow(vdrive, secondary, p->record) < 0)
			{
				/* Couldn't grow it, error generated in function. */
				return SERIAL_OK;
			}
		}
	}

	if (p->bufptr >= p->record_next) {
		/* We CANNOT write into the next record under any
		   circumstances, unlike the reads. */
		vdrive_command_set_error(vdrive, CBMDOS_IPE_OVERFLOW, 0, 0);

		/* But if we try, we still say it is okay, but with a DOS
		   error. */
		return SERIAL_OK;
	}

	/* write the data to the buffer */
	p->buffer[p->bufptr] = data;
	/* increment the pointer */
	p->bufptr++;
	/* flag this sector as dirty and written */
	p->needsupdate |= ( DIRTY_SECTOR | WRITTEN_RECORD ); 

	/* Mark this record as dirty only if we are still in it */
	if (p->bufptr!=p->record_next) {
		p->needsupdate |= DIRTY_RECORD;
	} else {
		p->needsupdate &= (~DIRTY_RECORD);
	}

	/* Any pointer overflow gets handled at the beginning of this
	   function. */

	return SERIAL_OK;
}