1284 lines
36 KiB
Plaintext
1284 lines
36 KiB
Plaintext
----------------------------------------------------------------------
|
|
Patch name: patch.sparsedisk-justinsb
|
|
Author: Justin SB
|
|
Date: 27 Jan 2003
|
|
Status: Obsolete, replaced by patch.harddisk-modes
|
|
|
|
Detailed description:
|
|
|
|
This patch enables "sparse hard drive" support:
|
|
|
|
1) A large hard drive can be created, and only used space will be stored
|
|
in the file. In practice this is not a large gain as Unix does this
|
|
anyway.
|
|
2) Multiple sparse drive images can be mounted on top of each other.
|
|
Writes go to the top image. This allows several similar configurations
|
|
to share a master "base" file, and also allows filesystem rollback or
|
|
no-write options. Up to 10 disk images can be layered on top of each other.
|
|
|
|
There is a need for supporting utilities:
|
|
1) to merge two sparse disk images into a single image
|
|
2) to defragment a sparse disk image and remove unused space
|
|
|
|
Examples:
|
|
Space Saving
|
|
1) Create a sparse disk image using bximage. Set size to eg 10GB. Only allocated space will be stored,
|
|
so your drive image should be only about as large as the files stored on it.
|
|
|
|
Disk Rollback:
|
|
1) Create a sparse disk image called "c.img.0". Point .bochsrc at "c.img.0".
|
|
In bochs, install your favourite OS. Switch off bochs.
|
|
2) Create a sparse disk image (of the same size) and name it "c.img.1". Point .bochsrc at "c.img.1"
|
|
"c.img.0" is visible, but all writes go to "c.img.1". After using bochs, you can simply delete
|
|
"c.img.1" to undo changes and go back to a clean OS install.
|
|
|
|
Disk Optional Commit:
|
|
1) Create a sparse disk image called "c.img.0". Point .bochsrc at "c.img.0".
|
|
In bochs, install your favourite OS. Switch off bochs.
|
|
2) Create a sparse disk image (of the same size) and name it "c.img.1". Point .bochsrc at "c.img.1"
|
|
"c.img.0" is visible, but all writes go to "c.img.1". After using bochs, if you want to keep the
|
|
changes, use the (currently non-existant) merge utility to make a single unified drive image.
|
|
Alternatively simply create a new partition on top called "c.img.3".
|
|
|
|
Common Base:
|
|
1) Create a sparse disk image called "base.img". Point .bochsrc at "base.img".
|
|
In bochs, install your favourite OS. Switch off bochs.
|
|
2) Create a sparse disk image (of the same size) and name it "www.img.1". Make "wwww.img.0" a symlink to
|
|
"base.img". Point .bochsrc at "www.img.1". Using bochs, install a webserver.
|
|
3) Create a symlink to "base.img" called "db.img.0". Create a sparse disk image (of the same size)
|
|
and name it "db.img.1". Point .bochsrc at "db.img.1". Using bochs, install a database server.
|
|
|
|
Now both a database server and webserver can be run in separate virtual machines, but they share
|
|
the common OS image, saving drive space.
|
|
|
|
|
|
|
|
Disk Rollback and Optional Commit will probably be the most used of these options.
|
|
|
|
|
|
Patch was created with:
|
|
cvs diff -u
|
|
Apply patch to what version:
|
|
cvs checked out on 27 Jan 2003
|
|
Instructions:
|
|
To patch, go to main bochs directory.
|
|
Type "patch -p0 < patch.sparsedisk".
|
|
----------------------------------------------------------------------
|
|
|
|
Index: bochs.h
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/bochs.h,v
|
|
retrieving revision 1.117
|
|
diff -u -r1.117 bochs.h
|
|
--- bochs.h 10 Jan 2003 22:43:51 -0000 1.117
|
|
+++ bochs.h 27 Jan 2003 12:37:19 -0000
|
|
@@ -49,6 +49,8 @@
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
+#include <errno.h>
|
|
+
|
|
#ifndef WIN32
|
|
# include <unistd.h>
|
|
#else
|
|
Index: config.h.in
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/config.h.in,v
|
|
retrieving revision 1.104
|
|
diff -u -r1.104 config.h.in
|
|
--- config.h.in 23 Jan 2003 19:31:25 -0000 1.104
|
|
+++ config.h.in 27 Jan 2003 12:37:21 -0000
|
|
@@ -294,6 +294,16 @@
|
|
// [[Provide example of partitioning]]
|
|
#define BX_SPLIT_HD_SUPPORT 0
|
|
|
|
+// This option enables "sparse hard drive" support, which means that
|
|
+// 1) A large hard drive can be created, and only used space will be stored
|
|
+// in the file. In practice this is not a large gain as Unix does this
|
|
+// anyway.
|
|
+// 2) Multiple sparse drive images can be mounted on top of each other.
|
|
+// Writes go to the top image. This allows several similar configurations
|
|
+// to share a master "base" file, and also allows filesystem rollback or
|
|
+// no-write options
|
|
+#define BX_SPARSE_HD_SUPPORT 0
|
|
+
|
|
// This option defines the number of supported ATA channels.
|
|
// There are up to two drives per ATA channel.
|
|
#define BX_MAX_ATA_CHANNEL 4
|
|
Index: configure
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/configure,v
|
|
retrieving revision 1.198
|
|
diff -u -r1.198 configure
|
|
--- configure 20 Jan 2003 20:12:59 -0000 1.198
|
|
+++ configure 27 Jan 2003 12:37:44 -0000
|
|
@@ -1015,6 +1015,7 @@
|
|
--enable-cpu-level select cpu level (3,4,5,6)
|
|
--enable-apic enable APIC support
|
|
--enable-split-hd allows split hard disk image
|
|
+ --enable-sparse-hd allows sparse hard disk image
|
|
--enable-ne2000 enable limited ne2000 support
|
|
--enable-pci enable limited i440FX PCI support
|
|
--enable-dc2300-vlb-ide enable Promise DC2300 VLB-IDE support
|
|
@@ -4208,7 +4209,7 @@
|
|
case $host in
|
|
*-*-irix6*)
|
|
# Find out which ABI we are using.
|
|
- echo '#line 4211 "configure"' > conftest.$ac_ext
|
|
+ echo '#line 4212 "configure"' > conftest.$ac_ext
|
|
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
|
(eval $ac_compile) 2>&5
|
|
ac_status=$?
|
|
@@ -4758,7 +4759,7 @@
|
|
save_CFLAGS="$CFLAGS"
|
|
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
|
|
compiler_c_o=no
|
|
-if { (eval echo configure:4761: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
|
|
+if { (eval echo configure:4762: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
|
|
# The compiler can only warn and ignore the option if not recognized
|
|
# So say no if there are warnings
|
|
if test -s out/conftest.err; then
|
|
@@ -6589,7 +6590,7 @@
|
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
|
lt_status=$lt_dlunknown
|
|
cat > conftest.$ac_ext <<EOF
|
|
-#line 6592 "configure"
|
|
+#line 6593 "configure"
|
|
#include "confdefs.h"
|
|
|
|
#if HAVE_DLFCN_H
|
|
@@ -6687,7 +6688,7 @@
|
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
|
lt_status=$lt_dlunknown
|
|
cat > conftest.$ac_ext <<EOF
|
|
-#line 6690 "configure"
|
|
+#line 6691 "configure"
|
|
#include "confdefs.h"
|
|
|
|
#if HAVE_DLFCN_H
|
|
@@ -8729,7 +8730,7 @@
|
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
|
lt_status=$lt_dlunknown
|
|
cat > conftest.$ac_ext <<EOF
|
|
-#line 8732 "configure"
|
|
+#line 8733 "configure"
|
|
#include "confdefs.h"
|
|
|
|
#if HAVE_DLFCN_H
|
|
@@ -19074,6 +19075,39 @@
|
|
fi;
|
|
|
|
|
|
+echo "$as_me:$LINENO: checking for sparse hard disk image support" >&5
|
|
+echo $ECHO_N "checking for sparse hard disk image support... $ECHO_C" >&6
|
|
+# Check whether --enable-sparse-hd or --disable-sparse-hd was given.
|
|
+if test "${enable_sparse_hd+set}" = set; then
|
|
+ enableval="$enable_sparse_hd"
|
|
+ if test "$enableval" = yes; then
|
|
+ echo "$as_me:$LINENO: result: yes" >&5
|
|
+echo "${ECHO_T}yes" >&6
|
|
+ cat >>confdefs.h <<\_ACEOF
|
|
+#define BX_SPARSE_HD_SUPPORT 1
|
|
+_ACEOF
|
|
+
|
|
+ else
|
|
+ echo "$as_me:$LINENO: result: no" >&5
|
|
+echo "${ECHO_T}no" >&6
|
|
+ cat >>confdefs.h <<\_ACEOF
|
|
+#define BX_SPARSE_HD_SUPPORT 0
|
|
+_ACEOF
|
|
+
|
|
+ fi
|
|
+else
|
|
+
|
|
+ echo "$as_me:$LINENO: result: no" >&5
|
|
+echo "${ECHO_T}no" >&6
|
|
+ cat >>confdefs.h <<\_ACEOF
|
|
+#define BX_SPARSE_HD_SUPPORT 0
|
|
+_ACEOF
|
|
+
|
|
+
|
|
+
|
|
+fi;
|
|
+
|
|
+
|
|
echo "$as_me:$LINENO: checking for NE2000 support" >&5
|
|
echo $ECHO_N "checking for NE2000 support... $ECHO_C" >&6
|
|
# Check whether --enable-ne2000 or --disable-ne2000 was given.
|
|
@@ -23453,6 +23487,7 @@
|
|
s,@IOAPIC_OBJS@,$IOAPIC_OBJS,;t t
|
|
s,@APIC_OBJS@,$APIC_OBJS,;t t
|
|
s,@BX_SPLIT_HD_SUPPORT@,$BX_SPLIT_HD_SUPPORT,;t t
|
|
+s,@BX_SPARSE_HD_SUPPORT@,$BX_SPARSE_HD_SUPPORT,;t t
|
|
s,@NE2K_OBJS@,$NE2K_OBJS,;t t
|
|
s,@NETLOW_OBJS@,$NETLOW_OBJS,;t t
|
|
s,@PCI_OBJ@,$PCI_OBJ,;t t
|
|
Index: configure.in
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/configure.in,v
|
|
retrieving revision 1.198
|
|
diff -u -r1.198 configure.in
|
|
--- configure.in 20 Jan 2003 20:10:25 -0000 1.198
|
|
+++ configure.in 27 Jan 2003 12:37:46 -0000
|
|
@@ -701,6 +701,23 @@
|
|
)
|
|
AC_SUBST(BX_SPLIT_HD_SUPPORT)
|
|
|
|
+AC_MSG_CHECKING(for sparse hard disk image support)
|
|
+AC_ARG_ENABLE(sparse-hd,
|
|
+ [ --enable-sparse-hd allows sparse hard disk image],
|
|
+ [if test "$enableval" = yes; then
|
|
+ AC_MSG_RESULT(yes)
|
|
+ AC_DEFINE(BX_SPARSE_HD_SUPPORT, 1)
|
|
+ else
|
|
+ AC_MSG_RESULT(no)
|
|
+ AC_DEFINE(BX_SPARSE_HD_SUPPORT, 0)
|
|
+ fi],
|
|
+ [
|
|
+ AC_MSG_RESULT(no)
|
|
+ AC_DEFINE(BX_SPARSE_HD_SUPPORT, 0)
|
|
+ ]
|
|
+ )
|
|
+AC_SUBST(BX_SPARSE_HD_SUPPORT)
|
|
+
|
|
AC_MSG_CHECKING(for NE2000 support)
|
|
AC_ARG_ENABLE(ne2000,
|
|
[ --enable-ne2000 enable limited ne2000 support],
|
|
Index: iodev/harddrv.cc
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/iodev/harddrv.cc,v
|
|
retrieving revision 1.94
|
|
diff -u -r1.94 harddrv.cc
|
|
--- iodev/harddrv.cc 5 Jan 2003 03:22:03 -0000 1.94
|
|
+++ iodev/harddrv.cc 27 Jan 2003 12:37:52 -0000
|
|
@@ -31,12 +31,14 @@
|
|
|
|
|
|
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
|
-// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
|
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
|
// is used to know when we are exporting symbols and when we are importing.
|
|
#define BX_PLUGGABLE
|
|
|
|
#include "bochs.h"
|
|
|
|
+#include <sys/mman.h>
|
|
+
|
|
#define LOG_THIS theHardDrive->
|
|
|
|
// WARNING: dangerous options!
|
|
@@ -118,31 +120,43 @@
|
|
#if DLL_HD_SUPPORT
|
|
# error code must be fixed to use DLL_HD_SUPPORT and 4 ata channels
|
|
#endif
|
|
-
|
|
+
|
|
for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
|
|
channels[channel].drives[0].hard_drive = NULL;
|
|
channels[channel].drives[1].hard_drive = NULL;
|
|
put("HD");
|
|
settype(HDLOG);
|
|
+
|
|
#if EXTERNAL_DISK_SIMULATOR
|
|
+
|
|
+// BX_INFO(("External disk simulator"));
|
|
channels[channel].drives[0].hard_drive = new EXTERNAL_DISK_SIMULATOR_CLASS();
|
|
channels[channel].drives[1].hard_drive = new EXTERNAL_DISK_SIMULATOR_CLASS();
|
|
#else
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+// BX_INFO(("Sparse hd support enabled"));
|
|
+
|
|
+ channels[channel].drives[0].hard_drive = new sparse_image_t();
|
|
+ channels[channel].drives[1].hard_drive = new sparse_image_t();
|
|
|
|
+#else
|
|
#if BX_SPLIT_HD_SUPPORT
|
|
+// BX_INFO(("Split hd support"));
|
|
// use new concatenated image object
|
|
channels[channel].drives[0].hard_drive = new concat_image_t();
|
|
-#if DLL_HD_SUPPORT
|
|
- channels[channel].drives[1].hard_drive = new dll_image_t();
|
|
-#else
|
|
- channels[channel].drives[1].hard_drive = new concat_image_t();
|
|
-#endif
|
|
+ #if DLL_HD_SUPPORT
|
|
+ channels[channel].drives[1].hard_drive = new dll_image_t();
|
|
+ #else
|
|
+ channels[channel].drives[1].hard_drive = new concat_image_t();
|
|
+ #endif
|
|
#else
|
|
+// BX_INFO(("Normal hd support"));
|
|
channels[channel].drives[0].hard_drive = new default_image_t();
|
|
-#if DLL_HD_SUPPORT
|
|
- channels[channel].drives[1].hard_drive = new dll_image_t();
|
|
-#else
|
|
- channels[channel].drives[1].hard_drive = new default_image_t();
|
|
+ #if DLL_HD_SUPPORT
|
|
+ channels[channel].drives[1].hard_drive = new dll_image_t();
|
|
+ #else
|
|
+ channels[channel].drives[1].hard_drive = new default_image_t();
|
|
+ #endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
@@ -3161,6 +3175,20 @@
|
|
return ::write(fd, (char*) buf, count);
|
|
}
|
|
|
|
+#if ((BX_SPLIT_HD_SUPPORT) || (BX_SPARSE_HD_SUPPORT))
|
|
+char increment_string (char *str, int diff)
|
|
+{
|
|
+ // find the last character of the string, and increment it.
|
|
+ char *p = str;
|
|
+ while (*p != 0) p++;
|
|
+ BX_ASSERT (p>str); // choke on zero length strings
|
|
+ p--; // point to last character of the string
|
|
+ (*p) += diff; // increment to next/previous ascii code.
|
|
+ BX_DEBUG(("increment string returning '%s'", str));
|
|
+ return (*p);
|
|
+}
|
|
+#endif
|
|
+
|
|
#if BX_SPLIT_HD_SUPPORT
|
|
/*** concat_image_t function definitions ***/
|
|
|
|
@@ -3171,13 +3199,7 @@
|
|
|
|
void concat_image_t::increment_string (char *str)
|
|
{
|
|
- // find the last character of the string, and increment it.
|
|
- char *p = str;
|
|
- while (*p != 0) p++;
|
|
- BX_ASSERT (p>str); // choke on zero length strings
|
|
- p--; // point to last character of the string
|
|
- ++(*p); // increment to next ascii code.
|
|
- BX_DEBUG(("concat_image.increment string returning '%s'", str));
|
|
+ ::increment_string(str, +1);
|
|
}
|
|
|
|
int concat_image_t::open (const char* pathname0)
|
|
@@ -3287,7 +3309,7 @@
|
|
// notice if anyone does sequential read or write without seek in between.
|
|
// This can be supported pretty easily, but needs additional checks for
|
|
// end of a partial image.
|
|
- if (!seek_was_last_op)
|
|
+ if (!seek_was_last_op)
|
|
BX_PANIC( ("no seek before read"));
|
|
return ::read(fd, (char*) buf, count);
|
|
}
|
|
@@ -3303,6 +3325,566 @@
|
|
return ::write(fd, (char*) buf, count);
|
|
}
|
|
#endif /* BX_SPLIT_HD_SUPPORT */
|
|
+
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+/* Do these utility functions maybe already exist elsewhere?
|
|
+*/
|
|
+
|
|
+inline uint32 little_to_local_endian(uint32 value)
|
|
+{
|
|
+#ifdef BX_LITTLE_ENDIAN
|
|
+ // Already in local endian
|
|
+ return value;
|
|
+#else /* BX_BIG_ENDIAN */
|
|
+ return read_32bit(&value);
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
+inline uint32 local_to_little_endian(uint32 value)
|
|
+{
|
|
+#ifdef BX_LITTLE_ENDIAN
|
|
+ // Already in local endian
|
|
+ return value;
|
|
+#else /* BX_BIG_ENDIAN */
|
|
+ uint32 ret = (((value >> 0) & 0xff) << 24) + (((value >> 8) & 0xff) << 16) + (((value >> 16) & 0xff) << 8) + (((value >> 24) & 0xff) << 0);
|
|
+
|
|
+ return ret;
|
|
+#endif
|
|
+}
|
|
+#endif // BX_SPARSE_HD_SUPPORT
|
|
+
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+
|
|
+/*** sparse_image_t function definitions ***/
|
|
+sparse_image_t::sparse_image_t ()
|
|
+{
|
|
+ fd = -1;
|
|
+ pathname = NULL;
|
|
+#ifdef _POSIX_MAPPED_FILES
|
|
+ mmap_header = NULL;
|
|
+#endif
|
|
+ pagetable = NULL;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+void showpagetable(uint32 * pagetable, size_t numpages)
|
|
+{
|
|
+ printf("Non null pages: ");
|
|
+ for (int i = 0; i < numpages; i++)
|
|
+ {
|
|
+ if (pagetable[i] != 0xffffffff)
|
|
+ {
|
|
+ printf("%d ", i);
|
|
+ }
|
|
+ }
|
|
+ printf("\n");
|
|
+}
|
|
+*/
|
|
+
|
|
+
|
|
+void sparse_image_t::read_header()
|
|
+{
|
|
+ BX_ASSERT(sizeof(header) == HEADER_SIZE);
|
|
+
|
|
+ int ret = ::read(fd, &header, sizeof(header));
|
|
+
|
|
+ if (-1 == ret)
|
|
+ {
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ if (sizeof(header) != ret)
|
|
+ {
|
|
+ panic("could not read entire header");
|
|
+ }
|
|
+
|
|
+ if (little_to_local_endian(header.magic) != SPARSE_HEADER_MAGIC)
|
|
+ {
|
|
+ panic("failed header magic check");
|
|
+ }
|
|
+
|
|
+ if (little_to_local_endian(header.version) != 1)
|
|
+ {
|
|
+ panic("unknown version in header");
|
|
+ }
|
|
+
|
|
+ pagesize = little_to_local_endian(header.pagesize);
|
|
+ uint32 numpages = little_to_local_endian(header.numpages);
|
|
+
|
|
+ total_size = pagesize;
|
|
+ total_size *= numpages;
|
|
+
|
|
+ pagesize_shift = 0;
|
|
+ while ((pagesize >> pagesize_shift) > 1) pagesize_shift++;
|
|
+
|
|
+ if ((1 << pagesize_shift) != pagesize)
|
|
+ {
|
|
+ panic("failed block size header check");
|
|
+ }
|
|
+
|
|
+ pagesize_mask = pagesize - 1;
|
|
+
|
|
+ size_t preamble_size = (sizeof(uint32) * numpages) + sizeof(header);
|
|
+ data_start = 0;
|
|
+ while (data_start < preamble_size) data_start += pagesize;
|
|
+
|
|
+ bool did_mmap = false;
|
|
+
|
|
+#ifdef _POSIX_MAPPED_FILES
|
|
+// Try to memory map from the beginning of the file (0 is trivially a page multiple)
|
|
+ void * mmap_header = mmap(NULL, preamble_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
+ if (mmap_header == MAP_FAILED)
|
|
+ {
|
|
+ BX_INFO(("failed to mmap sparse disk file - using conventional file access"));
|
|
+ mmap_header = NULL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ mmap_length = preamble_size;
|
|
+ did_mmap = true;
|
|
+ pagetable = ((uint32 *) (((uint8 *) mmap_header) + sizeof(header)));
|
|
+
|
|
+// system_pagesize = getpagesize();
|
|
+ system_pagesize_mask = getpagesize() - 1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (!did_mmap)
|
|
+ {
|
|
+ pagetable = new uint32[numpages];
|
|
+
|
|
+ if (pagetable == NULL)
|
|
+ {
|
|
+ panic("could not allocate memory for sparse disk block table");
|
|
+ }
|
|
+
|
|
+ ret = ::read(fd, pagetable, sizeof(uint32) * numpages);
|
|
+
|
|
+ if (-1 == ret)
|
|
+ {
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ if ((sizeof(uint32) * numpages) != ret)
|
|
+ {
|
|
+ panic("could not read entire block table");
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int sparse_image_t::open (const char* pathname0)
|
|
+{
|
|
+ pathname = strdup(pathname0);
|
|
+ BX_DEBUG(("sparse_image_t.open"));
|
|
+
|
|
+ fd = ::open(pathname, O_RDWR
|
|
+#ifdef O_BINARY
|
|
+ | O_BINARY
|
|
+#endif
|
|
+ );
|
|
+
|
|
+ if (fd < 0)
|
|
+ {
|
|
+ // open failed.
|
|
+ return -1;
|
|
+ }
|
|
+ BX_DEBUG(("sparse_image: open image %s", pathname));
|
|
+
|
|
+ read_header();
|
|
+
|
|
+ struct stat stat_buf;
|
|
+ if (0 != fstat(fd, &stat_buf)) panic(("fstat() returns error!"));
|
|
+
|
|
+ underlying_filesize = stat_buf.st_size;
|
|
+
|
|
+ if ((underlying_filesize % pagesize) != 0)
|
|
+ panic("size of sparse disk image is not multiple of page size");
|
|
+
|
|
+ underlying_current_filepos = 0;
|
|
+ if (-1 == ::lseek(fd, 0, SEEK_SET))
|
|
+ panic("error while seeking to start of file");
|
|
+
|
|
+ lseek(0, SEEK_SET);
|
|
+
|
|
+ //showpagetable(pagetable, header.numpages);
|
|
+
|
|
+ char * parentpathname = strdup(pathname);
|
|
+ char lastchar = ::increment_string(parentpathname, -1);
|
|
+
|
|
+ if ((lastchar >= '0') && (lastchar <= '9'))
|
|
+ {
|
|
+ struct stat stat_buf;
|
|
+ if (0 == lstat(parentpathname, &stat_buf))
|
|
+ {
|
|
+ parent_image = new sparse_image_t();
|
|
+ int ret = parent_image->open(parentpathname);
|
|
+ if (ret != 0) return ret;
|
|
+ if ( (parent_image->pagesize != pagesize)
|
|
+ || (parent_image->total_size != total_size))
|
|
+ {
|
|
+ panic("child drive image does not have same page count/page size configuration");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (parentpathname != NULL) free(parentpathname);
|
|
+
|
|
+ return 0; // success.
|
|
+}
|
|
+
|
|
+void sparse_image_t::close ()
|
|
+{
|
|
+ BX_DEBUG(("concat_image_t.close"));
|
|
+ if (pathname != NULL)
|
|
+ {
|
|
+ free(pathname);
|
|
+ }
|
|
+#ifdef _POSIX_MAPPED_FILES
|
|
+ if (mmap_header != NULL)
|
|
+ {
|
|
+ int ret = munmap(mmap_header, mmap_length);
|
|
+ if (ret != 0)
|
|
+ BX_INFO(("failed to un-memory map sparse disk file"));
|
|
+ }
|
|
+ pagetable = NULL; // We didn't malloc it
|
|
+#endif
|
|
+ if (fd > -1) {
|
|
+ ::close(fd);
|
|
+ }
|
|
+ if (pagetable != NULL)
|
|
+ {
|
|
+ delete [] pagetable;
|
|
+ }
|
|
+ if (parent_image != NULL)
|
|
+ {
|
|
+ delete parent_image;
|
|
+ }
|
|
+}
|
|
+
|
|
+off_t sparse_image_t::lseek (off_t offset, int whence)
|
|
+{
|
|
+ //showpagetable(pagetable, header.numpages);
|
|
+
|
|
+ if ((offset % 512) != 0)
|
|
+ BX_PANIC( ("lseek HD with offset not multiple of 512"));
|
|
+ if (whence != SEEK_SET)
|
|
+ BX_PANIC( ("lseek HD with whence not SEEK_SET"));
|
|
+
|
|
+ BX_DEBUG(("sparse_image_t.lseek(%d)", whence));
|
|
+
|
|
+ if (offset > total_size)
|
|
+ {
|
|
+ BX_PANIC(("sparse_image_t.lseek to byte %ld failed", (long)offset));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ //printf("Seeking to position %ld\n", (long) offset);
|
|
+
|
|
+ set_virtual_page(offset >> pagesize_shift);
|
|
+ position_page_offset = offset & pagesize_mask;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+inline off_t sparse_image_t::get_physical_offset()
|
|
+{
|
|
+ off_t physical_offset = data_start;
|
|
+ physical_offset += (position_physical_page << pagesize_shift);
|
|
+ physical_offset += position_page_offset;
|
|
+
|
|
+ return physical_offset;
|
|
+}
|
|
+
|
|
+inline void sparse_image_t::set_virtual_page(uint32 new_virtual_page)
|
|
+{
|
|
+ position_virtual_page = new_virtual_page;
|
|
+
|
|
+ position_physical_page = little_to_local_endian(pagetable[position_virtual_page]);
|
|
+}
|
|
+
|
|
+ssize_t sparse_image_t::read_page_fragment(uint32 read_virtual_page, uint32 read_page_offset, size_t read_size, void * buf)
|
|
+{
|
|
+ if (read_virtual_page != position_virtual_page)
|
|
+ {
|
|
+ set_virtual_page(read_virtual_page);
|
|
+ }
|
|
+
|
|
+ position_page_offset = read_page_offset;
|
|
+
|
|
+ if (position_physical_page == PAGE_NOT_ALLOCATED)
|
|
+ {
|
|
+ if (parent_image != NULL)
|
|
+ {
|
|
+ return parent_image->read_page_fragment(read_virtual_page, read_page_offset, read_size, buf);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ memset(buf, read_size, 0);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ off_t physical_offset = get_physical_offset();
|
|
+
|
|
+ if (physical_offset != underlying_current_filepos)
|
|
+ {
|
|
+ int ret = ::lseek(fd, physical_offset, SEEK_SET);
|
|
+ // underlying_current_filepos update deferred
|
|
+ if (ret == -1)
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ //printf("Reading %s at position %ld size %d\n", pathname, (long) physical_offset, (long) read_size);
|
|
+ ssize_t readret = ::read(fd, buf, read_size);
|
|
+
|
|
+ if (readret == -1)
|
|
+ {
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ if (readret != read_size)
|
|
+ {
|
|
+ panic("could not read block contents from file");
|
|
+ }
|
|
+
|
|
+ underlying_current_filepos = physical_offset + read_size;
|
|
+ }
|
|
+
|
|
+ return read_size;
|
|
+}
|
|
+
|
|
+ssize_t sparse_image_t::read(void* buf, size_t count)
|
|
+{
|
|
+ //showpagetable(pagetable, header.numpages);
|
|
+ ssize_t total_read = 0;
|
|
+
|
|
+ if (bx_dbg.disk)
|
|
+ BX_DEBUG(("sparse_image_t.read %ld bytes", (long)count));
|
|
+
|
|
+ while (count != 0)
|
|
+ {
|
|
+ size_t can_read = pagesize - position_page_offset;
|
|
+ if (count < can_read) can_read = count;
|
|
+
|
|
+ BX_ASSERT (can_read != 0);
|
|
+
|
|
+ size_t was_read = read_page_fragment(position_virtual_page, position_page_offset, can_read, buf);
|
|
+
|
|
+ BX_ASSERT(was_read == can_read);
|
|
+
|
|
+ total_read += can_read;
|
|
+
|
|
+ position_page_offset += can_read;
|
|
+ if (position_page_offset == pagesize)
|
|
+ {
|
|
+ position_page_offset = 0;
|
|
+ set_virtual_page(position_virtual_page + 1);
|
|
+ }
|
|
+
|
|
+ BX_ASSERT(position_page_offset < pagesize);
|
|
+
|
|
+ buf = (((uint8 *) buf) + can_read);
|
|
+ count -= can_read;
|
|
+ }
|
|
+
|
|
+ return total_read;
|
|
+}
|
|
+
|
|
+void sparse_image_t::panic(const char * message)
|
|
+{
|
|
+ char buffer[1024];
|
|
+ if (message == NULL)
|
|
+ {
|
|
+ snprintf(buffer, sizeof(buffer), "error with sparse disk image %s", pathname);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ snprintf(buffer, sizeof(buffer), "error with sparse disk image %s - %s", pathname, message);
|
|
+ }
|
|
+ BX_PANIC((buffer));
|
|
+}
|
|
+
|
|
+ssize_t sparse_image_t::write (const void* buf, size_t count)
|
|
+{
|
|
+ //showpagetable(pagetable, header.numpages);
|
|
+
|
|
+ ssize_t total_written = 0;
|
|
+
|
|
+ uint32 update_pagetable_start = position_virtual_page;
|
|
+ uint32 update_pagetable_count = 0;
|
|
+
|
|
+ if (bx_dbg.disk)
|
|
+ BX_DEBUG(("sparse_image_t.write %ld bytes", (long)count));
|
|
+
|
|
+ while (count != 0)
|
|
+ {
|
|
+ size_t can_write = pagesize - position_page_offset;
|
|
+ if (count < can_write) can_write = count;
|
|
+
|
|
+ BX_ASSERT (can_write != 0);
|
|
+
|
|
+ if (position_physical_page == PAGE_NOT_ALLOCATED)
|
|
+ {
|
|
+ // We just add on another page at the end of the file
|
|
+ // Reclamation, compaction etc should currently be done off-line
|
|
+
|
|
+ size_t data_size = underlying_filesize - data_start;
|
|
+ BX_ASSERT((data_size % pagesize) == 0);
|
|
+
|
|
+
|
|
+ uint32 data_size_pages = data_size / pagesize;
|
|
+ uint32 next_data_page = data_size_pages;
|
|
+
|
|
+ pagetable[position_virtual_page] = local_to_little_endian(next_data_page);
|
|
+ position_physical_page = next_data_page;
|
|
+
|
|
+ off_t page_file_start = data_start + (position_physical_page << pagesize_shift);
|
|
+
|
|
+ if (parent_image != NULL)
|
|
+ {
|
|
+ // If we have a parent, we must merge our portion with the parent
|
|
+ void * writebuffer = NULL;
|
|
+
|
|
+ if (can_write == pagesize)
|
|
+ {
|
|
+ writebuffer = (void *) buf;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ writebuffer = malloc(pagesize);
|
|
+ if (writebuffer == NULL)
|
|
+ panic("Cannot allocate sufficient memory for page-merge in write");
|
|
+
|
|
+ // Read entire page - could optimize, but simple for now
|
|
+ parent_image->read_page_fragment(position_virtual_page, 0, pagesize, writebuffer);
|
|
+
|
|
+ void * dest_start = ((uint8 *) writebuffer) + position_page_offset;
|
|
+ memcpy(dest_start, buf, can_write);
|
|
+ }
|
|
+
|
|
+ int ret;
|
|
+ ret = ::lseek(fd, page_file_start, SEEK_SET);
|
|
+ // underlying_current_filepos update deferred
|
|
+ if (-1 == ret) panic(strerror(errno));
|
|
+
|
|
+ ret = ::write(fd, writebuffer, pagesize);
|
|
+
|
|
+ if (-1 == ret) panic(strerror(errno));
|
|
+
|
|
+ if (pagesize != ret) panic("failed to write entire merged page to disk");
|
|
+
|
|
+ if (can_write != pagesize)
|
|
+ {
|
|
+ free(writebuffer);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ // We need to write a zero page because read has been returning zeroes
|
|
+ // We seek as close to the page end as possible, and then write a little
|
|
+ // This produces a sparse file which has blanks
|
|
+ // Also very quick, even when pagesize is massive
|
|
+ int ret;
|
|
+ ret = ::lseek(fd, page_file_start + pagesize - 4, SEEK_SET);
|
|
+ // underlying_current_filepos update deferred
|
|
+ if (-1 == ret) panic(strerror(errno));
|
|
+
|
|
+ uint32 zero = 0;
|
|
+ ret = ::write(fd, &zero, 4);
|
|
+
|
|
+ if (-1 == ret) panic(strerror(errno));
|
|
+
|
|
+ if (4 != ret) panic("failed to write entire blank page to disk");
|
|
+ }
|
|
+
|
|
+ update_pagetable_count = (position_virtual_page - update_pagetable_start) + 1;
|
|
+ underlying_filesize = underlying_current_filepos = page_file_start + pagesize;
|
|
+ }
|
|
+
|
|
+ BX_ASSERT(position_physical_page != PAGE_NOT_ALLOCATED);
|
|
+
|
|
+ off_t physical_offset = get_physical_offset();
|
|
+
|
|
+ if (physical_offset != underlying_current_filepos)
|
|
+ {
|
|
+ int ret = ::lseek(fd, physical_offset, SEEK_SET);
|
|
+ // underlying_current_filepos update deferred
|
|
+ if (ret == -1)
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ //printf("Writing at position %ld size %d\n", (long) physical_offset, can_write);
|
|
+ ssize_t writeret = ::write(fd, buf, can_write);
|
|
+
|
|
+ if (writeret == -1)
|
|
+ {
|
|
+ panic(strerror(errno));
|
|
+ }
|
|
+
|
|
+ if (writeret != can_write)
|
|
+ {
|
|
+ panic("could not write block contents to file");
|
|
+ }
|
|
+
|
|
+ underlying_current_filepos = physical_offset + can_write;
|
|
+
|
|
+ total_written += can_write;
|
|
+
|
|
+ position_page_offset += can_write;
|
|
+ if (position_page_offset == pagesize)
|
|
+ {
|
|
+ position_page_offset = 0;
|
|
+ set_virtual_page(position_virtual_page + 1);
|
|
+ }
|
|
+
|
|
+ BX_ASSERT(position_page_offset < pagesize);
|
|
+
|
|
+ buf = (((uint8 *) buf) + can_write);
|
|
+ count -= can_write;
|
|
+ }
|
|
+
|
|
+ if (update_pagetable_count != 0)
|
|
+ {
|
|
+ bool done = false;
|
|
+ off_t pagetable_write_from = sizeof(header) + (sizeof(uint32) * update_pagetable_start);
|
|
+ size_t write_bytecount = update_pagetable_count * sizeof(uint32);
|
|
+
|
|
+#ifdef _POSIX_MAPPED_FILES
|
|
+ if (mmap_header != NULL)
|
|
+ {
|
|
+ // Sync from the beginning of the page
|
|
+ size_t system_page_offset = pagetable_write_from & system_pagesize_mask;
|
|
+ void * start = ((uint8 *) mmap_header + pagetable_write_from - system_page_offset);
|
|
+
|
|
+ int ret = msync(start, system_page_offset + write_bytecount, MS_ASYNC);
|
|
+
|
|
+ if (ret != 0)
|
|
+ panic(strerror(errno));
|
|
+
|
|
+ done = true;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (!done)
|
|
+ {
|
|
+ int ret = ::lseek(fd, pagetable_write_from, SEEK_SET);
|
|
+ // underlying_current_filepos update deferred
|
|
+ if (ret == -1) panic(strerror(errno));
|
|
+
|
|
+ //printf("Writing header at position %ld size %ld\n", (long) pagetable_write_from, (long) write_bytecount);
|
|
+ ret = ::write(fd, &pagetable[update_pagetable_start], write_bytecount);
|
|
+ if (ret == -1) panic(strerror(errno));
|
|
+ if (ret != write_bytecount) panic("could not write entire updated block header");
|
|
+
|
|
+ underlying_current_filepos = pagetable_write_from + write_bytecount;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return total_written;
|
|
+}
|
|
+#endif /* BX_SPARSE_HD_SUPPORT */
|
|
|
|
#if DLL_HD_SUPPORT
|
|
/*** dll_image_t function definitions ***/
|
|
Index: iodev/harddrv.h
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/iodev/harddrv.h,v
|
|
retrieving revision 1.18
|
|
diff -u -r1.18 harddrv.h
|
|
--- iodev/harddrv.h 25 Oct 2002 11:44:40 -0000 1.18
|
|
+++ iodev/harddrv.h 27 Jan 2003 12:37:53 -0000
|
|
@@ -24,6 +24,32 @@
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
+
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+
|
|
+// Format of a sparse file:
|
|
+// 256 byte header, containing details such as page size and number of pages
|
|
+// Page indirection table, mapping virtual pages to physical pages within file
|
|
+// Physical pages till end of file
|
|
+
|
|
+#define SPARSE_HEADER_MAGIC (0x02468ace)
|
|
+#define SPARSE_HEADER_VERSION 1
|
|
+#define HEADER_SIZE (256) // Plenty of room for later
|
|
+#define PAGE_NOT_ALLOCATED (0xffffffff)
|
|
+
|
|
+ typedef struct
|
|
+ {
|
|
+ uint32 magic;
|
|
+ uint32 version;
|
|
+ uint32 pagesize;
|
|
+ uint32 numpages;
|
|
+
|
|
+ uint32 padding[60];
|
|
+ } sparse_header_t;
|
|
+#endif /* BX_SPARSE_HD_SUPPORT */
|
|
+
|
|
+#ifndef INCLUDE_ONLY_SPARSE_HEADER
|
|
+
|
|
typedef enum _sense {
|
|
SENSE_NONE = 0, SENSE_NOT_READY = 2, SENSE_ILLEGAL_REQUEST = 5,
|
|
SENSE_UNIT_ATTENTION = 6
|
|
@@ -87,7 +113,7 @@
|
|
|
|
private:
|
|
int fd;
|
|
-
|
|
+
|
|
};
|
|
|
|
#if BX_SPLIT_HD_SUPPORT
|
|
@@ -137,6 +163,77 @@
|
|
};
|
|
#endif /* BX_SPLIT_HD_SUPPORT */
|
|
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+
|
|
+class sparse_image_t : public device_image_t
|
|
+{
|
|
+ public:
|
|
+ // Default constructor
|
|
+ sparse_image_t();
|
|
+
|
|
+ // Open a image. Returns non-negative if successful.
|
|
+ int open (const char* pathname);
|
|
+
|
|
+ // Close the image.
|
|
+ void close ();
|
|
+
|
|
+ // Position ourselves. Return the resulting offset from the
|
|
+ // beginning of the file.
|
|
+ off_t lseek (off_t offset, int whence);
|
|
+
|
|
+ // Read count bytes to the buffer buf. Return the number of
|
|
+ // bytes read (count).
|
|
+ ssize_t read (void* buf, size_t count);
|
|
+
|
|
+ // Write count bytes from buf. Return the number of bytes
|
|
+ // written (count).
|
|
+ ssize_t write (const void* buf, size_t count);
|
|
+
|
|
+ private:
|
|
+ int fd;
|
|
+
|
|
+#ifdef _POSIX_MAPPED_FILES
|
|
+ void * mmap_header;
|
|
+ size_t mmap_length;
|
|
+ size_t system_pagesize_mask;
|
|
+#endif
|
|
+ uint32 * pagetable;
|
|
+
|
|
+ // Header is written to disk in little-endian (x86) format
|
|
+ // Thus needs to be converted on big-endian systems before read
|
|
+ // The pagetable is also kept little endian
|
|
+
|
|
+ sparse_header_t header;
|
|
+
|
|
+ uint32 pagesize;
|
|
+ int pagesize_shift;
|
|
+ uint32 pagesize_mask;
|
|
+
|
|
+ off_t data_start;
|
|
+ off_t underlying_filesize;
|
|
+
|
|
+ char * pathname;
|
|
+
|
|
+ off_t position;
|
|
+
|
|
+ uint32 position_virtual_page;
|
|
+ uint32 position_physical_page;
|
|
+ uint32 position_page_offset;
|
|
+
|
|
+ off_t underlying_current_filepos;
|
|
+
|
|
+ off_t total_size;
|
|
+
|
|
+ void panic(const char * message);
|
|
+ off_t sparse_image_t::get_physical_offset();
|
|
+ void sparse_image_t::set_virtual_page(uint32 new_virtual_page);
|
|
+ void read_header();
|
|
+ ssize_t read_page_fragment(uint32 read_virtual_page, uint32 read_page_offset, size_t read_size, void * buf);
|
|
+
|
|
+ sparse_image_t * parent_image;
|
|
+};
|
|
+#endif /* BX_SPARSE_HD_SUPPORT */
|
|
+
|
|
#if EXTERNAL_DISK_SIMULATOR
|
|
#include "external-disk-simulator.h"
|
|
#endif
|
|
@@ -367,3 +464,5 @@
|
|
#endif
|
|
|
|
};
|
|
+
|
|
+#endif
|
|
Index: misc/bximage.c
|
|
===================================================================
|
|
RCS file: /cvsroot/bochs/bochs/misc/bximage.c,v
|
|
retrieving revision 1.17
|
|
diff -u -r1.17 bximage.c
|
|
--- misc/bximage.c 26 Nov 2002 11:21:31 -0000 1.17
|
|
+++ misc/bximage.c 27 Jan 2003 12:37:53 -0000
|
|
@@ -1,4 +1,4 @@
|
|
-/*
|
|
+/*
|
|
* misc/bximage.c
|
|
* $Id: patch.sparsedisk-justinsb,v 1.2 2003-03-04 21:05:38 cbothamy Exp $
|
|
*
|
|
@@ -16,6 +16,18 @@
|
|
#endif
|
|
#include "config.h"
|
|
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+#include <string.h>
|
|
+
|
|
+#define uint8 Bit8u
|
|
+#define uint16 Bit16u
|
|
+#define uint32 Bit32u
|
|
+
|
|
+#define INCLUDE_ONLY_SPARSE_HEADER 1
|
|
+#include "../iodev/harddrv.h"
|
|
+
|
|
+#endif // BX_SPARSE_HD_SUPPORT
|
|
+
|
|
char *EOF_ERR = "ERROR: End of input";
|
|
char *rcsid = "$Id: patch.sparsedisk-justinsb,v 1.2 2003-03-04 21:05:38 cbothamy Exp $";
|
|
char *divider = "========================================================================";
|
|
@@ -190,12 +202,41 @@
|
|
return 0;
|
|
}
|
|
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+// fileset is like memset but for a file handle
|
|
+void fileset(FILE * fp, int c, size_t n)
|
|
+{
|
|
+#define BLOCK_SIZE (1024)
|
|
+ int block[BLOCK_SIZE];
|
|
+ size_t left_to_write = n;
|
|
+
|
|
+ memset(block, c, sizeof(block));
|
|
+
|
|
+ while (left_to_write > 0)
|
|
+ {
|
|
+ size_t write = sizeof(block);
|
|
+ if (write > left_to_write) write = left_to_write;
|
|
+
|
|
+ if (1 != fwrite(block, write, 1, fp))
|
|
+ {
|
|
+ fclose (fp);
|
|
+ fatal ("ERROR: The disk image is not complete - could not write data block!");
|
|
+ }
|
|
+
|
|
+ left_to_write -= write;
|
|
+ }
|
|
+
|
|
+}
|
|
+#endif
|
|
+
|
|
/* produce the image file */
|
|
-int make_image (Bit64u sec, char *filename)
|
|
+int make_image (Bit64u sec, char *filename, int sparse)
|
|
{
|
|
- FILE *fp;
|
|
+ FILE *fp;
|
|
char buffer[1024];
|
|
-
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+ Bit64u numpages;
|
|
+#endif
|
|
// check if it exists before trashing someone's disk image
|
|
fp = fopen (filename, "r");
|
|
if (fp) {
|
|
@@ -203,7 +244,7 @@
|
|
sprintf (buffer, "\nThe disk image '%s' already exists. Are you sure you want to replace it?\nPlease type yes or no. [no] ", filename);
|
|
if (ask_yn (buffer, 0, &confirm) < 0)
|
|
fatal (EOF_ERR);
|
|
- if (!confirm)
|
|
+ if (!confirm)
|
|
fatal ("ERROR: Aborted");
|
|
fclose (fp);
|
|
}
|
|
@@ -221,27 +262,69 @@
|
|
|
|
printf ("\nWriting: [");
|
|
|
|
- /*
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+ if (sparse)
|
|
+ {
|
|
+ sparse_header_t header;
|
|
+ size_t sizesofar;
|
|
+ size_t padtopagesize;
|
|
+
|
|
+ memset(&header, 0, sizeof(header));
|
|
+ header.magic = SPARSE_HEADER_MAGIC;
|
|
+ header.version = SPARSE_HEADER_VERSION;
|
|
+
|
|
+ header.pagesize = (1 << 10) * 32; // Use 32 KB Pages - could be configurable
|
|
+ numpages = (sec / (header.pagesize / 512)) + 1;
|
|
+
|
|
+ header.numpages = numpages;
|
|
+
|
|
+ if (numpages != header.numpages)
|
|
+ {
|
|
+ fclose (fp);
|
|
+ fatal ("ERROR: The disk image is too large for a sparse image!");
|
|
+ // Could increase page size here.
|
|
+ // But note this only happens at 128 Terabytes!
|
|
+ }
|
|
+
|
|
+ if (fwrite(&header, sizeof(header), 1, fp) != 1)
|
|
+ {
|
|
+ fclose (fp);
|
|
+ fatal ("ERROR: The disk image is not complete - could not write header!");
|
|
+ }
|
|
+
|
|
+ fileset(fp, 0xff, 4 * header.numpages);
|
|
+
|
|
+ sizesofar = HEADER_SIZE + (4 * header.numpages);
|
|
+ padtopagesize = header.pagesize - (sizesofar & (header.pagesize - 1));
|
|
+
|
|
+ fileset(fp, 0, padtopagesize);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (!sparse)
|
|
+ {
|
|
+ /*
|
|
* seek to sec*512-1 and write a single character.
|
|
* can't just do: fseek(fp, 512*sec-1, SEEK_SET)
|
|
* because 512*sec may be too large for signed int.
|
|
*/
|
|
- while (sec > 0)
|
|
- {
|
|
- /* temp <-- min(sec, 4194303)
|
|
+ while (sec > 0)
|
|
+ {
|
|
+ /* temp <-- min(sec, 4194303)
|
|
* 4194303 is (int)(0x7FFFFFFF/512)
|
|
*/
|
|
- long temp = ((sec < 4194303) ? sec : 4194303);
|
|
- fseek(fp, 512*temp, SEEK_CUR);
|
|
- sec -= temp;
|
|
- }
|
|
-
|
|
- fseek(fp, -1, SEEK_CUR);
|
|
- if (fputc('\0', fp) == EOF)
|
|
- {
|
|
- fclose (fp);
|
|
- fatal ("ERROR: The disk image is not complete!");
|
|
- }
|
|
+ long temp = ((sec < 4194303) ? sec : 4194303);
|
|
+ fseek(fp, 512*temp, SEEK_CUR);
|
|
+ sec -= temp;
|
|
+ }
|
|
+
|
|
+ fseek(fp, -1, SEEK_CUR);
|
|
+ if (fputc('\0', fp) == EOF)
|
|
+ {
|
|
+ fclose (fp);
|
|
+ fatal ("ERROR: The disk image is not complete!");
|
|
+ }
|
|
+ }
|
|
|
|
printf ("] Done.\n");
|
|
fclose (fp);
|
|
@@ -254,6 +337,7 @@
|
|
Bit64s sectors = 0;
|
|
char filename[256];
|
|
char bochsrc_line[256];
|
|
+ int sparse = 0;
|
|
print_banner ();
|
|
filename[0] = 0;
|
|
if (ask_menu (fdhd_menu, fdhd_n_choices, fdhd_choices, 1, &hd) < 0)
|
|
@@ -273,6 +357,10 @@
|
|
printf (" total size=%.2f megabytes\n", (float)sectors*512.0/1024.0/1024.0);
|
|
if (ask_string ("\nWhat should I name the image?\n[c.img] ", "c.img", filename) < 0)
|
|
fatal (EOF_ERR);
|
|
+#if BX_SPARSE_HD_SUPPORT
|
|
+ if (ask_yn ("\nShould I create a sparse image?\nPlease type yes or no. [no] ", 0, &sparse) < 0)
|
|
+ fatal (EOF_ERR);
|
|
+#endif //BX_SPARSE_HD_SUPPORT
|
|
sprintf (bochsrc_line, "ata0-master: type=disk, path=\"%s\", cylinders=%d, heads=%d, spt=%d", filename, cyl, heads, spt);
|
|
} else {
|
|
int fdsize, cyl=0, heads=0, spt=0;
|
|
@@ -285,7 +373,7 @@
|
|
case 2: name="1_2"; cyl=80; heads=2; spt=15; break; /* 1.2 meg */
|
|
case 3: name="1_44"; cyl=80; heads=2; spt=18; break; /* 1.44 meg */
|
|
case 4: name="2_88"; cyl=80; heads=2; spt=36; break; /* 2.88 meg */
|
|
- default:
|
|
+ default:
|
|
fatal ("ERROR: fdsize out of range");
|
|
}
|
|
sectors = cyl*heads*spt;
|
|
@@ -303,13 +391,13 @@
|
|
fatal ("ERROR: Illegal disk size!");
|
|
if (strlen (filename) < 1)
|
|
fatal ("ERROR: Illegal filename");
|
|
- make_image (sectors, filename);
|
|
+ make_image (sectors, filename, sparse);
|
|
printf ("\nI wrote %lld bytes to %s.\n", sectors*512, filename);
|
|
printf ("\nThe following line should appear in your bochsrc:\n");
|
|
printf (" %s\n", bochsrc_line);
|
|
myexit(0);
|
|
|
|
// make picky compilers (c++, gcc) happy,
|
|
- // even though we leave via 'myexit' just above
|
|
+ // even though we leave via 'myexit' just above
|
|
return 0;
|
|
}
|