Fix to allow raw disk access even if Large File support isn't available on the host

This commit is contained in:
Mark Pizzolato 2013-04-15 12:19:33 -07:00
parent b6e93b645e
commit 2c941c86d2

View file

@ -20,7 +20,7 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of Mark Pizzolato shall not be Except as contained in this notice, the names of Mark Pizzolato shall not be
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Mark Pizzolato. in this Software without prior written authorization from Mark Pizzolato.
@ -163,8 +163,8 @@ int sched_policy;
struct sched_param sched_priority; struct sched_param sched_priority;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
/* Boost Priority for this I/O thread vs the CPU instruction execution /* Boost Priority for this I/O thread vs the CPU instruction execution
thread which in general won't be readily yielding the processor when thread which in general won't be readily yielding the processor when
this thread needs to run */ this thread needs to run */
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority; ++sched_priority.sched_priority;
@ -202,16 +202,16 @@ sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) exiting\n", (int)(uptr-ctx->
return NULL; return NULL;
} }
/* This routine is called in the context of the main simulator thread before /* This routine is called in the context of the main simulator thread before
processing events for any unit. It is only called when an asynchronous processing events for any unit. It is only called when an asynchronous
thread has called sim_activate() to activate a unit. The job of this thread has called sim_activate() to activate a unit. The job of this
routine is to put the unit in proper condition to digest what may have routine is to put the unit in proper condition to digest what may have
occurred in the asynchrconous thread. occurred in the asynchrconous thread.
Since disk processing only handles a single I/O at a time to a Since disk processing only handles a single I/O at a time to a
particular disk device (due to using stdio for the SimH Disk format particular disk device (due to using stdio for the SimH Disk format
and stdio doesn't have an atomic seek+(read|write) operation), and stdio doesn't have an atomic seek+(read|write) operation),
we have the opportunity to possibly detect improper attempts to we have the opportunity to possibly detect improper attempts to
issue multiple concurrent I/O requests. */ issue multiple concurrent I/O requests. */
static void _disk_completion_dispatch (UNIT *uptr) static void _disk_completion_dispatch (UNIT *uptr)
{ {
@ -715,20 +715,20 @@ else { /* Unaligned and/or partial sector transfers */
((sects + lba - tlba) & (sspsts - 1))) ((sects + lba - tlba) & (sspsts - 1)))
switch (DK_GET_FMT (uptr)) { /* case on format */ switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */ case DKUF_F_VHD: /* VHD format */
sim_vhd_disk_rdsect (uptr, tlba + tsects - sspsts, sim_vhd_disk_rdsect (uptr, tlba + tsects - sspsts,
tbuf + (tsects - sspsts) * ctx->sector_size, tbuf + (tsects - sspsts) * ctx->sector_size,
NULL, sspsts); NULL, sspsts);
break; break;
case DKUF_F_RAW: /* Raw Physical Disk Access */ case DKUF_F_RAW: /* Raw Physical Disk Access */
sim_os_disk_rdsect (uptr, tlba + tsects - sspsts, sim_os_disk_rdsect (uptr, tlba + tsects - sspsts,
tbuf + (tsects - sspsts) * ctx->sector_size, tbuf + (tsects - sspsts) * ctx->sector_size,
NULL, sspsts); NULL, sspsts);
break; break;
default: default:
r = SCPE_NOFNC; r = SCPE_NOFNC;
break; break;
} }
sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size, sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size,
buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size); buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
switch (DK_GET_FMT (uptr)) { /* case on format */ switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */ case DKUF_F_VHD: /* VHD format */
@ -774,7 +774,7 @@ switch (DK_GET_FMT (uptr)) { /* case on format */
} }
} }
/* /*
This routine is called when the simulator stops and any time This routine is called when the simulator stops and any time
the asynch mode is changed (enabled or disabled) the asynch mode is changed (enabled or disabled)
*/ */
@ -812,7 +812,7 @@ return stat;
} }
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay) uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
{ {
struct disk_context *ctx; struct disk_context *ctx;
@ -875,7 +875,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop
sim_switches = saved_sim_switches; sim_switches = saved_sim_switches;
return r; return r;
} }
if (!sim_quiet) if (!sim_quiet)
printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf);
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */ capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */
vhd = sim_vhd_disk_create (gbuf, ((t_offset)uptr->capac)*capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)); vhd = sim_vhd_disk_create (gbuf, ((t_offset)uptr->capac)*capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1));
@ -1076,7 +1076,7 @@ else { /* normal */
uptr->fileref = open_function (cptr, "wb+");/* open new file */ uptr->fileref = open_function (cptr, "wb+");/* open new file */
if (uptr->fileref == NULL) /* open fail? */ if (uptr->fileref == NULL) /* open fail? */
return _err_return (uptr, SCPE_OPENERR);/* yes, error */ return _err_return (uptr, SCPE_OPENERR);/* yes, error */
if (!sim_quiet) if (!sim_quiet)
printf ("%s%d: creating new file\n", sim_dname (dptr), (int)(uptr-dptr->units)); printf ("%s%d: creating new file\n", sim_dname (dptr), (int)(uptr-dptr->units));
created = TRUE; created = TRUE;
} }
@ -1103,15 +1103,15 @@ if ((created) && (!copied)) {
t_stat r = SCPE_OK; t_stat r = SCPE_OK;
uint8 *secbuf = calloc (1, ctx->sector_size); /* alloc temp sector buf */ uint8 *secbuf = calloc (1, 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 a zero sector to the last and the
first sectors. This serves 3 purposes: first sectors. 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
avoid strange failures which may happen during simulator execution avoid strange failures which may happen during simulator execution
if the containing disk is full if the containing disk is full
3) it leaves a Sinh Format disk at the intended size so it may 3) it leaves a Sinh Format disk at the intended size so it may
subsequently be autosized with the correct size. subsequently be autosized with the correct size.
*/ */
if (secbuf == NULL) if (secbuf == NULL)
@ -1970,10 +1970,17 @@ fsync ((int)((long)f));
static t_offset sim_os_disk_size_raw (FILE *f) static t_offset sim_os_disk_size_raw (FILE *f)
{ {
#if defined (DONT_DO_LARGEFILE)
struct stat statb;
if (fstat ((int)((long)f), &statb))
return (t_offset)-1;
#else
struct stat64 statb; struct stat64 statb;
if (fstat64 ((int)((long)f), &statb)) if (fstat64 ((int)((long)f), &statb))
return (t_offset)-1; return (t_offset)-1;
#endif
return (t_offset)statb.st_size; return (t_offset)statb.st_size;
} }
@ -1996,7 +2003,7 @@ ssize_t bytesread;
sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);
addr = ((off_t)lba) * ctx->sector_size; addr = ((off_t)lba) * ctx->sector_size;
bytesread = pread((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); bytesread = pread((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr);
if (bytesread < 0) { if (bytesread < 0) {
if (sectsread) if (sectsread)
*sectsread = 0; *sectsread = 0;
@ -2016,7 +2023,7 @@ ssize_t byteswritten;
sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);
addr = ((off_t)lba) * ctx->sector_size; addr = ((off_t)lba) * ctx->sector_size;
byteswritten = pwrite((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); byteswritten = pwrite((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr);
if (byteswritten < 0) { if (byteswritten < 0) {
if (sectswritten) if (sectswritten)
*sectswritten = 0; *sectswritten = 0;
@ -2172,9 +2179,9 @@ return NULL;
#else #else
/*++ /*++
This code follows the details specified in the "Virtual Hard Disk Image This code follows the details specified in the "Virtual Hard Disk Image
Format Specification", Version 1.0 October 11, 2006. This format Format Specification", Version 1.0 October 11, 2006. This format
specification is available for anyone to implement under the specification is available for anyone to implement under the
"Microsoft Open Specification Promise" described at: "Microsoft Open Specification Promise" described at:
http://www.microsoft.com/interop/osp/default.mspx. http://www.microsoft.com/interop/osp/default.mspx.
--*/ --*/
@ -2184,75 +2191,75 @@ typedef t_int64 int64;
typedef struct _VHD_Footer { typedef struct _VHD_Footer {
/* /*
Cookies are used to uniquely identify the original creator of the hard disk Cookies are used to uniquely identify the original creator of the hard disk
image. The values are case-sensitive. Microsoft uses the "conectix" string image. The values are case-sensitive. Microsoft uses the "conectix" string
to identify this file as a hard disk image created by Microsoft Virtual to identify this file as a hard disk image created by Microsoft Virtual
Server, Virtual PC, and predecessor products. The cookie is stored as an Server, Virtual PC, and predecessor products. The cookie is stored as an
eight-character ASCII string with the "c" in the first byte, the "o" in eight-character ASCII string with the "c" in the first byte, the "o" in
the second byte, and so on. the second byte, and so on.
*/ */
char Cookie[8]; char Cookie[8];
/* /*
This is a bit field used to indicate specific feature support. The following This is a bit field used to indicate specific feature support. The following
table displays the list of features. table displays the list of features.
Any fields not listed are reserved. Any fields not listed are reserved.
Feature Value: Feature Value:
No features enabled 0x00000000 No features enabled 0x00000000
Temporary 0x00000001 Temporary 0x00000001
Reserved 0x00000002 Reserved 0x00000002
No features enabled. No features enabled.
The hard disk image has no special features enabled in it. The hard disk image has no special features enabled in it.
Temporary. Temporary.
This bit is set if the current disk is a temporary disk. A This bit is set if the current disk is a temporary disk. A
temporary disk designation indicates to an application that temporary disk designation indicates to an application that
this disk is a candidate for deletion on shutdown. this disk is a candidate for deletion on shutdown.
Reserved. Reserved.
This bit must always be set to 1. This bit must always be set to 1.
All other bits are also reserved and should be set to 0. All other bits are also reserved and should be set to 0.
*/ */
uint32 Features; uint32 Features;
/* /*
This field is divided into a major/minor version and matches the version of This field is divided into a major/minor version and matches the version of
the specification used in creating the file. The most-significant two bytes the specification used in creating the file. The most-significant two bytes
are for the major version. The least-significant two bytes are the minor are for the major version. The least-significant two bytes are the minor
version. This must match the file format specification. For the current version. This must match the file format specification. For the current
specification, this field must be initialized to 0x00010000. specification, this field must be initialized to 0x00010000.
The major version will be incremented only when the file format is modified The major version will be incremented only when the file format is modified
in such a way that it is no longer compatible with older versions of the in such a way that it is no longer compatible with older versions of the
file format. file format.
*/ */
uint32 FileFormatVersion; uint32 FileFormatVersion;
/* /*
This field holds the absolute byte offset, from the beginning of the file, This field holds the absolute byte offset, from the beginning of the file,
to the next structure. This field is used for dynamic disks and differencing to the next structure. This field is used for dynamic disks and differencing
disks, but not fixed disks. For fixed disks, this field should be set to disks, but not fixed disks. For fixed disks, this field should be set to
0xFFFFFFFF. 0xFFFFFFFF.
*/ */
uint64 DataOffset; uint64 DataOffset;
/* /*
This field stores the creation time of a hard disk image. This is the number This field stores the creation time of a hard disk image. This is the number
of seconds since January 1, 2000 12:00:00 AM in UTC/GMT. of seconds since January 1, 2000 12:00:00 AM in UTC/GMT.
*/ */
uint32 TimeStamp; uint32 TimeStamp;
/* /*
This field is used to document which application created the hard disk. The This field is used to document which application created the hard disk. The
field is a left-justified text field. It uses a single-byte character set. field is a left-justified text field. It uses a single-byte character set.
If the hard disk is created by Microsoft Virtual PC, "vpc " is written in If the hard disk is created by Microsoft Virtual PC, "vpc " is written in
this field. If the hard disk image is created by Microsoft Virtual Server, this field. If the hard disk image is created by Microsoft Virtual Server,
then "vs " is written in this field. then "vs " is written in this field.
Other applications should use their own unique identifiers. Other applications should use their own unique identifiers.
*/ */
char CreatorApplication[4]; char CreatorApplication[4];
/* /*
This field holds the major/minor version of the application that created This field holds the major/minor version of the application that created
the hard disk image. Virtual Server 2004 sets this value to 0x00010000 and the hard disk image. Virtual Server 2004 sets this value to 0x00010000 and
Virtual PC 2004 sets this to 0x00050000. Virtual PC 2004 sets this to 0x00050000.
*/ */
uint32 CreatorVersion; uint32 CreatorVersion;
/* /*
This field stores the type of host operating system this disk image is This field stores the type of host operating system this disk image is
created on. created on.
Host OS type Value Host OS type Value
Windows 0x5769326B (Wi2k) Windows 0x5769326B (Wi2k)
@ -2260,34 +2267,34 @@ typedef struct _VHD_Footer {
*/ */
uint8 CreatorHostOS[4]; uint8 CreatorHostOS[4];
/* /*
This field stores the size of the hard disk in bytes, from the perspective This field stores the size of the hard disk in bytes, from the perspective
of the virtual machine, at creation time. This field is for informational of the virtual machine, at creation time. This field is for informational
purposes. purposes.
*/ */
uint64 OriginalSize; uint64 OriginalSize;
/* /*
This field stores the current size of the hard disk, in bytes, from the This field stores the current size of the hard disk, in bytes, from the
perspective of the virtual machine. perspective of the virtual machine.
This value is same as the original size when the hard disk is created. This value is same as the original size when the hard disk is created.
This value can change depending on whether the hard disk is expanded. This value can change depending on whether the hard disk is expanded.
*/ */
uint64 CurrentSize; uint64 CurrentSize;
/* /*
This field stores the cylinder, heads, and sectors per track value for the This field stores the cylinder, heads, and sectors per track value for the
hard disk. hard disk.
Disk Geometry field Size (bytes) Disk Geometry field Size (bytes)
Cylinder 2 Cylinder 2
Heads 1 Heads 1
Sectors per track/cylinder 1 Sectors per track/cylinder 1
When a hard disk is configured as an ATA hard disk, the CHS values (that is, When a hard disk is configured as an ATA hard disk, the CHS values (that is,
Cylinder, Heads, Sectors per track) are used by the ATA controller to Cylinder, Heads, Sectors per track) are used by the ATA controller to
determine the size of the disk. When the user creates a hard disk of a determine the size of the disk. When the user creates a hard disk of a
certain size, the size of the hard disk image in the virtual machine is certain size, the size of the hard disk image in the virtual machine is
smaller than that created by the user. This is because CHS value calculated smaller than that created by the user. This is because CHS value calculated
from the hard disk size is rounded down. The pseudo-code for the algorithm from the hard disk size is rounded down. The pseudo-code for the algorithm
used to determine the CHS values can be found in the appendix of this used to determine the CHS values can be found in the appendix of this
document. document.
*/ */
uint32 DiskGeometry; uint32 DiskGeometry;
/* /*
@ -2302,49 +2309,49 @@ typedef struct _VHD_Footer {
*/ */
uint32 DiskType; uint32 DiskType;
/* /*
This field holds a basic checksum of the hard disk footer. It is just a This field holds a basic checksum of the hard disk footer. It is just a
one's complement of the sum of all the bytes in the footer without the one's complement of the sum of all the bytes in the footer without the
checksum field. checksum field.
If the checksum verification fails, the Virtual PC and Virtual Server If the checksum verification fails, the Virtual PC and Virtual Server
products will instead use the header. If the checksum in the header also products will instead use the header. If the checksum in the header also
fails, the file should be assumed to be corrupt. The pseudo-code for the fails, the file should be assumed to be corrupt. The pseudo-code for the
algorithm used to determine the checksum can be found in the appendix of algorithm used to determine the checksum can be found in the appendix of
this document. this document.
*/ */
uint32 Checksum; uint32 Checksum;
/* /*
Every hard disk has a unique ID stored in the hard disk. This is used to Every hard disk has a unique ID stored in the hard disk. This is used to
identify the hard disk. This is a 128-bit universally unique identifier identify the hard disk. This is a 128-bit universally unique identifier
(UUID). This field is used to associate a parent hard disk image with its (UUID). This field is used to associate a parent hard disk image with its
differencing hard disk image(s). differencing hard disk image(s).
*/ */
uint8 UniqueID[16]; uint8 UniqueID[16];
/* /*
This field holds a one-byte flag that describes whether the system is in This field holds a one-byte flag that describes whether the system is in
saved state. If the hard disk is in the saved state the value is set to 1. saved state. If the hard disk is in the saved state the value is set to 1.
Operations such as compaction and expansion cannot be performed on a hard Operations such as compaction and expansion cannot be performed on a hard
disk in a saved state. disk in a saved state.
*/ */
uint8 SavedState; uint8 SavedState;
/* /*
This field contains zeroes. It is 427 bytes in size. This field contains zeroes. It is 427 bytes in size.
*/ */
uint8 Reserved1[11]; uint8 Reserved1[11];
/* /*
This field is an extension to the VHD spec and includes a simh drive type This field is an extension to the VHD spec and includes a simh drive type
name as a nul terminated string. name as a nul terminated string.
*/ */
uint8 DriveType[16]; uint8 DriveType[16];
/* /*
This field contains zeroes. It is 400 bytes in size. This field contains zeroes. It is 400 bytes in size.
*/ */
uint8 Reserved[400]; uint8 Reserved[400];
} VHD_Footer; } VHD_Footer;
/* /*
For dynamic and differencing disk images, the "Data Offset" field within For dynamic and differencing disk images, the "Data Offset" field within
the image footer points to a secondary structure that provides additional the image footer points to a secondary structure that provides additional
information about the disk image. The dynamic disk header should appear on information about the disk image. The dynamic disk header should appear on
a sector (512-byte) boundary. a sector (512-byte) boundary.
*/ */
typedef struct _VHD_DynamicDiskHeader { typedef struct _VHD_DynamicDiskHeader {
@ -2353,79 +2360,79 @@ typedef struct _VHD_DynamicDiskHeader {
*/ */
char Cookie[8]; char Cookie[8];
/* /*
This field contains the absolute byte offset to the next structure in the This field contains the absolute byte offset to the next structure in the
hard disk image. It is currently unused by existing formats and should be hard disk image. It is currently unused by existing formats and should be
set to 0xFFFFFFFF. set to 0xFFFFFFFF.
*/ */
uint64 DataOffset; uint64 DataOffset;
/* /*
This field stores the absolute byte offset of the Block Allocation Table This field stores the absolute byte offset of the Block Allocation Table
(BAT) in the file. (BAT) in the file.
*/ */
uint64 TableOffset; uint64 TableOffset;
/* /*
This field stores the version of the dynamic disk header. The field is This field stores the version of the dynamic disk header. The field is
divided into Major/Minor version. The least-significant two bytes represent divided into Major/Minor version. The least-significant two bytes represent
the minor version, and the most-significant two bytes represent the major the minor version, and the most-significant two bytes represent the major
version. This must match with the file format specification. For this version. This must match with the file format specification. For this
specification, this field must be initialized to 0x00010000. specification, this field must be initialized to 0x00010000.
The major version will be incremented only when the header format is The major version will be incremented only when the header format is
modified in such a way that it is no longer compatible with older versions modified in such a way that it is no longer compatible with older versions
of the product. of the product.
*/ */
uint32 HeaderVersion; uint32 HeaderVersion;
/* /*
This field holds the maximum entries present in the BAT. This should be This field holds the maximum entries present in the BAT. This should be
equal to the number of blocks in the disk (that is, the disk size divided equal to the number of blocks in the disk (that is, the disk size divided
by the block size). by the block size).
*/ */
uint32 MaxTableEntries; uint32 MaxTableEntries;
/* /*
A block is a unit of expansion for dynamic and differencing hard disks. It A block is a unit of expansion for dynamic and differencing hard disks. It
is stored in bytes. This size does not include the size of the block bitmap. is stored in bytes. This size does not include the size of the block bitmap.
It is only the size of the data section of the block. The sectors per block It is only the size of the data section of the block. The sectors per block
must always be a power of two. The default value is 0x00200000 (indicating a must always be a power of two. The default value is 0x00200000 (indicating a
block size of 2 MB). block size of 2 MB).
*/ */
uint32 BlockSize; uint32 BlockSize;
/* /*
This field holds a basic checksum of the dynamic header. It is a one's This field holds a basic checksum of the dynamic header. It is a one's
complement of the sum of all the bytes in the header without the checksum complement of the sum of all the bytes in the header without the checksum
field. field.
If the checksum verification fails the file should be assumed to be corrupt. If the checksum verification fails the file should be assumed to be corrupt.
*/ */
uint32 Checksum; uint32 Checksum;
/* /*
This field is used for differencing hard disks. A differencing hard disk This field is used for differencing hard disks. A differencing hard disk
stores a 128-bit UUID of the parent hard disk. For more information, see stores a 128-bit UUID of the parent hard disk. For more information, see
"Creating Differencing Hard Disk Images" later in this paper. "Creating Differencing Hard Disk Images" later in this paper.
*/ */
uint8 ParentUniqueID[16]; uint8 ParentUniqueID[16];
/* /*
This field stores the modification time stamp of the parent hard disk. This This field stores the modification time stamp of the parent hard disk. This
is the number of seconds since January 1, 2000 12:00:00 AM in UTC/GMT. is the number of seconds since January 1, 2000 12:00:00 AM in UTC/GMT.
*/ */
uint32 ParentTimeStamp; uint32 ParentTimeStamp;
/* /*
This field should be set to zero. This field should be set to zero.
*/ */
uint32 Reserved0; uint32 Reserved0;
/* /*
This field contains a Unicode string (UTF-16) of the parent hard disk This field contains a Unicode string (UTF-16) of the parent hard disk
filename. filename.
*/ */
char ParentUnicodeName[512]; char ParentUnicodeName[512];
/* /*
These entries store an absolute byte offset in the file where the parent These entries store an absolute byte offset in the file where the parent
locator for a differencing hard disk is stored. This field is used only for locator for a differencing hard disk is stored. This field is used only for
differencing disks and should be set to zero for dynamic disks. differencing disks and should be set to zero for dynamic disks.
*/ */
struct VHD_ParentLocator { struct VHD_ParentLocator {
/* /*
The platform code describes which platform-specific format is used for the The platform code describes which platform-specific format is used for the
file locator. For Windows, a file locator is stored as a path (for example. file locator. For Windows, a file locator is stored as a path (for example.
"c:\disksimages\ParentDisk.vhd"). On a Macintosh system, the file locator "c:\disksimages\ParentDisk.vhd"). On a Macintosh system, the file locator
is a binary large object (blob) that contains an "alias." The parent locator is a binary large object (blob) that contains an "alias." The parent locator
table is used to support moving hard disk images across platforms. table is used to support moving hard disk images across platforms.
Some current platform codes include the following: Some current platform codes include the following:
Platform Code Description Platform Code Description
@ -2439,7 +2446,7 @@ typedef struct _VHD_DynamicDiskHeader {
*/ */
uint8 PlatformCode[4]; uint8 PlatformCode[4];
/* /*
This field stores the number of 512-byte sectors needed to store the parent This field stores the number of 512-byte sectors needed to store the parent
hard disk locator. hard disk locator.
*/ */
uint32 PlatformDataSpace; uint32 PlatformDataSpace;
@ -2452,12 +2459,12 @@ typedef struct _VHD_DynamicDiskHeader {
*/ */
uint32 Reserved; uint32 Reserved;
/* /*
This field stores the absolute file offset in bytes where the platform This field stores the absolute file offset in bytes where the platform
specific file locator data is stored. specific file locator data is stored.
*/ */
uint64 PlatformDataOffset; uint64 PlatformDataOffset;
/* /*
This field stores the absolute file offset in bytes where the platform This field stores the absolute file offset in bytes where the platform
specific file locator data is stored. specific file locator data is stored.
*/ */
} ParentLocatorEntries[8]; } ParentLocatorEntries[8];
@ -2513,7 +2520,7 @@ return (err ? SCPE_IOERR : SCPE_OK);
} }
static uint32 static uint32
CalculateVhdFooterChecksum(void *data, CalculateVhdFooterChecksum(void *data,
size_t size) size_t size)
{ {
uint32 sum = 0; uint32 sum = 0;
@ -2587,8 +2594,8 @@ return value;
static static
int int
GetVHDFooter(const char *szVHDPath, GetVHDFooter(const char *szVHDPath,
VHD_Footer *sFooter, VHD_Footer *sFooter,
VHD_DynamicDiskHeader *sDynamic, VHD_DynamicDiskHeader *sDynamic,
uint32 **aBAT, uint32 **aBAT,
uint32 *ModifiedTimeStamp, uint32 *ModifiedTimeStamp,
@ -2627,10 +2634,10 @@ if (((int64)position) == -1) {
goto Return_Cleanup; goto Return_Cleanup;
} }
position -= sizeof(*sFooter); position -= sizeof(*sFooter);
if (ReadFilePosition(File, if (ReadFilePosition(File,
sFooter, sFooter,
sizeof(*sFooter), sizeof(*sFooter),
NULL, NULL,
position)) { position)) {
Return = errno; Return = errno;
goto Return_Cleanup; goto Return_Cleanup;
@ -2643,10 +2650,10 @@ if ((sum != saved_sum) || (memcmp("conectix", sFooter->Cookie, sizeof(sFooter->C
Return = EINVAL; /* File Corrupt */ Return = EINVAL; /* File Corrupt */
goto Return_Cleanup; goto Return_Cleanup;
} }
if (ReadFilePosition(File, if (ReadFilePosition(File,
&sHeader, &sHeader,
sizeof(sHeader), sizeof(sHeader),
NULL, NULL,
(uint64)0)) { (uint64)0)) {
Return = errno; Return = errno;
goto Return_Cleanup; goto Return_Cleanup;
@ -2666,10 +2673,10 @@ if (((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) ||
if ((sDynamic) && if ((sDynamic) &&
((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) || ((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) ||
(NtoHl(sFooter->DiskType) == VHD_DT_Differencing))) { (NtoHl(sFooter->DiskType) == VHD_DT_Differencing))) {
if (ReadFilePosition(File, if (ReadFilePosition(File,
sDynamic, sDynamic,
sizeof (*sDynamic), sizeof (*sDynamic),
NULL, NULL,
NtoHll (sFooter->DataOffset))) { NtoHll (sFooter->DataOffset))) {
Return = errno; Return = errno;
goto Return_Cleanup; goto Return_Cleanup;
@ -2684,10 +2691,10 @@ if ((sDynamic) &&
} }
if (aBAT) { if (aBAT) {
*aBAT = (uint32*) malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512)); *aBAT = (uint32*) malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512));
if (ReadFilePosition(File, if (ReadFilePosition(File,
*aBAT, *aBAT,
sizeof (**aBAT)*NtoHl(sDynamic->MaxTableEntries), sizeof (**aBAT)*NtoHl(sDynamic->MaxTableEntries),
NULL, NULL,
NtoHll (sDynamic->TableOffset))) { NtoHll (sDynamic->TableOffset))) {
Return = EINVAL; /* File Corrupt */ Return = EINVAL; /* File Corrupt */
goto Return_Cleanup; goto Return_Cleanup;
@ -2715,10 +2722,10 @@ if ((sDynamic) &&
Pdata = (uint8*) calloc (1, PdataSize+2); Pdata = (uint8*) calloc (1, PdataSize+2);
if (!Pdata) if (!Pdata)
continue; continue;
if (ReadFilePosition(File, if (ReadFilePosition(File,
Pdata, Pdata,
PdataSize, PdataSize,
NULL, NULL,
NtoHll (sDynamic->ParentLocatorEntries[j].PlatformDataOffset))) { NtoHll (sDynamic->ParentLocatorEntries[j].PlatformDataOffset))) {
free (Pdata); free (Pdata);
continue; continue;
@ -2742,16 +2749,16 @@ if ((sDynamic) &&
strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1)); strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1));
} }
VhdPathToHostPath (CheckPath, CheckPath, sizeof (CheckPath)); VhdPathToHostPath (CheckPath, CheckPath, sizeof (CheckPath));
if ((0 == GetVHDFooter(CheckPath, if ((0 == GetVHDFooter(CheckPath,
&sParentFooter, &sParentFooter,
NULL, NULL,
NULL, NULL,
&ParentModificationTime, &ParentModificationTime,
NULL, NULL,
0)) && 0)) &&
(0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) && (0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) &&
((sDynamic->ParentTimeStamp == ParentModificationTime) || ((sDynamic->ParentTimeStamp == ParentModificationTime) ||
((NtoHl(sDynamic->ParentTimeStamp)-NtoHl(ParentModificationTime)) == 3600) || ((NtoHl(sDynamic->ParentTimeStamp)-NtoHl(ParentModificationTime)) == 3600) ||
(sim_switches & SWMASK ('O')))) { (sim_switches & SWMASK ('O')))) {
strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize); strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize);
break; break;
@ -2854,9 +2861,9 @@ static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess
if (!hVHD) if (!hVHD)
return (FILE *)hVHD; return (FILE *)hVHD;
Status = GetVHDFooter (szVHDPath, Status = GetVHDFooter (szVHDPath,
&hVHD->Footer, &hVHD->Footer,
&hVHD->Dynamic, &hVHD->Dynamic,
&hVHD->BAT, &hVHD->BAT,
NULL, NULL,
hVHD->ParentVHDPath, hVHD->ParentVHDPath,
@ -2873,9 +2880,9 @@ static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess
Status = errno; Status = errno;
goto Cleanup_Return; goto Cleanup_Return;
} }
Status = GetVHDFooter (hVHD->ParentVHDPath, Status = GetVHDFooter (hVHD->ParentVHDPath,
&ParentFooter, &ParentFooter,
&ParentDynamic, &ParentDynamic,
NULL, NULL,
&ParentModifiedTimeStamp, &ParentModifiedTimeStamp,
NULL, NULL,
@ -2926,9 +2933,9 @@ static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD)
if (!hVHD) if (!hVHD)
return (FILE *)hVHD; return (FILE *)hVHD;
if (0 != (Status = GetVHDFooter (szVHDPath, if (0 != (Status = GetVHDFooter (szVHDPath,
&hVHD->Footer, &hVHD->Footer,
&hVHD->Dynamic, &hVHD->Dynamic,
&hVHD->BAT, &hVHD->BAT,
NULL, NULL,
hVHD->ParentVHDPath, hVHD->ParentVHDPath,
@ -2984,11 +2991,11 @@ static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD)
&BytesRead, &BytesRead,
BlockOffset)) BlockOffset))
break; break;
if (WriteVirtualDiskSectors (Parent, if (WriteVirtualDiskSectors (Parent,
(uint8*)BlockData, (uint8*)BlockData,
BlockSectors, BlockSectors,
&SectorsWritten, &SectorsWritten,
SectorSize, SectorSize,
SectorsPerBlock*BlockNumber)) SectorsPerBlock*BlockNumber))
break; break;
if (!sim_quiet) if (!sim_quiet)
@ -3190,7 +3197,7 @@ if (1) { /* CHS Calculation */
cylinderTimesHeads = totalSectors / sectorsPerTrack; cylinderTimesHeads = totalSectors / sectorsPerTrack;
} }
else { else {
sectorsPerTrack = 17; sectorsPerTrack = 17;
cylinderTimesHeads = totalSectors / sectorsPerTrack; cylinderTimesHeads = totalSectors / sectorsPerTrack;
heads = (cylinderTimesHeads + 1023) / 1024; heads = (cylinderTimesHeads + 1023) / 1024;
@ -3390,7 +3397,7 @@ return szHostPath;
} }
static VHDHANDLE static VHDHANDLE
CreateDifferencingVirtualDisk(const char *szVHDPath, CreateDifferencingVirtualDisk(const char *szVHDPath,
const char *szParentVHDPath) const char *szParentVHDPath)
{ {
uint32 BytesPerSector = 512; uint32 BytesPerSector = 512;
@ -3407,12 +3414,12 @@ char *FullVHDPath = NULL;
size_t i, RelativeMatch, UpDirectories, LocatorsWritten = 0; size_t i, RelativeMatch, UpDirectories, LocatorsWritten = 0;
int64 LocatorPosition; int64 LocatorPosition;
if ((Status = GetVHDFooter (szParentVHDPath, if ((Status = GetVHDFooter (szParentVHDPath,
&ParentFooter, &ParentFooter,
&ParentDynamic, &ParentDynamic,
NULL, NULL,
&ParentTimeStamp, &ParentTimeStamp,
NULL, NULL,
0))) 0)))
goto Cleanup_Return; goto Cleanup_Return;
hVHD = CreateVirtualDisk (szVHDPath, hVHD = CreateVirtualDisk (szVHDPath,
@ -3806,7 +3813,7 @@ while (sects) {
BlockOffset)) BlockOffset))
goto Fatal_IO_Error; goto Fatal_IO_Error;
/* Write just the aligned sector which contains the updated BAT entry */ /* Write just the aligned sector which contains the updated BAT entry */
BATUpdateBufferAddress = (uint8 *)hVHD->BAT - (size_t)NtoHll(hVHD->Dynamic.TableOffset) + BATUpdateBufferAddress = (uint8 *)hVHD->BAT - (size_t)NtoHll(hVHD->Dynamic.TableOffset) +
(size_t)((((size_t)&hVHD->BAT[BlockNumber+1]) - (size_t)hVHD->BAT + (size_t)NtoHll(hVHD->Dynamic.TableOffset)) & ~(VHD_DATA_BLOCK_ALIGNMENT-1)); (size_t)((((size_t)&hVHD->BAT[BlockNumber+1]) - (size_t)hVHD->BAT + (size_t)NtoHll(hVHD->Dynamic.TableOffset)) & ~(VHD_DATA_BLOCK_ALIGNMENT-1));
if (BATUpdateBufferAddress < (uint8 *)hVHD->BAT) { if (BATUpdateBufferAddress < (uint8 *)hVHD->BAT) {
BATUpdateBufferAddress = (uint8 *)hVHD->BAT; BATUpdateBufferAddress = (uint8 *)hVHD->BAT;
@ -3834,14 +3841,14 @@ while (sects) {
if (((lba/SectorsPerBlock)*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize) if (((lba/SectorsPerBlock)*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize)
BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (lba/SectorsPerBlock)*SectorsPerBlock); BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (lba/SectorsPerBlock)*SectorsPerBlock);
if (ReadVirtualDiskSectors(hVHD->Parent, if (ReadVirtualDiskSectors(hVHD->Parent,
(uint8*) BlockData, (uint8*) BlockData,
BlockSectors, BlockSectors,
NULL, NULL,
SectorSize, SectorSize,
(lba/SectorsPerBlock)*SectorsPerBlock)) (lba/SectorsPerBlock)*SectorsPerBlock))
goto Fatal_IO_Error; goto Fatal_IO_Error;
if (WriteVirtualDiskSectors(hVHD, if (WriteVirtualDiskSectors(hVHD,
(uint8*) BlockData, (uint8*) BlockData,
BlockSectors, BlockSectors,
NULL, NULL,
SectorSize, SectorSize,