Update to version 0.5.2; adds support for Advanced Format disk partition
alignment
diff --git a/CHANGELOG b/CHANGELOG
index 9667715..ce293a9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,14 @@
+0.5.2 (12/31/2009):
+-------------------
+
+- Modified partition creation function to begin partitions on 8-sector
+  boundaries by default. This improves performance on the new Western
+  Digital Advanced Format drives. The new 'd' and 'l' options on the
+  experts' menu display and change, respectively, the boundary size.
+
+- Tweaked code to produce fewer warnings on the latest versions of
+  GCC.
+
 0.5.1:
 ------
 
diff --git a/gdisk.8 b/gdisk.8
index 6c87d0f..f65ec7e 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -1,6 +1,6 @@
 .\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
 .\" May be distributed under the GNU General Public License
-.TH "GDISK" "8" "0.5.0" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.5.1" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 gdisk \- GUID partition table (GPT) manipulator for Linux and Unix
 .SH "SYNOPSIS"
@@ -417,11 +417,19 @@
 not in \fBgdisk\fR) or sheer incredible coincidence.
 
 .TP
+.B d
+Display the number of logical sectors per physical sector. This value
+determines the sector alignment that GPT fdisk enforces. See the
+description of the 'l' option for more details. Note that this value
+is not actually detected on a disk-by-disk basis; it's set to 8 as a
+blanket default.
+
+.TP
 .B e
-Relocate backup GPT data structures. Use this command if you've added
-disks to a RAID array, thus creating a virtual disk with space that follows
-the backup GPT data structures. This command moves the backup GPT data
-structures to the end of the disk, where they belong.
+Move backup GPT data structures to the end of the disk. Use this command if
+you've added disks to a RAID array, thus creating a virtual disk with space
+that follows the backup GPT data structures. This command moves the backup
+GPT data structures to the end of the disk, where they belong.
 
 .TP 
 .B g
@@ -434,6 +442,22 @@
 Show detailed partition information. This option is identical to the 'i'
 option on the main menu.
 
+.TP
+.B l
+Change the number of logical sectors per physical sector. Prior to December
+of 2009, most hard disks used 512-byte physical sectors. Starting in
+December of 2009, disk manufacturers began transitioning to disks with
+larger physical sectors, but their firmware translated to 512-byte logical
+sectors to maintain compatibility with older OSes. If partitions begin
+mid-physical-sector, though, performance can suffer on such drives, since
+important filesystem data structures can span physical sectors on the disk.
+To minimize such problems, GPT fdisk aligns the start of partitions on the
+boundary of presumed physical sectors. You can set the number of logical
+sectors per physical sector with this option. The default is 8, which is
+set blindly; GPT fdisk does not currently read this information from the
+disk. The default value will result in a tiny amount of wasted disk space
+on older disks with true 512-byte sectors but will otherwise be harmless.
+
 .TP 
 .B m
 Return to the main menu. This option enables you to enter main\-menu commands.
@@ -501,7 +525,7 @@
 usually bypasses the prompt entirely.
 
 .SH "BUGS"
-As of September 2009 (version 0.5.0), \fBgdisk\fR
+As of November 2009 (version 0.5.1), \fBgdisk\fR
 should be considered beta software. Known bugs and limitations include:
 
 .TP 
diff --git a/gdisk.cc b/gdisk.cc
index bfee217..3414d89 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -29,7 +29,7 @@
    int doMore = 1;
    char* device = NULL;
 
-   printf("GPT fdisk (gdisk) version 0.5.1-pre3\n\n");
+   printf("GPT fdisk (gdisk) version 0.5.2\n\n");
 
     if (argc == 2) { // basic usage
       if (SizesOK()) {
@@ -309,6 +309,10 @@
                theGPT->SetPartitionGUID(pn, GetGUID());
             } else printf("No partitions\n");
             break;
+         case 'd': case 'D':
+            printf("The number of logical sectors per physical sector is set to %d.\n",
+                   theGPT->GetAlignment());
+            break;
          case 'e': case 'E':
             printf("Relocating backup data structures to the end of the disk\n");
             theGPT->MoveSecondHeaderToEnd();
@@ -320,6 +324,10 @@
          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;
@@ -366,9 +374,11 @@
 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");
diff --git a/gpt.cc b/gpt.cc
index 2e99714..c34c862 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -46,6 +46,7 @@
    secondPartsCrcOk = 0;
    apmFound = 0;
    bsdFound = 0;
+   sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
    srand((unsigned int) time(NULL));
    SetGPTSize(NUM_GPT_ENTRIES);
 } // GPTData default constructor
@@ -63,6 +64,7 @@
    secondPartsCrcOk = 0;
    apmFound = 0;
    bsdFound = 0;
+   sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
    srand((unsigned int) time(NULL));
    LoadPartitions(filename);
 } // GPTData(char* filename) constructor
