home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / libfdisk / partition.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-17  |  19.2 KB  |  573 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.  
  17.  
  18. /* not sure where this guy should go, we'll leave it here for now */
  19. /* make raw partition entry for the given partition               */
  20. /* partition should have the start, size, type, active fields set */
  21. /* rest are taken care of                                         */
  22. int fdiskMakeRawEntry( HardDrive *hd, Partition *pt, RawPartition *p ) {
  23.     unsigned int start, size, end;
  24.     unsigned int s_cyl, s_hd, s_sec;
  25.     unsigned int e_cyl, e_hd, e_sec;
  26.     unsigned int cur, low, hi, act;
  27.  
  28.     /* read in the current values for the various parameters */
  29.     fdiskGetConstraint( &pt->start,  &p->start,  &low, &hi, &act );
  30.     fdiskGetConstraint( &pt->size,   &p->size,   &low, &hi, &act );
  31.     fdiskGetConstraint( &pt->type,   &cur,       &low, &hi, &act );
  32.     p->type   = cur;
  33.     fdiskGetConstraint( &pt->active, &cur,       &low, &hi, &act );
  34.     p->active = cur;
  35.     
  36.     /* convert from sector to cyl/hd/sector */
  37.     start = p->start;
  38.     size  = p->size;
  39.     end   = start + size - 1;
  40.     
  41.     fdiskSectorToCHS( hd, start, &s_cyl, &s_hd, &s_sec );
  42.     fdiskSectorToCHS( hd, end  , &e_cyl, &e_hd, &e_sec );
  43.     
  44.     /* we have to store CHS in funky way */
  45.     /* handle cylinder limits on PC partitions correctly */
  46.     s_cyl = (s_cyl > 1023) ? 1023 : s_cyl;
  47.     p->start_cyl  = s_cyl & 0xff;
  48.     p->start_head = s_hd;
  49.     p->start_sec  = s_sec | ((s_cyl >> 2) &0xc0);
  50.  
  51.     e_cyl = (e_cyl > 1023) ? 1023 : e_cyl;
  52.     p->end_cyl    = e_cyl & 0xff;
  53.     p->end_head   = e_hd;
  54.     p->end_sec    = e_sec | ((e_cyl >> 2) &0xc0);
  55.     
  56.     return FDISK_SUCCESS;
  57. }
  58.  
  59.  
  60.  
  61. /* remove partition # n from drive hd. If it doesn't exist then a return */
  62. /* code > 0 is returned, else 0 is returned                              */
  63. /* First primary partition is number 1, not 0!                           */
  64. int fdiskRemovePartition( HardDrive *hd, unsigned int n ) {
  65.     
  66.     if (n < 1)
  67.     return FDISK_ERR_BADNUM;
  68.     
  69.     if (n < 5) {
  70.     return fdiskRemovePrimary( hd, n );
  71.     } else {
  72.     return fdiskRemoveLogical( hd, n );
  73.     }
  74. }
  75.  
  76. /*                                                                         */
  77. /* not currently used, unclear what numbering scheme to use to index       */
  78. /* partitions we wish to create beyond the first 4.  Logical partition     */
  79. /* numbers are sequential, so only 'free' number to create a new partition */
  80. /* at would be the number of the last logical plus one. Seems kludgey to   */
  81. /* require user to figure out that number just to call the function.       */
  82. /* Instead I will have a fdiskCreatePrimary() and fdiskAppendLogical()     */
  83. /*                                                                         */
  84. #if 0
  85. /* create partition number n, where n can be 1-4 for primary,   */
  86. /* or 5 or greater to append a logical partition (this is       */
  87. /* because of screwy way logicals are numbered )                */ 
  88. /* DO NOT USE THIS FUNCTION YET - UNCLEAR IF IT ACTS LIKE WE WANT!  */
  89. /* DOES NOT MAKE EXTENDED PARTITIONS IF THEY ARE NEEDED FOR LOGICAL */
  90. int fdiskCreatePartition( HardDrive *hd, unsigned int n,
  91.               unsigned int start, unsigned int size) {
  92.  
  93.     if (n < 1 )
  94.     return FDISK_ERR_BADNUM;
  95.     
  96.     if (n < 5) {
  97.     return fdiskCreatePrimary(hd, n, start, size);
  98.     } else {
  99.     /* append a logical partition */
  100.     return fdiskAppendLogical( hd, start, size );
  101.     }
  102. }
  103. #endif
  104.  
  105.  
  106. /* Set    partition #n into the current partition table */
  107. /* DOES NOT create an extended partition if necessary   */
  108. /* does not do any sanity checking on attributes        */
  109. int fdiskSetAttrPartition( HardDrive *hd, unsigned int n, Partition *p ) {
  110.     
  111.     if (n < 1)
  112.     return FDISK_ERR_BADNUM;
  113.     
  114.     if (n < 5)
  115.     return fdiskSetAttrPrimary(hd, n, p);
  116.     else
  117.     return fdiskSetAttrLogical(hd, n, p);
  118. }
  119.  
  120.  
  121. int fdiskGetAttrPartition( HardDrive *hd, unsigned int n, Partition **p ) {
  122.     
  123.     if (n < 1)
  124.     return FDISK_ERR_BADNUM;
  125.     
  126.     if (n < 5)
  127.     return fdiskGetAttrPrimary(hd, n, p);
  128.     else
  129.     return fdiskGetAttrLogical(hd, n, p);
  130. }
  131.  
  132. /* give a hard drive hd, read in the partition data        */
  133. /* COMPLETELY trashes all partition info in the hard drive */
  134. int fdiskReadPartitions( HardDrive *hd ) {
  135.     int i, s;
  136.     unsigned int exttype;
  137.     RawPartitionTable *pt;
  138.     Partition         p, ept, *pti;
  139.     
  140.     s = fdiskReadMBR(hd, &pt );
  141.     if (s)
  142.     return s;
  143.  
  144.     /* move data from raw partition table into abstract data type */
  145.     /* primary partitions store absolute sector offsets/sizes already */
  146.     for (i=1; i < 5; i++) {
  147.     if ((s=fdiskCreatePrimary( hd, i )) != 0)
  148.         return s;
  149.  
  150.     /* get initial attr of the partition */
  151.     fdiskGetAttrPartition( hd, i, &pti );
  152.     memcpy(&p, pti, sizeof(Partition));
  153.     free(pti);
  154.  
  155.     /* if the partition is defined                                */
  156.     /* have to set this up so that we don't try to mangle this    */
  157.     /* partition later when we are automatically allocating space */
  158.     /* for newly created partitions                               */
  159.     /* remember the rawPT index starts at 0, PT starts at 1       */
  160.     if (pt->entry[i-1].size && pt->entry[i-1].type) {
  161.         fdiskSetFixedConstraint( &p.size,    pt->entry[i-1].size    );
  162.         fdiskSetFixedConstraint( &p.start,   pt->entry[i-1].start   );
  163.         fdiskSetFixedConstraint( &p.type,    pt->entry[i-1].type    );
  164.         fdiskSetFixedConstraint( &p.active,  pt->entry[i-1].active  );
  165.         fdiskSetFixedConstraint( &p.offset,  0                      );
  166.         fdiskDeactivateAllDriveSet( &p.drive );
  167.         fdiskActivateDriveSet( &p.drive, hd->num );
  168.         fdiskSetCurrentDriveSet( &p.drive, hd->num );
  169.         fdiskSetFixedConstraint( &p.num, i );
  170.         
  171.         /* now to make sure NOTHING can happen to this partition */
  172.         p.immutable = 1;
  173.         p.status    = ALLOCATED;
  174.     } else {
  175.         p.status = AVAILABLE;
  176.     }
  177.  
  178.     /* store in the partition table */
  179.     fdiskSetAttrPartition( hd, i, &p );
  180.     }
  181.  
  182.     /* now pursue extended partition */
  183.     /* we do not handle more than one extended partition per drive */
  184.     /* read in extended partition(s) if they exist */
  185.     hd->pep = 0;
  186.     for (i=1; i<5; i++) {
  187.     exttype = hd->table[i].type.current;
  188.     if (fdiskIsExtended(exttype)) {
  189.         
  190.         RawPartitionTable *extended;
  191.         unsigned int ext_start;
  192.         unsigned int ext_size;
  193.         unsigned int cur_start;
  194.         unsigned int cur_size;
  195.         unsigned int lp;
  196.         int sawext, sawlog;
  197.         int j;
  198.  
  199.         /* if we also have seen the PEP, we have trouble */
  200.         if (hd->pep)
  201.         return FDISK_ERR_TWOEXT;
  202.  
  203.         /* mark which primary hold the PEP */
  204.         hd->pep = i;
  205.  
  206.         /* start/size of the PEP */
  207.         ext_start  = hd->table[i].start.current;
  208.         ext_size   = hd->table[i].size.current;
  209.  
  210.         /* start/size of the EP within the next LP must fall */
  211.         cur_start = ext_start;
  212.         cur_size  = ext_size;
  213.         
  214.         /* follow linked list of extended partitions              */
  215.         /* watch out for more than one logical partition          */
  216.         /* per EPT. This is bad and we will die and they will cry */
  217.         /* fdisk and cfdisk cant handle this either. You should   */
  218.         /* be using your OS's fdisk if this is the case, cause    */
  219.         /* it is insane and only it can understand the madness    */
  220.         while (1) {
  221.         if ((s=fdiskReadPartitionTable(hd, cur_start, &extended)))
  222.             return s;
  223.  
  224.         /* insert this extended partition into the partition table */
  225.         /* we also insert a logical partition as well              */
  226.         /* since there is only 1 LP per EPT/EP, we store the type  */
  227.         /* in the main partition table as the type of the LP.      */
  228.         /* We also store information on the EP in the eptable[].   */
  229.         /* Later when we write the entire                          */
  230.         /* partition table out to disk, we'll remember that there  */
  231.         /* is also an extended partition as well.                  */
  232.         /*                                                         */
  233.         /* The number assigned to the logical partition created is */
  234.         /* passed back in the variable lp                          */
  235.         if ((s=fdiskAppendLogical( hd, &lp )) != 0)
  236.             return s;
  237.  
  238.         /* start from scratch */
  239.         fdiskGetAttrPartition( hd, lp, &pti );
  240.         memcpy(&p, pti, sizeof(Partition));
  241.         free(pti);
  242.         fdiskGetAttrExtended( hd, lp, &pti );
  243.         memcpy(&ept, pti, sizeof(Partition));
  244.         free(pti);
  245.  
  246.         /* store the size/start of the EP                          */
  247.         /* we DO NOT set end because we are interested in          */
  248.         /* restricted the position on disk to the CURRENT position */
  249.         /* endcyl is used if we are trying to restrict the          */
  250.         /* placement of a NEW partition to a region of disk, like  */
  251.         /* the first 1024 cylinfers. Storing the start sector isnt */
  252.         /* useful in that case since the mapping from sector->cyl  */
  253.         /* depends upon the geom of the drive, and we may be       */
  254.         /* considering several different drives of differring geom */
  255.         /* for the placement of the NEW partition.                 */
  256.         fdiskSetFixedConstraint( &ept.size,    cur_size   );
  257.         fdiskSetFixedConstraint( &ept.start,   cur_start  );
  258.         fdiskDeactivateAllDriveSet( &ept.drive );
  259.         fdiskActivateDriveSet( &ept.drive, hd->num );
  260.         fdiskSetCurrentDriveSet( &ept.drive, hd->num );
  261.         fdiskSetFixedConstraint( &ept.num,     lp         );
  262.         fdiskSetFixedConstraint( &ept.type,    exttype    );
  263.         
  264.         /* now to make sure NOTHING can happen to this partition */
  265.         ept.immutable = 1;
  266.         ept.status    = ALLOCATED;
  267.  
  268.         /* setup the extended partition which corresponds to the */
  269.         /* logical partition we are going to setup next          */
  270.         fdiskSetAttrExtended( hd, lp, &ept );
  271.         
  272.         /* ok, now figure out what logical partitions are */
  273.         /* in this extended partition */
  274.         sawlog = 0;
  275.         sawext = 0;
  276.         for (j=1; j<5; j++) {
  277.             RawPartition        *raw;
  278.  
  279.             raw = &extended->entry[j-1];
  280.  
  281.             /* skip link to next in extended partition chain for now */
  282.             /* we put it in the logical partitions for future ref */
  283.             if (fdiskIsExtended(raw->type)) {
  284.             if (sawext)
  285.                 return FDISK_ERR_TWOEXT;
  286.             sawext = j;
  287.             exttype = raw->type;
  288.             continue;
  289.             }
  290.  
  291.             /* make sure the log partition exists */
  292.             if (!raw->size || !raw->type)
  293.             continue;
  294.  
  295.             if (sawlog)
  296.             return FDISK_ERR_TWOLOG;
  297.             else
  298.             sawlog = 1;
  299.             
  300.             /* make sure that numbers make sense */
  301.             /* we test that:                     */
  302.             /*  - the current partition isnt bigger than */
  303.             /*    the extended partition its in          */
  304.             /*  - start isnt before the start of the "primary" */
  305.             /*    extended partition                           */
  306.             /*  - end isnt past end of "primary" extended partition */
  307.             if (((raw->start+raw->size) > (cur_start+cur_size)) ||
  308.             ((cur_start+raw->start) < ext_start) ||
  309.             ((cur_start+raw->start+raw->size) >
  310.              (ext_start+ext_size)))
  311.             return FDISK_ERR_CORRUPT;
  312.  
  313.             fdiskSetFixedConstraint( &p.size,   raw->size   );
  314.             fdiskSetFixedConstraint( &p.start,  raw->start+cur_start );
  315.             fdiskDeactivateAllDriveSet( &p.drive );
  316.             fdiskActivateDriveSet( &p.drive, hd->num );
  317.             fdiskSetCurrentDriveSet( &p.drive, hd->num );
  318.             fdiskSetFixedConstraint( &p.num,    lp         );
  319.             fdiskSetFixedConstraint( &p.type,   raw->type    );
  320.             fdiskSetFixedConstraint( &p.active, raw->active  );
  321.  
  322.             /* we currently set ALL offsets to 0       */
  323.             /* the start parameter stores the absolute */
  324.             /* starting position of the LP             */
  325.             /* get the offset by comparing start of LP */
  326.             /* to that of the EP who EPT it is in      */
  327.             fdiskSetFixedConstraint( &p.offset, 0 );
  328.  
  329.             /* now to make sure NOTHING can happen to this partition */
  330.             p.immutable = 1;
  331.             p.status    = ALLOCATED;
  332.             
  333.             fdiskSetAttrPartition( hd, lp, &p );
  334.         }
  335.  
  336.         /* see if we have another extended partition to follow */
  337.         if (!sawext)
  338.             break;
  339.         else {
  340.             cur_start  = extended->entry[sawext-1].start + ext_start;
  341.             cur_size   = extended->entry[sawext-1].size;
  342.         }
  343.         }
  344.     }
  345.     }
  346.     
  347.     return FDISK_SUCCESS;
  348. }
  349.  
  350. /* give a hard drive hd, write the partition data */
  351. int fdiskWritePartitions( HardDrive *hd ) {
  352.     int i;
  353.     int n;
  354.     int error=0;
  355.     unsigned int ext_start=0, ext_size, cur_start=0, cur_size;
  356.     unsigned int next_start;
  357.     unsigned int low, hi, act;
  358.     unsigned int lpart;
  359.     RawPartitionTable rpt;
  360.     RawPartition *p;
  361.     Partition *pt, *ept;
  362.     
  363.     /* move data to raw partition table from the abstract data type  */
  364.     /* first we handle the primary partitions                        */
  365.     /* we write them NO MATTER what they hold, since they MUST exist */
  366.     /* in the MBR of the hard drive.                                 */
  367.     memset(&rpt, 0, sizeof(RawPartitionTable));
  368.     for (i=1; i < 5; i++) {
  369.     p = &rpt.entry[i-1];
  370.     if (fdiskGetAttrPartition( hd, i, &pt ) == FDISK_SUCCESS) {
  371.         fdiskMakeRawEntry( hd, pt, p );
  372.         free(pt);
  373.     } else {
  374.         memset( p, 0, sizeof(RawPartition) );
  375.     }
  376.     }
  377.  
  378.     /* write the primary partition */
  379.     fdiskWriteMBR(hd, &rpt);
  380.     
  381.     /* now pursue extended partition                               */
  382.     /* we do not handle more than one extended partition per drive */
  383.     /* we do not handle more than one logical partition per EP     */
  384.     /* we do not handle a tree of EP, just a EP chain              */
  385.     if (hd->pep) {
  386.     fdiskGetAttrPartition( hd, hd->pep, &pt );
  387.     fdiskGetConstraint( &pt->start, &ext_start, &low, &hi, &act );
  388.     fdiskGetConstraint( &pt->size,  &ext_size, &low, &hi, &act );
  389.     free(pt);
  390.     
  391.     cur_start = ext_start;
  392.     cur_size  = ext_size;
  393.     }
  394.  
  395.     /* now we loop over all logical partitions */
  396.     if (fdiskLastPartition( hd, &lpart ) != FDISK_SUCCESS)
  397.     lpart = 0;
  398.     
  399.     for (n=5; n <= lpart; n++) {
  400.     /* start with a clean table */
  401.     memset(&rpt, 0, sizeof(RawPartitionTable));
  402.  
  403.     /* move data to raw partition table from the abstract data type */
  404.     /* the raw partition table can hold up to 4 entries, just like  */
  405.     /* the one in the MBR. However, we will have at most 2 entries. */
  406.     /* If there is an EP following the current in the chain, it will*/
  407.     /* have an entry. And there will ALWAYS be an entry for the     */
  408.     /* current LP.                                                  */
  409.     /*                                                              */
  410.     /* stick the extended partition first, then the logical         */
  411.     p = &rpt.entry[0];
  412.  
  413.     /* see if there is an extended partition following this one in */
  414.     /* the EPT chain.                                              */
  415.     if (fdiskGetAttrExtended( hd, n+1, &ept ) == FDISK_SUCCESS) {
  416.         fdiskMakeRawEntry( hd, ept, p);
  417.         free(ept);
  418.  
  419.         /* HACK - we have to translate start sector   */
  420.         /*        to a value relative to the start of */
  421.         /*        the PEP. We use absolute values     */
  422.         /*        up until we write to disk (like now)*/
  423.         /*                                            */
  424.         /* NOTE - CHS appears to NOT be translated    */
  425.         /*        Not sure why this is...             */
  426.         next_start = p->start; /* save for later use */
  427.         p->start  -= ext_start;
  428.  
  429.         /* move pointer to next entry in partition table */
  430.         p = &rpt.entry[1];
  431.     } else
  432.         next_start = 0;
  433.     
  434.     /* now do the logical partition */
  435.     fdiskGetAttrPartition( hd, n, &pt );
  436.     fdiskMakeRawEntry( hd, pt, p );
  437.     free(pt);
  438.  
  439.     /* HACK - we have to translate start sector   */
  440.     /*        relative to the start of the current*/
  441.     /*        extended partition                  */
  442.     /*                                            */
  443.     /* NOTE - CHS appears to NOT be translated    */
  444.     /*        Not sure why this is...             */
  445.     p->start  -= cur_start;
  446.         
  447.     /* write the partition */
  448.     fdiskWritePartitionTable(hd, cur_start, &rpt);
  449.  
  450.     /* point to next partition table, if it exists */
  451.     if (next_start)
  452.         cur_start = next_start;
  453.     }
  454.  
  455.     /* now sync disk and re-read the partition table */
  456.     sync();
  457.     if ((i = fdiskReReadPartitions( hd ))<0) {
  458.     error = errno;
  459.     } else {
  460.     /* some kernel versions (1.2.x) seem to have trouble
  461.        rereading the partition table, but if asked to do it
  462.        twice, the second time works. - biro@yggdrasil.com */
  463.  
  464.     /* FIXME: is this really necessary -- ewt */
  465.     sync();
  466.     if ((i=fdiskReReadPartitions( hd ))<0)
  467.         error = errno;
  468.     }
  469.     
  470.     if (i < 0) {
  471.     close(hd->fd);
  472.     
  473.     printf("Syncing disks.\n");
  474.     sync();
  475.     
  476.     printf("Re-read table failed with error %d: %s.\nReboot your "
  477.            "system to ensure the partition table is updated.\n",
  478.            error, strerror(error));
  479.     }
  480.     
  481.     return i;
  482. }
  483.  
  484. /* return value of first partition, starting with primaries and working */
  485. /* down thru logical  partitions                                        */
  486. /* returns FDISK_ERR_BADNUM if NO partitions exists                     */
  487. int fdiskFirstPartition( HardDrive *hd, unsigned int *first ) {
  488.     if (fdiskFirstPrimary( hd, first ) == 0 )
  489.     return FDISK_SUCCESS;
  490.  
  491.     if (fdiskFirstLogical( hd, first ) == 0 )
  492.     return FDISK_SUCCESS;
  493.  
  494.     return FDISK_ERR_BADNUM;
  495. }
  496.  
  497. /* return value of Last partition, starting with logical and working    */
  498. /* down thru primary partitions                                         */
  499. /* returns FDISK_ERR_BADNUM if NO partitions exists                     */
  500. int fdiskLastPartition( HardDrive *hd, unsigned int *last ) {
  501.     if (fdiskLastLogical( hd, last ) == 0 )
  502.     return FDISK_SUCCESS;
  503.  
  504.     if (fdiskLastPrimary( hd, last ) == 0 )
  505.     return FDISK_SUCCESS;
  506.  
  507.     *last = 0;
  508.     return FDISK_ERR_BADNUM;
  509. }
  510.  
  511. /* return pointer to partition #n if it exists            */
  512. /* returns null pointer and FDISK_ERR_BADNUM if it doesnt */
  513. int fdiskFindPartition( HardDrive *hd, unsigned int n, Partition **p ) {
  514.     if (n < 5)
  515.     return fdiskFindPrimary( hd, n, p );
  516.     else
  517.     return fdiskFindLogical( hd, n, p );
  518. }    
  519.     
  520. #ifdef NEED_WALK_ROUTINES
  521. /* these routines walk through the list of partitions on a hard drive */
  522. /* Point to 'first' partition on drive                                */
  523. /* returns FDISK_ERR_BADNUM if no partitions exist                    */
  524. /* also sets key to NULL                                              */
  525. int fdiskWalkReset( HardDrive *hd, WalkKey **key ) {
  526.     unsigned int first;
  527.     
  528.     /* find first partition and initialize the key used to walk list */
  529.     if (fdiskFirstPartition( hd, &first ) != 0)
  530.     return FDISK_ERR_BADNUM;
  531.  
  532.     *key = (WalkKey *) malloc( sizeof(WalkKey) );
  533.     *key->value = first;
  534. }
  535.  
  536. /* return partition information for where key is currently pointing */
  537. /* and increment key to next position                               */
  538. /* if key is NULL then we're at end of list                         */
  539. int fdiskWalkNext( HardDrive *hd, WalkKey **key, Partition **p ) {
  540.  
  541.     Partition **q;
  542.     int s, next, last;
  543.  
  544.     /* find current partition */
  545.     s = fdiskFindPartition( hd, *key->value, p );
  546.     if (s != 0) {
  547.     free(*key);
  548.     *key = NULL;
  549.     return s;
  550.     }
  551.  
  552.     /* point to next */
  553.     fdiskLastPartition( hd, &last );
  554.     next = *key->value+1;
  555.  
  556.     for (; next <= last; next++)
  557.     s = fdiskFindPartition( hd, next, q );
  558.     if (!s)
  559.         break;
  560.     
  561.     /* we've reached the end */
  562.     if (next >= last) {
  563.     free(*key);
  564.     *key = NULL;
  565.     }
  566.  
  567.     return FDISK_SUCCESS;
  568. }
  569.  
  570. #endif
  571.  
  572.  
  573.