home *** CD-ROM | disk | FTP | other *** search
- /* this file has 'high-level' operations which only use the partition # */
- /* For example, on a disk the first 4 partitions are the primary partitions */
- /* and are numbered 1 thru 4. Then each subsequent logical paritition */
- /* is numbered sequentially starting with 5. */
- /* The functions in this file use this partition number as the index of */
- /* the operation. */
- /* Recoded to use new HardDrive struct with single partition table */
-
-
- #include <stdio.h>
- #include <unistd.h>
- #include <malloc.h>
- #include <string.h>
- #include <errno.h>
- #include "libfdisk.h"
-
-
- /* not sure where this guy should go, we'll leave it here for now */
- /* make raw partition entry for the given partition */
- /* partition should have the start, size, type, active fields set */
- /* rest are taken care of */
- int fdiskMakeRawEntry( HardDrive *hd, Partition *pt, RawPartition *p ) {
- unsigned int start, size, end;
- unsigned int s_cyl, s_hd, s_sec;
- unsigned int e_cyl, e_hd, e_sec;
- unsigned int cur, low, hi, act;
-
- /* read in the current values for the various parameters */
- fdiskGetConstraint( &pt->start, &p->start, &low, &hi, &act );
- fdiskGetConstraint( &pt->size, &p->size, &low, &hi, &act );
- fdiskGetConstraint( &pt->type, &cur, &low, &hi, &act );
- p->type = cur;
- fdiskGetConstraint( &pt->active, &cur, &low, &hi, &act );
- p->active = cur;
-
- /* convert from sector to cyl/hd/sector */
- start = p->start;
- size = p->size;
- end = start + size - 1;
-
- fdiskSectorToCHS( hd, start, &s_cyl, &s_hd, &s_sec );
- fdiskSectorToCHS( hd, end , &e_cyl, &e_hd, &e_sec );
-
- /* we have to store CHS in funky way */
- /* handle cylinder limits on PC partitions correctly */
- s_cyl = (s_cyl > 1023) ? 1023 : s_cyl;
- p->start_cyl = s_cyl & 0xff;
- p->start_head = s_hd;
- p->start_sec = s_sec | ((s_cyl >> 2) &0xc0);
-
- e_cyl = (e_cyl > 1023) ? 1023 : e_cyl;
- p->end_cyl = e_cyl & 0xff;
- p->end_head = e_hd;
- p->end_sec = e_sec | ((e_cyl >> 2) &0xc0);
-
- return FDISK_SUCCESS;
- }
-
-
-
- /* remove partition # n from drive hd. If it doesn't exist then a return */
- /* code > 0 is returned, else 0 is returned */
- /* First primary partition is number 1, not 0! */
- int fdiskRemovePartition( HardDrive *hd, unsigned int n ) {
-
- if (n < 1)
- return FDISK_ERR_BADNUM;
-
- if (n < 5) {
- return fdiskRemovePrimary( hd, n );
- } else {
- return fdiskRemoveLogical( hd, n );
- }
- }
-
- /* */
- /* not currently used, unclear what numbering scheme to use to index */
- /* partitions we wish to create beyond the first 4. Logical partition */
- /* numbers are sequential, so only 'free' number to create a new partition */
- /* at would be the number of the last logical plus one. Seems kludgey to */
- /* require user to figure out that number just to call the function. */
- /* Instead I will have a fdiskCreatePrimary() and fdiskAppendLogical() */
- /* */
- #if 0
- /* create partition number n, where n can be 1-4 for primary, */
- /* or 5 or greater to append a logical partition (this is */
- /* because of screwy way logicals are numbered ) */
- /* DO NOT USE THIS FUNCTION YET - UNCLEAR IF IT ACTS LIKE WE WANT! */
- /* DOES NOT MAKE EXTENDED PARTITIONS IF THEY ARE NEEDED FOR LOGICAL */
- int fdiskCreatePartition( HardDrive *hd, unsigned int n,
- unsigned int start, unsigned int size) {
-
- if (n < 1 )
- return FDISK_ERR_BADNUM;
-
- if (n < 5) {
- return fdiskCreatePrimary(hd, n, start, size);
- } else {
- /* append a logical partition */
- return fdiskAppendLogical( hd, start, size );
- }
- }
- #endif
-
-
- /* Set partition #n into the current partition table */
- /* DOES NOT create an extended partition if necessary */
- /* does not do any sanity checking on attributes */
- int fdiskSetAttrPartition( HardDrive *hd, unsigned int n, Partition *p ) {
-
- if (n < 1)
- return FDISK_ERR_BADNUM;
-
- if (n < 5)
- return fdiskSetAttrPrimary(hd, n, p);
- else
- return fdiskSetAttrLogical(hd, n, p);
- }
-
-
- int fdiskGetAttrPartition( HardDrive *hd, unsigned int n, Partition **p ) {
-
- if (n < 1)
- return FDISK_ERR_BADNUM;
-
- if (n < 5)
- return fdiskGetAttrPrimary(hd, n, p);
- else
- return fdiskGetAttrLogical(hd, n, p);
- }
-
- /* give a hard drive hd, read in the partition data */
- /* COMPLETELY trashes all partition info in the hard drive */
- int fdiskReadPartitions( HardDrive *hd ) {
- int i, s;
- unsigned int exttype;
- RawPartitionTable *pt;
- Partition p, ept, *pti;
-
- s = fdiskReadMBR(hd, &pt );
- if (s)
- return s;
-
- /* move data from raw partition table into abstract data type */
- /* primary partitions store absolute sector offsets/sizes already */
- for (i=1; i < 5; i++) {
- if ((s=fdiskCreatePrimary( hd, i )) != 0)
- return s;
-
- /* get initial attr of the partition */
- fdiskGetAttrPartition( hd, i, &pti );
- memcpy(&p, pti, sizeof(Partition));
- free(pti);
-
- /* if the partition is defined */
- /* have to set this up so that we don't try to mangle this */
- /* partition later when we are automatically allocating space */
- /* for newly created partitions */
- /* remember the rawPT index starts at 0, PT starts at 1 */
- if (pt->entry[i-1].size && pt->entry[i-1].type) {
- fdiskSetFixedConstraint( &p.size, pt->entry[i-1].size );
- fdiskSetFixedConstraint( &p.start, pt->entry[i-1].start );
- fdiskSetFixedConstraint( &p.type, pt->entry[i-1].type );
- fdiskSetFixedConstraint( &p.active, pt->entry[i-1].active );
- fdiskSetFixedConstraint( &p.offset, 0 );
- fdiskDeactivateAllDriveSet( &p.drive );
- fdiskActivateDriveSet( &p.drive, hd->num );
- fdiskSetCurrentDriveSet( &p.drive, hd->num );
- fdiskSetFixedConstraint( &p.num, i );
-
- /* now to make sure NOTHING can happen to this partition */
- p.immutable = 1;
- p.status = ALLOCATED;
- } else {
- p.status = AVAILABLE;
- }
-
- /* store in the partition table */
- fdiskSetAttrPartition( hd, i, &p );
- }
-
- /* now pursue extended partition */
- /* we do not handle more than one extended partition per drive */
- /* read in extended partition(s) if they exist */
- hd->pep = 0;
- for (i=1; i<5; i++) {
- exttype = hd->table[i].type.current;
- if (fdiskIsExtended(exttype)) {
-
- RawPartitionTable *extended;
- unsigned int ext_start;
- unsigned int ext_size;
- unsigned int cur_start;
- unsigned int cur_size;
- unsigned int lp;
- int sawext, sawlog;
- int j;
-
- /* if we also have seen the PEP, we have trouble */
- if (hd->pep)
- return FDISK_ERR_TWOEXT;
-
- /* mark which primary hold the PEP */
- hd->pep = i;
-
- /* start/size of the PEP */
- ext_start = hd->table[i].start.current;
- ext_size = hd->table[i].size.current;
-
- /* start/size of the EP within the next LP must fall */
- cur_start = ext_start;
- cur_size = ext_size;
-
- /* follow linked list of extended partitions */
- /* watch out for more than one logical partition */
- /* per EPT. This is bad and we will die and they will cry */
- /* fdisk and cfdisk cant handle this either. You should */
- /* be using your OS's fdisk if this is the case, cause */
- /* it is insane and only it can understand the madness */
- while (1) {
- if ((s=fdiskReadPartitionTable(hd, cur_start, &extended)))
- return s;
-
- /* insert this extended partition into the partition table */
- /* we also insert a logical partition as well */
- /* since there is only 1 LP per EPT/EP, we store the type */
- /* in the main partition table as the type of the LP. */
- /* We also store information on the EP in the eptable[]. */
- /* Later when we write the entire */
- /* partition table out to disk, we'll remember that there */
- /* is also an extended partition as well. */
- /* */
- /* The number assigned to the logical partition created is */
- /* passed back in the variable lp */
- if ((s=fdiskAppendLogical( hd, &lp )) != 0)
- return s;
-
- /* start from scratch */
- fdiskGetAttrPartition( hd, lp, &pti );
- memcpy(&p, pti, sizeof(Partition));
- free(pti);
- fdiskGetAttrExtended( hd, lp, &pti );
- memcpy(&ept, pti, sizeof(Partition));
- free(pti);
-
- /* store the size/start of the EP */
- /* we DO NOT set end because we are interested in */
- /* restricted the position on disk to the CURRENT position */
- /* endcyl is used if we are trying to restrict the */
- /* placement of a NEW partition to a region of disk, like */
- /* the first 1024 cylinfers. Storing the start sector isnt */
- /* useful in that case since the mapping from sector->cyl */
- /* depends upon the geom of the drive, and we may be */
- /* considering several different drives of differring geom */
- /* for the placement of the NEW partition. */
- fdiskSetFixedConstraint( &ept.size, cur_size );
- fdiskSetFixedConstraint( &ept.start, cur_start );
- fdiskDeactivateAllDriveSet( &ept.drive );
- fdiskActivateDriveSet( &ept.drive, hd->num );
- fdiskSetCurrentDriveSet( &ept.drive, hd->num );
- fdiskSetFixedConstraint( &ept.num, lp );
- fdiskSetFixedConstraint( &ept.type, exttype );
-
- /* now to make sure NOTHING can happen to this partition */
- ept.immutable = 1;
- ept.status = ALLOCATED;
-
- /* setup the extended partition which corresponds to the */
- /* logical partition we are going to setup next */
- fdiskSetAttrExtended( hd, lp, &ept );
-
- /* ok, now figure out what logical partitions are */
- /* in this extended partition */
- sawlog = 0;
- sawext = 0;
- for (j=1; j<5; j++) {
- RawPartition *raw;
-
- raw = &extended->entry[j-1];
-
- /* skip link to next in extended partition chain for now */
- /* we put it in the logical partitions for future ref */
- if (fdiskIsExtended(raw->type)) {
- if (sawext)
- return FDISK_ERR_TWOEXT;
- sawext = j;
- exttype = raw->type;
- continue;
- }
-
- /* make sure the log partition exists */
- if (!raw->size || !raw->type)
- continue;
-
- if (sawlog)
- return FDISK_ERR_TWOLOG;
- else
- sawlog = 1;
-
- /* make sure that numbers make sense */
- /* we test that: */
- /* - the current partition isnt bigger than */
- /* the extended partition its in */
- /* - start isnt before the start of the "primary" */
- /* extended partition */
- /* - end isnt past end of "primary" extended partition */
- if (((raw->start+raw->size) > (cur_start+cur_size)) ||
- ((cur_start+raw->start) < ext_start) ||
- ((cur_start+raw->start+raw->size) >
- (ext_start+ext_size)))
- return FDISK_ERR_CORRUPT;
-
- fdiskSetFixedConstraint( &p.size, raw->size );
- fdiskSetFixedConstraint( &p.start, raw->start+cur_start );
- fdiskDeactivateAllDriveSet( &p.drive );
- fdiskActivateDriveSet( &p.drive, hd->num );
- fdiskSetCurrentDriveSet( &p.drive, hd->num );
- fdiskSetFixedConstraint( &p.num, lp );
- fdiskSetFixedConstraint( &p.type, raw->type );
- fdiskSetFixedConstraint( &p.active, raw->active );
-
- /* we currently set ALL offsets to 0 */
- /* the start parameter stores the absolute */
- /* starting position of the LP */
- /* get the offset by comparing start of LP */
- /* to that of the EP who EPT it is in */
- fdiskSetFixedConstraint( &p.offset, 0 );
-
- /* now to make sure NOTHING can happen to this partition */
- p.immutable = 1;
- p.status = ALLOCATED;
-
- fdiskSetAttrPartition( hd, lp, &p );
- }
-
- /* see if we have another extended partition to follow */
- if (!sawext)
- break;
- else {
- cur_start = extended->entry[sawext-1].start + ext_start;
- cur_size = extended->entry[sawext-1].size;
- }
- }
- }
- }
-
- return FDISK_SUCCESS;
- }
-
- /* give a hard drive hd, write the partition data */
- int fdiskWritePartitions( HardDrive *hd ) {
- int i;
- int n;
- int error=0;
- unsigned int ext_start=0, ext_size, cur_start=0, cur_size;
- unsigned int next_start;
- unsigned int low, hi, act;
- unsigned int lpart;
- RawPartitionTable rpt;
- RawPartition *p;
- Partition *pt, *ept;
-
- /* move data to raw partition table from the abstract data type */
- /* first we handle the primary partitions */
- /* we write them NO MATTER what they hold, since they MUST exist */
- /* in the MBR of the hard drive. */
- memset(&rpt, 0, sizeof(RawPartitionTable));
- for (i=1; i < 5; i++) {
- p = &rpt.entry[i-1];
- if (fdiskGetAttrPartition( hd, i, &pt ) == FDISK_SUCCESS) {
- fdiskMakeRawEntry( hd, pt, p );
- free(pt);
- } else {
- memset( p, 0, sizeof(RawPartition) );
- }
- }
-
- /* write the primary partition */
- fdiskWriteMBR(hd, &rpt);
-
- /* now pursue extended partition */
- /* we do not handle more than one extended partition per drive */
- /* we do not handle more than one logical partition per EP */
- /* we do not handle a tree of EP, just a EP chain */
- if (hd->pep) {
- fdiskGetAttrPartition( hd, hd->pep, &pt );
- fdiskGetConstraint( &pt->start, &ext_start, &low, &hi, &act );
- fdiskGetConstraint( &pt->size, &ext_size, &low, &hi, &act );
- free(pt);
-
- cur_start = ext_start;
- cur_size = ext_size;
- }
-
- /* now we loop over all logical partitions */
- if (fdiskLastPartition( hd, &lpart ) != FDISK_SUCCESS)
- lpart = 0;
-
- for (n=5; n <= lpart; n++) {
- /* start with a clean table */
- memset(&rpt, 0, sizeof(RawPartitionTable));
-
- /* move data to raw partition table from the abstract data type */
- /* the raw partition table can hold up to 4 entries, just like */
- /* the one in the MBR. However, we will have at most 2 entries. */
- /* If there is an EP following the current in the chain, it will*/
- /* have an entry. And there will ALWAYS be an entry for the */
- /* current LP. */
- /* */
- /* stick the extended partition first, then the logical */
- p = &rpt.entry[0];
-
- /* see if there is an extended partition following this one in */
- /* the EPT chain. */
- if (fdiskGetAttrExtended( hd, n+1, &ept ) == FDISK_SUCCESS) {
- fdiskMakeRawEntry( hd, ept, p);
- free(ept);
-
- /* HACK - we have to translate start sector */
- /* to a value relative to the start of */
- /* the PEP. We use absolute values */
- /* up until we write to disk (like now)*/
- /* */
- /* NOTE - CHS appears to NOT be translated */
- /* Not sure why this is... */
- next_start = p->start; /* save for later use */
- p->start -= ext_start;
-
- /* move pointer to next entry in partition table */
- p = &rpt.entry[1];
- } else
- next_start = 0;
-
- /* now do the logical partition */
- fdiskGetAttrPartition( hd, n, &pt );
- fdiskMakeRawEntry( hd, pt, p );
- free(pt);
-
- /* HACK - we have to translate start sector */
- /* relative to the start of the current*/
- /* extended partition */
- /* */
- /* NOTE - CHS appears to NOT be translated */
- /* Not sure why this is... */
- p->start -= cur_start;
-
- /* write the partition */
- fdiskWritePartitionTable(hd, cur_start, &rpt);
-
- /* point to next partition table, if it exists */
- if (next_start)
- cur_start = next_start;
- }
-
- /* now sync disk and re-read the partition table */
- sync();
- if ((i = fdiskReReadPartitions( hd ))<0) {
- error = errno;
- } else {
- /* some kernel versions (1.2.x) seem to have trouble
- rereading the partition table, but if asked to do it
- twice, the second time works. - biro@yggdrasil.com */
-
- /* FIXME: is this really necessary -- ewt */
- sync();
- if ((i=fdiskReReadPartitions( hd ))<0)
- error = errno;
- }
-
- if (i < 0) {
- close(hd->fd);
-
- printf("Syncing disks.\n");
- sync();
-
- printf("Re-read table failed with error %d: %s.\nReboot your "
- "system to ensure the partition table is updated.\n",
- error, strerror(error));
- }
-
- return i;
- }
-
- /* return value of first partition, starting with primaries and working */
- /* down thru logical partitions */
- /* returns FDISK_ERR_BADNUM if NO partitions exists */
- int fdiskFirstPartition( HardDrive *hd, unsigned int *first ) {
- if (fdiskFirstPrimary( hd, first ) == 0 )
- return FDISK_SUCCESS;
-
- if (fdiskFirstLogical( hd, first ) == 0 )
- return FDISK_SUCCESS;
-
- return FDISK_ERR_BADNUM;
- }
-
- /* return value of Last partition, starting with logical and working */
- /* down thru primary partitions */
- /* returns FDISK_ERR_BADNUM if NO partitions exists */
- int fdiskLastPartition( HardDrive *hd, unsigned int *last ) {
- if (fdiskLastLogical( hd, last ) == 0 )
- return FDISK_SUCCESS;
-
- if (fdiskLastPrimary( hd, last ) == 0 )
- return FDISK_SUCCESS;
-
- *last = 0;
- return FDISK_ERR_BADNUM;
- }
-
- /* return pointer to partition #n if it exists */
- /* returns null pointer and FDISK_ERR_BADNUM if it doesnt */
- int fdiskFindPartition( HardDrive *hd, unsigned int n, Partition **p ) {
- if (n < 5)
- return fdiskFindPrimary( hd, n, p );
- else
- return fdiskFindLogical( hd, n, p );
- }
-
- #ifdef NEED_WALK_ROUTINES
- /* these routines walk through the list of partitions on a hard drive */
- /* Point to 'first' partition on drive */
- /* returns FDISK_ERR_BADNUM if no partitions exist */
- /* also sets key to NULL */
- int fdiskWalkReset( HardDrive *hd, WalkKey **key ) {
- unsigned int first;
-
- /* find first partition and initialize the key used to walk list */
- if (fdiskFirstPartition( hd, &first ) != 0)
- return FDISK_ERR_BADNUM;
-
- *key = (WalkKey *) malloc( sizeof(WalkKey) );
- *key->value = first;
- }
-
- /* return partition information for where key is currently pointing */
- /* and increment key to next position */
- /* if key is NULL then we're at end of list */
- int fdiskWalkNext( HardDrive *hd, WalkKey **key, Partition **p ) {
-
- Partition **q;
- int s, next, last;
-
- /* find current partition */
- s = fdiskFindPartition( hd, *key->value, p );
- if (s != 0) {
- free(*key);
- *key = NULL;
- return s;
- }
-
- /* point to next */
- fdiskLastPartition( hd, &last );
- next = *key->value+1;
-
- for (; next <= last; next++)
- s = fdiskFindPartition( hd, next, q );
- if (!s)
- break;
-
- /* we've reached the end */
- if (next >= last) {
- free(*key);
- *key = NULL;
- }
-
- return FDISK_SUCCESS;
- }
-
- #endif
-
-
-