@@ -83,8 +85,8 @@
 // do *NOT* recover from these problems. Returns the total number of
 // problems identified.
 int GPTData::Verify(void) {
-   int problems = 0, numSegments;
-   uint64_t totalFree, largestSegment;
+   int problems = 0, numSegments, i;
+   uint64_t totalFree, largestSegment, firstSector;
    char tempStr[255], siTotal[255], siLargest[255];
 
    // First, check for CRC errors in the GPT data....
@@ -199,6 +201,16 @@
    // Verify that partitions don't run into GPT data areas....
    problems += CheckGPTSize();
 
+   // Check that partitions are aligned on proper boundaries (for WD Advanced
+   // Format and similar disks)....
+   for (i = 0; i < mainHeader.numParts; i++) {
+      if ((partitions[i].GetFirstLBA() % sectorAlignment) != 0) {
+         printf("\nCaution: Partition %d doesn't begin on a %d-sector boundary. This may\n"
+                "result in degraded performance on some modern (2010 and later) hard disks.\n",
+                i + 1, sectorAlignment);
+      } // if
+   } // for
+
    // Now compute available space, but only if no problems found, since
    // problems could affect the results
    if (problems == 0) {
@@ -726,7 +738,7 @@
          printf("Error! Couldn't seek to backup partition table!\n");
       } // if/else
    } else {
-      printf("Error! Couldn't open device %s when recovering backup partition table!\n");
+      printf("Error! Couldn't open device %s when recovering backup partition table!\n", device);
    } // if/else
 } // GPTData::LoadSecondTableAsMain()
 
@@ -755,7 +767,7 @@
    if (mainHeader.backupLBA > diskSize) {
       fprintf(stderr, "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n"
               "problem (or it might not). Aborting!\n");
-      printf("(Disk size is %ld sectors, needs to be %ld sectors.)\n", diskSize,
+      printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n", diskSize,
              mainHeader.backupLBA);
       allOK = 0;
    } // if
@@ -1183,6 +1195,7 @@
       do {
          sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt);
       } while (IsFree(sector) == 0);
+      Align(&sector); // Align sector to correct multiple
       firstBlock = sector;
 
       // Get last block for new partitions...
@@ -1315,7 +1328,7 @@
          printf("GPT data structures destroyed! You may now partition the disk using fdisk or\n"
                "other utilities. Program will now terminate.\n");
       } else {
-         printf("Problem opening %s for writing! Program will now terminate.\n");
+         printf("Problem opening %s for writing! Program will now terminate.\n", device);
       } // if/else (fd != -1)
    } // if (goOn == 'Y')
    return (goOn == 'Y');
@@ -1885,6 +1898,71 @@
    return retval;
 } // GPTData::SetPartitionGUID()
 
