diff --git a/sim_disk.c b/sim_disk.c index bd7ebfd..e26a68d 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -361,7 +361,7 @@ static t_stat sim_os_disk_write (UNIT *uptr, t_offset addr, uint8 *buf, uint32 * static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom); static char *HostPathToVhdPath (const char *szHostPath, char *szVhdPath, size_t VhdPathSize); static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize); -static t_offset get_filesystem_size (UNIT *uptr); +static t_offset get_filesystem_size (UNIT *uptr, t_bool *readonly); struct sim_disk_fmt { const char *name; /* name */ @@ -566,7 +566,7 @@ if ((uptr->flags & UNIT_ATT) == 0) return (t_offset)-1; physical_size = ctx->container_size; sim_quiet = TRUE; -filesystem_size = get_filesystem_size (uptr); +filesystem_size = get_filesystem_size (uptr, NULL); sim_quiet = saved_quiet; if ((filesystem_size == (t_offset)-1) || (filesystem_size < physical_size)) @@ -1254,7 +1254,7 @@ ODSChecksum (void *Buffer, uint16 WordCount) } -static t_offset get_ods2_filesystem_size (UNIT *uptr, uint32 physsectsz) +static t_offset get_ods2_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) { DEVICE *dptr; t_addr saved_capac; @@ -1335,10 +1335,12 @@ ret_val = ((t_offset)Scb.scb_l_volsize) * 512; Return_Cleanup: uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr); return ret_val; } -static t_offset get_ods1_filesystem_size (UNIT *uptr, uint32 physsectsz) +static t_offset get_ods1_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) { DEVICE *dptr; t_addr saved_capac; @@ -1394,6 +1396,8 @@ sim_messagef (SCPE_OK, "%s: Volume Name: %12.12s Format: %12.12s Sectors In Volu sim_uname (uptr), Home.hm1_t_volname, Home.hm1_t_format, (uint32)(ret_val / 512)); Return_Cleanup: uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr); return ret_val; } @@ -1409,7 +1413,7 @@ typedef struct ultrix_disklabel { #define PT_MAGIC 0x032957 /* Partition magic number */ #define PT_VALID 1 /* Indicates if struct is valid */ -static t_offset get_ultrix_filesystem_size (UNIT *uptr, uint32 physsectsz) +static t_offset get_ultrix_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) { DEVICE *dptr; t_addr saved_capac; @@ -1447,6 +1451,106 @@ ret_val = ((t_offset)max_lbn) * 512; Return_Cleanup: uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr); +return ret_val; +} + + +/* ISO 9660 Volume Recognizer - Structure Info gathered from: https://wiki.osdev.org/ISO_9660 */ + +typedef struct ISO_9660_Volume_Descriptor { + uint8 Type; // Volume Descriptor type code (0, 1, 2, 3 and 255) + uint8 Identifier[5]; // Always 'CD001'. + uint8 Version; // Volume Descriptor Version (0x01). + uint8 Data[2041]; // Depends on the volume descriptor type. + } ISO_9660_Volume_Descriptor; + +typedef struct ISO_9660_Primary_Volume_Descriptor { + uint8 Type; // Always 0x01 for a Primary Volume Descriptor. + uint8 Identifier[5]; // Always 'CD001'. + uint8 Version; // Always 0x01. + uint8 Unused; // Always 0x00. + uint8 SystemIdentifier[32]; // The name of the system that can act upon sectors 0x00-0x0F for the volume. + uint8 VolumeIdentifier[32]; // Identification of this volume. + uint8 UnusedField[8]; // All zeros. + uint32 VolumeSpaceSize[2]; // Number of Logical Blocks in which the volume is recorded + uint8 UnusedField2[32]; // All zeroes. + uint16 VolumeSetSize[2]; // The size of the set in this logical volume (number of disks). + uint16 VolumeSequenceNumber[2]; // The number of this disk in the Volume Set. + uint16 LogicalBlockSize[2]; // The size in bytes of a logical block. NB: This means that a logical block on a CD could be something other than 2 KiB! + uint32 PathTableSize[2]; // The size in bytes of the path table. + uint32 LocationTypeLPathTable; // LBA location of the path table. The path table pointed to contains only little-endian values. + uint32 LocationOptTypeLPathTable; // LBA location of the optional path table. The path table pointed to contains only little-endian values. Zero means that no optional path table exists. + uint32 LocationTypeMPathTable; // LBA location of the path table. The path table pointed to contains only big-endian values. + uint32 LocationOptTypeMPathTable; // LBA location of the optional path table. The path table pointed to contains only big-endian values. Zero means that no optional path table exists. + uint8 DirectoryEntryRootDirectory[34];// Note that this is not an LBA address, it is the actual Directory Record, which contains a single byte Directory Identifier (0x00), hence the fixed 34 byte size. + uint8 VolumeSetIdentifier[128]; // Identifier of the volume set of which this volume is a member. + uint8 PublisherIdentifier[128]; // The volume publisher. For extended publisher information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. + uint8 DataPreparerIdentifier[128];// The identifier of the person(s) who prepared the data for this volume. For extended preparation information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. + uint8 ApplicationIdentifier[128]; // Identifies how the data are recorded on this volume. For extended information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. + uint8 CopyrightFileIdentifier[37];// Filename of a file in the root directory that contains copyright information for this volume set. If not specified, all bytes should be 0x20. + uint8 AbstractFileIdentifier[37]; // Filename of a file in the root directory that contains abstract information for this volume set. If not specified, all bytes should be 0x20. + uint8 BibliographicFileIdentifier[37];// Filename of a file in the root directory that contains bibliographic information for this volume set. If not specified, all bytes should be 0x20. + uint8 VolumeCreationDateTime[17]; // The date and time of when the volume was created. + uint8 VolumeModificationDateTime[17];// The date and time of when the volume was modified. + uint8 VolumeExpirationDateTime[17];// The date and time after which this volume is considered to be obsolete. If not specified, then the volume is never considered to be obsolete. + uint8 VolumeEffectiveDateTime[17];// The date and time after which the volume may be used. If not specified, the volume may be used immediately. + uint8 FileStructureVersion; // The directory records and path table version (always 0x01). + uint8 Unused2; // Always 0x00. + uint8 ApplicationUsed[512]; // Contents not defined by ISO 9660. + uint8 Reserved[653]; // Reserved by ISO. + } ISO_9660_Primary_Volume_Descriptor; + +static t_offset get_iso9660_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) +{ +DEVICE *dptr; +t_addr saved_capac; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +t_addr temp_capac = (sim_toffset_64 ? (t_addr)0xFFFFFFFFu : (t_addr)0x7FFFFFFFu); /* Make sure we can access the largest sector */ +uint8 sector_buf[2048]; +ISO_9660_Volume_Descriptor *Desc = (ISO_9660_Volume_Descriptor *)sector_buf; +uint8 primary_buf[2048]; +ISO_9660_Primary_Volume_Descriptor *Primary = NULL; +t_lba sectfactor = sizeof (*Desc) / ctx->sector_size; +t_offset ret_val = (t_offset)-1; +t_offset cur_pos = 32768; /* Beyond the boot area of an ISO 9660 image */ +t_seccnt sectsread; +int read_count = 0; + +if ((dptr = find_dev_from_unit (uptr)) == NULL) + return ret_val; +saved_capac = uptr->capac; +uptr->capac = temp_capac; + +while (sim_disk_rdsect(uptr, (t_lba)(sectfactor * cur_pos / sizeof (*Desc)), (uint8 *)Desc, §sread, sectfactor) == DKSE_OK) { + if ((sectsread != sectfactor) || + (Desc->Version != 1) || + (0 != memcmp (Desc->Identifier, "CD001", sizeof (Desc->Identifier)))) + break; + if (Desc->Type == 1) { /* Primary Volume Descriptor */ + Primary = (ISO_9660_Primary_Volume_Descriptor *)primary_buf; + *Primary = *(ISO_9660_Primary_Volume_Descriptor *)Desc; + } + cur_pos += sizeof (*Desc); + ++read_count; + if ((Desc->Type == 255) || + (read_count >= 32)) { + ret_val = ctx->container_size; + sim_messagef (SCPE_OK, "%s: '%s' Contains an ISO 9660 filesystem\n", sim_uname (uptr), uptr->filename); + if (Primary) { + char VolId[sizeof (Primary->VolumeIdentifier) + 1]; + + memcpy (VolId, Primary->VolumeIdentifier, sizeof (Primary->VolumeIdentifier)); + VolId[sizeof (Primary->VolumeIdentifier)] = '\0'; + sim_messagef (SCPE_OK, "%s: Volume Identifier: %s Containing %u %u Byte Sectors\n", sim_uname (uptr), sim_trim_endspc (VolId), (uint32)(ctx->container_size / Primary->LogicalBlockSize[1 - sim_end]), (uint32)Primary->LogicalBlockSize[1 - sim_end]); + } + break; + } + } +uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr) || (ret_val != (t_offset)-1); return ret_val; } @@ -1856,7 +1960,7 @@ if (uar != 0) { return SCPE_IOERR; } -static t_offset get_rsts_filesystem_size (UNIT *uptr, uint32 physsectsz) +static t_offset get_rsts_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) { DEVICE *dptr; t_addr saved_capac; @@ -1925,7 +2029,7 @@ for (context.dcshift = 0; context.dcshift < 8; context.dcshift++) { sim_messagef(SCPE_OK, "%s: '%s' Contains a RSTS File system\n", sim_uname (uptr), uptr->filename); sim_messagef(SCPE_OK, "%s: Pack ID: %6.6s Revision Level: %3s Pack Clustersize: %d\n", sim_uname (uptr), context.packid, fmt, context.pcs); - sim_messagef(SCPE_OK, "%s: Last Unallocated Sector In File System: %u\n", sim_uname (uptr), (uint32)(ret_val / 512)); + sim_messagef(SCPE_OK, "%s: Last Unallocated Sector In File System: %u\n", sim_uname (uptr), (uint32)((ret_val / 512) - 1)); goto cleanup_done; } } @@ -1936,6 +2040,8 @@ for (context.dcshift = 0; context.dcshift < 8; context.dcshift++) { } cleanup_done: uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr); return ret_val; } @@ -2018,7 +2124,7 @@ if (strncmp((char *)&home->hb_b_sysid, HB_C_VMSSYSID, strlen(HB_C_VMSSYSID)) == return RT11_NOPART; } -static t_offset get_rt11_filesystem_size (UNIT *uptr, uint32 physsectsz) +static t_offset get_rt11_filesystem_size (UNIT *uptr, uint32 physsectsz, t_bool *readonly) { DEVICE *dptr; t_addr saved_capac; @@ -2149,19 +2255,22 @@ if (partitions) { sim_messagef (SCPE_OK, "%d valid partition%s, Type: %s, Sectors On Disk: %u\n", partitions, partitions == 1 ? "" : "s", parttype, (uint32)(ret_val / 512)); } uptr->capac = saved_capac; +if (readonly) + *readonly = sim_disk_wrp (uptr); return ret_val; } t_offset pseudo_filesystem_size = 0; /* Dummy file system check return used during testing */ -typedef t_offset (*FILESYSTEM_CHECK)(UNIT *uptr, uint32); +typedef t_offset (*FILESYSTEM_CHECK)(UNIT *uptr, uint32, t_bool *); -static t_offset get_filesystem_size (UNIT *uptr) +static t_offset get_filesystem_size (UNIT *uptr, t_bool *readonly) { static FILESYSTEM_CHECK checks[] = { &get_ods2_filesystem_size, &get_ods1_filesystem_size, &get_ultrix_filesystem_size, + &get_iso9660_filesystem_size, &get_rsts_filesystem_size, &get_rt11_filesystem_size, /* This should be the last entry in the table to reduce the @@ -2181,7 +2290,7 @@ if (pseudo_filesystem_size != 0) { /* Dummy file system size mechanism? */ } for (i = 0; checks[i] != NULL; i++) - if ((ret_val = checks[i] (uptr, 0)) != (t_offset)-1) + if ((ret_val = checks[i] (uptr, 0, readonly)) != (t_offset)-1) return ret_val; /* * The only known interleaved disk devices have either 256 byte @@ -2192,10 +2301,10 @@ for (i = 0; checks[i] != NULL; i++) for (i = 0; checks[i] != NULL; i++) { ctx->sector_size = 256; - if ((ret_val = checks[i] (uptr, ctx->sector_size)) != (t_offset)-1) + if ((ret_val = checks[i] (uptr, ctx->sector_size, readonly)) != (t_offset)-1) break; ctx->sector_size = 128; - if ((ret_val = checks[i] (uptr, ctx->sector_size)) != (t_offset)-1) + if ((ret_val = checks[i] (uptr, ctx->sector_size, readonly)) != (t_offset)-1) break; } if ((ret_val != (t_offset)-1) && (ctx->sector_size != saved_sector_size )) @@ -2526,6 +2635,7 @@ if (sim_switches & SWMASK ('C')) { /* create new disk conta source_capac = uptr->capac; sim_messagef (SCPE_OK, "%s: Creating new %s '%s' disk container copied from '%s'\n", sim_uname (uptr), dest_fmt, gbuf, cptr); capac_factor = ((dptr->dwidth / dptr->aincr) >= 32) ? 8 : ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (quadword: 8, word: 2, byte: 1) */ + uptr->capac = target_capac; if (strcmp ("VHD", dest_fmt) == 0) dest = sim_vhd_disk_create (gbuf, ((t_offset)uptr->capac)*capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)); else @@ -3021,7 +3131,7 @@ if (get_disk_footer (uptr) != SCPE_OK) { sim_disk_detach (uptr); return SCPE_OPENERR; } -filesystem_size = get_filesystem_size (uptr); +filesystem_size = get_filesystem_size (uptr, NULL); if (filesystem_size != (t_offset)-1) filesystem_size += reserved_sectors * sector_size; container_size = sim_disk_size (uptr); @@ -3164,6 +3274,22 @@ if (container_size && (container_size != (t_offset)-1)) { } } +if ((uptr->flags & UNIT_RO) == 0) { + t_bool readonly; + int32 saved_quiet = sim_quiet; + + sim_quiet = 1; + get_filesystem_size (uptr, &readonly); + if (readonly) { + sim_disk_detach (uptr); + sim_switches |= SWMASK ('R'); + sim_disk_attach_ex2 (uptr, cptr, sector_size, xfer_element_size, dontchangecapac, + dbit, dtype, pdp11tracksize, completion_delay, drivetypes, + reserved_sectors); + + } + sim_quiet = saved_quiet; + } if (dtype && (created || (autosized && (ctx->footer == NULL)))) store_disk_footer (uptr, dtype); diff --git a/sim_ether.c b/sim_ether.c index 041b7e1..83ebe66 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -407,7 +407,7 @@ t_stat eth_mac_scan_ex (ETH_MAC* mac, const char* strmac, UNIT *uptr) ETH_MAC newmac; struct { uint32 bits; - char system_id[37]; + char system_id[64]; char cwd[PATH_MAX]; char file[PATH_MAX]; ETH_MAC base_mac; diff --git a/sim_fio.c b/sim_fio.c index f836e40..5032140 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -155,7 +155,7 @@ if ((size == 0) || (count == 0)) /* check arguments */ c = fread (bptr, size, count, fptr); /* read buffer */ if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */ return c; /* done */ -sim_buf_swap_data (bptr, size, count); +sim_buf_swap_data (bptr, size, c); return c; } diff --git a/sim_imd.c b/sim_imd.c index 546b77d..ebaf64f 100644 --- a/sim_imd.c +++ b/sim_imd.c @@ -1,6 +1,6 @@ /************************************************************************* * * - * Copyright (c) 2007-2020 Howard M. Harte. * + * Copyright (c) 2007-2022 Howard M. Harte. * * https://github.com/hharte * * * * Permission is hereby granted, free of charge, to any person obtaining * @@ -150,7 +150,10 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) do { sim_debug(myDisk->debugmask, myDisk->device, "start of track %d at file offset %ld\n", myDisk->ntracks, ftell(myDisk->file)); - sim_fread(&imd, 1, 5, myDisk->file); + if (sim_fread(&imd, 1, 5, myDisk->file) != 5) { + return (SCPE_OPENERR); + } + if (feof(myDisk->file)) break; sectorSize = 128 << (imd.sectsize & 0x1f); @@ -169,6 +172,18 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) myDisk->nsides = imd.head + 1; } + if (imd.head >= MAX_HEAD) { + sim_printf("SIM_IMD: Invalid head %d, a maximum of %d heads are supported.\n", + imd.head, MAX_HEAD); + return (SCPE_IERR); + } + + if (imd.cyl >= MAX_CYL) { + sim_printf("SIM_IMD: Invalid cylinder %d, a maximum of %d cylinders are supported.\n", + imd.cyl, MAX_CYL); + return (SCPE_IERR); + } + myDisk->track[imd.cyl][imd.head].mode = imd.mode; myDisk->track[imd.cyl][imd.head].nsects = imd.nsects; myDisk->track[imd.cyl][imd.head].sectsize = sectorSize;