Imported Upstream version 4.0.43
[platform/upstream/mtools.git] / mpartition.c
index 24ac840..56e2b6a 100644 (file)
 #define DONT_NEED_WAIT
 
 #include "sysincludes.h"
-#include "msdos.h"
 #include "mtools.h"
-#include "mainloop.h"
 #include "fsP.h"
 #include "file.h"
 #include "plain_io.h"
 #include "nameclash.h"
 #include "buffer.h"
-#include "scsi.h"
 #include "partition.h"
+#include "open_image.h"
+#include "lba.h"
 
 #ifdef OS_linux
 #include "linux/hdreg.h"
-
-#define _LINUX_STRING_H_
-#define kdev_t int
 #include "linux/fs.h"
-#undef _LINUX_STRING_H_
-
 #endif
 
-#define tolinear(x) \
-(sector(x)-1+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors)
-
-
-static __inline__ void print_hsc(hsc *h)
-{
-       printf(" h=%d s=%d c=%d\n", 
-              head(*h), sector(*h), cyl(*h));
-}
-
-static void set_offset(hsc *h, int offset, int heads, int sectors)
+static void set_offset(hsc *h, unsigned long offset,
+                      uint16_t heads, uint16_t sectors)
 {
-       int head, sector, cyl;
+       uint16_t head, sector;
+       unsigned int cyl;
 
        if(! heads || !sectors)
                head = sector = cyl = 0; /* linear mode */
@@ -61,18 +47,43 @@ static void set_offset(hsc *h, int offset, int heads, int sectors)
                offset = offset / sectors;
 
                head = offset % heads;
-               cyl = offset / heads;
-               if(cyl > 1023) cyl = 1023;
+               offset = offset / heads;
+               if(offset > 1023)
+                       cyl = 1023;
+               else
+                       cyl = (uint16_t) offset;
        }
-
-       h->head = head;
+       if(head > UINT8_MAX) {
+               /* sector or head out of range => linear mode */
+               head = sector = cyl = 0;
+       }
+       h->head = (uint8_t) head;
        h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
        h->cyl = cyl & 0xff;
 }
 
