DISK: Add robust disk container validation
This commit is contained in:
parent
3950478e00
commit
049ba32505
3 changed files with 286 additions and 51 deletions
2
scp.c
2
scp.c
|
@ -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),
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
333
sim_disk.c
333
sim_disk.c
|
@ -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, §or_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, §or_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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue