DISK: Add robust disk container validation

This commit is contained in:
Mark Pizzolato 2020-04-11 13:01:48 -07:00
parent 3950478e00
commit 049ba32505
3 changed files with 286 additions and 51 deletions

2
scp.c
View file

@ -805,7 +805,7 @@ const struct scp_error {
{"SIGTERM", "SIGTERM received"}, {"SIGTERM", "SIGTERM received"},
{"FSSIZE", "File System size larger than disk size"}, {"FSSIZE", "File System size larger than disk size"},
{"RUNTIME", "Run time limit exhausted"}, {"RUNTIME", "Run time limit exhausted"},
{"INCOMPVHD", "Incompatible VHD Container"}, {"INCOMPDSK", "Incompatible Disk Container"},
}; };
const size_t size_map[] = { sizeof (int8), const size_t size_map[] = { sizeof (int8),

View file

@ -433,7 +433,7 @@ typedef uint32 t_addr;
#define SCPE_SIGTERM (SCPE_BASE + 48) /* SIGTERM has been received */ #define SCPE_SIGTERM (SCPE_BASE + 48) /* SIGTERM has been received */
#define SCPE_FSSIZE (SCPE_BASE + 49) /* File System size larger than disk size */ #define SCPE_FSSIZE (SCPE_BASE + 49) /* File System size larger than disk size */
#define SCPE_RUNTIME (SCPE_BASE + 50) /* Run Time Limit Exhausted */ #define SCPE_RUNTIME (SCPE_BASE + 50) /* Run Time Limit Exhausted */
#define SCPE_INCOMPVHD (SCPE_BASE + 51) /* Incompatible VHD Container */ #define SCPE_INCOMPDSK (SCPE_BASE + 51) /* Incompatible Disk Container */
#define SCPE_MAX_ERR (SCPE_BASE + 51) /* Maximum SCPE Error Value */ #define SCPE_MAX_ERR (SCPE_BASE + 51) /* Maximum SCPE Error Value */
#define SCPE_KFLAG 0x10000000 /* tti data flag */ #define SCPE_KFLAG 0x10000000 /* tti data flag */

View file

@ -86,17 +86,79 @@ Internal routines:
#include <pthread.h> #include <pthread.h>
#endif #endif
/* Newly created SIMH (and possibly RAW) disk containers */
/* will have this data as the last 512 bytes of the container */
/* It will not be considered part of the data in the container */
/* Previously existing containers will have this appended to */
/* the end of the container if they are opened for write */
struct simh_disk_footer {
uint8 Signature[4]; /* must be 'simh' */
uint8 CreatingSimulator[64]; /* name of simulator */
uint8 DriveType[16];
uint32 SectorSize;
uint32 SectorCount;
uint32 TransferElementSize;
uint8 CreationTime[28]; /* Result of ctime() */
uint8 FooterVersion; /* Initially 0 */
uint8 AccessFormat; /* 1 - SIMH, 2 - RAW */
uint8 Reserved[382]; /* Currently unused */
uint32 Checksum; /* CRC32 of the prior 508 bytes */
};
/* OS Independent Disk Virtual Disk (VHD) I/O support */
#if (defined (VMS) && !(defined (__ALPHA) || defined (__ia64)))
#define DONT_DO_VHD_SUPPORT /* VAX/VMS compilers don't have 64 bit integers */
#endif
#if defined(_WIN32) || defined (__ALPHA) || defined (__ia64) || defined (VMS)
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif
#endif
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ UNKNOWN
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static uint32
NtoHl(uint32 value)
{
uint8 *l = (uint8 *)&value;
return (uint32)l[3] | ((uint32)l[2]<<8) | ((uint32)l[1]<<16) | ((uint32)l[0]<<24);
}
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
static uint32
NtoHl(uint32 value)
{
return value;
}
#else
static uint32
NtoHl(uint32 value)
{
uint8 *l = (uint8 *)&value;
if (sim_end)
return l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24);
return value;
}
#endif
struct disk_context { struct disk_context {
t_offset container_size; /* Size of the data portion (of the pseudo disk) */
DEVICE *dptr; /* Device for unit (access to debug flags) */ DEVICE *dptr; /* Device for unit (access to debug flags) */
uint32 dbit; /* debugging bit */ uint32 dbit; /* debugging bit */
uint32 sector_size; /* Disk Sector Size (of the pseudo disk) */ uint32 sector_size; /* Disk Sector Size (of the pseudo disk) */
uint32 capac_factor; /* Units of Capacity (8 = quadword, 2 = word, 1 = byte) */ uint32 capac_factor; /* Units of Capacity (8 = quadword, 2 = word, 1 = byte) */
uint32 xfer_element_size; /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */ uint32 xfer_element_size; /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */
uint32 storage_sector_size;/* Sector size of the containing storage */ uint32 storage_sector_size;/* Sector size of the containing storage */
uint32 removable; /* Removable device flag */ uint32 removable; /* Removable device flag */
uint32 is_cdrom; /* Host system CDROM Device */ uint32 is_cdrom; /* Host system CDROM Device */
uint32 media_removed; /* Media not available flag */ uint32 media_removed; /* Media not available flag */
uint32 auto_format; /* Format determined dynamically */ uint32 auto_format; /* Format determined dynamically */
struct simh_disk_footer
*footer;
#if defined _WIN32 #if defined _WIN32
HANDLE disk_handle; /* OS specific Raw device handle */ HANDLE disk_handle; /* OS specific Raw device handle */
#endif #endif
@ -276,7 +338,7 @@ static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *
static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects); static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_vhd_disk_clearerr (UNIT *uptr); static t_stat sim_vhd_disk_clearerr (UNIT *uptr);
static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype, uint32 SectorSize, uint32 xfer_element_size); static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype, uint32 SectorSize, uint32 xfer_element_size);
static const char *sim_vhd_disk_get_dtype (FILE *f, uint32 *SectorSize, uint32 *xfer_element_size); static const char *sim_vhd_disk_get_dtype (FILE *f, uint32 *SectorSize, uint32 *xfer_element_size, char sim_name[64]);
static t_stat sim_os_disk_implemented_raw (void); static t_stat sim_os_disk_implemented_raw (void);
static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode); static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode);
static int sim_os_disk_close_raw (FILE *f); static int sim_os_disk_close_raw (FILE *f);
@ -285,7 +347,9 @@ static t_offset sim_os_disk_size_raw (FILE *f);
static t_stat sim_os_disk_unload_raw (FILE *f); static t_stat sim_os_disk_unload_raw (FILE *f);
static t_bool sim_os_disk_isavailable_raw (FILE *f); static t_bool sim_os_disk_isavailable_raw (FILE *f);
static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects); static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
static t_stat sim_os_disk_read (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *bytesread, uint32 bytes);
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects); static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_os_disk_write (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *byteswritten, uint32 bytes);
static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom); 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 *HostPathToVhdPath (const char *szHostPath, char *szVhdPath, size_t VhdPathSize);
static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize); static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize);
@ -451,22 +515,13 @@ return (uptr->flags & DKUF_WRP)? TRUE: FALSE;
t_offset sim_disk_size (UNIT *uptr) t_offset sim_disk_size (UNIT *uptr)
{ {
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset physical_size, filesystem_size; t_offset physical_size, filesystem_size;
t_bool saved_quiet = sim_quiet; t_bool saved_quiet = sim_quiet;
switch (DK_GET_FMT (uptr)) { /* case on format */ if ((uptr->flags & UNIT_ATT) == 0)
case DKUF_F_STD: /* SIMH format */ return (t_offset)-1;
physical_size = sim_fsize_ex (uptr->fileref); physical_size = ctx->container_size;
break;
case DKUF_F_VHD: /* VHD format */
physical_size = sim_vhd_disk_size (uptr->fileref);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
physical_size = sim_os_disk_size_raw (uptr->fileref);
break;
default:
return (t_offset)-1;
}
sim_quiet = TRUE; sim_quiet = TRUE;
filesystem_size = get_filesystem_size (uptr); filesystem_size = get_filesystem_size (uptr);
sim_quiet = saved_quiet; sim_quiet = saved_quiet;
@ -2024,6 +2079,98 @@ for (i = 0; checks[i] != NULL; i++) {
return ret_val; return ret_val;
} }
static t_stat get_disk_footer (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
struct simh_disk_footer *f = (struct simh_disk_footer *)calloc (1, sizeof (*f));
t_offset container_size;
t_offset sim_fsize_ex (FILE *fptr);
uint32 bytesread;
if (f == NULL)
return SCPE_MEM;
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_STD: /* SIMH format */
container_size = sim_fsize_ex (uptr->fileref);
if ((container_size != (t_offset)-1) && (container_size > sizeof (*f)) &&
(sim_fseeko (uptr->fileref, container_size - sizeof (*f), SEEK_SET) == 0) &&
(sizeof (*f) == sim_fread (f, 1, sizeof (*f), uptr->fileref)))
break;
free (f);
f = NULL;
break;
case DKUF_F_RAW: /* RAW format */
container_size = sim_os_disk_size_raw (uptr->fileref);
if ((container_size != (t_offset)-1) && (container_size > sizeof (*f)) &&
(sim_os_disk_read (uptr, container_size - sizeof (*f), (uint8 *)f, &bytesread, sizeof (*f)) == SCPE_OK) &&
(bytesread == sizeof (*f)))
break;
free (f);
f = NULL;
break;
case DKUF_F_VHD: /* VHD format */
memcpy (f->Signature, "simh", 4);
strncpy ((char *)f->DriveType, sim_vhd_disk_get_dtype (uptr->fileref, &f->SectorSize, &f->TransferElementSize, (char *)f->CreatingSimulator), sizeof (f->DriveType));
container_size = sim_vhd_disk_size (uptr->fileref);
f->SectorCount = (uint32)(container_size / f->SectorSize);
f->Checksum = NtoHl (eth_crc32 (0, f, sizeof (*f) - sizeof (f->Checksum)));
break;
}
if (f) {
if (f->Checksum != NtoHl (eth_crc32 (0, f, sizeof (*f) - sizeof (f->Checksum)))) {
free (f);
f = NULL;
}
else {
ctx->footer = f;
container_size -= sizeof (*f);
}
}
ctx->container_size = container_size;
return SCPE_OK;
}
static t_stat store_disk_footer (UNIT *uptr, const char *dtype)
{
DEVICE *dptr;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
struct simh_disk_footer *f;
time_t now = time (NULL);
t_offset total_sectors;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
return SCPE_NOATT;
if (uptr->flags & UNIT_RO)
return SCPE_RO;
f = (struct simh_disk_footer *)calloc (1, sizeof (*f));
f->AccessFormat = DK_GET_FMT (uptr);
total_sectors = (((t_offset)uptr->capac) * ctx->capac_factor * ((dptr->flags & DEV_SECTORS) ? 512 : 1)) / ctx->sector_size;
memcpy (f->Signature, "simh", 4);
strncpy ((char *)f->CreatingSimulator, sim_name, sizeof (f->CreatingSimulator));
strncpy ((char *)f->DriveType, dtype, sizeof (f->DriveType));
f->SectorSize = NtoHl (ctx->sector_size);
f->SectorCount = NtoHl ((uint32)total_sectors);
f->TransferElementSize = NtoHl (ctx->xfer_element_size);
strncpy ((char*)f->CreationTime, ctime (&now), sizeof (f->CreationTime));
f->Checksum = NtoHl (eth_crc32 (0, f, sizeof (*f) - sizeof (f->Checksum)));
free (ctx->footer);
ctx->footer = f;
switch (f->AccessFormat) {
case DKUF_F_STD: /* SIMH format */
sim_fseeko ((FILE *)uptr->fileref, total_sectors * ctx->sector_size, SEEK_SET);
sim_fwrite (f, sizeof (*f), 1, (FILE *)uptr->fileref);
break;
case DKUF_F_VHD: /* VHD format */
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
sim_os_disk_write (uptr, total_sectors * ctx->sector_size, (uint8 *)f, NULL, sizeof (*f));
break;
default:
break;
}
return SCPE_OK;
}
t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontchangecapac, t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontchangecapac,
uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay) uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
{ {
@ -2320,31 +2467,40 @@ else { /* normal */
} }
} /* end if null */ } /* end if null */
} /* end else */ } /* end else */
if (DK_GET_FMT (uptr) == DKUF_F_VHD) { if ((DK_GET_FMT (uptr) == DKUF_F_VHD) || (ctx->footer)) {
uint32 sector_size, xfer_element_size; uint32 sector_size, xfer_element_size;
char created_name[64];
const char *container_dtype = ctx->footer ? (char *)ctx->footer->DriveType : sim_vhd_disk_get_dtype (uptr->fileref, &sector_size, &xfer_element_size, created_name);
if ((created) && dtype) if (ctx->footer) {
sector_size = NtoHl (ctx->footer->SectorSize);
xfer_element_size = NtoHl (ctx->footer->TransferElementSize);
}
if ((DK_GET_FMT (uptr) == DKUF_F_VHD) && created && dtype)
sim_vhd_disk_set_dtype (uptr->fileref, dtype, ctx->sector_size, ctx->xfer_element_size); sim_vhd_disk_set_dtype (uptr->fileref, dtype, ctx->sector_size, ctx->xfer_element_size);
if (dtype && strcmp (dtype, sim_vhd_disk_get_dtype (uptr->fileref, &sector_size, &xfer_element_size))) { if (dtype) {
char cmd[32]; char cmd[32];
t_stat r = SCPE_OK; t_stat r = SCPE_OK;
if (((sector_size == 0) || (sector_size == ctx->sector_size)) && if (((sector_size == 0) || (sector_size == ctx->sector_size)) &&
((xfer_element_size == 0) || (xfer_element_size == ctx->xfer_element_size))) { ((xfer_element_size == 0) || (xfer_element_size == ctx->xfer_element_size))) {
sprintf (cmd, "%s%d %s", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref, NULL, NULL)); sprintf (cmd, "%s%d %s", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref, NULL, NULL, NULL));
r = set_cmd (0, cmd); r = set_cmd (0, cmd);
if (r != SCPE_OK) if (r != SCPE_OK)
r = sim_messagef (r, "Can't set %s%d to drive type %s\n", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref, NULL, NULL)); r = sim_messagef (r, "Can't set %s%d to drive type %s\n", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref, NULL, NULL, NULL));
} }
else else
r = sim_messagef (SCPE_INCOMPVHD, "VHD incompatible with %s simulator\n", sim_name); r = sim_messagef (SCPE_INCOMPDSK, "Disk created by the %s simulator is incompatible with the %s simulator\n", created_name, sim_name);
if (r != SCPE_OK) { if (r != SCPE_OK) {
uptr->flags |= UNIT_ATT;
sim_disk_detach (uptr); /* report error now */ sim_disk_detach (uptr); /* report error now */
sprintf (cmd, "%s%d %s", dptr->name, (int)(uptr-dptr->units), dtype);/* restore original dtype */
set_cmd (0, cmd);
return r; return r;
} }
} }
} }
uptr->flags = uptr->flags | UNIT_ATT; uptr->flags |= UNIT_ATT;
uptr->pos = 0; uptr->pos = 0;
/* Get Device attributes if they are available */ /* Get Device attributes if they are available */
@ -2356,8 +2512,8 @@ if ((created) && (!copied)) {
uint8 *secbuf = (uint8 *)calloc (128, ctx->sector_size); /* alloc temp sector buf */ uint8 *secbuf = (uint8 *)calloc (128, ctx->sector_size); /* alloc temp sector buf */
/* /*
On a newly created disk, we write a zero sector to the last and the On a newly created disk, we write zeros to the whole disk.
first sectors. This serves 3 purposes: This serves 3 purposes:
1) it avoids strange allocation delays writing newly allocated 1) it avoids strange allocation delays writing newly allocated
storage at the end of the disk during simulator operation storage at the end of the disk during simulator operation
2) it allocates storage for the whole disk at creation time to 2) it allocates storage for the whole disk at creation time to
@ -2421,7 +2577,6 @@ if ((created) && (!copied)) {
if (pdp11tracksize) if (pdp11tracksize)
sim_disk_pdp11_bad_block (uptr, pdp11tracksize, sector_size/sizeof(uint16)); sim_disk_pdp11_bad_block (uptr, pdp11tracksize, sector_size/sizeof(uint16));
} }
if (sim_switches & SWMASK ('K')) { if (sim_switches & SWMASK ('K')) {
t_stat r = SCPE_OK; t_stat r = SCPE_OK;
t_lba lba, sect; t_lba lba, sect;
@ -2471,8 +2626,12 @@ if (sim_switches & SWMASK ('K')) {
uptr->dynflags |= UNIT_DISK_CHK; uptr->dynflags |= UNIT_DISK_CHK;
} }
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);
container_size = size_function (uptr->fileref); container_size = sim_disk_size (uptr);
current_unit_size = ((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1); current_unit_size = ((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1);
if (container_size && (container_size != (t_offset)-1)) { if (container_size && (container_size != (t_offset)-1)) {
if (dontchangecapac) { if (dontchangecapac) {
@ -2507,14 +2666,17 @@ if (container_size && (container_size != (t_offset)-1)) {
return SCPE_FSSIZE; return SCPE_FSSIZE;
} }
} }
if ((container_size < current_unit_size) && if ((container_size != current_unit_size) &&
((DKUF_F_VHD == DK_GET_FMT (uptr)) || (0 != (uptr->flags & UNIT_RO)))) { ((DKUF_F_VHD == DK_GET_FMT (uptr)) || (0 != (uptr->flags & UNIT_RO)) ||
(ctx->footer))) {
if (!sim_quiet) { if (!sim_quiet) {
int32 saved_switches = sim_switches; int32 saved_switches = sim_switches;
const char *container_dtype = ctx->footer ? (const char *)ctx->footer->DriveType : "";
sim_switches = SWMASK ('R'); sim_switches = SWMASK ('R');
uptr->capac = (t_addr)(container_size/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); uptr->capac = (t_addr)(container_size/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
sim_printf ("%s%d: non expandable disk container '%s' is smaller than simulated device (%s < ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr)); sim_printf ("%s%d: non expandable %s disk container '%s' is %s than simulated device (%s %s ",
sim_dname (dptr), (int)(uptr-dptr->units), container_dtype, cptr, (container_size < current_unit_size) ? "smaller" : "larger", sprint_capac (dptr, uptr), (container_size < current_unit_size) ? "<" : ">");
uptr->capac = saved_capac; uptr->capac = saved_capac;
sim_printf ("%s)\n", sprint_capac (dptr, uptr)); sim_printf ("%s)\n", sprint_capac (dptr, uptr));
sim_switches = saved_switches; sim_switches = saved_switches;
@ -2523,7 +2685,7 @@ if (container_size && (container_size != (t_offset)-1)) {
return SCPE_OPENERR; return SCPE_OPENERR;
} }
} }
else { /* Autosize */ else { /* Autosize by changing capacity */
if (filesystem_size != (t_offset)-1) { /* Known file system data size AND */ if (filesystem_size != (t_offset)-1) { /* Known file system data size AND */
if (filesystem_size > container_size) /* Data size greater than container size? */ if (filesystem_size > container_size) /* Data size greater than container size? */
container_size = filesystem_size + /* Use file system data size */ container_size = filesystem_size + /* Use file system data size */
@ -2539,6 +2701,9 @@ if (container_size && (container_size != (t_offset)-1)) {
} }
} }
if (dtype && (created || (ctx->footer == NULL)))
store_disk_footer (uptr, dtype);
#if defined (SIM_ASYNCH_IO) #if defined (SIM_ASYNCH_IO)
sim_disk_set_async (uptr, completion_delay); sim_disk_set_async (uptr, completion_delay);
#endif #endif
@ -2595,6 +2760,7 @@ uptr->dynflags &= ~(UNIT_NO_FIO | UNIT_DISK_CHK);
free (uptr->filename); free (uptr->filename);
uptr->filename = NULL; uptr->filename = NULL;
uptr->fileref = NULL; uptr->fileref = NULL;
free (ctx->footer);
free (uptr->disk_ctx); free (uptr->disk_ctx);
uptr->disk_ctx = NULL; uptr->disk_ctx = NULL;
uptr->io_flush = NULL; uptr->io_flush = NULL;
@ -3396,6 +3562,28 @@ _set_errno_from_status (GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
static t_stat sim_os_disk_read (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *bytesread, uint32 bytes)
{
OVERLAPPED pos;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
sim_debug_unit (ctx->dbit, uptr, "sim_os_disk_read(unit=%d, addr=0x%X, bytes=%u)\n", (int)(uptr-ctx->dptr->units), (uint32)addr, bytes);
memset (&pos, 0, sizeof (pos));
pos.Offset = (DWORD)addr;
pos.OffsetHigh = (DWORD)(addr >> 32);
if (ReadFile ((HANDLE)(uptr->fileref), buf, (DWORD)bytes, (LPDWORD)bytesread, &pos))
return SCPE_OK;
if (ERROR_HANDLE_EOF == GetLastError ()) { /* Return 0's for reads past EOF */
memset (buf, 0, bytes);
if (bytesread)
*bytesread = bytes;
return SCPE_OK;
}
_set_errno_from_status (GetLastError ());
return SCPE_IOERR;
}
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{ {
OVERLAPPED pos; OVERLAPPED pos;
@ -3417,6 +3605,22 @@ _set_errno_from_status (GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
static t_stat sim_os_disk_write (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *byteswritten, uint32 bytes)
{
OVERLAPPED pos;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
sim_debug_unit (ctx->dbit, uptr, "sim_os_disk_write(unit=%d, lba=0x%X, bytes=%u)\n", (int)(uptr-ctx->dptr->units), (uint32)addr, bytes);
memset (&pos, 0, sizeof (pos));
pos.Offset = (DWORD)addr;
pos.OffsetHigh = (DWORD)(addr >> 32);
if (WriteFile ((HANDLE)(uptr->fileref), buf, bytes, (LPDWORD)byteswritten, &pos))
return SCPE_OK;
_set_errno_from_status (GetLastError ());
return SCPE_IOERR;
}
#elif defined (__linux) || defined (__linux__) || defined (__APPLE__)|| defined (__sun) || defined (__sun__) || defined (__hpux) || defined (_AIX) #elif defined (__linux) || defined (__linux__) || defined (__APPLE__)|| defined (__sun) || defined (__sun__) || defined (__hpux) || defined (_AIX)
#include <sys/types.h> #include <sys/types.h>
@ -3530,6 +3734,24 @@ if (sectsread)
return SCPE_OK; return SCPE_OK;
} }
static t_stat sim_os_disk_read (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *rbytesread, uint32 bytes)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
ssize_t bytesread;
sim_debug_unit (ctx->dbit, uptr, "sim_os_disk_read(unit=%d, addr=0x%X, bytes=%u)\n", (int)(uptr-ctx->dptr->units), (uint32)addr, bytes);
bytesread = pread((int)((long)uptr->fileref), buf, bytes, (off_t)addr);
if (bytesread < 0) {
if (rbytesread)
*rbytesread = 0;
return SCPE_IOERR;
}
if (rbytesread)
*rbytesread = bytesread;
return SCPE_OK;
}
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{ {
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
@ -3550,6 +3772,24 @@ if (sectswritten)
return SCPE_OK; return SCPE_OK;
} }
static t_stat sim_os_disk_write (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *rbyteswritten, uint32 bytes)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
ssize_t byteswritten;
sim_debug_unit (ctx->dbit, uptr, "sim_os_disk_write(unit=%d, addr=0x%X, bytes=%u)\n", (int)(uptr-ctx->dptr->units), (uint32)addr, bytes);
byteswritten = pwrite((int)((long)uptr->fileref), buf, bytes, (off_t)addr);
if (byteswritten < 0) {
if (rbyteswritten)
*rbyteswritten = 0;
return SCPE_IOERR;
}
if (rbyteswritten)
*rbyteswritten = byteswritten;
return SCPE_OK;
}
static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom) static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom)
{ {
if (sector_size) { if (sector_size) {
@ -3624,11 +3864,21 @@ static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *s
return SCPE_NOFNC; return SCPE_NOFNC;
} }
static t_stat sim_os_disk_read (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *bytesread, uint32 bytes)
{
return SCPE_NOFNC;
}
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{ {
return SCPE_NOFNC; return SCPE_NOFNC;
} }
static t_stat sim_os_disk_write (UNIT *uptr, t_offset addr, uint8 *buf, uint32 *byteswritten, uint32 bytes)
{
return SCPE_NOFNC;
}
static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom) static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom)
{ {
return SCPE_NOFNC; return SCPE_NOFNC;
@ -3708,7 +3958,7 @@ static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype)
return SCPE_NOFNC; return SCPE_NOFNC;
} }
static const char *sim_vhd_disk_get_dtype (FILE *f) static const char *sim_vhd_disk_get_dtype (FILE *f, uint32 *SectorSize, uint32 *xfer_element_size, char sim_name[64])
{ {
return NULL; return NULL;
} }
@ -4021,10 +4271,6 @@ typedef struct _VHD_DynamicDiskHeader {
#define VHD_DT_Dynamic 3 /* Dynamic hard disk */ #define VHD_DT_Dynamic 3 /* Dynamic hard disk */
#define VHD_DT_Differencing 4 /* Differencing hard disk */ #define VHD_DT_Differencing 4 /* Differencing hard disk */
static uint32 NtoHl(uint32 value);
static uint64 NtoHll(uint64 value);
typedef struct VHD_IOData *VHDHANDLE; typedef struct VHD_IOData *VHDHANDLE;
static t_stat ReadFilePosition(FILE *File, void *buf, size_t bufsize, size_t *bytesread, uint64 position) static t_stat ReadFilePosition(FILE *File, void *buf, size_t bufsize, size_t *bytesread, uint64 position)
@ -4080,13 +4326,6 @@ return ~sum;
#define __BYTE_ORDER__ UNKNOWN #define __BYTE_ORDER__ UNKNOWN
#endif #endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static uint32
NtoHl(uint32 value)
{
uint8 *l = (uint8 *)&value;
return (uint32)l[3] | ((uint32)l[2]<<8) | ((uint32)l[1]<<16) | ((uint32)l[0]<<24);
}
static uint64 static uint64
NtoHll(uint64 value) NtoHll(uint64 value)
{ {
@ -4096,12 +4335,6 @@ uint32 lowresult = (uint64)l[7] | ((uint64)l[6]<<8) | ((uint64)l[5]<<16) | ((uin
return (highresult << 32) | lowresult; return (highresult << 32) | lowresult;
} }
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
static uint32
NtoHl(uint32 value)
{
return value;
}
static uint64 static uint64
NtoHll(uint64 value) NtoHll(uint64 value)
{ {
@ -4364,7 +4597,7 @@ memset (hVHD->Footer.DriveType, '\0', sizeof hVHD->Footer.DriveType);
memcpy (hVHD->Footer.DriveType, dtype, ((1+strlen (dtype)) < sizeof (hVHD->Footer.DriveType)) ? (1+strlen (dtype)) : sizeof (hVHD->Footer.DriveType)); memcpy (hVHD->Footer.DriveType, dtype, ((1+strlen (dtype)) < sizeof (hVHD->Footer.DriveType)) ? (1+strlen (dtype)) : sizeof (hVHD->Footer.DriveType));
hVHD->Footer.DriveSectorSize = NtoHl (SectorSize); hVHD->Footer.DriveSectorSize = NtoHl (SectorSize);
hVHD->Footer.DriveTransferElementSize = NtoHl (xfer_element_size); hVHD->Footer.DriveTransferElementSize = NtoHl (xfer_element_size);
strncpy (hVHD->Footer.CreatingSimulator, sim_name, sizeof (hVHD->Footer.CreatingSimulator)); strncpy ((char *)hVHD->Footer.CreatingSimulator, sim_name, sizeof (hVHD->Footer.CreatingSimulator));
hVHD->Footer.Checksum = 0; hVHD->Footer.Checksum = 0;
hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer))); hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer)));
@ -4410,7 +4643,7 @@ if (Status)
return SCPE_OK; return SCPE_OK;
} }
static const char *sim_vhd_disk_get_dtype (FILE *f, uint32 *SectorSize, uint32 *xfer_element_size) static const char *sim_vhd_disk_get_dtype (FILE *f, uint32 *SectorSize, uint32 *xfer_element_size, char sim_name[64])
{ {
VHDHANDLE hVHD = (VHDHANDLE)f; VHDHANDLE hVHD = (VHDHANDLE)f;
@ -4418,6 +4651,8 @@ if (SectorSize)
*SectorSize = NtoHl (hVHD->Footer.DriveSectorSize); *SectorSize = NtoHl (hVHD->Footer.DriveSectorSize);
if (xfer_element_size) if (xfer_element_size)
*xfer_element_size = NtoHl (hVHD->Footer.DriveTransferElementSize); *xfer_element_size = NtoHl (hVHD->Footer.DriveTransferElementSize);
if (sim_name)
memcpy (sim_name, hVHD->Footer.CreatingSimulator, 64);
return (char *)(&hVHD->Footer.DriveType[0]); return (char *)(&hVHD->Footer.DriveType[0]);
} }