-void setBeginEnd(struct partition *partTable, int begin, int end,
-                int heads, int sectors, int activate, int type)
+void setBeginEnd(struct partition *partTable,
+                uint32_t begin, uint32_t end,
+                uint16_t iheads, uint16_t isectors,
+                int activate, uint8_t type, unsigned int fat_bits)
 {
+       uint8_t heads, sectors;
+
+       if(iheads > UINT8_MAX) {
+               fprintf(stderr,
+                       "Too many heads for partition: %d\n",
+                       iheads);
+               exit(1);
+       }
+       heads=(uint8_t) iheads;
+       if(isectors > UINT8_MAX) {
+               fprintf(stderr,
+                       "Too many sectors for partition: %d\n",
+                       isectors);
+               exit(1);
+       }
+       sectors=(uint8_t) isectors;
+
        set_offset(&partTable->start, begin, heads, sectors);
        set_offset(&partTable->end, end-1, heads, sectors);
        set_dword(partTable->start_sect, begin);
@@ -82,93 +93,59 @@ void setBeginEnd(struct partition *partTable, int begin, int end,
        else
                partTable->boot_ind = 0;
        if(!type) {
-               if(end-begin < 4096)
-                       type = 1; /* DOS 12-bit FAT */
-               else if(end-begin<32*2048)
-                       type = 4; /* DOS 16-bit FAT, <32M */
+               if (fat_bits == 0) {
+                       /**
+                        * Fat bits unknown / not specified. We look
+                        * at size to get a rough estimate what FAT
+                        * bits are used.  Note: this is only an
+                        * estimate, the precise calculation would
+                        * involve the number of clusters, which is
+                        * not necessarily known here.
+                        */
+                       /* cc977219 would have a cutoff number of 32680,
+                        * corresponding to a FAT12 partition with 4K
+                        * clusters, however other information hints that
+                        * only partitions with less than 4096 sectors are
+                        * considered */
+                       if(end-begin < 4096)
+                               fat_bits = 12;
+                       else
+                               fat_bits = 16;
+               }
+
+               /* Description of various partition types in
+                * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
+                * and
+                * https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)
+                */
+               if (fat_bits == 32)
+                       /* FAT 32 partition. For now, we disregard the
+                        * possibility of FAT 32 CHS partitions */
+                       type = 0x0C; /* Win95 FAT32, LBA */
+               else if (end < 65536) {
+                       /* FAT 12 or FAT 16 partitions which fit entirely below
+                          the 32M mark */
+                       /* The 32M restriction doesn't apply to logical
+                          partitions within an extended partition, but for the
+                          moment mpartition only makes primary partitions */
+                       if(fat_bits == 12)
+                               /* FAT 12 partition */
+                               type = 0x01; /* DOS FAT12, CHS */
+                       else if (fat_bits == 16)
+                               /* FAT 16 partition */
+                               type = 0x04; /* DOS FAT16, CHS */
+               } else if (end <  sectors * heads * 1024u)
+                       /* FAT 12 or FAT16 partition above the 32M
+                        * mark but below the 1024 cylinder mark.
+                        * Indeed, there can be no CHS partition
+                        * beyond 1024 cylinders */
+                       type = 0x06; /* DOS BIG FAT16 or FAT12, CHS */
                else
-                       type = 6; /* DOS 16-bit FAT >= 32M */
+                       type = 0x0E; /* Win95 BIG FAT16, LBA */
        }
        partTable->sys_ind = type;
 }
 
-int consistencyCheck(struct partition *partTable, int doprint, int verbose,
-                    int *has_activated, unsigned int *last_end,
-                    unsigned int *j, 
-                    struct device *used_dev, int target_partition)
-{
-       unsigned int i;
-       unsigned int inconsistency;
-       
-       *j = 0;
-       *last_end = 1;
-
-       /* quick consistency check */
-       inconsistency = 0;
-       *has_activated = 0;
-       for(i=1; i<5; i++){
-               if(!partTable[i].sys_ind)
-                       continue;
-               if(partTable[i].boot_ind)
-                       (*has_activated)++;
-               if((used_dev && 
-                   (used_dev->heads != head(partTable[i].end)+1 ||
-                    used_dev->sectors != sector(partTable[i].end))) ||
-                  sector(partTable[i].start) != 1){
-                       fprintf(stderr,
-                               "Partition %d is not aligned\n",
-                               i);
-                       inconsistency=1;
-               }
-               
-               if(*j && 
-                  *last_end > BEGIN(partTable[i])) {
-                       fprintf(stderr,
-                               "Partitions %d and %d badly ordered or overlapping\n",
-                               *j,i);
-                       inconsistency=1;
-               }
-                       
-               *last_end = END(partTable[i]);
-               *j = i;
-
-               if(used_dev &&
-                  cyl(partTable[i].start) != 1023 &&
-                  tolinear(partTable[i].start) != BEGIN(partTable[i])) {
-                       fprintf(stderr,
-                               "Start position mismatch for partition %d\n",
-                               i);
-                       inconsistency=1;
-               }
-               if(used_dev &&
-                  cyl(partTable[i].end) != 1023 &&
-                  tolinear(partTable[i].end)+1 != END(partTable[i])) {
-                       fprintf(stderr,
-                               "End position mismatch for partition %d\n",
-                               i);
-                       inconsistency=1;
-               }
-
-               if(doprint && verbose) {
-                       if(i==target_partition)
-                               putchar('*');
-                       else
-                               putchar(' ');
-                       printf("Partition %d\n",i);
-
-                       printf("  active=%x\n", partTable[i].boot_ind);
-                       printf("  start:");
-                       print_hsc(&partTable[i].start);
-                       printf("  type=0x%x\n", partTable[i].sys_ind);
-                       printf("  end:");
-                       print_hsc(&partTable[i].end);
-                       printf("  start=%d\n", BEGIN(partTable[i]));
-                       printf("  nr=%d\n", _DWORD(partTable[i].nr_sects));
-                       printf("\n");
-               }
-       }
-       return inconsistency;
-}
 
 /* setsize function.  Determines scsicam mapping if this cannot be inferred from
  * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
@@ -194,7 +171,7 @@ int consistencyCheck(struct partition *partTable, int doprint, int verbose,
  * Information technology -
  * SCSI-2 Common access method
  * transport and SCSI interface module
- * 
+ *
  * ANNEX A :
  *
  * setsize() converts a read capacity value to int 13h
@@ -204,40 +181,40 @@ int consistencyCheck(struct partition *partTable, int doprint, int verbose,
  * will not fit in 4 bits (or 6 bits). This algorithm also
  * minimizes the number of sectors that will be unused at the end
  * of the disk while allowing for very large disks to be
- * accommodated. This algorithm does not use physical geometry. 
+ * accommodated. This algorithm does not use physical geometry.
  */
 
-static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
-    unsigned int *secs) { 
-    unsigned int rv = 0; 
-    unsigned long heads, sectors, cylinders, temp; 
+static int setsize(unsigned long capacity,unsigned int *cyls,
+                  uint16_t *hds,  uint16_t *secs) {
+    int rv = 0;
+    unsigned long heads, sectors, cylinders, temp;
 
-    cylinders = 1024L;                 /* Set number of cylinders to max */ 
-    sectors = 62L;                     /* Maximize sectors per track */ 
+    cylinders = 1024L;                 /* Set number of cylinders to max */
+    sectors = 62L;                     /* Maximize sectors per track */
 
-    temp = cylinders * sectors;                /* Compute divisor for heads */ 
+    temp = cylinders * sectors;                /* Compute divisor for heads */
     heads = capacity / temp;           /* Compute value for number of heads */
-    if (capacity % temp) {             /* If no remainder, done! */ 
-       heads++;                        /* Else, increment number of heads */ 
-       temp = cylinders * heads;       /* Compute divisor for sectors */ 
+    if (capacity % temp) {             /* If no remainder, done! */
+       heads++;                        /* Else, increment number of heads */
+       temp = cylinders * heads;       /* Compute divisor for sectors */
        sectors = capacity / temp;      /* Compute value for sectors per
-                                              track */ 
-       if (capacity % temp) {          /* If no remainder, done! */ 
-           sectors++;                  /* Else, increment number of sectors */ 
+                                              track */
+       if (capacity % temp) {          /* If no remainder, done! */
+           sectors++;                  /* Else, increment number of sectors */
            temp = heads * sectors;     /* Compute divisor for cylinders */
-           cylinders = capacity / temp;/* Compute number of cylinders */ 
-       } 
-    } 
-    if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ 
-
-    *cyls = (unsigned int) cylinders;  /* Stuff return values */ 
-    *secs = (unsigned int) sectors; 
-    *hds  = (unsigned int) heads; 
-    return(rv); 
-} 
-
-static void setsize0(unsigned long capacity,unsigned int *cyls,
-                    unsigned int *hds, unsigned int *secs)
+           cylinders = capacity / temp;/* Compute number of cylinders */
+       }
+    }
+    if (cylinders == 0) rv=-1;/* Give error if 0 cylinders */
+
+    *cyls = (unsigned int) cylinders;  /* Stuff return values */
+    *secs = (uint16_t) sectors;
+    *hds  = (uint16_t) heads;
+    return(rv);
+}
+
+static void setsize0(uint32_t capacity,unsigned int *cyls,
+                    uint16_t *hds, uint16_t *secs)
 {
        int r;
 
@@ -264,9 +241,9 @@ static void setsize0(unsigned long capacity,unsigned int *cyls,
 static void usage(int ret) NORETURN;
 static void usage(int ret)
 {
-       fprintf(stderr, 
+       fprintf(stderr,
                "Mtools version %s, dated %s\n", mversion, mdate);
-       fprintf(stderr, 
+       fprintf(stderr,
                "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] "
                        "[-t cylinders] "
                "[-h heads] [-T type] [-b begin] [-l length] "
@@ -274,46 +251,50 @@ static void usage(int ret)
        exit(ret);
 }
 
-void mpartition(int argc, char **argv, int dummy)
+void mpartition(int argc, char **argv, int dummy UNUSEDP) NORETURN;
+void mpartition(int argc, char **argv, int dummy UNUSEDP)
 {
        Stream_t *Stream;
        unsigned int dummy2;
 
-       unsigned int i,j;
+       unsigned int i;
 
-       int sec_per_cyl;
+       uint16_t sec_per_cyl;
        int doprint = 0;
        int verbose = 0;
        int create = 0;
        int force = 0;
-       int length = 0;
+       unsigned int length = 0;
        int do_remove = 0;
        int initialize = 0;
-       unsigned int tot_sectors=0;
-       int type = 0;
+
+       uint32_t tot_sectors=0;
+       /* Needs to be long due to BLKGETSIZE ioctl */
+
+       uint8_t type = 0;
        int begin_set = 0;
        int size_set = 0;
        int end_set = 0;
-       unsigned int last_end = 0;
        int activate = 0;
        int has_activated = 0;
        int inconsistency=0;
-       int begin=0;
-       int end=0;
-       int sizetest=0;
+       unsigned int begin=0;
+       unsigned int end=0;
        int dirty = 0;
-       int open2flags = NO_OFFSET;
-       
+       int open2flags = 0;
+
        int c;
        struct device used_dev;
-       int argtracks, argheads, argsectors;
+       unsigned int argtracks;
+       uint16_t argheads, argsectors;
 
        char drive, name[EXPAND_BUF];
        unsigned char buf[512];
        struct partition *partTable=(struct partition *)(buf+ 0x1ae);
        struct device *dev;
-       char errmsg[200];
+       char errmsg[2100];
        char *bootSector=0;
+       struct partition *tpartition;
 
        argtracks = 0;
        argheads = 0;
@@ -323,6 +304,8 @@ void mpartition(int argc, char **argv, int dummy)
        if(helpFlag(argc, argv))
                usage(0);
        while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
+               char *endptr=NULL;
+               errno=0;
                switch (c) {
                        case 'i':
                                set_cmd_line_image(optarg);
@@ -350,7 +333,7 @@ void mpartition(int argc, char **argv, int dummy)
                                dirty = 1;
                                break;
                        case 'I':
-                               /* could be abused to nuke all other 
+                               /* could be abused to nuke all other
                                 * partitions */
                                open2flags |= NO_PRIV;
                                initialize = 1;
@@ -365,17 +348,17 @@ void mpartition(int argc, char **argv, int dummy)
                                /* could be abused to "manually" create
                                 * extended partitions */
                                open2flags |= NO_PRIV;
-                               type = strtoul(optarg,0,0);
+                               type = strtou8(optarg, &endptr, 0);
                                break;
 
                        case 't':
-                               argtracks = atoi(optarg);
+                               argtracks = atoui(optarg);
                                break;
                        case 'h':
-                               argheads = atoi(optarg);
+                               argheads = atou16(optarg);
                                break;
                        case 's':
-                               argsectors = atoi(optarg);
+                               argsectors = atou16(optarg);
                                break;
 
                        case 'f':
@@ -388,36 +371,28 @@ void mpartition(int argc, char **argv, int dummy)
                        case 'v':
                                verbose++;
                                break;
-                       case 'S':
-                               /* testing only */
-                               /* could be abused to create partitions
-                                * extending beyond the actual size of the
-                                * device */
-                               open2flags |= NO_PRIV;
-                               tot_sectors = strtoul(optarg,0,0);
-                               sizetest = 1;
-                               break;
                        case 'b':
                                begin_set = 1;
-                               begin = atoi(optarg);
+                               begin = strtoui(optarg, &endptr, 0);
                                break;
                        case 'l':
                                size_set = 1;
-                               length = atoi(optarg);
+                               length = parseSize(optarg);
                                break;
 
                        default:
                                usage(1);
                }
+               check_number_parse_errno((char)c, optarg, endptr);
        }
 
        if (argc - optind != 1 ||
            !argv[optind][0] || argv[optind][1] != ':')
                usage(1);
-       
-       drive = toupper(argv[optind][0]);
 
-       /* check out a drive whose letter and parameters match */       
+       drive = ch_toupper(argv[optind][0]);
+
+       /* check out a drive whose letter and parameters match */
        sprintf(errmsg, "Drive '%c:' not supported", drive);
        Stream = 0;
        for(dev=devices;dev->drive;dev++) {
@@ -428,8 +403,8 @@ void mpartition(int argc, char **argv, int dummy)
                if (dev->drive != drive)
                        continue;
                if (dev->partition < 1 || dev->partition > 4) {
-                       sprintf(errmsg, 
-                               "Drive '%c:' is not a partition", 
+                       sprintf(errmsg,
+                               "Drive '%c:' is not a partition",
                                drive);
                        continue;
                }
@@ -438,7 +413,7 @@ void mpartition(int argc, char **argv, int dummy)
                SET_INT(used_dev.tracks, argtracks);
                SET_INT(used_dev.heads, argheads);
                SET_INT(used_dev.sectors, argsectors);
-               
+
                expand(dev->name, name);
 
                mode = dirty ? O_RDWR : O_RDONLY;
@@ -448,50 +423,26 @@ void mpartition(int argc, char **argv, int dummy)
 #ifdef USING_NEW_VOLD
                strcpy(name, getVoldName(dev, name));
 #endif
-               Stream = SimpleFileOpen(&used_dev, dev, name, mode, 
-                                       errmsg, open2flags, 1, 0);
+               Stream = OpenImage(&used_dev, dev, name, mode, errmsg,
+                                  open2flags | SKIP_PARTITION | ALWAYS_GET_GEOMETRY,
+                                  mode, NULL, NULL, NULL);
 
                if (!Stream) {
 #ifdef HAVE_SNPRINTF
-                       snprintf(errmsg,199,"init: open: %s", strerror(errno));
+                       snprintf(errmsg,sizeof(errmsg)-1,
+                                "init: open: %s", strerror(errno));
 #else
                        sprintf(errmsg,"init: open: %s", strerror(errno));
 #endif
                        continue;
-               }                       
-
-
-               /* try to find out the size */
-               if(!sizetest)
-                       tot_sectors = 0;
-               if(IS_SCSI(dev)) {
-                       unsigned char cmd[10];
-                       unsigned char data[10];
-                       cmd[0] = SCSI_READ_CAPACITY;
-                       memset ((void *) &cmd[2], 0, 8);
-                       memset ((void *) &data[0], 137, 10);
-                       scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
-                                data, 10, get_extra_data(Stream));
-                       
-                       tot_sectors = 1 +
-                               (data[0] << 24) +
-                               (data[1] << 16) +
-                               (data[2] <<  8) +
-                               (data[3]      );
-                       if(verbose)
-                               printf("%d sectors in total\n", tot_sectors);
                }
 
-#ifdef OS_linux
-               if (tot_sectors == 0) {
-                       ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
-               }
-#endif
+               tot_sectors = used_dev.tot_sectors;
 
                /* read the partition table */
-               if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
+               if (PREADS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
 #ifdef HAVE_SNPRINTF
-                       snprintf(errmsg, 199,
+                       snprintf(errmsg, sizeof(errmsg)-1,
                                "Error reading from '%s', wrong parameters?",
                                name);
 #else
@@ -506,7 +457,7 @@ void mpartition(int argc, char **argv, int dummy)
                break;
        }
 
-       /* print error msg if needed */ 
+       /* print error msg if needed */
        if ( dev->drive == 0 ){
                FREE(&Stream);
                fprintf(stderr,"%s: %s\n", argv[0],errmsg);
@@ -544,13 +495,14 @@ void mpartition(int argc, char **argv, int dummy)
                        "Use the -I flag to initialize the partition table, and set the boot signature\n");
                inconsistency = 1;
        }
-       
+
+       tpartition=&partTable[dev->partition];
        if(do_remove){
-               if(!partTable[dev->partition].sys_ind)
+               if(!tpartition->sys_ind)
                        fprintf(stderr,
                                "Partition for drive %c: does not exist\n",
                                drive);
-               if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
+               if((tpartition->sys_ind & 0x3f) == 5) {
                        fprintf(stderr,
                                "Partition for drive %c: may be an extended partition\n",
                                drive);
@@ -558,149 +510,122 @@ void mpartition(int argc, char **argv, int dummy)
                                "Use the -f flag to remove it anyways\n");
                        inconsistency = 1;
                }
-               memset(&partTable[dev->partition], 0, sizeof(*partTable));
+               memset(tpartition, 0, sizeof(*tpartition));
        }
 
-       if(create && partTable[dev->partition].sys_ind) {
+       if(create && tpartition->sys_ind) {
                fprintf(stderr,
                        "Partition for drive %c: already exists\n", drive);
                fprintf(stderr,
                        "Use the -r flag to remove it before attempting to recreate it\n");
        }
 
+       /* if number of heads and sectors not known yet, set "reasonable"
+        * defaults */
+       compute_lba_geom_from_tot_sectors(&used_dev);
 
-       /* find out number of heads and sectors, and whether there is
-       * any activated partition */
+       /* find out whether there is any activated partition. Moreover
+        * if no offset of a partition to be created have been
+        * specificed, find out whether it may be placed between the
+        * preceding and following partition already existing */
        has_activated = 0;
        for(i=1; i<5; i++){
-               if(!partTable[i].sys_ind)
+               struct partition *partition=&partTable[i];
+               if(!partition->sys_ind)
                        continue;
-               
-               if(partTable[i].boot_ind)
+
+               if(partition->boot_ind)
                        has_activated++;
 
-               /* set geometry from entry */
-               if (!used_dev.heads)
-                       used_dev.heads = head(partTable[i].end)+1;
-               if(!used_dev.sectors)
-                       used_dev.sectors = sector(partTable[i].end);
                if(i<dev->partition && !begin_set)
-                       begin = END(partTable[i]);
+                       begin = END(partition);
                if(i>dev->partition && !end_set && !size_set) {
-                       end = BEGIN(partTable[i]);
+                       end = BEGIN(partition);
                        end_set = 1;
                }
        }
 
-#ifdef OS_linux
-       if(!used_dev.sectors && !used_dev.heads) {
-               if(!IS_SCSI(dev)) {
-                       struct hd_geometry geom;
-                       if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) {
-                               used_dev.heads = geom.heads;
-                               used_dev.sectors = geom.sectors;
-                       }
-               }
-       }
-#endif
-
        if(!used_dev.sectors && !used_dev.heads) {
-               if(tot_sectors)
-                       setsize0(tot_sectors,&dummy2,&used_dev.heads,
-                                        &used_dev.sectors);
-               else {
+               if(tot_sectors) {
+                       setsize0((uint32_t)tot_sectors,&dummy2,&used_dev.heads,
+                                &used_dev.sectors);
+               else {
                        used_dev.heads = 64;
                        used_dev.sectors = 32;
                }
        }
 
        if(verbose)
-               fprintf(stderr,"sectors: %d heads: %d %d\n",
+               fprintf(stderr,"sectors: %d heads: %d %u\n",
                        used_dev.sectors, used_dev.heads, tot_sectors);
 
        sec_per_cyl = used_dev.sectors * used_dev.heads;
        if(create) {
-               if(!end_set && tot_sectors) {
+               unsigned int overlap;
+               if(!end_set && !size_set && tot_sectors) {
                        end = tot_sectors - tot_sectors % sec_per_cyl;
                        end_set = 1;
                }
-               
+
                /* if the partition starts right at the beginning of
                 * the disk, keep one track unused to allow place for
                 * the master boot record */
                if(!begin && !begin_set)
-                       begin = used_dev.sectors;
-               if(!size_set && used_dev.tracks) {
-                       size_set = 2;
-                       length = sec_per_cyl * used_dev.tracks;
-
-                       /*  round the size in order to take
-                        * into account any "hidden" sectors */
-
-                       /* do we anchor this at the beginning ?*/
-                       if(begin_set || dev->partition <= 2 || !end_set)
-                               length -= begin % sec_per_cyl;
-                       else if(end - length < begin)
-                               /* truncate any overlap */
-                               length = end - begin;
-               }
+                       begin = used_dev.sectors ? used_dev.sectors : 2048;
+
+               /* Do not try to align  partitions (other than first) on track
+                * boundaries here: apparently this was a thing of the past */
+
                if(size_set) {
-                       if(!begin_set && dev->partition >2 && end_set)
-                               begin = end - length;
-                       else
-                               end = begin + length;
+                       end = begin + length;
                } else if(!end_set) {
                        fprintf(stderr,"Unknown size\n");
                        exit(1);
                }
 
-               setBeginEnd(&partTable[dev->partition], begin, end,
-                                       used_dev.heads, used_dev.sectors, 
-                                       !has_activated, type);
+               /* Make sure partition boundaries are correctly ordered
+                * (end > begin) */
+               if(begin >= end) {
+                       fprintf(stderr, "Begin larger than end\n");
+                       exit(1);
+               }
+
+               /* Check whether new partition doesn't overlap with
+                * any of those already in place */
+               if((overlap=findOverlap(partTable, 4, begin, end))) {
+                       fprintf(stderr,
+                               "Partition would overlap with partition %d\n",
+                               overlap);
+                       exit(1);
+               }
+
+               setBeginEnd(tpartition, begin, end,
+                           used_dev.heads, used_dev.sectors,
+                           !has_activated, type,
+                           abs(dev->fat_bits));
        }
 
        if(activate) {
-               if(!partTable[dev->partition].sys_ind) {
+               if(!tpartition->sys_ind) {
                        fprintf(stderr,
                                "Partition for drive %c: does not exist\n",
                                drive);
                } else {
                        switch(activate) {
                                case 1:
-                                       partTable[dev->partition].boot_ind=0x80;
+                                       tpartition->boot_ind=0x80;
                                        break;
                                case -1:
-                                       partTable[dev->partition].boot_ind=0x00;
+                                       tpartition->boot_ind=0x00;
                                        break;
                        }
                }
        }
 
-
        inconsistency |= consistencyCheck(partTable, doprint, verbose,
-                                         &has_activated, &last_end, &j,
+                                         &has_activated, tot_sectors,
                                          &used_dev, dev->partition);
 
-       if(doprint && !inconsistency && partTable[dev->partition].sys_ind) {
-               printf("The following command will recreate the partition for drive %c:\n", 
-                      drive);
-               used_dev.tracks = 
-                       (_DWORD(partTable[dev->partition].nr_sects) +
-                        (BEGIN(partTable[dev->partition]) % sec_per_cyl)) / 
-                       sec_per_cyl;
-               printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
-                      used_dev.tracks, used_dev.heads, used_dev.sectors,
-                      BEGIN(partTable[dev->partition]), drive);
-       }
-
-       if(tot_sectors && last_end >tot_sectors) {
-               fprintf(stderr,
-                       "Partition %d exceeds beyond end of disk\n",
-                       j);
-               exit(1);
-       }
-
-       
        switch(has_activated) {
                case 0:
                        fprintf(stderr,
@@ -716,21 +641,35 @@ void mpartition(int argc, char **argv, int dummy)
                                "Usually, a disk should have exactly one active partition\n");
                        break;
        }
-       
+
        if(inconsistency && !force) {
                fprintf(stderr,
                        "inconsistency detected!\n" );
-               if(dirty)
+               if(dirty) {
                        fprintf(stderr,
                                "Retry with the -f switch to go ahead anyways\n");
-               exit(1);
+                       exit(1);
+               }
+       }
+
+       if(doprint && tpartition->sys_ind) {
+               printf("The following command will recreate the partition for drive %c:\n",
+                      drive);
+               used_dev.tracks =
+                       (DWORD(tpartition->nr_sects) +
+                        (BEGIN(tpartition) % sec_per_cyl)) /
+                       sec_per_cyl;
+               printf("mpartition -c -b %d -l %d -t %d -h %d -s %d -b %u %c:\n",
+                      BEGIN(tpartition), PART_SIZE(tpartition),
+                      used_dev.tracks, used_dev.heads, used_dev.sectors,
+                      BEGIN(tpartition), drive);
        }
 
        if(dirty) {
                /* write data back to the disk */
                if(verbose>=2)
                        print_sector("Writing sector", buf, 512);
-               if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
+               if (PWRITES(Stream, (char *) buf, 0, 512) != 512) {
                        fprintf(stderr,"Error writing partition table");
                        exit(1);
                }