home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / libfdisk / partition.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-12  |  27.5 KB  |  842 lines

  1. /* this file has 'high-level' operations which only use the partition # */
  2. /* For example, on a disk the first 4 partitions are the primary partitions */
  3. /* and are numbered 1 thru 4. Then each subsequent logical paritition   */
  4. /* is numbered sequentially starting with 5.                            */
  5. /* The functions in this file use this partition number as the index of */
  6. /* the operation.                                                       */
  7. /* Recoded to use new HardDrive struct with single partition table      */
  8.  
  9.  
  10. #include <stdio.h>
  11. #include <unistd.h>
  12. #include <malloc.h>
  13. #include <string.h>
  14. #include <errno.h>
  15. #include "libfdisk.h"
  16. #include "sunlabel.h"
  17. #include "bsdlabel.h"
  18.  
  19. static int fdiskWritePartitions ( HardDrive *hd) ;
  20. static int fdiskWriteSunPartitions( HardDrive *hd );
  21.  
  22. /* not sure where this guy should go, we'll leave it here for now */
  23. /* make raw partition entry for the given partition               */
  24. /* partition should have the start, size, type, active fields set */
  25. /* rest are taken care of                                         */
  26. int fdiskMakeRawEntry( HardDrive *hd, Partition *pt, RawPartition *p ) {
  27.     unsigned int start, size, end;
  28.     unsigned int s_cyl, s_hd, s_sec;
  29.     unsigned int e_cyl, e_hd, e_sec;
  30.     unsigned int cur, low, hi, act;
  31.  
  32.     /* read in the current values for the various parameters */
  33.     fdiskGetConstraint( &pt->start,  &p->start,  &low, &hi, &act );
  34.     fdiskGetConstraint( &pt->size,   &p->size,   &low, &hi, &act );
  35.     fdiskGetConstraint( &pt->type,   &cur,       &low, &hi, &act );
  36.     p->type   = cur;
  37.     fdiskGetConstraint( &pt->active, &cur,       &low, &hi, &act );
  38.     p->active = cur;
  39.     
  40.     /* convert from sector to cyl/hd/sector */
  41.     start = p->start;
  42.     size  = p->size;
  43.     end   = start + size - 1;
  44.     
  45.     fdiskSectorToCHS( hd, start, &s_cyl, &s_hd, &s_sec );
  46.     fdiskSectorToCHS( hd, end  , &e_cyl, &e_hd, &e_sec );
  47.     
  48.     /* we have to store CHS in funky way */
  49.     /* handle cylinder limits on PC partitions correctly */
  50.     s_cyl = (s_cyl > 1023) ? 1023 : s_cyl;
  51.     p->start_cyl  = s_cyl & 0xff;
  52.     p->start_head = s_hd;
  53.     p->start_sec  = s_sec | ((s_cyl >> 2) &0xc0);
  54.  
  55.     e_cyl = (e_cyl > 1023) ? 1023 : e_cyl;
  56.     p->end_cyl    = e_cyl & 0xff;
  57.     p->end_head   = e_hd;
  58.     p->end_sec    = e_sec | ((e_cyl >> 2) &0xc0);
  59.     
  60.     return FDISK_SUCCESS;
  61. }
  62.  
  63.  
  64.  
  65. /* remove partition # n from drive hd. If it doesn't exist then a return */
  66. /* code > 0 is returned, else 0 is returned                              */
  67. /* First primary partition is number 1, not 0!                           */
  68. int fdiskRemovePartition( HardDrive *hd, unsigned int n ) {
  69.     
  70.     if (n < 1)
  71.     return FDISK_ERR_BADNUM;
  72.     
  73.     if (n <= hd->limits.maxPrimary) {
  74.     return fdiskRemovePrimary( hd, n );
  75.     } else {
  76.     return fdiskRemoveLogical( hd, n );
  77.     }
  78. }
  79.  
  80. /*                                                                         */
  81. /* not currently used, unclear what numbering scheme to use to index       */
  82. /* partitions we wish to create beyond the first 4.  Logical partition     */
  83. /* numbers are sequential, so only 'free' number to create a new partition */
  84. /* at would be the number of the last logical plus one. Seems kludgey to   */
  85. /* require user to figure out that number just to call the function.       */
  86. /* Instead I will have a fdiskCreatePrimary() and fdiskAppendLogical()     */
  87. /*                                                                         */
  88. #if 0
  89. /* create partition number n, where n can be 1-4 for primary,   */
  90. /* or 5 or greater to append a logical partition (this is       */
  91. /* because of screwy way logicals are numbered )                */ 
  92. /* DO NOT USE THIS FUNCTION YET - UNCLEAR IF IT ACTS LIKE WE WANT!  */
  93. /* DOES NOT MAKE EXTENDED PARTITIONS IF THEY ARE NEEDED FOR LOGICAL */
  94. int fdiskCreatePartition( HardDrive *hd, unsigned int n,
  95.               unsigned int start, unsigned int size) {
  96.  
  97.     if (n < 1 )
  98.     return FDISK_ERR_BADNUM;
  99.     
  100.     if (n <= hd->limits.maxPrimary) {
  101.     return fdiskCreatePrimary(hd, n, start, size);
  102.     } else {
  103.     /* append a logical partition */
  104.     return fdiskAppendLogical( hd, start, size );
  105.     }
  106. }
  107. #endif
  108.  
  109.  
  110. /* Set    partition #n into the current partition table */
  111. /* DOES NOT create an extended partition if necessary   */
  112. /* does not do any sanity checking on attributes        */
  113. int fdiskSetAttrPartition( HardDrive *hd, unsigned int n, Partition *p ) {
  114.     
  115.     if (n < 1)
  116.     return FDISK_ERR_BADNUM;
  117.     
  118.     if (n <= hd->limits.maxPrimary)
  119.     return fdiskSetAttrPrimary(hd, n, p);
  120.     else
  121.     return fdiskSetAttrLogical(hd, n, p);
  122. }
  123.  
  124.  
  125. int fdiskGetAttrPartition( HardDrive *hd, unsigned int n, Partition **p ) {
  126.     
  127.     if (n < 1)
  128.     return FDISK_ERR_BADNUM;
  129.     
  130.     if (n <= hd->limits.maxPrimary)
  131.     return fdiskGetAttrPrimary(hd, n, p);
  132.     else
  133.     return fdiskGetAttrLogical(hd, n, p);
  134. }
  135.  
  136. static void initializeHardDrive(HardDrive * hd) {
  137.     int i;
  138.  
  139.     /* set all primaries as available and all extended as unavailable */
  140.     for (i=1; i <= hd->limits.maxPartitions; i++) {
  141.     if (i < (hd->limits.maxPrimary + 1))
  142.         hd->table[i].status = AVAILABLE;
  143.     else
  144.         hd->table[i].status = UNAVAILABLE;
  145.  
  146.     /* set all eptable entries as UNAVAILABLE */
  147.     hd->eptable[i].status = UNAVAILABLE;
  148.     }
  149. }
  150.  
  151. int fdiskInitSunLabel( HardDrive * hd) {
  152.     struct sun_disklabel label;
  153.     unsigned short * sp;
  154.  
  155.     memset(&label, 0, sizeof(label));
  156.  
  157.     label.magic = SUN_LABEL_MAGIC;
  158.     label.rspeed = 5400;
  159.     label.nacyl = 2;
  160.     label.sparecyl = 0;
  161.     label.ilfact = 1;
  162.     label.pcylcount = hd->geom.cylinders;
  163.     hd->geom.cylinders -= label.nacyl;
  164.     label.ncyl = hd->geom.cylinders;
  165.     label.ntrks = hd->geom.heads;
  166.     label.nsect = hd->geom.sectors;
  167.  
  168.     label.partitions[2].num_sectors = label.ncyl * label.ntrks * label.nsect;
  169.     label.partitions[2].start_cylinder = 0;
  170.     label.infos[2].id = 5;
  171.  
  172.     label.csum = 0;
  173.     for (sp = (unsigned short *) &label; sp < &label.csum; sp++)
  174.     label.csum ^= *sp;
  175.  
  176.     if (lseek(hd->fd, 0, SEEK_SET)) return -1;
  177.     if (write(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  178.  
  179.     return 0;
  180. }
  181.  
  182. static int fdiskWriteSunPartitions( HardDrive *hd ) {
  183.     struct sun_disklabel label;
  184.     int i;
  185.     Partition * p;
  186.     unsigned short * sp;
  187.  
  188.     if (lseek(hd->fd, 0, SEEK_SET)) return -1;
  189.     if (read(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  190.     if (label.magic != SUN_LABEL_MAGIC) return FDISK_ERR_BADMAGIC;
  191.  
  192.     for (i = 0; i < 8; i++) {
  193.     if (fdiskGetAttrPartition( hd, i + 1, &p ) == FDISK_SUCCESS) {
  194.         label.partitions[i].num_sectors = p->size.current;
  195.         label.partitions[i].start_cylinder = p->start.current /
  196.             (hd->geom.sectors * hd->geom.heads);
  197.         /* How's this for a hack? */
  198.         if (p->type.current == 0x82 && !label.partitions[i].start_cylinder)
  199.         label.partitions[i].start_cylinder++;
  200.         label.infos[i].id = p->type.current;
  201.     } else {
  202.         label.partitions[i].num_sectors = 0;
  203.         label.partitions[i].start_cylinder = 0;
  204.         label.infos[i].id = 0;
  205.     }
  206.     }
  207.  
  208.     label.csum = 0;
  209.     for (sp = (unsigned short *) &label; sp < &label.csum; sp++)
  210.     label.csum ^= *sp;
  211.  
  212.     if (lseek(hd->fd, 0, SEEK_SET)) return -1;
  213.     if (write(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  214.  
  215.     return fdiskReReadPartitions(hd);
  216. }
  217.  
  218. static int fdiskReadSunPartitions( HardDrive *hd ) {
  219.     struct sun_disklabel label;
  220.     int s, i;
  221.     Partition p;
  222.  
  223.     if (lseek(hd->fd, 0, SEEK_SET)) return -1;
  224.     if (read(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  225.     if (label.magic != SUN_LABEL_MAGIC) return FDISK_ERR_BADMAGIC;
  226.  
  227.     hd->limits.maxPrimary = 8;
  228.     hd->limits.maxPartitions = 8;
  229.     initializeHardDrive(hd);
  230.  
  231.     hd->geom.cylinders = label.ncyl;
  232.     hd->totalsectors = hd->geom.cylinders * hd->geom.heads * hd->geom.sectors;
  233.     hd->write_f = fdiskWriteSunPartitions;
  234.  
  235.     for (i = 0; i < 8; i++) {
  236.     if (label.partitions[i].num_sectors && label.infos[i].id) {
  237.         if ((s=fdiskCreatePrimary( hd, i + 1)) != 0)
  238.         return s;
  239.  
  240.         fdiskSetFixedConstraint(&p.size,    
  241.                     label.partitions[i].num_sectors);
  242.         fdiskSetFixedConstraint(&p.start,   
  243.             label.partitions[i].start_cylinder * hd->geom.sectors * hd->geom.heads);
  244.     
  245.         fdiskSetFixedConstraint(&p.offset,   0);
  246.         fdiskSetFixedConstraint(&p.type,    label.infos[i].id);
  247.         fdiskSetFixedConstraint(&p.active,  0               );
  248.         fdiskSetFixedConstraint(&p.offset,  0                      );
  249.         fdiskDeactivateAllDriveSet( &p.drive );
  250.         fdiskActivateDriveSet( &p.drive, hd->num );
  251.         fdiskSetCurrentDriveSet( &p.drive, hd->num );
  252.         fdiskSetFixedConstraint( &p.num, i + 1);
  253.         
  254.         /* now to make sure NOTHING can happen to this partition */
  255.         p.immutable = 1;
  256.         p.status    = ALLOCATED;
  257.  
  258.         /* store in the partition table */
  259.         fdiskSetAttrPartition( hd, i+ 1, &p );
  260.     }
  261.     }
  262.     
  263.     return 0;
  264. }
  265.  
  266. static unsigned short xbsd_dkcksum (struct bsd_disklabel *lp) {
  267.   unsigned short *start, *end;
  268.   unsigned short sum = 0;
  269.   
  270.   lp->d_checksum = 0;
  271.   start = (u_short *)lp;
  272.   end = (u_short *)&lp->d_partitions[lp->d_npartitions];
  273.   while (start < end)
  274.     sum ^= *start++;
  275.   return (sum);
  276. }
  277.  
  278. void alpha_bootblock_checksum (char *boot) {
  279.   u_int64_t *dp, sum;
  280.   int i;
  281.    
  282.   dp = (u_int64_t *)boot;
  283.   sum = 0;
  284.   for (i = 0; i < 63; i++)
  285.     sum += dp[i];
  286.   dp[63] = sum;
  287. }
  288.  
  289. static int fdiskWriteLabelPartitions( HardDrive *hd ) {
  290.     struct bsd_disklabel label;
  291.     int i, s;
  292.     Partition * p;
  293.     char boot[512];
  294.  
  295.     if (lseek(hd->fd, BSD_LABEL_OFFSET, SEEK_SET) < 0) return -1;
  296.     if (read(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  297.     if (label.d_magic != BSD_DISKMAGIC) return FDISK_ERR_BADMAGIC;
  298.  
  299.     for (i = 0; i < 8; i++) {
  300.     if (fdiskGetAttrPartition( hd, i + 1, &p ) == FDISK_SUCCESS) {
  301.         label.d_partitions[i].p_size = p->size.current;
  302.         label.d_partitions[i].p_offset = p->start.current;
  303.         /* How's this for a hack? */
  304.         if (p->type.current == 0x82 && !label.d_partitions[i].p_offset)
  305.         label.d_partitions[i].p_offset++;
  306.  
  307.         switch (p->type.current) {
  308.           case LINUX_SWAP_PARTITION: s = 1; break;
  309.           case LINUX_NATIVE_PARTITION: s = 8; break;
  310.           default: s = p->type.current; break;
  311.         }
  312.  
  313.         label.d_partitions[i].p_fstype = s;
  314.     } else {
  315.         label.d_partitions[i].p_size = 0;
  316.         label.d_partitions[i].p_offset = 0;
  317.         label.d_partitions[i].p_fstype = 0;
  318.     }
  319.     }
  320.  
  321.     label.d_checksum = xbsd_dkcksum (&label);
  322.  
  323.     if (lseek(hd->fd, BSD_LABEL_OFFSET, SEEK_SET) < 0) return -1;
  324.     if (write(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  325.  
  326.     if (lseek(hd->fd, 0, SEEK_SET) < 0) return -1;
  327.     if (read(hd->fd, &boot, sizeof(boot)) != sizeof(boot)) return -1;
  328.     alpha_bootblock_checksum(boot);
  329.     if (lseek(hd->fd, 0, SEEK_SET) < 0) return -1;
  330.     if (write(hd->fd, &boot, sizeof(boot)) != sizeof(boot)) return -1;
  331.  
  332.     return fdiskReReadPartitions(hd);
  333. }
  334.  
  335. static int fdiskReadLabelPartitions( HardDrive *hd ) {
  336.     struct bsd_disklabel label;
  337.     int i, s;
  338.     Partition p;
  339.  
  340.     if (lseek(hd->fd, BSD_LABEL_OFFSET, SEEK_SET) < 0) return -1;
  341.     if (read(hd->fd, &label, sizeof(label)) != sizeof(label)) return -1;
  342.     if (label.d_magic != BSD_DISKMAGIC) return FDISK_ERR_BADMAGIC;
  343.  
  344.     hd->limits.maxPrimary = 8;
  345.     hd->limits.maxPartitions = 8;
  346.     initializeHardDrive(hd);
  347.  
  348.     hd->totalsectors = hd->geom.cylinders * hd->geom.heads * hd->geom.sectors;
  349.     hd->write_f = fdiskWriteLabelPartitions;
  350.     
  351.     for (i = 0; i < 8; i++) {
  352.     if (label.d_partitions[i].p_size && label.d_partitions[i].p_fstype) {
  353.         if ((s=fdiskCreatePrimary( hd, i + 1)) != 0)
  354.         return s;
  355.  
  356.         fdiskSetFixedConstraint(&p.size,    
  357.                     label.d_partitions[i].p_size);
  358.         fdiskSetFixedConstraint(&p.start,   
  359.             label.d_partitions[i].p_offset);
  360.     
  361.         fdiskSetFixedConstraint(&p.offset,   0);
  362.  
  363.         switch (label.d_partitions[i].p_fstype) {
  364.           case 1: s = LINUX_SWAP_PARTITION; break;
  365.           case 8: s = LINUX_NATIVE_PARTITION; break;
  366.           default: s = label.d_partitions[i].p_fstype; break;
  367.         }
  368.  
  369.         fdiskSetFixedConstraint(&p.type,    s               );
  370.  
  371.         fdiskSetFixedConstraint(&p.active,  0               );
  372.         fdiskSetFixedConstraint(&p.offset,  0                      );
  373.         fdiskDeactivateAllDriveSet( &p.drive );
  374.         fdiskActivateDriveSet( &p.drive, hd->num );
  375.         fdiskSetCurrentDriveSet( &p.drive, hd->num );
  376.         fdiskSetFixedConstraint( &p.num, i + 1);
  377.         
  378.         /* now to make sure NOTHING can happen to this partition */
  379.         p.immutable = 1;
  380.         p.status    = ALLOCATED;
  381.  
  382.         /* store in the partition table */
  383.         fdiskSetAttrPartition( hd, i+ 1, &p );
  384.     }
  385.     }
  386.  
  387.     return 0;
  388. }
  389.  
  390. /* give a hard drive hd, read in the partition data        */
  391. /* COMPLETELY trashes all partition info in the hard drive */
  392. int fdiskReadPartitions( HardDrive *hd ) {
  393.     int i, s;
  394.     unsigned int exttype;
  395.     RawPartitionTable *pt;
  396.     Partition         p, ept, *pti;
  397.     
  398.     s = fdiskReadPartitionTable(hd, 0L, &pt );
  399.     if (s == FDISK_ERR_BADMAGIC) {
  400.     s = fdiskReadSunPartitions(hd);
  401.     if (s == FDISK_ERR_BADMAGIC)
  402.         s = fdiskReadLabelPartitions(hd);
  403.  
  404.     return s;
  405.     } else if (s) {
  406.     return s;
  407.     }
  408.  
  409.     hd->limits.maxPrimary = 4;
  410.     hd->limits.maxPartitions = 16;
  411.     initializeHardDrive(hd);
  412.     hd->write_f = fdiskWritePartitions;
  413.  
  414.     /* move data from raw partition table into abstract data type */
  415.     /* primary partitions store absolute sector offsets/sizes already */
  416.     for (i=1; i <= hd->limits.maxPrimary; i++) {
  417.     if ((s=fdiskCreatePrimary( hd, i )) != 0)
  418.         return s;
  419.  
  420.     /* get initial attr of the partition */
  421.     fdiskGetAttrPartition( hd, i, &pti );
  422.     memcpy(&p, pti, sizeof(Partition));
  423.     free(pti);
  424.  
  425.     /* if the partition is defined                                */
  426.     /* have to set this up so that we don't try to mangle this    */
  427.     /* partition later when we are automatically allocating space */
  428.     /* for newly created partitions                               */
  429.     /* remember the rawPT index starts at 0, PT starts at 1       */
  430.     if (pt->entry[i-1].size && pt->entry[i-1].type) {
  431.         fdiskSetFixedConstraint( &p.size,    pt->entry[i-1].size    );
  432.         fdiskSetFixedConstraint( &p.start,   pt->entry[i-1].start   );
  433.         fdiskSetFixedConstraint( &p.type,    pt->entry[i-1].type    );
  434.         fdiskSetFixedConstraint( &p.active,  pt->entry[i-1].active  );
  435.         fdiskSetFixedConstraint( &p.offset,  0                      );
  436.         fdiskDeactivateAllDriveSet( &p.drive );
  437.         fdiskActivateDriveSet( &p.drive, hd->num );
  438.         fdiskSetCurrentDriveSet( &p.drive, hd->num );
  439.         fdiskSetFixedConstraint( &p.num, i );
  440.         
  441.         /* now to make sure NOTHING can happen to this partition */
  442.         p.immutable = 1;
  443.         p.status    = ALLOCATED;
  444.     } else {
  445.         p.status = AVAILABLE;
  446.     }
  447.  
  448.     /* store in the partition table */
  449.     fdiskSetAttrPartition( hd, i, &p );
  450.     }
  451.  
  452.     /* now pursue extended partition */
  453.     /* we do not handle more than one extended partition per drive */
  454.     /* read in extended partition(s) if they exist */
  455.     hd->pep = 0;
  456.     for (i=1; i<=hd->limits.maxPrimary; i++) {
  457.     exttype = hd->table[i].type.current;
  458.     if (fdiskIsExtended(exttype)) {
  459.         
  460.         RawPartitionTable *extended;
  461.         unsigned int ext_start;
  462.         unsigned int ext_size;
  463.         unsigned int cur_start;
  464.         unsigned int cur_size;
  465.         unsigned int lp;
  466.         int sawext, sawlog;
  467.         int j;
  468.  
  469.         /* if we also have seen the PEP, we have trouble */
  470.         if (hd->pep)
  471.         return FDISK_ERR_TWOEXT;
  472.  
  473.         /* mark which primary hold the PEP */
  474.         hd->pep = i;
  475.  
  476.         /* start/size of the PEP */
  477.         ext_start  = hd->table[i].start.current;
  478.         ext_size   = hd->table[i].size.current;
  479.  
  480.         /* start/size of the EP within the next LP must fall */
  481.         cur_start = ext_start;
  482.         cur_size  = ext_size;
  483.         
  484.         /* follow linked list of extended partitions              */
  485.         /* watch out for more than one logical partition          */
  486.         /* per EPT. This is bad and we will die and they will cry */
  487.         /* fdisk and cfdisk cant handle this either. You should   */
  488.         /* be using your OS's fdisk if this is the case, cause    */
  489.         /* it is insane and only it can understand the madness    */
  490.         while (1) {
  491.         if ((s=fdiskReadPartitionTable(hd, cur_start, &extended)))
  492.             return s;
  493.  
  494.         /* insert this extended partition into the partition table */
  495.         /* we also insert a logical partition as well              */
  496.         /* since there is only 1 LP per EPT/EP, we store the type  */
  497.         /* in the main partition table as the type of the LP.      */
  498.         /* We also store information on the EP in the eptable[].   */
  499.         /* Later when we write the entire                          */
  500.         /* partition table out to disk, we'll remember that there  */
  501.         /* is also an extended partition as well.                  */
  502.         /*                                                         */
  503.         /* The number assigned to the logical partition created is */
  504.         /* passed back in the variable lp                          */
  505.         if ((s=fdiskAppendLogical( hd, &lp )) != 0)
  506.             return s;
  507.  
  508.         /* start from scratch */
  509.         fdiskGetAttrPartition( hd, lp, &pti );
  510.         memcpy(&p, pti, sizeof(Partition));
  511.         free(pti);
  512.         fdiskGetAttrExtended( hd, lp, &pti );
  513.         memcpy(&ept, pti, sizeof(Partition));
  514.         free(pti);
  515.  
  516.         /* store the size/start of the EP                          */
  517.         /* we DO NOT set end because we are interested in          */
  518.         /* restricted the position on disk to the CURRENT position */
  519.         /* endcyl is used if we are trying to restrict the          */
  520.         /* placement of a NEW partition to a region of disk, like  */
  521.         /* the first 1024 cylinfers. Storing the start sector isnt */
  522.         /* useful in that case since the mapping from sector->cyl  */
  523.         /* depends upon the geom of the drive, and we may be       */
  524.         /* considering several different drives of differring geom */
  525.         /* for the placement of the NEW partition.                 */
  526.         fdiskSetFixedConstraint( &ept.size,    cur_size   );
  527.         fdiskSetFixedConstraint( &ept.start,   cur_start  );
  528.         fdiskDeactivateAllDriveSet( &ept.drive );
  529.         fdiskActivateDriveSet( &ept.drive, hd->num );
  530.         fdiskSetCurrentDriveSet( &ept.drive, hd->num );
  531.         fdiskSetFixedConstraint( &ept.num,     lp         );
  532.         fdiskSetFixedConstraint( &ept.type,    exttype    );
  533.         
  534.         /* now to make sure NOTHING can happen to this partition */
  535.         ept.immutable = 1;
  536.         ept.status    = ALLOCATED;
  537.  
  538.         /* setup the extended partition which corresponds to the */
  539.         /* logical partition we are going to setup next          */
  540.         fdiskSetAttrExtended( hd, lp, &ept );
  541.         
  542.         /* ok, now figure out what logical partitions are */
  543.         /* in this extended partition */
  544.         sawlog = 0;
  545.         sawext = 0;
  546.         for (j=1; j<=hd->limits.maxPrimary; j++) {
  547.             RawPartition        *raw;
  548.  
  549.             raw = &extended->entry[j-1];
  550.  
  551.             /* skip link to next in extended partition chain for now */
  552.             /* we put it in the logical partitions for future ref */
  553.             if (fdiskIsExtended(raw->type)) {
  554.             if (sawext)
  555.                 return FDISK_ERR_TWOEXT;
  556.             sawext = j;
  557.             exttype = raw->type;
  558.             continue;
  559.             }
  560.  
  561.             /* make sure the log partition exists */
  562.             if (!raw->size || !raw->type)
  563.             continue;
  564.  
  565.             if (sawlog)
  566.             return FDISK_ERR_TWOLOG;
  567.             else
  568.             sawlog = 1;
  569.             
  570.             /* make sure that numbers make sense */
  571.             /* we test that:                     */
  572.             /*  - the current partition isnt bigger than */
  573.             /*    the extended partition its in          */
  574.             /*  - start isnt before the start of the "primary" */
  575.             /*    extended partition                           */
  576.             /*  - end isnt past end of "primary" extended partition */
  577.             if (((raw->start+raw->size) > (cur_start+cur_size)) ||
  578.             ((cur_start+raw->start) < ext_start) ||
  579.             ((cur_start+raw->start+raw->size) >
  580.              (ext_start+ext_size)))
  581.             return FDISK_ERR_CORRUPT;
  582.  
  583.             fdiskSetFixedConstraint( &p.size,   raw->size   );
  584.             fdiskSetFixedConstraint( &p.start,  raw->start+cur_start );
  585.             fdiskDeactivateAllDriveSet( &p.drive );
  586.             fdiskActivateDriveSet( &p.drive, hd->num );
  587.             fdiskSetCurrentDriveSet( &p.drive, hd->num );
  588.             fdiskSetFixedConstraint( &p.num,    lp         );
  589.             fdiskSetFixedConstraint( &p.type,   raw->type    );
  590.             fdiskSetFixedConstraint( &p.active, raw->active  );
  591.  
  592.             /* we currently set ALL offsets to 0       */
  593.             /* the start parameter stores the absolute */
  594.             /* starting position of the LP             */
  595.             /* get the offset by comparing start of LP */
  596.             /* to that of the EP who EPT it is in      */
  597.             fdiskSetFixedConstraint( &p.offset, 0 );
  598.  
  599.             /* now to make sure NOTHING can happen to this partition */
  600.             p.immutable = 1;
  601.             p.status    = ALLOCATED;
  602.             
  603.             fdiskSetAttrPartition( hd, lp, &p );
  604.         }
  605.  
  606.         /* see if we have another extended partition to follow */
  607.         if (!sawext)
  608.             break;
  609.         else {
  610.             cur_start  = extended->entry[sawext-1].start + ext_start;
  611.             cur_size   = extended->entry[sawext-1].size;
  612.         }
  613.         }
  614.     }
  615.     }
  616.     
  617.     return FDISK_SUCCESS;
  618. }
  619.  
  620. /* give a hard drive hd, write the partition data */
  621. static int fdiskWritePartitions ( HardDrive *hd ) {
  622.     int i;
  623.     int n;
  624.     int error=0;
  625.     unsigned int ext_start=0, ext_size, cur_start=0, cur_size;
  626.     unsigned int next_start;
  627.     unsigned int low, hi, act;
  628.     unsigned int lpart;
  629.     RawPartitionTable rpt;
  630.     RawPartition *p;
  631.     Partition *pt, *ept;
  632.     
  633.     /* move data to raw partition table from the abstract data type  */
  634.     /* first we handle the primary partitions                        */
  635.     /* we write them NO MATTER what they hold, since they MUST exist */
  636.     /* in the MBR of the hard drive.                                 */
  637.     memset(&rpt, 0, sizeof(RawPartitionTable));
  638.     for (i=1; i <= hd->limits.maxPrimary ; i++) {
  639.     p = &rpt.entry[i-1];
  640.     if (fdiskGetAttrPartition( hd, i, &pt ) == FDISK_SUCCESS) {
  641.         fdiskMakeRawEntry( hd, pt, p );
  642.         free(pt);
  643.     } else {
  644.         memset( p, 0, sizeof(RawPartition) );
  645.     }
  646.     }
  647.  
  648.     /* write the primary partition */
  649.     fdiskWritePartitionTable(hd, 0, &rpt);
  650.     
  651.     /* now pursue extended partition                               */
  652.     /* we do not handle more than one extended partition per drive */
  653.     /* we do not handle more than one logical partition per EP     */
  654.     /* we do not handle a tree of EP, just a EP chain              */
  655.     if (hd->pep) {
  656.     fdiskGetAttrPartition( hd, hd->pep, &pt );
  657.     fdiskGetConstraint( &pt->start, &ext_start, &low, &hi, &act );
  658.     fdiskGetConstraint( &pt->size,  &ext_size, &low, &hi, &act );
  659.     free(pt);
  660.     
  661.     cur_start = ext_start;
  662.     cur_size  = ext_size;
  663.     }
  664.  
  665.     /* now we loop over all logical partitions */
  666.     if (fdiskLastPartition( hd, &lpart ) != FDISK_SUCCESS)
  667.     lpart = 0;
  668.     
  669.     for (n=hd->limits.maxPrimary + 1; n <= lpart; n++) {
  670.     /* start with a clean table */
  671.     memset(&rpt, 0, sizeof(RawPartitionTable));
  672.  
  673.     /* move data to raw partition table from the abstract data type */
  674.     /* the raw partition table can hold up to 4 entries, just like  */
  675.     /* the one in the MBR. However, we will have at most 2 entries. */
  676.     /* If there is an EP following the current in the chain, it will*/
  677.     /* have an entry. And there will ALWAYS be an entry for the     */
  678.     /* current LP.                                                  */
  679.     /*                                                              */
  680.     /* stick the logical partition first, then the extended         */
  681.     p = &rpt.entry[0];
  682.  
  683.     /* now do the logical partition */
  684.     fdiskGetAttrPartition( hd, n, &pt );
  685.     fdiskMakeRawEntry( hd, pt, p );
  686.     free(pt);
  687.  
  688.     /* HACK - we have to translate start sector   */
  689.     /*        relative to the start of the current*/
  690.     /*        extended partition                  */
  691.     /*                                            */
  692.     /* NOTE - CHS appears to NOT be translated    */
  693.     /*        Not sure why this is...             */
  694.     /* HUH? - This code appears to do *nothing*,  */
  695.     /*      but I'm scared to remove it until I */
  696.     /*      have time to actually look over it  */
  697.     /*      (ewt)                      */
  698.     p->start  -= cur_start;
  699.     p++;
  700.         
  701.     /* see if there is an extended partition following this one in */
  702.     /* the EPT chain.                                              */
  703.     if (fdiskGetAttrExtended( hd, n+1, &ept ) == FDISK_SUCCESS) {
  704.         fdiskMakeRawEntry( hd, ept, p);
  705.         free(ept);
  706.  
  707.         /* HACK - we have to translate start sector   */
  708.         /*        to a value relative to the start of */
  709.         /*        the PEP. We use absolute values     */
  710.         /*        up until we write to disk (like now)*/
  711.         /*                                            */
  712.         /* NOTE - CHS appears to NOT be translated    */
  713.         /*        Not sure why this is...             */
  714.         next_start = p->start; /* save for later use */
  715.         p->start  -= ext_start;
  716.  
  717.         /* move pointer to next entry in partition table */
  718.     } else
  719.         next_start = 0;
  720.     
  721.     /* write the partition */
  722.     fdiskWritePartitionTable(hd, cur_start, &rpt);
  723.  
  724.     /* point to next partition table, if it exists */
  725.     if (next_start)
  726.         cur_start = next_start;
  727.     }
  728.  
  729.     /* now sync disk and re-read the partition table */
  730.     sync();
  731.     if ((i = fdiskReReadPartitions( hd ))<0) {
  732.     error = errno;
  733.     } else {
  734.     /* some kernel versions (1.2.x) seem to have trouble
  735.        rereading the partition table, but if asked to do it
  736.        twice, the second time works. - biro@yggdrasil.com */
  737.  
  738.     /* FIXME: is this really necessary -- ewt */
  739.     sync();
  740.     if ((i=fdiskReReadPartitions( hd ))<0)
  741.         error = errno;
  742.     }
  743.     
  744.     if (i < 0) {
  745.     close(hd->fd);
  746.     
  747.     sync();
  748.     }
  749.     
  750.     return i;
  751. }
  752.  
  753. /* return value of first partition, starting with primaries and working */
  754. /* down thru logical  partitions                                        */
  755. /* returns FDISK_ERR_BADNUM if NO partitions exists                     */
  756. int fdiskFirstPartition( HardDrive *hd, unsigned int *first ) {
  757.     if (fdiskFirstPrimary( hd, first ) == 0 )
  758.     return FDISK_SUCCESS;
  759.  
  760.     if (fdiskFirstLogical( hd, first ) == 0 )
  761.     return FDISK_SUCCESS;
  762.  
  763.     return FDISK_ERR_BADNUM;
  764. }
  765.  
  766. /* return value of Last partition, starting with logical and working    */
  767. /* down thru primary partitions                                         */
  768. /* returns FDISK_ERR_BADNUM if NO partitions exists                     */
  769. int fdiskLastPartition( HardDrive *hd, unsigned int *last ) {
  770.     if (fdiskLastLogical( hd, last ) == 0 )
  771.     return FDISK_SUCCESS;
  772.  
  773.     if (fdiskLastPrimary( hd, last ) == 0 )
  774.     return FDISK_SUCCESS;
  775.  
  776.     *last = 0;
  777.     return FDISK_ERR_BADNUM;
  778. }
  779.  
  780. /* return pointer to partition #n if it exists            */
  781. /* returns null pointer and FDISK_ERR_BADNUM if it doesnt */
  782. int fdiskFindPartition( HardDrive *hd, unsigned int n, Partition **p ) {
  783.     if (n <= hd->limits.maxPrimary)
  784.     return fdiskFindPrimary( hd, n, p );
  785.     else
  786.     return fdiskFindLogical( hd, n, p );
  787. }    
  788.     
  789. #ifdef NEED_WALK_ROUTINES
  790. /* these routines walk through the list of partitions on a hard drive */
  791. /* Point to 'first' partition on drive                                */
  792. /* returns FDISK_ERR_BADNUM if no partitions exist                    */
  793. /* also sets key to NULL                                              */
  794. int fdiskWalkReset( HardDrive *hd, WalkKey **key ) {
  795.     unsigned int first;
  796.     
  797.     /* find first partition and initialize the key used to walk list */
  798.     if (fdiskFirstPartition( hd, &first ) != 0)
  799.     return FDISK_ERR_BADNUM;
  800.  
  801.     *key = (WalkKey *) malloc( sizeof(WalkKey) );
  802.     *key->value = first;
  803. }
  804.  
  805. /* return partition information for where key is currently pointing */
  806. /* and increment key to next position                               */
  807. /* if key is NULL then we're at end of list                         */
  808. int fdiskWalkNext( HardDrive *hd, WalkKey **key, Partition **p ) {
  809.  
  810.     Partition **q;
  811.     int s, next, last;
  812.  
  813.     /* find current partition */
  814.     s = fdiskFindPartition( hd, *key->value, p );
  815.     if (s != 0) {
  816.     free(*key);
  817.     *key = NULL;
  818.     return s;
  819.     }
  820.  
  821.     /* point to next */
  822.     fdiskLastPartition( hd, &last );
  823.     next = *key->value+1;
  824.  
  825.     for (; next <= last; next++)
  826.     s = fdiskFindPartition( hd, next, q );
  827.     if (!s)
  828.         break;
  829.     
  830.     /* we've reached the end */
  831.     if (next >= last) {
  832.     free(*key);
  833.     *key = NULL;
  834.     }
  835.  
  836.     return FDISK_SUCCESS;
  837. }
  838.  
  839. #endif
  840.  
  841.  
  842.