diff --git a/CHANGELOG b/CHANGELOG
index bebcf1bb915164d497e563e215cd2334b1e2dfd7..4280d4eb064838937bbd5c0636ab1dce176aac13 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,13 @@
-0.5.3 (1/??/2009):
+0.6.0 (1/??/2009):
 ------------------
 
+- Added support for disks with other than 512-byte sectors.
+
+- Created embryonic sgdisk program.
+
+0.5.3 (1/4/2009):
+-----------------
+
 - Fixed bug in display of GUIDs when compiled with some versions of GCC.
 
 - Eliminated warnings caused by additional checks in latest versions of
diff --git a/Makefile b/Makefile
index 7484b89927b11fbd4adfe80b32717c0ec4d357ba..9c73a7a2678fe7140702dc33cd3c47b183aceb1b 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,9 @@ DEPEND= makedepend $(CFLAGS)
 gdisk:	$(LIB_OBJS) gdisk.o
 	$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
 
+sgdisk: $(LIB_OBJS) sgdisk.o
+	$(CXX) $(LIB_OBJS) sgdisk.o -o sgdisk
+
 wipegpt:	$(LIB_OBJS) wipegpt.o
 	$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
 
diff --git a/bsd.cc b/bsd.cc
index e03a98cbd2f6c925629d36c6bfab62126e434652..ccac9534a991c9fa4e3169ec1adabae69778206a 100644
--- a/bsd.cc
+++ b/bsd.cc
@@ -63,7 +63,7 @@ int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector)
 // Load the BSD disklabel data from an already-opened disk
 // file, starting with the specified sector number.
 void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
-   uint8_t buffer[2048]; // I/O buffer
+   uint8_t buffer[4096]; // I/O buffer
    int i, err, foundSig = 0, bigEnd = 0;
    int relative = 0; // assume absolute partition sector numbering
    uint32_t realSig;
@@ -74,10 +74,10 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
    labelFirstLBA = startSector;
    labelLastLBA = endSector;
 
-   // Read two sectors into memory; we'll extract data from
+   // Read eight sectors into memory; we'll extract data from
    // this buffer. (Done to work around FreeBSD limitation)
-   lseek64(fd, startSector * 512, SEEK_SET);
-   err = read(fd, buffer, 2048);
+   lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
+   err = read(fd, buffer, 4096);
 
    // Do some strangeness to support big-endian architectures...
    bigEnd = (IsLittleEndian() == 0);
diff --git a/gdisk.cc b/gdisk.cc
index f11207ee637eaa9024f5efe63c7cd5567e574eec..bc238a0363371dadc197ac37ae3dba689ee8c185 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -4,7 +4,7 @@
 //
 // by Rod Smith, project began February 2009
 
-/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
+/* 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. */
 
 //#include <iostream>
@@ -16,7 +16,6 @@
 #include "support.h"
 
 // Function prototypes....
-// int ReadPartitions(char* filename, struct GPTData* theGPT);
 void MainMenu(char* filename, struct GPTData* theGPT);
 void ShowCommands(void);
 void ExpertsMenu(char* filename, struct GPTData* theGPT);
