---
 fdisk/sfdisk.c |  144 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 110 insertions(+), 34 deletions(-)

Index: util-linux-2.19.1/fdisk/sfdisk.c
===================================================================
--- util-linux-2.19.1.orig/fdisk/sfdisk.c
+++ util-linux-2.19.1/fdisk/sfdisk.c
@@ -46,6 +46,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
+#include <limits.h>
 
 #include "c.h"
 #include "nls.h"
@@ -186,7 +187,7 @@ sseek(char *dev, unsigned int fd, unsign
  */
 struct sector {
     struct sector *next;
-    unsigned long sectornumber;
+    unsigned long long sectornumber;
     int to_be_written;
     char data[512];
 } *sectorhead;
@@ -203,7 +204,7 @@ free_sectors(void) {
 }
 
 static struct sector *
-get_sector(char *dev, int fd, unsigned long sno) {
+get_sector(char *dev, int fd, unsigned long long sno) {
     struct sector *s;
 
     for(s = sectorhead; s; s = s->next)
@@ -732,9 +733,9 @@ copy_from_part(struct partition *p, char
    for equality with EXTENDED_PARTITION (and these Disk Manager types). */
 
 struct part_desc {
-    unsigned long start;
-    unsigned long size;
-    unsigned long sector, offset; /* disk location of this info */
+    unsigned long long start;
+    unsigned long long size;
+    unsigned long long sector, offset; /* disk location of this info */
     struct partition p;
     struct part_desc *ep;	  /* extended partition containing this one */
     int ptype;
@@ -908,7 +909,7 @@ unitsize(int format) {
     }
 }
 
-static unsigned long
+static unsigned long long
 get_disksize(int format) {
     if (B.total_size && leave_last)
 	    /* don't use last cylinder (--leave-last option) */
@@ -961,27 +962,27 @@ out_partition_header(char *dev, int form
 }
 
 static void
-out_rounddown(int width, unsigned long n, unsigned long unit, int inc) {
-    printf("%*lu", width, inc + n/unit);
+out_rounddown(int width, unsigned long long n, unsigned long unit, int inc) {
+    printf("%*llu", width, inc + n/unit);
     if (unit != 1)
       putchar((n % unit) ? '+' : ' ');
     putchar(' ');
 }
 
 static void
-out_roundup(int width, unsigned long n, unsigned long unit, int inc) {
+out_roundup(int width, unsigned long long n, unsigned long unit, int inc) {
     if (n == (unsigned long)(-1))
       printf("%*s", width, "-");
     else
-      printf("%*lu", width, inc + n/unit);
+      printf("%*llu", width, inc + n/unit);
     if (unit != 1)
       putchar(((n+1) % unit) ? '-' : ' ');
     putchar(' ');
 }
 
 static void
-out_roundup_size(int width, unsigned long n, unsigned long unit) {
-    printf("%*lu", width, (n+unit-1)/unit);
+out_roundup_size(int width, unsigned long long n, unsigned long unit) {
+    printf("%*llu", width, (n+unit-1)/unit);
     if (unit != 1)
       putchar((n % unit) ? '-' : ' ');
     putchar(' ');
@@ -1028,7 +1029,7 @@ get_fdisk_geometry(struct disk_desc *z)
 static void
 out_partition(char *dev, int format, struct part_desc *p,
 	      struct disk_desc *z, struct geometry G) {
-    unsigned long start, end, size;
+    unsigned long long start, end, size;
     int pno, lpno;
 
     if (!format && !(format = specified_format))
@@ -1049,8 +1050,8 @@ out_partition(char *dev, int format, str
     size = p->size;
 
     if (dump) {
-	printf(" start=%9lu", start);
-	printf(", size=%9lu", size);
+	printf(" start=%9llu", start);
+	printf(", size=%9llu", size);
 	if (p->ptype == DOS_TYPE) {
 	    printf(", Id=%2x", p->p.sys_type);
 	    if (p->p.bootable == 0x80)
@@ -1179,7 +1180,7 @@ pnumber(struct part_desc *p, struct disk
 }
 
 static int
-partitions_ok(struct disk_desc *z) {
+partitions_ok(int fd, struct disk_desc *z) {
     struct part_desc *partitions = &(z->partitions[0]), *p, *q;
     int partno = z->partno;
 
@@ -1241,14 +1242,14 @@ partitions_ok(struct disk_desc *z) {
 	  if (is_extended(q->p.sys_type))
 	    if (p->start <= q->start && p->start + p->size > q->start) {
 		warn(_("Warning: partition %s contains part of "
-		       "the partition table (sector %lu),\n"
+		       "the partition table (sector %llu),\n"
 		       "and will destroy it when filled\n"),
 		     PNO(p), q->start);
 		return 0;
 	    }
 
     /* Do they start past zero and end before end-of-disk? */
-    { unsigned long ds = get_disksize(F_SECTOR);
+    { unsigned long long ds = get_disksize(F_SECTOR);
     for (p = partitions; p < partitions+partno; p++)
       if (p->size) {
 	  if (p->start == 0) {
@@ -1283,6 +1284,43 @@ partitions_ok(struct disk_desc *z) {
       }
      }
 
+    int sector_size;
+    if (blkdev_get_sector_size(fd, &sector_size) == -1)
+	sector_size = DEFAULT_SECTOR_SIZE;
+
+    /* Is the size of partitions less than 2^32 sectors limit? */
+    for (p = partitions; p < partitions + partno; p++)
+	if (p->size > UINT_MAX) {
+	    unsigned long long bytes = p->size * sector_size;
+	    int giga = bytes / 1000000000;
+	    int hectogiga = (giga + 50) / 100;
+	    warn(_("Warning: partition %s has size %d.%d TB (%llu bytes),\n"
+		      "which is larger than the %llu bytes limit imposed\n"
+		      "by the DOS partition table for %d-byte sectors\n"),
+		    PNO(p), hectogiga / 10, hectogiga % 10,
+		    bytes,
+		    (unsigned long long) UINT_MAX * sector_size,
+		    sector_size);
+	    return 0;
+	}
+
+    /* Do the partitions start below the 2^32 sectors limit? */
+    for (p = partitions; p < partitions + partno; p++)
+	if (p->start > UINT_MAX) {
+	    unsigned long long bytes = p->start * sector_size;
+	    int giga = bytes / 1000000000;
+	    int hectogiga = (giga + 50) / 100;
+	    warn(_("Warning: partition %s starts at sector %llu (%d.%d TB for %d-byte sectors),\n"
+		      "which exceeds the DOS partition table limit of %llu sectors\n"),
+		    PNO(p),
+		    p->start,
+		    hectogiga / 10,
+		    hectogiga % 10,
+		    sector_size,
+		    (unsigned long long) UINT_MAX);
+	    return 0;
+	}
+
     /* At most one chain of DOS extended partitions ? */
     /* It seems that the OS/2 fdisk has the additional requirement
        that the extended partition must be the fourth one */
@@ -1388,7 +1426,7 @@ static void
 extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
     char *cp;
     struct sector *s;
-    unsigned long start, here, next;
+    unsigned long long start, here, next;
     int i, moretodo = 1;
     struct partition p;
     struct part_desc *partitions = &(z->partitions[0]);
@@ -1487,7 +1525,7 @@ static void
 bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
 	struct bsd_disklabel *l;
 	struct bsd_partition *bp, *bp0;
-	unsigned long start = ep->start;
+	unsigned long long start = ep->start;
 	struct sector *s;
 	struct part_desc *partitions = &(z->partitions[0]);
 	int pno = z->partno;
@@ -1849,6 +1887,44 @@ get_ul(char *u, unsigned long *up, unsig
     return 0;
 }
 
+
+/* read a number, use default if absent */
+/* a sign gives an offset from the default */
+static int
+get_ull(char *u, unsigned long long *up, unsigned long long def, int base) {
+    char *nu;
+    int sign = 0;
+    unsigned long long val;
+
+    if (*u == '+') {
+	sign = 1;
+	u++;
+    } else if (*u == '-') {
+	sign = -1;
+	u++;
+    }
+    if (*u) {
+	errno = 0;
+	val = strtoull(u, &nu, base);
+	if (errno == ERANGE) {
+	    do_warn(_("number too big\n"));
+	    return -1;
+	}
+	if (*nu) {
+	    do_warn(_("trailing junk after number\n"));
+	    return -1;
+	}
+	if (sign == 1)
+	    val = def + val;
+	else if (sign == -1)
+	    val = def - val;
+	*up = val;
+    } else
+	*up = def;
+    return 0;
+}
+
+
 /* There are two common ways to structure extended partitions:
    as nested boxes, and as a chain. Sometimes the partitions
    must be given in order. Sometimes all logical partitions
@@ -1866,10 +1942,10 @@ int all_logicals_inside_outermost_extend
 enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
 
 /* find the default value for <start> - assuming entire units */
-static unsigned long
+static unsigned long long
 first_free(int pno, int is_extended, struct part_desc *ep, int format,
-	   unsigned long mid, struct disk_desc *z) {
-    unsigned long ff, fff;
+	   unsigned long long mid, struct disk_desc *z) {
+    unsigned long long ff, fff;
     unsigned long unit = unitsize(format);
     struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
 
@@ -1910,10 +1986,10 @@ first_free(int pno, int is_extended, str
 }
 
 /* find the default value for <size> - assuming entire units */
-static unsigned long
+static unsigned long long
 max_length(int pno, int is_extended, struct part_desc *ep, int format,
-	   unsigned long start, struct disk_desc *z) {
-    unsigned long fu;
+	   unsigned long long start, struct disk_desc *z) {
+    unsigned long long fu;
     unsigned long unit = unitsize(format);
     struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
 
@@ -1942,7 +2018,7 @@ max_length(int pno, int is_extended, str
 /* ep is 0 or points to surrounding extended partition */
 static int
 compute_start_sect(struct part_desc *p, struct part_desc *ep) {
-    unsigned long base;
+    unsigned long long base;
     int inc = (DOS && B.sectors) ? B.sectors : 1;
     long long delta;
 
@@ -1954,7 +2030,7 @@ compute_start_sect(struct part_desc *p,
       delta = 0;
 
     if (delta < 0) {
-	unsigned long old_size = p->size;
+	unsigned long long old_size = p->size;
 	p->start -= delta;
 	p->size += delta;
 	if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
@@ -2023,7 +2099,7 @@ read_line(int pno, struct part_desc *ep,
     char *fields[11];
     int fno, pct = pno%4;
     struct part_desc p, *orig;
-    unsigned long ff, ff1, ul, ml, ml1, def;
+    unsigned long long ff, ff1, ul, ml, ml1, def;
     int format, lpno, is_extd;
 
     if (eof || eob)
@@ -2094,7 +2170,7 @@ read_line(int pno, struct part_desc *ep,
       ul = EXTENDED_PARTITION;
     else if (!strcmp(fields[2], "X"))
       ul = LINUX_EXTENDED;
-    else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16))
+    else if (get_ull(fields[2], &ul, LINUX_NATIVE, 16))
       return 0;
     if (ul > 255) {
 	warn(_("Illegal type\n"));
@@ -2110,7 +2186,7 @@ read_line(int pno, struct part_desc *ep,
     if (fno < 1 || !*(fields[0]))
       p.start = def;
     else {
-	if (get_ul(fields[0], &ul, def / unitsize(0), 0))
+	if (get_ull(fields[0], &ul, def / unitsize(0), 0))
 	  return 0;
 	p.start = ul * unitsize(0);
 	p.start -= (p.start % unitsize(format));
@@ -2125,7 +2201,7 @@ read_line(int pno, struct part_desc *ep,
     else if (!strcmp(fields[1], "+"))
       p.size = ml1;
     else {
-	if (get_ul(fields[1], &ul, def / unitsize(0), 0))
+	if (get_ull(fields[1], &ul, def / unitsize(0), 0))
 	  return 0;
 	p.size = ul * unitsize(0) + unitsize(format) - 1;
 	p.size -= (p.size % unitsize(format));
@@ -2756,7 +2832,7 @@ do_list (char *dev, int silent) {
       out_partitions(dev, z);
 
     if (verify) {
-	if (partitions_ok(z))
+	if (partitions_ok(fd, z))
 	  warn(_("%s: OK\n"), dev);
 	else
 	  exit_status = 1;
@@ -3089,7 +3165,7 @@ do_fdisk(char *dev){
 	printf(_("New situation:\n"));
 	out_partitions(dev, z);
 
-	if (!partitions_ok(z) && !force) {
+	if (!partitions_ok(fd, z) && !force) {
 	    if (!interactive)
 	      fatal(_("I don't like these partitions - nothing changed.\n"
 		      "(If you really want this, use the --force option.)\n"));
