Updates for version 0.4.2
New feature: Ability to edit disk images.
Several small bug fixes and feature enhancements (see CHANGELOG).
diff --git a/support.cc b/support.cc
index 798aff8..e5b1860 100644
--- a/support.cc
+++ b/support.cc
@@ -15,6 +15,7 @@
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/stat.h>
#include "support.h"
#include <sys/types.h>
@@ -184,8 +185,9 @@
return theValue;
} // BlocksToSI()
-// Returns block size of device pointed to by fd file descriptor, or -1
-// if there's a problem
+// Returns block size of device pointed to by fd file descriptor. If the ioctl
+// returns an error condition, print a warning but return a value of SECTOR_SIZE
+// (512)..
int GetBlockSize(int fd) {
int err, result;
@@ -199,13 +201,21 @@
#endif
#endif
+ if (err == -1) {
+ result = SECTOR_SIZE;
+ // ENOTTY = inappropriate ioctl; probably being called on a disk image
+ // file, so don't display the warning message....
+ if (errno != ENOTTY) {
+ printf("\aError %d when determining sector size! Setting sector size to %d\n",
+ errno, SECTOR_SIZE);
+ } // if
+ } // if
+
if (result != 512) {
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to ");
printf("misbehave!\nProceed at your own risk!\n\n");
} // if
- if (err == -1)
- result = -1;
return (result);
} // GetBlockSize()
@@ -380,7 +390,37 @@
fd = open(deviceFilename, O_WRONLY|O_SHLOCK);
} // if
#endif
-} // MyOpen()
+ return fd;
+} // OpenForWrite()
+
+// Resync disk caches so the OS uses the new partition table. This code varies
+// a lot from one OS to another.
+void DiskSync(int fd) {
+ int i;
+
+ sync();
+#ifdef __APPLE__
+ printf("Warning: The kernel may continue to use old or deleted partitions.\n"
+ "You should reboot or remove the drive.\n");
+ /* don't know if this helps
+ * it definitely will get things on disk though:
+ * http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
+ i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
+#else
+#ifdef __FreeBSD__
+ sleep(2);
+ i = ioctl(fd, DIOCGFLUSH);
+ printf("Warning: The kernel may continue to use old or deleted partitions.\n"
+ "You should reboot or remove the drive.\n");
+#else
+ sleep(2);
+ i = ioctl(fd, BLKRRPART);
+ if (i)
+ printf("Warning: The kernel is still using the old partition table.\n"
+ "The new table will be used at the next reboot.\n");
+#endif
+#endif
+} // DiskSync()
/**************************************************************************************
* *
@@ -392,35 +432,62 @@
// The disksize function is taken from the Linux fdisk code and modified
// to work around a problem returning a uint64_t value on Mac OS.
uint64_t disksize(int fd, int *err) {
- long sz; // Do not delete; needed for Linux
- long long b; // Do not delete; needed for Linux
- uint64_t sectors;
+ long sz; // Do not delete; needed for Linux
+ long long b; // Do not delete; needed for Linux
+ uint64_t sectors = 0, bytes = 0; // size in sectors & bytes
+ struct stat st;
- // Note to self: I recall testing a simplified version of
- // this code, similar to what's in the __APPLE__ block,
- // on Linux, but I had some problems. IIRC, it ran OK on 32-bit
- // systems but not on 64-bit. Keep this in mind in case of
- // 32/64-bit issues on MacOS....
+ // Note to self: I recall testing a simplified version of
+ // this code, similar to what's in the __APPLE__ block,
+ // on Linux, but I had some problems. IIRC, it ran OK on 32-bit
+ // systems but not on 64-bit. Keep this in mind in case of
+ // 32/64-bit issues on MacOS....
#ifdef __APPLE__
- *err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
+ *err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
#else
#ifdef __FreeBSD__
- *err = ioctl(fd, DIOCGMEDIASIZE, &sz);
- b = GetBlockSize(fd);
- sectors = sz / b;
+ *err = ioctl(fd, DIOCGMEDIASIZE, &sz);
+ b = GetBlockSize(fd);
+ sectors = sz / b;
#else
- *err = ioctl(fd, BLKGETSIZE, &sz);
- if (*err) {
- sz = 0;
- if (errno != EFBIG)
- return sz;
- }
- *err = ioctl(fd, BLKGETSIZE64, &b);
- if (*err || b == 0 || b == sz)
- sectors = sz;
- else
- sectors = (b >> 9);
+ *err = ioctl(fd, BLKGETSIZE, &sz);
+ if (*err) {
+ sectors = sz = 0;
+ } // if
+ if ((errno == EFBIG) || (!*err)) {
+ *err = ioctl(fd, BLKGETSIZE64, &b);
+ if (*err || b == 0 || b == sz)
+ sectors = sz;
+ else
+ sectors = (b >> 9);
+ } // if
+
+// if (*err) {
+// sz = 0;
+// if (errno != EFBIG)
+// return sz;
+// }
+// *err = ioctl(fd, BLKGETSIZE64, &b);
+// if (*err || b == 0 || b == sz)
+// sectors = sz;
+// else
+// sectors = (b >> 9);
+
#endif
#endif
- return sectors;
+
+ // The above methods have failed (or it's a bum filename reference),
+ // so let's assume it's a regular file (a QEMU image, dd backup, or
+ // what have you) and see what stat() gives us....
+ if (sectors == 0) {
+ if (fstat(fd, &st) == 0) {
+ bytes = (uint64_t) st.st_size;
+ if ((bytes % UINT64_C(512)) != 0)
+ fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
+ " Misbehavior is likely!\n\a");
+ sectors = bytes / UINT64_C(512);
+ } // if
+ } // if
+// printf("In disksize(), sectors is %lld.\n", sectors);
+ return sectors;
}