@@ -29,7 +28,7 @@ int main(int argc, char* argv[]) {
    int doMore = 1;
    char* device = NULL;
 
-   printf("GPT fdisk (gdisk) version 0.5.3\n\n");
+   printf("GPT fdisk (gdisk) version 0.5.4-pre1\n\n");
 
     if (argc == 2) { // basic usage
       if (SizesOK()) {
diff --git a/gpt.cc b/gpt.cc
index 7204f2c0a271e88ad789c4597252ed5d4104d389..7352edc55a1234f6c50f870a5d85627591b2ba37 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -49,6 +49,7 @@ GPTData::GPTData(void) {
    bsdFound = 0;
    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
    srand((unsigned int) time(NULL));
+   mainHeader.numParts = 0;
    SetGPTSize(NUM_GPT_ENTRIES);
 } // GPTData default constructor
 
@@ -68,6 +69,7 @@ GPTData::GPTData(char* filename) {
    bsdFound = 0;
    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
    srand((unsigned int) time(NULL));
+   mainHeader.numParts = 0;
    LoadPartitions(filename);
 } // GPTData(char* filename) constructor
 
@@ -601,9 +603,9 @@ int GPTData::ForceLoadGPTData(int fd) {
    uint32_t newCRC, sizeOfParts;
 
    // Seek to and read the main GPT header
-   lseek64(fd, 512, SEEK_SET);
-   if (read(fd, &mainHeader, 512) != 512) { // read main GPT header
-      fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
+   lseek64(fd, blockSize, SEEK_SET);
+   if (myRead(fd, (char*) &mainHeader, 512) != 512) { // read main GPT header
+      fprintf(stderr, "Warning! Error %d reading main GPT header!\n", errno);
    } // if
    mainCrcOk = CheckHeaderCRC(&mainHeader);
    if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
@@ -618,19 +620,19 @@ int GPTData::ForceLoadGPTData(int fd) {
       if (mainHeader.backupLBA < diskSize) {
          seekTo = mainHeader.backupLBA * blockSize;
       } else {
-         seekTo = (diskSize * blockSize) - UINT64_C(512);
+         seekTo = (diskSize * blockSize) - blockSize;
          printf("Warning! Disk size is smaller than the main header indicates! Loading\n"
                 "secondary header from the last sector of the disk! You should use 'v' to\n"
                 "verify disk integrity, and perhaps options on the experts' menu to repair\n"
                 "the disk.\n");
       } // else
    } else {
-      seekTo = (diskSize * blockSize) - UINT64_C(512);
+      seekTo = (diskSize * blockSize) - blockSize;
    } // if/else (mainCrcOk)
 
    if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
-      if (read(fd, &secondHeader, 512) != 512) { // read secondary GPT header
-         fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
+      if (myRead(fd, (char*) &secondHeader, 512) != 512) { // read secondary GPT header
+         fprintf(stderr, "Warning! Error %d reading secondary GPT header!\n", errno);
       } // if
       secondCrcOk = CheckHeaderCRC(&secondHeader);
       if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
@@ -681,7 +683,7 @@ int GPTData::ForceLoadGPTData(int fd) {
       if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
          sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
          storage = (char*) malloc(sizeOfParts);
-         if (read(fd, storage, sizeOfParts) != sizeOfParts) {
+         if (myRead(fd, storage, sizeOfParts) != sizeOfParts) {
             fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
          } // if
          newCRC = chksum_crc32((unsigned char*) storage,  sizeOfParts);
@@ -716,7 +718,7 @@ int GPTData::LoadMainTable(void) {
       // matches the stored value
       lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
       sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
-      if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
+      if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
          fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
       } // if
       newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
@@ -740,7 +742,7 @@ void GPTData::LoadSecondTableAsMain(void) {
       if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
          SetGPTSize(secondHeader.numParts);
          sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
-         if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
+         if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
             fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
          } // if
          newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
@@ -852,15 +854,21 @@ int GPTData::SaveGPTData(void) {
          protectiveMBR.WriteMBRData(fd);
 
          // Now write the main GPT header...
-         if (allOK)
-            if (write(fd, &mainHeader, 512) == -1)
-               allOK = 0;
+         if (allOK) {
+            if (lseek64(fd, blockSize, SEEK_SET) != (off_t) -1) {
+               if (myWrite(fd, (char*) &mainHeader, 512) == -1)
+                  allOK = 0;
+	       } else allOK = 0; // if (lseek64()...)
+	 } // if (allOK)
 
          // Now write the main partition tables...
          if (allOK) {
-            if (write(fd, partitions, GPT_SIZE * numParts) == -1)
+	    offset = mainHeader.partitionEntriesLBA * blockSize;
+	    if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
+            if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
                allOK = 0;
-         } // if
+            } else allOK = 0; // if (lseek64()...)
+         } // if (allOK)
 
          // Now seek to near the end to write the secondary GPT....
          if (allOK) {
@@ -872,14 +880,19 @@ int GPTData::SaveGPTData(void) {
          } // if
 
          // Now write the secondary partition tables....
-         if (allOK)
-            if (write(fd, partitions, GPT_SIZE * numParts) == -1)
+         if (allOK) {
+            if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
                allOK = 0;
+	 } // if (allOK)
 
          // Now write the secondary GPT header...
-         if (allOK)
-            if (write(fd, &secondHeader, 512) == -1)
-               allOK = 0;
+         if (allOK) {
+	    offset = mainHeader.backupLBA * blockSize;
+	    if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
+               if (myWrite(fd, (char*) &secondHeader, 512) == -1)
+                  allOK = 0;
+	       } else allOK = 0; // if (lseek64()...)
+	 } // if (allOK)
 
          // re-read the partition table
          if (allOK) {
@@ -944,17 +957,17 @@ int GPTData::SaveGPTBackup(char* filename) {
 
       // Now write the main GPT header...
       if (allOK)
-         if (write(fd, &mainHeader, 512) == -1)
+         if (myWrite(fd, (char*) &mainHeader, 512) == -1)
             allOK = 0;
 
       // Now write the secondary GPT header...
       if (allOK)
-         if (write(fd, &secondHeader, 512) == -1)
+         if (myWrite(fd, (char*) &secondHeader, 512) == -1)
             allOK = 0;
 
       // Now write the main partition tables...
       if (allOK) {
-         if (write(fd, partitions, GPT_SIZE * numParts) == -1)
+         if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
             allOK = 0;
       } // if
 
@@ -997,7 +1010,7 @@ int GPTData::LoadGPTBackup(char* filename) {
 
       // Load the main GPT header, check its vaility, and set the GPT
       // size based on the data
-      if (read(fd, &mainHeader, 512)) {
+      if (myRead(fd, (char*) &mainHeader, 512)) {
          fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
       } // if
       mainCrcOk = CheckHeaderCRC(&mainHeader);
@@ -1009,7 +1022,7 @@ int GPTData::LoadGPTBackup(char* filename) {
 
       // Load the backup GPT header in much the same way as the main
       // GPT header....
-      if (read(fd, &secondHeader, 512) != 512) {
+      if (myRead(fd, (char*) &secondHeader, 512) != 512) {
          fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
       } // if
       secondCrcOk = CheckHeaderCRC(&secondHeader);
@@ -1045,7 +1058,7 @@ int GPTData::LoadGPTBackup(char* filename) {
          // Load main partition table, and record whether its CRC
          // matches the stored value
          sizeOfParts = numParts * sizeOfEntries;
-         if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
+         if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
             fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
          } // if
 
@@ -1109,6 +1122,7 @@ void GPTData::DisplayGPTData(void) {
    BytesToSI(diskSize * blockSize, sizeInSI);
    printf("Disk %s: %llu sectors, %s\n", device,
           (unsigned long long) diskSize, sizeInSI);
+   printf("Logical sector size: %d bytes\n", blockSize);
    printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
    printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
    printf("First usable sector is %llu, last usable sector is %llu\n",
@@ -1302,8 +1316,9 @@ void GPTData::SetAttributes(uint32_t partNum) {
 // If prompt == 0, don't ask user about proceeding and do NOT wipe out
 // MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
 int GPTData::DestroyGPT(int prompt) {
-   int fd, i, sum;
+   int fd, i, sum, tableSize;
    char blankSector[512], goOn = 'Y', blank = 'N';
+   char* emptyTable;
 
    for (i = 0; i < 512; i++) {
       blankSector[i] = '\0';
@@ -1326,24 +1341,24 @@ int GPTData::DestroyGPT(int prompt) {
       } // if
 #endif
       if (fd != -1) {
-         lseek64(fd, mainHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
-         if (write(fd, blankSector, 512) != 512) { // blank it out
+         lseek64(fd, mainHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
+         if (myWrite(fd, blankSector, 512) != 512) { // blank it out
             fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno);
          } // if
-         lseek64(fd, mainHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
-         sum = 0;
-         for (i = 0; i < GetBlocksInPartTable(); i++)
-            sum += write(fd, blankSector, 512);
-         if (sum != 512 * GetBlocksInPartTable())
+         lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
+         tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
+         emptyTable = (char*) malloc(tableSize);
+         for (i = 0; i < tableSize; i++)
+            emptyTable[i] = (char) 0;
+         sum = myWrite(fd, emptyTable, tableSize);
+         if (sum != tableSize)
             fprintf(stderr, "Warning! GPT main partition table not overwritten! Error is %d\n", errno);
-         lseek64(fd, secondHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
-         sum = 0;
-         for (i = 0; i < GetBlocksInPartTable(); i++)
-            sum += write(fd, blankSector, 512);
-         if (sum != 512 * GetBlocksInPartTable())
+         lseek64(fd, secondHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
+         sum = myWrite(fd, emptyTable, tableSize);
+         if (sum != tableSize)
             fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno);
-         lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
-         if (write(fd, blankSector, 512) != 512) { // blank it out
+         lseek64(fd, secondHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
+         if (myWrite(fd, blankSector, 512) != 512) { // blank it out
             fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
          } // if
          if (prompt) {
@@ -1357,7 +1372,7 @@ int GPTData::DestroyGPT(int prompt) {
          // structures).
          if (blank == 'Y') {
             lseek64(fd, 0, SEEK_SET);
-            if (write(fd, blankSector, 512) != 512) { // blank it out
+            if (myWrite(fd, blankSector, 512) != 512) { // blank it out
                fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
             } // if
          } else {
diff --git a/gpt.h b/gpt.h
index f5f862b5dfff61450464ce7120a2a87be9767aea..68baf1e65f3b409ca088616eaaaaf2859b59f1db 100644
--- a/gpt.h
+++ b/gpt.h
@@ -145,8 +145,6 @@ public:
    uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
    uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
    uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
-   uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
-                   mainHeader.sizeOfPartitionEntries) / blockSize;}
    uint32_t CountParts(void);
    int GetAlignment(void) {return sectorAlignment;}
 
diff --git a/mbr.cc b/mbr.cc
index e06d821c7068299e92e3ab49b14d8b3859eaeefd..efd6fd345ea6df5b4610ee4845880c386a80681f 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -98,7 +98,7 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
    EmptyMBR(0);
 
    err = lseek64(fd, 0, SEEK_SET);
-   err = read(fd, &tempMBR, 512);
+   err = myRead(fd, (char*) &tempMBR, 512);
    for (i = 0; i < 440; i++)
       code[i] = tempMBR.code[i];
    diskSignature = tempMBR.diskSignature;
@@ -202,7 +202,7 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
          fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
          partNum = -1;
       }
-      if (read(fd, &ebr, 512) != 512) { // Load the data....
+      if (myRead(fd, (char*) &ebr, 512) != 512) { // Load the data....
          fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
                  (unsigned long) offset);
          partNum = -1;
@@ -289,7 +289,7 @@ void MBRData::WriteMBRData(int fd) {
 
    // Now write that data structure...
    lseek64(fd, 0, SEEK_SET);
-   if (write(fd, &tempMBR, 512) != 512) {
+   if (myWrite(fd, (char*) &tempMBR, 512) != 512) {
       fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
    } // if
 
diff --git a/sgdisk.cc b/sgdisk.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9479afb4fcd5c1a90e1fe70299cc23d874b52735
--- /dev/null
+++ b/sgdisk.cc
@@ -0,0 +1,464 @@
+// sgdisk.cc
+// Program modelled after Linux sfdisk, but it manipulates GPT partitions
+// rather than MBR partitions. This is effectively a new user interface
+// to my gdisk program.
+//
+// by Rod Smith, project began February 2009
+
+/* 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. */
+
+//#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include "mbr.h"
+#include "gpt.h"
+#include "support.h"
+
+#define MAX_OPTIONS 50
+
+// Function prototypes....
+/* void MainMenu(char* filename, struct GPTData* theGPT);
+void ShowCommands(void);
+void ExpertsMenu(char* filename, struct GPTData* theGPT);
+void ShowExpertCommands(void);
+void RecoveryMenu(char* filename, struct GPTData* theGPT);
+void ShowRecoveryCommands(void); */
+
+enum Commands { NONE, LIST, VERIFY };
+
+struct Options {
+   Commands theCommand;
+   char* theArgument;
+}; // struct Options
+
+int verbose_flag;
+
+static struct option long_options[] =
+{
+   {"verify",  no_argument, NULL, 'v'},
+   {"list",    no_argument, NULL, 'l'},
+   {0, 0, NULL, 0}
+};
+
+int ParseOptions(int argc, char* argv[], Options* theOptions, char** device);
+
+int main(int argc, char* argv[]) {
+   GPTData theGPT;
+   int doMore = 1, opt, i, numOptions = 0;
+   char* device = NULL;
+   Options theOptions[MAX_OPTIONS];
+
+   printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
+   numOptions = ParseOptions(argc, argv, theOptions, &device);
+
+   if (device != NULL) {
+      if (theGPT.LoadPartitions(device)) {
+         for (i = 0; i < numOptions; i++) {
+            switch (theOptions[i].theCommand) {
+               case LIST:
+                  theGPT.JustLooking();
+                  theGPT.DisplayGPTData();
+                  break;
+               case VERIFY:
+                  theGPT.JustLooking();
+                  theGPT.Verify();
+                  break;
+               case NONE:
+                  printf("Usage: %s {-lv} device\n", argv[0]);
+                  break;
+            } // switch
+         } // for
+      } // if loaded OK
+   } // if (device != NULL)
+
+   return 0;
+} // main
+
+// Parse command-line options. Returns the number of arguments retrieved
+int ParseOptions(int argc, char* argv[], Options* theOptions, char** device) {
+   int opt, i, numOptions = 0;
+   int verbose_flag;
+
+   // Use getopt() to extract commands and their arguments
+   /* getopt_long stores the option index here. */
+   int option_index = 0;
+
+//   c = getopt_long (argc, argv, "abc:d:f:",
+//                    long_options, &option_index);
+
+   while (((opt = getopt_long(argc, argv, "vl", long_options, &option_index)) != -1)
+          && (numOptions < MAX_OPTIONS)) {
+      printf("opt is %c, option_index is %d\n", opt, option_index);
+      switch (opt) {
+         case 'l':
+            printf("Entering list option, numOptions = %d!\n", numOptions);
+            theOptions[numOptions].theCommand = LIST;
+            theOptions[numOptions++].theArgument = NULL;
+            break;
+         case 'v':
+            theOptions[numOptions].theCommand = VERIFY;
+            theOptions[numOptions++].theArgument = NULL;
+            break;
+         default:
+            printf("Default switch; opt is %c\n", opt);
+            break;
+//            abort();
+      } // switch
+   } // while
+
+   // Find non-option arguments. If the user types a legal command, there
+   // will be only one of these: The device filename....
+   opt = 0;
+   printf("Searching for device filename; optind is %d\n", optind);
+   for (i = optind; i < argc; i++) {
+      *device = argv[i];
+      printf("Setting device to %s\n", argv[i]);
+      opt++;
+   } // for
+   if (opt > 1) {
+      fprintf(stderr, "Warning! Found stray unrecognized arguments! Program may misbehave!\n");
+   } // if
+
+   return numOptions;
+} // ParseOptions()
+
+/* // Accept a command and execute it. Returns only when the user
+// wants to exit (such as after a 'w' or 'q' command).
+void MainMenu(char* filename, struct GPTData* theGPT) {
+   char command, line[255], buFile[255];
+   char* junk;
+   int goOn = 1;
+   PartTypes typeHelper;
+   uint32_t temp1, temp2;
+
+   do {
+      printf("\nCommand (? for help): ");
+      junk = fgets(line, 255, stdin);
+      sscanf(line, "%c", &command);
+      switch (command) {
+         case 'b': case 'B':
+            printf("Enter backup filename to save: ");
+            junk = fgets(line, 255, stdin);
+            sscanf(line, "%s", (char*) &buFile);
+            theGPT->SaveGPTBackup(buFile);
+            break;
+         case 'c': case 'C':
+            if (theGPT->GetPartRange(&temp1, &temp2) > 0)
+               theGPT->SetName(theGPT->GetPartNum());
+            else
+               printf("No partitions\n");
+            break;
+         case 'd': case 'D':
+            theGPT->DeletePartition();
+            break;
+         case 'i': case 'I':
+            theGPT->ShowDetails();
+            break;
+         case 'l': case 'L':
+            typeHelper.ShowTypes();
+            break;
+         case 'n': case 'N':
+            theGPT->CreatePartition();
+            break;
+         case 'o': case 'O':
+            printf("This option deletes all partitions and creates a new "
+                  "protective MBR.\nProceed? ");
+            if (GetYN() == 'Y') {
+               theGPT->ClearGPTData();
+               theGPT->MakeProtectiveMBR();
+            } // if
+            break;
+         case 'p': case 'P':
+            theGPT->DisplayGPTData();
+            break;
+         case 'q': case 'Q':
+            goOn = 0;
+            break;
+         case 'r': case 'R':
+            RecoveryMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         case 's': case 'S':
+            theGPT->SortGPT();
+            printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
+            break;
+         case 't': case 'T':
+            theGPT->ChangePartType();
+            break;
+         case 'v': case 'V':
+            if (theGPT->Verify() > 0) { // problems found
+               printf("You may be able to correct the problems by using options on the experts\n"
+                     "menu (press 'x' at the command prompt). Good luck!\n");
+            } // if
+            break;
+         case 'w': case 'W':
+            if (theGPT->SaveGPTData() == 1)
+               goOn = 0;
+            break;
+         case 'x': case 'X':
+            ExpertsMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         default:
+            ShowCommands();
+            break;
+      } // switch
+   } while (goOn);
+} // MainMenu()
+
+void ShowCommands(void) {
+   printf("b\tback up GPT data to a file\n");
+   printf("c\tchange a partition's name\n");
+   printf("d\tdelete a partition\n");
+   printf("i\tshow detailed information on a partition\n");
+   printf("l\tlist known partition types\n");
+   printf("n\tadd a new partition\n");
+   printf("o\tcreate a new empty GUID partition table (GPT)\n");
+   printf("p\tprint the partition table\n");
+   printf("q\tquit without saving changes\n");
+   printf("r\trecovery and transformation options (experts only)\n");
+   printf("s\tsort partitions\n");
+   printf("t\tchange a partition's type code\n");
+   printf("v\tverify disk\n");
+   printf("w\twrite table to disk and exit\n");
+   printf("x\textra functionality (experts only)\n");
+   printf("?\tprint this menu\n");
+} // ShowCommands()
+
+// Accept a recovery & transformation menu command. Returns only when the user
+// issues an exit command, such as 'w' or 'q'.
+void RecoveryMenu(char* filename, struct GPTData* theGPT) {
+   char command, line[255], buFile[255];
+   char* junk;
+   PartTypes typeHelper;
+   uint32_t temp1;
+   int goOn = 1;
+
+   do {
+      printf("\nrecovery/transformation command (? for help): ");
+      junk = fgets(line, 255, stdin);
+      sscanf(line, "%c", &command);
+      switch (command) {
+         case 'b': case 'B':
+            theGPT->RebuildMainHeader();
+            break;
+         case 'c': case 'C':
+            printf("Warning! This will probably do weird things if you've converted an MBR to\n"
+                  "GPT form and haven't yet saved the GPT! Proceed? ");
+            if (GetYN() == 'Y')
+               theGPT->LoadSecondTableAsMain();
+            break;
+         case 'd': case 'D':
+            theGPT->RebuildSecondHeader();
+            break;
+         case 'e': case 'E':
+            printf("Warning! This will probably do weird things if you've converted an MBR to\n"
+                  "GPT form and haven't yet saved the GPT! Proceed? ");
+            if (GetYN() == 'Y')
+               theGPT->LoadMainTable();
+            break;
+         case 'f': case 'F':
+            printf("Warning! This will destroy the currently defined partitions! Proceed? ");
+            if (GetYN() == 'Y') {
+               if (theGPT->LoadMBR(filename) == 1) { // successful load
+                  theGPT->XFormPartitions();
+               } else {
+                  printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
+                  theGPT->MakeProtectiveMBR();
+               } // if/else
+            } // if
+            break;
+         case 'g': case 'G':
+            temp1 = theGPT->XFormToMBR();
+            if (temp1 > 0) {
+               printf("Converted %d partitions. Finalize and exit? ", temp1);
+               if (GetYN() == 'Y') {
+                  if (theGPT->DestroyGPT(0) > 0)
+                     goOn = 0;
+               } else {
+                  theGPT->MakeProtectiveMBR();
+                  printf("Note: New protective MBR created.\n");
+               } // if/else
+            } // if
+            break;
+         case 'h': case 'H':
+            theGPT->MakeHybrid();
+            break;
+         case 'i': case 'I':
+            theGPT->ShowDetails();
+            break;
+         case 'l': case 'L':
+            printf("Enter backup filename to load: ");
+            junk = fgets(line, 255, stdin);
+            sscanf(line, "%s", (char*) &buFile);
+            theGPT->LoadGPTBackup(buFile);
+            break;
+         case 'm': case 'M':
+            MainMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         case 'o': case 'O':
+            theGPT->DisplayMBRData();
+            break;
+         case 'p': case 'P':
+            theGPT->DisplayGPTData();
+            break;
+         case 'q': case 'Q':
+            goOn = 0;
+            break;
+         case 't': case 'T':
+            theGPT->XFormDisklabel();
+            break;
+         case 'v': case 'V':
+            theGPT->Verify();
+            break;
+         case 'w': case 'W':
+            if (theGPT->SaveGPTData() == 1) {
+               goOn = 0;
+            } // if
+            break;
+         case 'x': case 'X':
+            ExpertsMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         default:
+            ShowRecoveryCommands();
+            break;
+      } // switch
+   } while (goOn);
+} // RecoveryMenu()
+
+void ShowRecoveryCommands(void) {
+   printf("b\tuse backup GPT header (rebuilding main)\n");
+   printf("c\tload backup partition table from disk (rebuilding main)\n");
+   printf("d\tuse main GPT header (rebuilding backup)\n");
+   printf("e\tload main partition table from disk (rebuilding backup)\n");
+   printf("f\tload MBR and build fresh GPT from it\n");
+   printf("g\tconvert GPT into MBR and exit\n");
+   printf("h\tmake hybrid MBR\n");
+   printf("i\tshow detailed information on a partition\n");
+   printf("l\tload partition data from a backup file\n");
+   printf("m\treturn to main menu\n");
+   printf("o\tprint protective MBR data\n");
+   printf("p\tprint the partition table\n");
+   printf("q\tquit without saving changes\n");
+   printf("t\ttransform BSD disklabel partition\n");
+   printf("v\tverify disk\n");
+   printf("w\twrite table to disk and exit\n");
+   printf("x\textra functionality (experts only)\n");
+   printf("?\tprint this menu\n");
+} // ShowRecoveryCommands()
+
+// Accept an experts' menu command. Returns only after the user
+// selects an exit command, such as 'w' or 'q'.
+void ExpertsMenu(char* filename, struct GPTData* theGPT) {
+   char command, line[255];
+   char* junk;
+   PartTypes typeHelper;
+   uint32_t pn;
+   uint32_t temp1, temp2;
+   int goOn = 1;
+
+   do {
+      printf("\nExpert command (? for help): ");
+      junk = fgets(line, 255, stdin);
+      sscanf(line, "%c", &command);
+      switch (command) {
+         case 'a': case 'A':
+            if (theGPT->GetPartRange(&temp1, &temp2) > 0)
+               theGPT->SetAttributes(theGPT->GetPartNum());
+           else
+               printf("No partitions\n");
+            break;
+         case 'c': case 'C':
+            if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
+               pn = theGPT->GetPartNum();
+               printf("Enter the partition's new unique GUID:\n");
+               theGPT->SetPartitionGUID(pn, GetGUID());
+            } else printf("No partitions\n");
+            break;
+         case 'd': case 'D':
+            printf("The number of logical sectors per physical sector is %d.\n",
+                   theGPT->GetAlignment());
+            break;
+         case 'e': case 'E':
+            printf("Relocating backup data structures to the end of the disk\n");
+            theGPT->MoveSecondHeaderToEnd();
+            break;
+         case 'g': case 'G':
+            printf("Enter the disk's unique GUID:\n");
+            theGPT->SetDiskGUID(GetGUID());
+            break;
+         case 'i': case 'I':
+            theGPT->ShowDetails();
+            break;
+         case 'l': case 'L':
+            temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
+            theGPT->SetAlignment(temp1);
+            break;
+         case 'm': case 'M':
+            MainMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         case 'n': case 'N':
+            theGPT->MakeProtectiveMBR();
+            break;
+         case 'o': case 'O':
+            theGPT->DisplayMBRData();
+            break;
+         case 'p': case 'P':
+            theGPT->DisplayGPTData();
+	    break;
+         case 'q': case 'Q':
+	    goOn = 0;
+	    break;
+         case 'r': case 'R':
+            RecoveryMenu(filename, theGPT);
+            goOn = 0;
+            break;
+         case 's': case 'S':
+            theGPT->ResizePartitionTable();
+            break;
+         case 'v': case 'V':
+            theGPT->Verify();
+            break;
+         case 'w': case 'W':
+            if (theGPT->SaveGPTData() == 1) {
+               goOn = 0;
+            } // if
+            break;
+         case 'z': case 'Z':
+            if (theGPT->DestroyGPT() == 1) {
+               goOn = 0;
+            }
+            break;
+         default:
+            ShowExpertCommands();
+            break;
+      } // switch
+   } while (goOn);
+} // ExpertsMenu()
+
+void ShowExpertCommands(void) {
+   printf("a\tset attributes\n");
+   printf("c\tchange partition GUID\n");
+   printf("d\tdisplay the number of logical sectors per physical sector\n");
+   printf("e\trelocate backup data structures to the end of the disk\n");
+   printf("g\tchange disk GUID\n");
+   printf("i\tshow detailed information on a partition\n");
+   printf("b\tset the number of logical sectors per physical sector\n");
+   printf("m\treturn to main menu\n");
+   printf("n\tcreate a new protective MBR\n");
+   printf("o\tprint protective MBR data\n");
+   printf("p\tprint the partition table\n");
+   printf("q\tquit without saving changes\n");
+   printf("r\trecovery and transformation options (experts only)\n");
+   printf("s\tresize partition table\n");
+   printf("v\tverify disk\n");
+   printf("w\twrite table to disk and exit\n");
+   printf("z\tzap (destroy) GPT data structures and exit\n");
+   printf("?\tprint this menu\n");
+} // ShowExpertCommands()
+*/
diff --git a/support.cc b/support.cc
index 9763dbf78ec406ec09113e2c93acec9056a9e4d9..8ab9a2e4cdbec06fc26580599daf72df2266b696 100644
--- a/support.cc
+++ b/support.cc
@@ -223,10 +223,10 @@ int GetBlockSize(int fd) {
       } // if
    } // if
 
-   if (result != 512) {
+/*   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 */
 
    return (result);
 } // GetBlockSize()
@@ -244,9 +244,12 @@ int FindAlignment(int fd) {
    err = -1;
 #endif
 
-   if (err < 0) {
-      result = 8;
-   } else {
+   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
+   } else { // ioctl worked; compute alignment
       result = physicalSectorSize / GetBlockSize(fd);
    } // if/else
    return result;
@@ -501,7 +504,9 @@ uint64_t disksize(int fd, int *err) {
       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(fd) / 512);
 #endif
 #endif
 
@@ -517,7 +522,72 @@ uint64_t disksize(int fd, int *err) {
          sectors = bytes / UINT64_C(512);
       } // if
    } // if
-//   sectors = 25000000;
-//   printf("Returning bogus sector size: %d\n", sectors);
    return sectors;
-}
+} // disksize()
+
+// 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
+int myRead(int fd, char* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks, retval;
+   char* tempSpace;
+
+   // Compute required space and allocate memory
+   blockSize = GetBlockSize(fd);
+   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);
+   for (i = 0; i < numBytes; i++) {
+      buffer[i] = tempSpace[i];
+   } // for
+
+   // Adjust the return value, if necessary....
+   if (((numBlocks * blockSize) != numBytes) && (retval > 0))
+      retval = numBytes;
+
+   free(tempSpace);
+   return retval;
+} // myRead()
+
+// 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
+int myWrite(int fd, char* buffer, int numBytes) {
+   int blockSize = 512, i, numBlocks, retval;
+   char* tempSpace;
+
+   // Compute required space and allocate memory
+   blockSize = GetBlockSize(fd);
+   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] = buffer[i];
+   } // for
+   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);
+   return retval;
+} // myRead()
diff --git a/support.h b/support.h
index e414df0f95bf5ff70ab177f5d173113cab72aa47..b261b76e45ae5253497d39ee83838b3d1a4456f9 100644
--- a/support.h
+++ b/support.h
@@ -68,6 +68,8 @@ int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-en
 void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
 uint64_t PowerOf2(int value);
 int OpenForWrite(char* deviceFilename);
+int myRead(int fd, char* buffer, int numBytes);
+int myWrite(int fd, char* buffer, int numBytes);
 void DiskSync(int fd); // resync disk caches to use new partitions
 
 uint64_t disksize(int fd, int* err);