New files to support I/O restructuring and (currently broken) Windows
version.
diff --git a/Makefile.mingw b/Makefile.mingw
new file mode 100644
index 0000000..0976a5a
--- /dev/null
+++ b/Makefile.mingw
@@ -0,0 +1,37 @@
+CC=/usr/bin/i586-mingw32msvc-gcc
+CXX=/usr/bin/i586-mingw32msvc-g++
+CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
+CXXFLAGS=-O2 -DMINGW -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
+LIB_NAMES=gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
+LIB_SRCS=$(NAMES:=.cc)
+LIB_OBJS=$(LIB_NAMES:=.o)
+LIB_HEADERS=$(LIB_NAMES:=.h)
+DEPEND= makedepend $(CFLAGS)
+
+#$(APPNAME):	$(MBR2GPT_OBJS)
+#	$(CC) $(MBR2GPT_OBJS) -o $@
+
+all:	gdisk
+
+gdisk:	$(LIB_OBJS) gdisk.o
+	$(CXX) $(LIB_OBJS) gdisk.o -o gdisk.exe
+
+sgdisk: $(LIB_OBJS) sgdisk.o
+	$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk
+
+wipegpt:	$(LIB_OBJS) wipegpt.o
+	$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
+
+lint:	#no pre-reqs
+	lint $(SRCS)
+
+clean:	#no pre-reqs
+	rm -f core *.o *~ gdisk sgdisk
+
+# what are the source dependencies
+depend: $(SRCS)
+	$(DEPEND) $(SRCS)
+
+$(OBJS):
+
+# DO NOT DELETE
diff --git a/diskio-unix.cc b/diskio-unix.cc
new file mode 100644
index 0000000..573af56
--- /dev/null
+++ b/diskio-unix.cc
@@ -0,0 +1,366 @@
+//
+// C++ Interface: diskio (Unix components [Linux, FreeBSD, Mac OS X])
+//
+// Description: Class to handle low-level disk I/O for GPT fdisk
+//
+//
+// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
+// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
+
+#define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <iostream>
+
+#include "support.h"
+#include "diskio.h"
+
+using namespace std;
+
+// Returns the official "real" name for a shortened version of same.
+// Trivial here; more important in Windows
+void DiskIO::MakeRealName(void) {
+   realFilename = userFilename;
+} // DiskIO::MakeRealName()
+
+// Open the currently on-record file for reading
+int DiskIO::OpenForRead(void) {
+   int shouldOpen = 1;
+
+   if (isOpen) { // file is already open
+      if (openForWrite) {
+         Close();
+      } else {
+         shouldOpen = 0;
+      } // if/else
+   } // if
+
+   if (shouldOpen) {
+      fd = open(realFilename.c_str(), O_RDONLY);
+      if (fd == -1) {
+         fprintf(stderr, "Problem opening %s for reading! Error is %d\n",
+                 realFilename.c_str(), errno);
+         if (errno == EACCES) { // User is probably not running as root
+            fprintf(stderr, "You must run this program as root or use sudo!\n");
+         } // if
+         realFilename = "";
+         userFilename = "";
+         isOpen = 0;
+         openForWrite = 0;
+      } else {
+         isOpen = 1;
+         openForWrite = 0;
+      } // if/else
+   } // if
+
+   return isOpen;
+} // DiskIO::OpenForRead(void)
+
+// An extended file-open function. This includes some system-specific checks.
+// Returns 1 if the file is open, 0 otherwise....
+int DiskIO::OpenForWrite(void) {
+   if ((isOpen) && (openForWrite))
+      return 1;
+
+   // Close the disk, in case it's already open for reading only....
+   Close();
+
+   // try to open the device; may fail....
+   fd = open(realFilename.c_str(), O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+#ifdef __APPLE__
+   // MacOS X requires a shared lock under some circumstances....
+   if (fd < 0) {
+      fd = open(realFilename.c_str(), O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH | O_SHLOCK);
+   } // if
+#endif
+   if (fd >= 0) {
+      isOpen = 1;
+      openForWrite = 1;
+   } else {
+      isOpen = 0;
+      openForWrite = 0;
+   } // if/else
+   return isOpen;
+} // DiskIO::OpenForWrite(void)
+
+// Close the disk device. Note that this does NOT erase the stored filenames,
+// so the file can be re-opened without specifying the filename.
+void DiskIO::Close(void) {
+   if (isOpen)
+      close(fd);
+   isOpen = 0;
+   openForWrite = 0;
+} // DiskIO::Close()
+
+// 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 DiskIO::GetBlockSize(void) {
+   int err = -1, blockSize = 0;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+#ifdef __APPLE__
+      err = ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize);
+#endif
+#ifdef __FreeBSD__
+      err = ioctl(fd, DIOCGSECTORSIZE, &blockSize);
+#endif
+#ifdef __linux__
+      err = ioctl(fd, BLKSSZGET, &blockSize);
+#endif
+
+      if (err == -1) {
+         blockSize = SECTOR_SIZE;
+         // ENOTTY = inappropriate ioctl; probably being called on a disk image
+         // file, so don't display the warning message....
+         // 32-bit code returns EINVAL, I don't know why. I know I'm treading on
+         // thin ice here, but it should be OK in all but very weird cases....
+         if ((errno != ENOTTY) && (errno != EINVAL)) {
+            printf("\aError %d when determining sector size! Setting sector size to %d\n",
+                  errno, SECTOR_SIZE);
+         } // if
+      } // if (err == -1)
+   } // if (isOpen)
+
+   return (blockSize);
+} // DiskIO::GetBlockSize()
+
+// Resync disk caches so the OS uses the new partition table. This code varies
+// a lot from one OS to another.
+void DiskIO::DiskSync(void) {
+   int i, platformFound = 0;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+      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);
+      platformFound++;
+#endif
+#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");
+      platformFound++;
+#endif
+#ifdef __linux__
+      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");
+      platformFound++;
+#endif
+      if (platformFound == 0)
+         fprintf(stderr, "Warning: Platform not recognized!\n");
+      if (platformFound > 1)
+         fprintf(stderr, "\nWarning: We seem to be running on multiple platforms!\n");
+   } // if (isOpen)
+} // DiskIO::DiskSync()
+
+// Seek to the specified sector. Returns 1 on success, 0 on failure.
+int DiskIO::Seek(uint64_t sector) {
+   int retval = 1;
+   off_t seekTo, sought;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      retval = OpenForRead();
+   } // if
+
+   if (isOpen) {
+      seekTo = sector * (uint64_t) GetBlockSize();
+      sought = lseek64(fd, seekTo, SEEK_SET);
+      if (sought != seekTo) {
+         retval = 0;
+      } // if
+   } // if
+   return retval;
+} // DiskIO::Seek()
+
+// A variant on the standard read() function. Done to work around
+// limitations in FreeBSD concerning the matching of the sector
+// size with the number of bytes read.
+// Returns the number of bytes read into buffer.
+int DiskIO::Read(void* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks, retval = 0;
+   char* tempSpace;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+      // Compute required space and allocate memory
+      blockSize = GetBlockSize();
+      if (numBytes <= blockSize) {
+         numBlocks = 1;
+         tempSpace = (char*) malloc(blockSize);
+      } else {
+         numBlocks = numBytes / blockSize;
+         if ((numBytes % blockSize) != 0) numBlocks++;
+         tempSpace = (char*) malloc(numBlocks * blockSize);
+      } // if/else
+
+      // Read the data into temporary space, then copy it to buffer
+      retval = read(fd, tempSpace, numBlocks * blockSize);
+      memcpy(buffer, tempSpace, numBytes);
+/*      for (i = 0; i < numBytes; i++) {
+         ((char*) buffer)[i] = tempSpace[i];
+      } // for */
+
+      // Adjust the return value, if necessary....
+      if (((numBlocks * blockSize) != numBytes) && (retval > 0))
+         retval = numBytes;
+
+      free(tempSpace);
+   } // if (isOpen)
+   return retval;
+} // DiskIO::Read()
+
+// A variant on the standard write() function. Done to work around
+// limitations in FreeBSD concerning the matching of the sector
+// size with the number of bytes read.
+// Returns the number of bytes written.
+int DiskIO::Write(void* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks, retval = 0;
+   char* tempSpace;
+
+   // If disk isn't open, try to open it....
+   if ((!isOpen) || (!openForWrite)) {
+      OpenForWrite();
+   } // if
+
+   if (isOpen) {
+      // Compute required space and allocate memory
+      blockSize = GetBlockSize();
+      if (numBytes <= blockSize) {
+         numBlocks = 1;
+         tempSpace = (char*) malloc(blockSize);
+      } else {
+         numBlocks = numBytes / blockSize;
+         if ((numBytes % blockSize) != 0) numBlocks++;
+         tempSpace = (char*) malloc(numBlocks * blockSize);
+      } // if/else
+
+      // Copy the data to my own buffer, then write it
+/*      for (i = 0; i < numBytes; i++) {
+         tempSpace[i] = ((char*) buffer)[i];
+      } // for */
+      memcpy(tempSpace, buffer, numBytes);
+      for (i = numBytes; i < numBlocks * blockSize; i++) {
+         tempSpace[i] = 0;
+      } // for
+      retval = write(fd, tempSpace, numBlocks * blockSize);
+
+      // Adjust the return value, if necessary....
+      if (((numBlocks * blockSize) != numBytes) && (retval > 0))
+         retval = numBytes;
+
+      free(tempSpace);
+   } // if (isOpen)
+   return retval;
+} // DiskIO:Write()
+
+/**************************************************************************************
+ *                                                                                    *
+ * Below functions are lifted from various sources, as documented in comments before  *
+ * each one.                                                                          *
+ *                                                                                    *
+ **************************************************************************************/
+
+// The disksize function is taken from the Linux fdisk code and modified
+// greatly since then to enable FreeBSD and MacOS support, as well as to
+// return correct values for disk image files.
+uint64_t DiskIO::DiskSize(int *err) {
+   long sz; // Do not delete; needed for Linux
+   long long b; // Do not delete; needed for Linux
+   uint64_t sectors = 0; // size in sectors
+   off_t bytes = 0; // size in bytes
+   struct stat64 st;
+   int platformFound = 0;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+      // 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, &sectors);
+      platformFound++;
+#endif
+#ifdef __FreeBSD__
+      *err = ioctl(fd, DIOCGMEDIASIZE, &bytes);
+      b = GetBlockSize();
+      sectors = bytes / b;
+      platformFound++;
+#endif
+#ifdef __linux__
+      *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
+      // Unintuitively, the above returns values in 512-byte blocks, no
+      // matter what the underlying device's block size. Correct for this....
+      sectors /= (GetBlockSize() / 512);
+      platformFound++;
+#endif
+      if (platformFound != 1)
+         fprintf(stderr, "Warning! We seem to be running on no known platform!\n");
+
+      // The above methods have failed, so let's assume it's a regular
+      // file (a QEMU image, dd backup, or what have you) and see what
+      // fstat() gives us....
+      if ((sectors == 0) || (*err == -1)) {
+         if (fstat64(fd, &st) == 0) {
+            bytes = (off_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
+   } // if (isOpen)
+   return sectors;
+} // DiskIO::DiskSize()
diff --git a/diskio-windows.cc b/diskio-windows.cc
new file mode 100644
index 0000000..84b77ee
--- /dev/null
+++ b/diskio-windows.cc
@@ -0,0 +1,345 @@
+//
+// C++ Interface: diskio (Windows-specific components)
+//
+// Description: Class to handle low-level disk I/O for GPT fdisk
+//
+//
+// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+// This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
+// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
+
+#define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+
+#include <windows.h>
+#include <winioctl.h>
+#define fstat64 fstat
+#define stat64 stat
+#define S_IRGRP 0
+#define S_IROTH 0
+#include <stdio.h>
+#include <string>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <iostream>
+
+#include "support.h"
+#include "diskio.h"
+
+using namespace std;
+
+// Returns the official Windows name for a shortened version of same.
+void DiskIO::MakeRealName(void) {
+   int colonPos;
+
+   colonPos = userFilename.find(':', 0);
+   if ((colonPos != string::npos) && (colonPos <= 3)) {
+      realFilename = "\\\\.\\physicaldrive";
+      realFilename += userFilename.substr(0, colonPos);
+   } // if/else
+   printf("Exiting DiskIO::MakeRealName(); translated '%s' ", userFilename.c_str());
+   printf("to '%s'\n", realFilename.c_str());
+} // DiskIO::MakeRealName()
+
+// Open the currently on-record file for reading
+int DiskIO::OpenForRead(void) {
+   int shouldOpen = 1;
+
+   if (isOpen) { // file is already open
+      if (openForWrite) {
+         Close();
+      } else {
+         shouldOpen = 0;
+      } // if/else
+   } // if
+
+   if (shouldOpen) {
+      printf("Opening '%s' for reading.\n", realFilename.c_str());
+      fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (fd == INVALID_HANDLE_VALUE) {
+         CloseHandle(fd);
+         fprintf(stderr, "Problem opening %s for reading!\n", realFilename.c_str());
+         realFilename = "";
+         userFilename = "";
+         isOpen = 0;
+         openForWrite = 0;
+      } else {
+         isOpen = 1;
+         openForWrite = 0;
+      } // if/else
+   } // if
+
+   return isOpen;
+} // DiskIO::OpenForRead(void)
+
+// An extended file-open function. This includes some system-specific checks.
+// Returns 1 if the file is open, 0 otherwise....
+int DiskIO::OpenForWrite(void) {
+   if ((isOpen) && (openForWrite))
+      return 1;
+
+   // Close the disk, in case it's already open for reading only....
+   Close();
+
+   // try to open the device; may fail....
+   fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+                   FILE_ATTRIBUTE_NORMAL, NULL);
+   if (fd == INVALID_HANDLE_VALUE) {
+      CloseHandle(fd);
+      isOpen = 1;
+      openForWrite = 1;
+   } else {
+      isOpen = 0;
+      openForWrite = 0;
+   } // if/else
+   return isOpen;
+} // DiskIO::OpenForWrite(void)
+
+// Close the disk device. Note that this does NOT erase the stored filenames,
+// so the file can be re-opened without specifying the filename.
+void DiskIO::Close(void) {
+   if (isOpen)
+      CloseHandle(fd);
+   isOpen = 0;
+   openForWrite = 0;
+} // DiskIO::Close()
+
+// 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 DiskIO::GetBlockSize(void) {
+   int err;
+   DWORD blockSize, junk1, junk2, junk3;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+/*      BOOL WINAPI GetDiskFreeSpace(
+                                   __in   LPCTSTR lpRootPathName,
+                                   __out  LPDWORD lpSectorsPerCluster,
+                                   __out  LPDWORD lpBytesPerSector,
+                                   __out  LPDWORD lpNumberOfFreeClusters,
+                                   __out  LPDWORD lpTotalNumberOfClusters
+                                  ); */
+//      err = GetDiskFreeSpace(realFilename.c_str(), &junk1, &blockSize, &junk2, &junk3);
+      err = 1;
+      blockSize = 512;
+
+      if (err == 0) {
+         blockSize = SECTOR_SIZE;
+         // ENOTTY = inappropriate ioctl; probably being called on a disk image
+         // file, so don't display the warning message....
+         // 32-bit code returns EINVAL, I don't know why. I know I'm treading on
+         // thin ice here, but it should be OK in all but very weird cases....
+         if ((errno != ENOTTY) && (errno != EINVAL)) {
+            printf("\aError %d when determining sector size! Setting sector size to %d\n",
+                   GetLastError(), SECTOR_SIZE);
+         } // if
+      } // if (err == -1)
+   } // if (isOpen)
+
+   return (blockSize);
+} // DiskIO::GetBlockSize()
+
+// Resync disk caches so the OS uses the new partition table. This code varies
+// a lot from one OS to another.
+void DiskIO::DiskSync(void) {
+   int i;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+#ifndef MINGW
+      sync();
+#endif
+#ifdef MINGW
+      printf("Warning: I don't know how to sync disks in Windows! The old partition table is\n"
+            "probably still in use!\n");
+#endif
+   } // if (isOpen)
+} // DiskIO::DiskSync()
+
+// Seek to the specified sector. Returns 1 on success, 0 on failure.
+int DiskIO::Seek(uint64_t sector) {
+   int retval = 1;
+   LARGE_INTEGER seekTo;
+   uint32_t lowBits, highBits;
+   uint64_t bytePos;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      retval = OpenForRead();
+   } // if
+
+   if (isOpen) {
+      bytePos = sector * (uint64_t) GetBlockSize();
+      lowBits = (uint32_t) (bytePos / UINT64_C(4294967296));
+      highBits = (uint32_t) (bytePos % UINT64_C(4294967296));
+      seekTo.LowPart = lowBits;
+      seekTo.HighPart = highBits;
+//      seekTo.QuadPart = (LONGLONG) (sector * (uint64_t) GetBlockSize());
+/*      printf("In DiskIO::Seek(), sector = %llu, ", sector);
+      printf("block size = %d, ", GetBlockSize());
+      printf("seekTo.QuadPart = %lld\n", seekTo.QuadPart);
+      printf("   seekTo.LowPart = %lu, ", seekTo.LowPart);
+      printf("seekTo.HighPart = %lu\n", seekTo.HighPart); */
+      retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN);
+      if (retval == 0) {
+         errno = GetLastError();
+         fprintf(stderr, "Error when seeking to %lld! Error is %d\n",
+                 seekTo.QuadPart, errno);
+         retval = 0;
+      } // if
+   } // if
+   return retval;
+} // DiskIO::Seek()
+
+// A variant on the standard read() function. Done to work around
+// limitations in FreeBSD concerning the matching of the sector
+// size with the number of bytes read.
+// Returns the number of bytes read into buffer.
+int DiskIO::Read(void* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks;
+   char* tempSpace;
+   DWORD retval = 0;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+      // Compute required space and allocate memory
+      blockSize = GetBlockSize();
+      if (numBytes <= blockSize) {
+         numBlocks = 1;
+         tempSpace = (char*) malloc(blockSize);
+      } else {
+         numBlocks = numBytes / blockSize;
+         if ((numBytes % blockSize) != 0) numBlocks++;
+         tempSpace = (char*) malloc(numBlocks * blockSize);
+      } // if/else
+
+      // Read the data into temporary space, then copy it to buffer
+//      retval = read(fd, tempSpace, numBlocks * blockSize);
+      ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL);
+      printf("In DiskIO::Read(), have read %d bytes.\n", (int) retval);
+      for (i = 0; i < numBytes; i++) {
+         ((char*) buffer)[i] = tempSpace[i];
+      } // for
+
+      // Adjust the return value, if necessary....
+      if (((numBlocks * blockSize) != numBytes) && (retval > 0))
+         retval = numBytes;
+
+      free(tempSpace);
+   } // if (isOpen)
+   return retval;
+} // DiskIO::Read()
+
+// A variant on the standard write() function. Done to work around
+// limitations in FreeBSD concerning the matching of the sector
+// size with the number of bytes read.
+// Returns the number of bytes written.
+int DiskIO::Write(void* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks, retval = 0;
+   char* tempSpace;
+   DWORD numWritten;
+
+   // If disk isn't open, try to open it....
+   if ((!isOpen) || (!openForWrite)) {
+      OpenForWrite();
+   } // if
+
+   if (isOpen) {
+      // Compute required space and allocate memory
+      blockSize = GetBlockSize();
+      if (numBytes <= blockSize) {
+         numBlocks = 1;
+         tempSpace = (char*) malloc(blockSize);
+      } else {
+         numBlocks = numBytes / blockSize;
+         if ((numBytes % blockSize) != 0) numBlocks++;
+         tempSpace = (char*) malloc(numBlocks * blockSize);
+      } // if/else
+
+      // Copy the data to my own buffer, then write it
+      for (i = 0; i < numBytes; i++) {
+         tempSpace[i] = ((char*) buffer)[i];
+      } // for
+      for (i = numBytes; i < numBlocks * blockSize; i++) {
+         tempSpace[i] = 0;
+      } // for
+//      retval = write(fd, tempSpace, numBlocks * blockSize);
+      WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL);
+      retval = (int) numWritten;
+
+      // Adjust the return value, if necessary....
+      if (((numBlocks * blockSize) != numBytes) && (retval > 0))
+         retval = numBytes;
+
+      free(tempSpace);
+   } // if (isOpen)
+   return retval;
+} // DiskIO:Write()
+
+// Returns the size of the disk in blocks.
+uint64_t DiskIO::DiskSize(int *err) {
+   uint64_t sectors = 0; // size in sectors
+   off_t bytes = 0; // size in bytes
+   struct stat64 st;
+   GET_LENGTH_INFORMATION buf;
+   DWORD i;
+
+   // If disk isn't open, try to open it....
+   if (!isOpen) {
+      OpenForRead();
+   } // if
+
+   if (isOpen) {
+      // 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....
+/*      HANDLE fin;
+      fin = CreateFile(realFilename.c_str(), GENERIC_READ,
+                     FILE_SHARE_READ|FILE_SHARE_WRITE,
+                     NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); */
+      if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) {
+         sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize();
+//         printf("disk_get_size_win32 IOCTL_DISK_GET_LENGTH_INFO = %llu\n",
+//               (long long unsigned) sectors);
+      } else {
+         fprintf(stderr, "Couldn't determine disk size!\n");
+      }
+
+/*      // The above methods have failed, so let's assume it's a regular
+      // file (a QEMU image, dd backup, or what have you) and see what
+      // fstat() gives us....
+      if ((sectors == 0) || (*err == -1)) {
+         if (fstat64(fd, &st) == 0) {
+            bytes = (off_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 */
+   } // if (isOpen)
+   return sectors;
+} // DiskIO::DiskSize()
diff --git a/diskio.cc b/diskio.cc
new file mode 100644
index 0000000..3fc3726
--- /dev/null
+++ b/diskio.cc
@@ -0,0 +1,164 @@
+//
+// C++ Interface: diskio (platform-independent components)
+//
+// Description: Class to handle low-level disk I/O for GPT fdisk
+//
+//
+// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
+// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
+
+#define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+
+#ifdef MINGW
+#include <windows.h>
+#include <winioctl.h>
+#define fstat64 fstat
+#define stat64 stat
+#define S_IRGRP 0
+#define S_IROTH 0
+#else
+#include <sys/ioctl.h>
+#endif
+#include <stdio.h>
+#include <string>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <iostream>
+
+#include "support.h"
+#include "diskio.h"
+
+using namespace std;
+
+DiskIO::DiskIO(void) {
+   userFilename = "";
+   realFilename = "";
+   isOpen = 0;
+   openForWrite = 0;
+   sectorData = NULL;
+} // constructor
+
+DiskIO::~DiskIO(void) {
+   Close();
+   free(sectorData);
+} // destructor
+
+// Open a disk device for reading. Returns 1 on success, 0 on failure.
+int DiskIO::OpenForRead(string filename) {
+   int shouldOpen = 1;
+
+   if (isOpen) { // file is already open
+      if (((realFilename != filename) && (userFilename != filename)) || (openForWrite)) {
+         Close();
+      } else {
+         shouldOpen = 0;
+      } // if/else
+   } // if
+
+   if (shouldOpen) {
+      userFilename = filename;
+      MakeRealName();
+      OpenForRead();
+   } // if
+
+   return isOpen;
+} // DiskIO::OpenForRead(string filename)
+
+// Open a disk for reading and writing by filename.
+// Returns 1 on success, 0 on failure.
+int DiskIO::OpenForWrite(string filename) {
+   int retval = 0;
+
+   if ((isOpen) && (openForWrite) && ((filename == realFilename) || (filename == userFilename))) {
+      retval = 1;
+   } else {
+      userFilename = filename;
+      MakeRealName();
+      retval = OpenForWrite();
+      if (retval == 0) {
+         realFilename = userFilename = "";
+      } // if
+   } // if/else
+   return retval;
+} // DiskIO::OpenForWrite(string filename)
+
+// My original FindAlignment() function (after this one) isn't working, since
+// the BLKPBSZGET ioctl() isn't doing what I expected (it returns 512 even on
+// a WD Advanced Format drive). Therefore, I'm using a simpler function that
+// returns 1-sector alignment for unusual sector sizes and drives smaller than
+// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for
+// larger drives with 512-byte sectors.
+int DiskIO::FindAlignment(void) {
+   int err, result;
+
+   if ((GetBlockSize() == 512) && (DiskSize(&err) >= SMALLEST_ADVANCED_FORMAT)) {
+      result = 8; // play it safe; align for 4096-byte sectors
+   } else {
+      result = 1; // unusual sector size; assume it's the real physical size
+   } // if/else
+   return result;
+} // DiskIO::FindAlignment
+
+// Return the partition alignment value in sectors. Right now this works
+// only for Linux 2.6.32 and later, since I can't find equivalent ioctl()s
+// for OS X or FreeBSD, and the Linux ioctl is new
+/* int DiskIO::FindAlignment(int fd) {
+   int err = -2, errnum = 0, result = 8, physicalSectorSize = 4096;
+   uint64_t diskSize;
+
+   printf("Entering FindAlignment()\n");
+#if defined (__linux__) && defined (BLKPBSZGET)
+   err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
+   printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err);
+//   printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
+#else
+   err = -1;
+#endif
+
+   if (err < 0) { // ioctl didn't work; have to guess....
+      if (GetBlockSize(fd) == 512) {
+         result = 8; // play it safe; align for 4096-byte sectors
+} else {
+         result = 1; // unusual sector size; assume it's the real physical size
+} // if/else
+} else { // ioctl worked; compute alignment
+      result = physicalSectorSize / GetBlockSize(fd);
+      // Disks with larger physical than logical sectors must theoretically
+      // have a total disk size that's a multiple of the physical sector
+      // size; however, some such disks have compatibility jumper settings
+      // meant for one-partition MBR setups, and these reduce the total
+      // number of sectors by 1. If such a setting is used, it'll result
+      // in improper alignment, so look for this condition and warn the
+      // user if it's found....
+      diskSize = disksize(fd, &errnum);
+      if ((diskSize % (uint64_t) result) != 0) {
+         fprintf(stderr, "\aWarning! Disk size (%llu) is not a multiple of alignment\n"
+                         "size (%d), but it should be! Check disk manual and jumper settings!\n",
+                         (unsigned long long) diskSize, result);
+} // if
+} // if/else
+   if (result <= 0) // can happen if physical sector size < logical sector size
+      result = 1;
+   return result;
+} // DiskIO::FindAlignment(int) */
+
+// The same as FindAlignment(int), but opens and closes a device by filename
+int DiskIO::FindAlignment(string filename) {
+   int fd;
+   int retval = 1;
+
+   if (!isOpen)
+      OpenForRead(filename);
+   if (isOpen) {
+      retval = FindAlignment();
+   } // if
+   return retval;
+} // DiskIO::FindAlignment(char)
diff --git a/diskio.h b/diskio.h
new file mode 100644
index 0000000..2435cc5
--- /dev/null
+++ b/diskio.h
@@ -0,0 +1,85 @@
+//
+// C++ Interface: diskio
+//
+// Description: Class to handle low-level disk I/O for GPT fdisk
+//
+//
+// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
+// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
+
+#ifndef __DISKIO_H
+#define __DISKIO_H
+
+#include <string>
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef MINGW
+#include <windows.h>
+#include <winioctl.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#if defined (__FreeBSD__) || defined (__APPLE__)
+#define fstat64 fstat
+#define stat64 stat
+#endif
+
+#include "support.h"
+#include "parttypes.h"
+
+using namespace std;
+
+// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
+// cutoff
+#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
+
+/***************************************
+ *                                     *
+ * DiskIO class and related structures *
+ *                                     *
+ ***************************************/
+
+class DiskIO {
+   protected:
+      string userFilename;
+      string realFilename;
+      int isOpen;
+      int openForWrite;
+      uint8_t *sectorData;
+#ifdef MINGW
+      HANDLE fd;
+#else
+      int fd;
+#endif
+   public:
+      DiskIO(void);
+//      DiskIO(const DiskIO & orig);
+      ~DiskIO(void);
+
+//      DiskIO & operator=(const DiskIO & orig);
+      void MakeRealName(void);
+      int OpenForRead(string filename);
+      int OpenForRead(void);
+      int OpenForWrite(string filename);
+      int OpenForWrite(void);
+      void Close();
+      int Seek(uint64_t sector);
+      int Read(void* buffer, int numBytes);
+      int Write(void* buffer, int numBytes);
+      void DiskSync(void); // resync disk caches to use new partitions
+      int GetBlockSize(void);
+      int FindAlignment(void);
+      int FindAlignment(string filename);
+      int IsOpen(void) {return isOpen;}
+      int IsOpenForWrite(void) {return openForWrite;}
+
+      uint64_t DiskSize(int* err);
+}; // struct GPTPart
+
+#endif