+// Adjust sector number so that it falls on a sector boundary that's a
+// multiple of sectorAlignment. This is done to improve the performance
+// of Western Digital Advanced Format disks and disks with similar
+// technology from other companies, which use 4096-byte sectors
+// internally although they translate to 512-byte sectors for the
+// benefit of the OS. If partitions aren't properly aligned on these
+// disks, some filesystem data structures can span multiple physical
+// sectors, degrading performance. This function should be called
+// only on the FIRST sector of the partition, not the last!
+// This function returns 1 if the alignment was altered, 0 if it
+// was unchanged.
+int GPTData::Align(uint64_t* sector) {
+   int retval = 0, sectorOK = 0;
+   uint64_t earlier, later, testSector, original;
+
+   if ((*sector % sectorAlignment) != 0) {
+      original = *sector;
+      retval = 1;
+      earlier = (*sector / sectorAlignment) * sectorAlignment;
+      later = earlier + (uint64_t) sectorAlignment;
+
+      // Check to see that every sector between the earlier one and the
+      // requested one is clear, and that it's not too early....
+      if (earlier >= mainHeader.firstUsableLBA) {
+//         printf("earlier is %llu, first usable is %llu\n", earlier, mainHeader.firstUsableLBA);
+         sectorOK = 1;
+         testSector = earlier;
+         do {
+            sectorOK = IsFree(testSector++);
+         } while ((sectorOK == 1) && (testSector < *sector));
+         if (sectorOK == 1) {
+            *sector = earlier;
+//            printf("Moved sector earlier.\n");
+         } // if
+      } // if firstUsableLBA check
+
+      // If couldn't move the sector earlier, try to move it later instead....
+      if ((sectorOK != 1) && (later <= mainHeader.lastUsableLBA)) {
+         sectorOK = 1;
+         testSector = later;
+         do {
+            sectorOK = IsFree(testSector--);
+         } while ((sectorOK == 1) && (testSector > *sector));
+         if (sectorOK == 1) {
+            *sector = later;
+//            printf("Moved sector later\n");
+         } // if
+      } // if
+
+      // If sector was changed successfully, inform the user of this fact.
+      // Otherwise, notify the user that it couldn't be done....
+      if (sectorOK == 1) {
+         printf("Information: Moved requested sector from %llu to %llu for\n"
+               "alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
+               original, *sector);
+      } else {
+         printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n"
+                "If you're using a Western Digital Advanced Format or similar disk with\n"
+                "underlying 4096-byte sectors, performance may suffer.\n", sectorAlignment);
+         retval = 0;
+      } // if/else
+   } // if
+   return retval;
+} // GPTData::Align()
+
 /********************************************************
  *                                                      *
  * Functions that return data about GPT data structures *
@@ -2141,35 +2219,35 @@
    int allOK = 1;
 
    if (sizeof(uint8_t) != 1) {
-      fprintf(stderr, "uint8_t is %d bytes, should be 1 byte; aborting!\n", sizeof(uint8_t));
+      fprintf(stderr, "uint8_t is %lu bytes, should be 1 byte; aborting!\n", sizeof(uint8_t));
       allOK = 0;
    } // if
    if (sizeof(uint16_t) != 2) {
-      fprintf(stderr, "uint16_t is %d bytes, should be 2 bytes; aborting!\n", sizeof(uint16_t));
+      fprintf(stderr, "uint16_t is %lu bytes, should be 2 bytes; aborting!\n", sizeof(uint16_t));
       allOK = 0;
    } // if
    if (sizeof(uint32_t) != 4) {
-      fprintf(stderr, "uint32_t is %d bytes, should be 4 bytes; aborting!\n", sizeof(uint32_t));
+      fprintf(stderr, "uint32_t is %lu bytes, should be 4 bytes; aborting!\n", sizeof(uint32_t));
       allOK = 0;
    } // if
    if (sizeof(uint64_t) != 8) {
-      fprintf(stderr, "uint64_t is %d bytes, should be 8 bytes; aborting!\n", sizeof(uint64_t));
+      fprintf(stderr, "uint64_t is %lu bytes, should be 8 bytes; aborting!\n", sizeof(uint64_t));
       allOK = 0;
    } // if
    if (sizeof(struct MBRRecord) != 16) {
-      fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
+      fprintf(stderr, "MBRRecord is %lu bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
       allOK = 0;
    } // if
    if (sizeof(struct TempMBR) != 512) {
-      fprintf(stderr, "TempMBR is %d bytes, should be 512 bytes; aborting!\n", sizeof(TempMBR));
+      fprintf(stderr, "TempMBR is %lu bytes, should be 512 bytes; aborting!\n", sizeof(TempMBR));
       allOK = 0;
    } // if
    if (sizeof(struct GPTHeader) != 512) {
-      fprintf(stderr, "GPTHeader is %d bytes, should be 512 bytes; aborting!\n", sizeof(GPTHeader));
+      fprintf(stderr, "GPTHeader is %lu bytes, should be 512 bytes; aborting!\n", sizeof(GPTHeader));
       allOK = 0;
    } // if
    if (sizeof(GPTPart) != 128) {
-      fprintf(stderr, "GPTPart is %d bytes, should be 128 bytes; aborting!\n", sizeof(GPTPart));
+      fprintf(stderr, "GPTPart is %lu bytes, should be 128 bytes; aborting!\n", sizeof(GPTPart));
       allOK = 0;
    } // if
 // Determine endianness; set allOK = 0 if running on big-endian hardware
diff --git a/gpt.h b/gpt.h
index f22bd61..c0bf53c 100644
--- a/gpt.h
+++ b/gpt.h
@@ -67,6 +67,7 @@
    int secondPartsCrcOk;
    int apmFound; // set to 1 if APM detected
    int bsdFound; // set to 1 if BSD disklabel detected in MBR
+   int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
    PartTypes typeHelper;
 public:
    // Basic necessary functions....
@@ -132,6 +133,8 @@
    void SetDiskGUID(GUIDData newGUID);
    int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
    void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();}
+   int Align(uint64_t* sector);
+   void SetAlignment(int n) {sectorAlignment = n;}
 
    // Return data about the GPT structures....
    int GetPartRange(uint32_t* low, uint32_t* high);
@@ -143,7 +146,7 @@
    uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
                    mainHeader.sizeOfPartitionEntries) / blockSize;}
    uint32_t CountParts(void);
-
+   int GetAlignment(void) {return sectorAlignment;}
 
    // Find information about free space
    uint64_t FindFirstAvailable(uint64_t start = 0);
diff --git a/support.cc b/support.cc
index bb419ed..0902617 100644
--- a/support.cc
+++ b/support.cc
@@ -34,7 +34,7 @@
    if (low != high) { // bother only if low and high differ...
       response = low - 1; // force one loop by setting response outside range
       while ((response < low) || (response > high)) {
-         printf(prompt);
+         printf("%s", prompt);
          fgets(line, 255, stdin);
          num = sscanf(line, "%d", &response);
          if (num == 1) { // user provided a response
@@ -83,7 +83,7 @@
 
    response = low - 1; // Ensure one pass by setting a too-low initial value
    while ((response < low) || (response > high)) {
-      printf(prompt);
+      printf("%s", prompt);
       fgets(line, 255, stdin);
 
       // Remove leading spaces, if present