Fix to allow raw disk access even if Large File support isn't available on the host
This commit is contained in:
parent
b6e93b645e
commit
2c941c86d2
1 changed files with 188 additions and 181 deletions
369
sim_disk.c
369
sim_disk.c
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue