home *** CD-ROM | disk | FTP | other *** search
- /* handles automatic allocation of space for requested new partitions */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <malloc.h>
- #include <string.h>
-
- #include "libfdisk.h"
-
-
- /* these routines manipulate a space map - can be used or free space */
- /* the space map is a array of structures, each structure indicating */
- /* the start and size of a chunk of space */
- /* if the size is 0, then it is an UNUSED entry in the free space table */
-
- /* initialze a space map data type */
- int fdiskSpaceMapInit( SpaceMap **map ) {
- *map = (SpaceMap *) malloc( sizeof(SpaceMap) );
- (*map)->len = 0;
- (*map)->num = 0;
- (*map)->entry = NULL;
- return FDISK_SUCCESS;
- }
-
- /* reduce # entries to smallest possible number by combining */
- /* touching/overlapping entries */
- /* fuzz introduced because can't allocate space in less than */
- /* that size chunk ususally */
- int fdiskSpaceMapKrunch( SpaceMap *map, unsigned int fuzz ) {
- unsigned int start;
- unsigned int end;
- unsigned int maxend;
- unsigned int tmpend;
- unsigned int i, j;
-
- for (i=0; i < map->num-1; ) {
-
- start = map->entry[i].start;
- end = start + map->entry[i].size;
- maxend = end;
-
- /* see if next partition can merge with existing */
- if (map->entry[i+1].start <= end+fuzz) {
- /* find last space which starts inside existing space */
- for (j=i+1; j < map->num; )
- if (map->entry[j].start <= end+fuzz) {
- tmpend=map->entry[j].start+map->entry[j].size;
- if (tmpend > maxend)
- maxend = tmpend;
-
- fdiskSpaceMapDel( map, j );
- continue;
- } else
- break;
-
- /* adjust first space to contain all */
- map->entry[i].size = maxend - map->entry[i].start;
- } else {
- /* move to the next entry and keep going */
- i++;
- }
- }
-
- return FDISK_SUCCESS;
- }
-
- /* add an entry to a map */
- /* fuzz is the smallest chunk we can allocate, used to close up holes */
- /* in the space map which are not usable */
- int fdiskSpaceMapAdd( SpaceMap *map, SpaceMapEntry *entry, unsigned int fuzz ){
- int i;
- int spot;
- int num, len;
-
- /* see if anything exists yet */
- if (map->entry) {
- /* we want to keep map space sorted by start */
- num = map->num;
- len = map->len;
- if (num == 0) {
- spot = -1;
- } else if (entry->start < map->entry[0].start) {
- spot = -1;
- } else if (entry->start > map->entry[num-1].start) {
- spot = num;
- } else {
- /* NEW CODE (Nov 7 1997) WATCH CLOSELY! */
- for (spot=0; spot < num-1; spot++)
- if (entry->start >= map->entry[spot].start &&
- entry->start <= map->entry[spot+1].start)
- break;
- }
- } else {
- /* new list */
- num = 0;
- len = 0;
- spot = -1;
- }
-
- /* are we simply adjusting an existing chunk, or creating a new one ? */
- /* if its a new entry at end of list we skip this check altogether */
- if (spot > -1 && spot != num && entry->start == map->entry[spot].start){
- /* editting existing entry */
- if (entry->size > map->entry[spot].size)
- map->entry[spot].size = entry->size;
- } else {
- /* insert into list */
- map->num++;
- if (map->num > len) {
- len += SpaceMapChunk;
- map->len = len;
- map->entry = (SpaceMapEntry *) realloc(map->entry,
- len*sizeof(SpaceMapEntry));
- memset(&map->entry[map->num-1], 0, len*sizeof(SpaceMapEntry));
- }
-
- for (i=map->num-1; i >= 0 && i > spot; i--)
- memcpy(&map->entry[i], &map->entry[i-1], sizeof(SpaceMapEntry));
-
- if (spot != num)
- memcpy(&map->entry[spot+1], entry, sizeof(SpaceMapEntry));
- else
- memcpy(&map->entry[spot], entry, sizeof(SpaceMapEntry));
- }
-
- /* go thru and consolidate to smallest set of entries */
- /* for now lets not use fuzz, as it erases spaces where we may */
- /* actually want to put an EPT, for example */
- /* fdiskSpaceMapKrunch( map, fuzz ); */
- fdiskSpaceMapKrunch( map, 0 );
-
- return FDISK_SUCCESS;
- }
-
-
- /* delete an entry from a map, index by position in list */
- int fdiskSpaceMapDel( SpaceMap *map, unsigned int n ) {
- int i;
-
- /* see if anything exists yet */
- if (!map->entry || n < 0 || n > map->num-1)
- return FDISK_ERR_BADNUM;
-
- for (i=n; i<map->num-1; i++)
- memcpy(&map->entry[i], &map->entry[i+1], sizeof(SpaceMapEntry));
-
- memset(&map->entry[map->num-1], 0, sizeof(SpaceMapEntry));
- map->num--;
- return FDISK_SUCCESS;
- }
-
-
- int fdiskSpaceMapFree( SpaceMap *map ) {
-
- if (!map)
- return FDISK_ERR_BADPTR;
-
- if (map->entry)
- free(map->entry);
-
- free(map);
- return FDISK_SUCCESS;
- }
-
-
-
- /* */
- /* END OF SPACE MAP MANAGEMENT ROUTINES */
- /* */
-
-
-
- /* */
- /* These routines handle making maps of used and free space on a given hd */
- /* */
-
- /* */
- /* Routine to build a 'used' space map for the given hard drive */
- /* */
- int fdiskUsedMapGen( HardDrive *hd, SpaceMap **map ) {
- unsigned int i, first, last;
- int status;
- unsigned int diskempty=0;
- Partition *p, *ep;
- SpaceMapEntry m;
-
- /* find range of partitions to include */
- /* if no partitions then its easy to compute free space */
- if ((status=fdiskFirstPartition( hd, &first )) )
- if (status != FDISK_ERR_BADNUM)
- return status;
- else
- diskempty = 1;
-
- if (diskempty) {
- first = 0;
- last = 0;
- } else {
- if ((status=fdiskLastPartition( hd, &last )))
- return status;
- }
-
- fdiskSpaceMapInit( map );
-
- /* insert the Master Boot record */
- m.start = 0;
- m.size = hd->geom.sectors;
- fdiskSpaceMapAdd( *map, &m, hd->geom.sectors );
-
- /* if no partitions we're free to go */
- if (diskempty)
- return FDISK_SUCCESS;
-
- /* otherwise go thru list and figure allocated space */
- for (i=first; i <= last; i++) {
- status = fdiskGetAttrPartition( hd, i, &p );
- if (!status) {
- if (i<5) {
- /* this is a primary partition */
- /* is it an extended partition? */
- if (!fdiskIsExtended( p->type.current )) {
- m.start = p->start.current;
- m.size = p->size.current;
- } else {
- /* this is the PEP */
- /* we insert a used region for the PEPT */
- m.start = p->start.current;
- m.size = hd->geom.sectors;
- }
- fdiskSpaceMapAdd( *map, &m, hd->geom.sectors );
- } else {
- /* this is a logical/extended partition pair. */
- /* We take into account the space used by the EPT */
- /* and the logical partition */
-
- /* first the EPT */
- fdiskGetAttrExtended( hd, i, &ep );
- m.start = ep->start.current;
- m.size = hd->geom.sectors; /* EPT takes 1 sector but */
- /* usually takes 1 head */
- fdiskSpaceMapAdd( *map, &m, hd->geom.sectors );
-
- /* now the logical partition */
- /* see if the offset is due to a true offset, or because */
- /* of cyl/head/sector stuff */
- /* could probably use p->offset.current but not sure */
- /* that is setup correctly (yet) */
- if ((p->start.current-ep->start.current)<=hd->geom.sectors) {
- m.start = ep->start.current;
- m.size = p->size.current +
- (p->start.current-ep->start.current);
- } else {
- m.start = p->start.current;
- m.size = p->size.current;
- }
- fdiskSpaceMapAdd( *map, &m, hd->geom.sectors );
- free(ep);
- }
- free(p);
- }
- }
-
- return FDISK_SUCCESS;
- }
-
- /* */
- /* Routine to build a 'free' space map for the given hard drive */
- /* */
- int fdiskFreeMapGen( HardDrive *hd, SpaceMap **map ) {
- unsigned int i, first, diff;
- int status;
- SpaceMapEntry m;
- SpaceMap *umap;
-
- /* make a 'used' map, and invert it */
- if ((status=fdiskUsedMapGen( hd, &umap )))
- return status;
-
- fdiskSpaceMapInit( map );
-
- /* start with first sector, find first used sector */
- /* and keep building free space map that way. */
- first = 0;
- for (i=0; i < umap->num; i++) {
- diff = umap->entry[i].start - first;
- if (diff) {
- m.start = first;
- m.size = diff;
- fdiskSpaceMapAdd( *map, &m, 0 ); /* no fuzz needed */
- }
-
- /* move over used block to next possible free space */
- first = umap->entry[i].start + umap->entry[i].size;
- }
-
- /* now handle the end */
- diff = hd->totalsectors - first;
- if (diff) {
- m.start = first;
- m.size = diff;
- fdiskSpaceMapAdd( *map, &m, 0 ); /* no fuzz needed */
- }
-
- return FDISK_SUCCESS;
- }
-
-
- /* given a partition describing a request and a candidate freespace entry */
- /* determine if the space will work */
- /* Handles aligning to cylinder boundaries */
- /* modifies partition p if the constraints worked out ok */
- /* Returns FDISK_ERR_NOFREE if nothing found */
- int fdiskCheckConstraints( HardDrive *hd, SpaceMapEntry *freespace,
- Partition *p, unsigned int type ) {
-
- unsigned int lsize, msize, csize, size;
- unsigned int lstart, mstart, cstart, start;
- unsigned int lcyl, mcyl, ccyl, cyl;
- unsigned int end;
- unsigned int extstart, extsize, extend;
- unsigned int tmp1, tmp2;
- unsigned int fuzz;
- unsigned int inpep;
- unsigned int satisfied, satis1, satis2, pass;
-
- /* see if we're looking for a logical partition or not */
- fuzz = 0;
- inpep = 0;
- if (type & LOGICAL)
- if (!hd->pep)
- return FDISK_ERR_NOPEP;
- else {
- fuzz = hd->geom.sectors;
- inpep = 1;
- fdiskQueryPEP( hd, &extstart, &extsize );
- extend = extstart + extsize - 1;
- }
- else if (type & PRIMARY_EXTENDED)
- fuzz = 32;
-
- /* setup all of the constrains */
- fdiskQueryConstraint(&p->size, &csize, &lsize, &msize,
- FDISK_SIZE_MIN, FDISK_SIZE_MAX );
- fdiskQueryConstraint(&p->endcyl, &ccyl, &lcyl, &mcyl,
- FDISK_ENDCYL_MIN, FDISK_ENDCYL_MAX );
- fdiskQueryConstraint(&p->start, &cstart, &lstart, &mstart,
- FDISK_START_MIN, FDISK_START_MAX );
-
- /* we have several constraints to satisfy, here we are interested */
- /* in the size and start requirements of the partition */
- /* First see if we have a big enough chunk of free space */
- size = freespace->size;
- start = freespace->start;
- end = start + size - 1;
-
- /* handle cylinder boundaries here */
- fdiskRoundStartToCylinder(hd, &start);
- fdiskRoundEndToCylinder(hd, &end);
- size = end - start + 1;
-
- pass = 0;
- satis1 = satis2 = 0;
- while (pass < 2) {
- /* make sure its big enough and is inside PEP if so desired */
- satisfied = 0;
- if (size >= lsize && (!inpep || (start>=extstart && start<=extend))) {
- end = start + lsize - 1;
-
- /* round end to the cylinder boundary */
- fdiskRoundEndToCylinder( hd, &end );
-
- /* now check that we can satisfy and start/end contraints */
- satisfied = 1;
- if (fdiskConstraintIsActive( &p->endcyl )) {
- fdiskSectorToCHS(hd,end,&cyl,&tmp1,&tmp2);
- satisfied = satisfied && (cyl >= lcyl) && (cyl <= mcyl );
- if (!pass && !satisfied && LastAllocStat != ALLOC_UNDEF)
- LastAllocStat = ALLOC_CYL;
- }
-
- if (fdiskConstraintIsActive( &p->start )) {
- satisfied = satisfied && (start>=lstart) && (start<=mstart);
- if (!pass && !satisfied && LastAllocStat != ALLOC_UNDEF)
- LastAllocStat = ALLOC_START;
- }
-
- if (inpep) {
- satisfied = satisfied && (end <= extend);
- }
- } else {
- if (!pass && LastAllocStat != ALLOC_UNDEF)
- LastAllocStat = ALLOC_SIZE;
- }
-
- /* did we pass all the tests? */
- if (pass == 0) {
- satis1 = satisfied;
- if (satisfied) {
- /* save working params into partition entry */
- p->size.current = end - start + 1;
- p->start.current = start;
-
- LastAllocStat = ALLOC_OK;
-
- /* now lets get greedy and grab extra cylinder */
- /* this makes up for the fact that we almost */
- /* always grab a little less space than requested */
- /* due to overhead of partition tables */
- pass++;
- lsize += hd->geom.heads*hd->geom.sectors;
- if (lsize > size)
- lsize = size;
- } else {
- pass = 3;
- }
- } else {
- satis2 = satisfied;
- if (satisfied) {
- /* save working params into partition entry */
- p->size.current = end - start + 1;
- p->start.current = start;
-
- /* we're done */
- pass = 3;
- } else {
- /* we're done */
- pass = 3;
- }
- }
- }
-
- if (satis1 || satis2)
- return FDISK_SUCCESS;
- else
- return FDISK_ERR_NOFREE;
- }
-
- /* Looking at current partition table of drive hd, find a chunk of */
- /* free space that will contain the partition p with all its constraints */
- /* if inpep!=0, we look in pep area only, and add some space required */
- /* for logical partitions over their requested size. */
- /* Handles aligning to cylinder boundaries */
- /* Returns FDISK_ERR_NOFREE if nothing found */
- int fdiskFindFreeSlot( HardDrive *hd, SpaceMap *freespace, Partition *p,
- unsigned int type, unsigned int *freeslot ) {
-
- unsigned int done, j;
-
- /* we have several constraints to satisfy, here we are interested */
- /* in the size and start requirements of the partition */
- /* First see if we have a big enough chunk of free space */
- done = 0;
- for (j=0; j<freespace->num && !done; j++) {
- if (fdiskCheckConstraints(hd, &freespace->entry[j],
- p, type ) == FDISK_SUCCESS) {
- done = 1;
- *freeslot = j;
- }
- }
-
- if (done) {
- return FDISK_SUCCESS;
- } else {
- LastAllocStat = ALLOC_SIZE;
- return FDISK_ERR_NOFREE;
- }
- }
-
- /* characteristics of primary are handled in constraints in p */
- /* if pri < 0, autoallocate primary slot */
- int fdiskMakeNewPrimary( HardDrive *hd, int pri, Partition *p ) {
-
- unsigned int lsize, msize, csize;
- unsigned int lstart, mstart, cstart;
- unsigned int lcyl, mcyl, ccyl;
- int status;
-
- Partition *pt;
-
- /* See if we need to auto-allocate the partition */
- if (pri < 0)
- if (fdiskFindFreePrimary( hd, &pri ) == FDISK_ERR_NOFREEPRIM) {
- LastAllocStat = ALLOC_FREEPRI;
- return FDISK_ERR_NOFREEPRIM;
- }
-
- /* setup all of the constrains */
- fdiskQueryConstraint(&p->size, &csize, &lsize, &msize,
- FDISK_SIZE_MIN, FDISK_SIZE_MAX );
- fdiskQueryConstraint(&p->endcyl, &ccyl, &lcyl, &mcyl,
- FDISK_ENDCYL_MIN, FDISK_ENDCYL_MAX );
- fdiskQueryConstraint(&p->start, &cstart, &lstart, &mstart,
- FDISK_START_MIN, FDISK_START_MAX );
-
- status=fdiskCreatePrimary( hd, pri );
- if (status != FDISK_SUCCESS) {
- LastAllocStat = ALLOC_FREEPRI;
- return status;
- }
-
- fdiskGetAttrPartition( hd, 1, &pt );
- fdiskSetConstraint( &pt->size, csize, lsize, msize,
- fdiskConstraintIsActive(&p->size) );
- fdiskSetConstraint( &pt->start, cstart, lstart, mstart,
- fdiskConstraintIsActive(&p->start) );
- fdiskSetFixedConstraint( &pt->type, p->type.current );
- fdiskSetFixedConstraint( &pt->active, p->active.current );
- fdiskSetFixedConstraint( &pt->offset, 0 );
- fdiskDeactivateAllDriveSet( &pt->drive );
- fdiskActivateDriveSet( &pt->drive, hd->num );
- fdiskSetCurrentDriveSet( &pt->drive, hd->num );
- fdiskSetFixedConstraint( &pt->num, pri );
- pt->status = ALLOCATED;
-
- fdiskSetAttrPartition( hd, pri, pt );
-
- /* store current value in the partition we were passed */
- fdiskSetCurrentConstraint(&p->num, pri);
- fdiskSetCurrentDriveSet(&p->drive, hd->num);
- fdiskSetCurrentConstraint(&p->size, csize);
- fdiskSetCurrentConstraint(&p->start, cstart);
-
- free(pt);
-
- return FDISK_SUCCESS;
- }
-
- /* if no primary extended partition exists, this routine will do it */
- int fdiskMakeNewPrimaryExtended(HardDrive *hd,
- int pep,
- unsigned int freestart,
- unsigned int freesize ) {
-
- unsigned int extstart, extend, extsize;
- int status;
-
- Partition *pt;
-
- /* no primary extended partition (yet) */
- /* lets make one the size of the free space block we're putting */
- /* the requested partition in */
- /* then we make our logical partition */
- if (pep < 0)
- if (fdiskFindFreePrimary( hd, &pep ) == FDISK_ERR_NOFREEPRIM) {
- LastAllocStat = ALLOC_FREEPRI;
- return FDISK_ERR_NOFREEPRIM;
- }
-
- hd->pep = pep;
- if ((status=fdiskCreatePrimary( hd, pep )) != FDISK_SUCCESS) {
- LastAllocStat = ALLOC_FREEPRI;
- return status;
- }
-
- fdiskGetAttrPartition( hd, pep, &pt );
-
- /* we need to make size/start that of the free block we're using */
- /* and NOT the size of the logical partition we want to make */
- /* We DO NOT set the size/start constraints ACTIVE, since we may */
- /* want to grow them later. */
- extstart = freestart;
- extend = freestart + freesize - 1;
-
- /* handle cylinder boundaries here */
- fdiskRoundStartToCylinder(hd, &extstart);
- fdiskRoundEndToCylinder(hd, &extend);
- extsize = extend - extstart + 1;
-
- fdiskSetConstraint( &pt->size, extsize, extsize, FDISK_SIZE_MAX, 0 );
- fdiskSetConstraint( &pt->start,extstart, extstart, FDISK_START_MAX, 0);
- fdiskSetFixedConstraint( &pt->type, DOS_EXTENDED_PARTITION );
- fdiskSetFixedConstraint( &pt->active, 0 );
- fdiskSetFixedConstraint( &pt->offset, 0 );
- fdiskDeactivateAllDriveSet( &pt->drive );
- fdiskActivateDriveSet( &pt->drive, hd->num );
- fdiskSetCurrentDriveSet( &pt->drive, hd->num );
- fdiskSetFixedConstraint( &pt->num, pep );
- pt->status = ALLOCATED;
-
- fdiskSetAttrPartition( hd, pep, pt );
- free(pt);
-
- return FDISK_SUCCESS;
- }
-
- /* Make an extended partition within the specified region */
- /* Must have a PEP before this call will work. */
- /* The size and start of the partition p are used */
- /* However, the user data is offset because there is a EPT*/
- /* at the start of this space */
- int fdiskMakeNewLogical( HardDrive *hd, Partition *p ) {
- int status;
-
- unsigned int lp, pep;
-
- unsigned int cstart, lstart, mstart;
- unsigned int csize, lsize, msize;
- unsigned int extstart, extend, extsize;
- unsigned int sector_offset;
-
- Partition *pt, *ept;
-
- /* see if pep exists */
- pep = hd->pep;
- if (!pep)
- return FDISK_ERR_NOPEP;
-
- /* use it as a template for the extented partition part of the */
- /* EP/LP pair we are creating */
- if ((status=fdiskAppendLogical( hd, &lp )) != FDISK_SUCCESS)
- return status;
-
-
- /* setup all of the constrains */
- fdiskQueryConstraint(&p->size, &csize, &lsize, &msize,
- FDISK_SIZE_MIN, FDISK_SIZE_MAX );
- fdiskQueryConstraint(&p->start, &cstart, &lstart, &mstart,
- FDISK_START_MIN, FDISK_START_MAX );
-
- /* get initial starting points for extended and logical entries */
- fdiskGetAttrPartition( hd, lp, &pt );
- fdiskGetAttrPartition( hd, pep, &ept );
-
- /* since we are creating a logical partition from scratch, */
- /* we can make the offset anything we like. The existing */
- /* 'fdisk' program makes the offset equal to one head */
- sector_offset = hd->geom.sectors;
-
- /* setup the extended partition first */
- /* it describes the partition which the logical is IN */
- extstart = cstart;
- extend = cstart + csize + sector_offset - 1;
-
- /* handle cylinder boundaries here */
- fdiskRoundStartToCylinder(hd, &extstart);
- fdiskRoundEndToCylinder(hd, &extend);
- extsize = extend - extstart + 1;
-
- fdiskSetConstraint( &ept->size, extsize, extsize, FDISK_SIZE_MAX, 0 );
- fdiskSetConstraint( &ept->start,extstart, extstart, FDISK_START_MAX, 0);
- fdiskSetFixedConstraint( &ept->type, DOS_EXTENDED_PARTITION );
- fdiskSetFixedConstraint( &ept->active, 0 );
- fdiskSetFixedConstraint( &ept->offset, 0 );
- fdiskDeactivateAllDriveSet( &ept->drive );
- fdiskActivateDriveSet( &ept->drive, hd->num );
- fdiskSetCurrentDriveSet( &ept->drive, hd->num );
- fdiskSetFixedConstraint( &ept->num, lp );
- ept->status = ALLOCATED;
-
- fdiskSetAttrExtended( hd, lp, ept );
- free(ept);
-
- /* now the logical partition */
- fdiskSetConstraint( &pt->size,
- extsize-sector_offset,
- lsize, msize, fdiskConstraintIsActive(&p->size) );
- fdiskSetConstraint( &pt->start,
- extstart+sector_offset,
- lstart, mstart,fdiskConstraintIsActive(&p->start) );
- fdiskSetFixedConstraint( &pt->type, p->type.current );
- fdiskSetFixedConstraint( &pt->active, p->active.current );
- fdiskSetFixedConstraint( &pt->offset, 0 );
- fdiskDeactivateAllDriveSet( &pt->drive );
- fdiskActivateDriveSet( &pt->drive, hd->num );
- fdiskSetCurrentDriveSet( &pt->drive, hd->num );
- fdiskSetFixedConstraint( &pt->num, lp );
- pt->status = ALLOCATED;
-
- /* store current value in the partition we were passed */
- fdiskSetCurrentConstraint(&p->num, lp);
- fdiskSetCurrentDriveSet(&p->drive, hd->num);
- fdiskSetCurrentConstraint(&p->size, extsize-sector_offset);
- fdiskSetCurrentConstraint(&p->start, extstart+sector_offset);
-
- fdiskSetAttrPartition( hd, lp, pt );
- free(pt);
-
- return FDISK_SUCCESS;
- }
-
-
- /* */
- /* These routines handle inserting a desired partition into an existing */
- /* partition table on a hard drive. */
- /* */
- /* We pass an array of HardDrive's, each of which is considered for the */
- /* possible home of the partition. */
- /* HardDrive's are assumed to be in arranged in increasing number */
- /* Note that the index of the drive in the HardDrive array IS NOT the same*/
- /* as its actual 'num'. */
- int fdiskAutoInsertPartition(HardDrive **hdarr,
- unsigned int nhd,
- Partition *p ) {
-
- unsigned int drive;
- unsigned int extstart, extsize;
- unsigned int i;
- unsigned int freeslot, freedrive;
-
- unsigned int extExists, priExists, noneExists;
- unsigned int extCreate, priCreate, logCreate;
- unsigned int extTried, priTried, logTried;
- unsigned int done, donesearch, errsearch, lasttry, trynext;
- int status;
-
- HardDrive *hd;
- SpaceMap **freespace;
- DriveSet drives;
- Partition *ptmp;
-
- /* first lets generate free space maps for all possible drives */
- /* also figure out what range of drives exist */
- /* index of freespace[] will be the same as for accessing */
- /* the entries of the hdarr[] of HardDrive's */
- freespace = (SpaceMap **) alloca((nhd)*sizeof(SpaceMap));
- fdiskDeactivateAllDriveSet( &drives );
- for (drive=0; drive < nhd; drive++) {
- fdiskFreeMapGen( hdarr[drive], &freespace[drive] );
- fdiskActivateDriveSet( &drives, hdarr[drive]->num );
- }
-
- /* loop over all the drives which are valid to consider */
- /* For each drive, go through a list of 'preferable' places to put */
- /* the new partition. */
- /* */
- /* Rules: */
- /* */
- /* If No Partitions Exist */
- /* Create New Primary */
- /* DONE */
- /* Else If No Extended Exists */
- /* Create Extended in largest hole fitting all constraints */
- /* DONE */
- /* Else */
- /* Try to create a logical partition */
- /* If Success */
- /* DONE */
- /* Else */
- /* Try to create a primary partition */
- /* If Success */
- /* DONE */
- /* Else */
- /* FAIL */
- /* */
- done = 0;
- LastAllocStat = ALLOC_UNDEF;
- for (drive = 0; drive < nhd && !done; drive++) {
- hd = hdarr[drive];
- if (!fdiskThisDriveSetIsActive( &p->drive, hd->num ))
- continue;
-
- /* Figure out what partitions currently exist on this drive */
- extExists = (hd->pep != 0);
- priExists = 0;
- for (i=1; i<4; i++) {
- if (fdiskGetAttrPrimary(hd, i, &ptmp) != FDISK_SUCCESS)
- continue;
- priExists |= !fdiskIsExtended(ptmp->type.current);
- }
- /* priExists = !(fdiskLastPartition( hd, &tmp1 ) == FDISK_ERR_BADNUM); */
- noneExists = !(extExists || priExists);
-
- /* Keeps trying strategies for placing new partition in existing */
- /* scheme until we hit a solution we like */
- donesearch = 0;
- errsearch = 0;
- lasttry = 0;
- trynext = 0;
- extTried = 0;
- logTried = 0;
- priTried = 0;
- while (!donesearch && !errsearch && !lasttry && !trynext) {
- priCreate = 0;
- extCreate = 0;
- logCreate = 0;
-
- if (noneExists || !priExists) {
- /* gonna make a primary partition */
- priCreate = 1;
- if ((status=fdiskFindFreeSlot(hd,freespace[drive],p,
- PRIMARY,&freeslot)) != FDISK_SUCCESS)
- trynext = 1;
- else {
- freedrive = drive;
- lasttry = 1;
- }
- } else if (!extExists) {
-
- if (!extTried) {
- /* let try to make a primary extended partition */
- extCreate = 1;
- if ((status=fdiskFindFreeSlot(hd,freespace[drive],p,
- PRIMARY_EXTENDED,
- &freeslot)) != FDISK_SUCCESS)
- trynext = 1;
- else {
- freedrive = drive;
- }
- } else if (!priTried) {
- /* couldnt make extended work, try to make another PP */
- priCreate = 1;
- if ((status=fdiskFindFreeSlot(hd,freespace[drive],p,
- PRIMARY,&freeslot)) != FDISK_SUCCESS)
- trynext = 1;
- else {
- freedrive = drive;
- lasttry = 1;
- }
- } else
- /* nothing else to try */
- trynext = 1;
- } else {
- /* try to make a logical first, then a primary */
- if (!logTried) {
- logCreate = 1;
- if ((status=fdiskFindFreeSlot(hd,freespace[drive],p,
- LOGICAL,&freeslot)) != FDISK_SUCCESS) {
- if (!priTried) {
- priCreate = 1;
- if ((status=fdiskFindFreeSlot(hd,freespace[drive],p,
- PRIMARY,&freeslot)) != FDISK_SUCCESS)
- trynext = 1;
- else {
- freedrive = drive;
- lasttry = 1;
- }
- } else {
- trynext = 1;
- }
- } else {
- freedrive = drive;
- }
- } else
- /* nothing else to try */
- trynext = 1;
- }
-
- /* move on to next drive */
- if (trynext)
- continue;
-
- if (!errsearch) {
- /* now try to create whatever we decided was the best choice */
- /* parameters of the allocated partition are in the partition*/
- /* structure 'p' */
- if (priCreate) {
- priTried = 1;
- if ((status=fdiskMakeNewPrimary(hd,-1,p))==FDISK_SUCCESS)
- donesearch = 1;
- } else if (extCreate) {
- extTried = 1;
- if (!extExists) {
- /* gotta make a PEP */
- extstart = freespace[drive]->entry[freeslot].start;
- extsize = freespace[drive]->entry[freeslot].size;
- status=fdiskMakeNewPrimaryExtended(hd, -1,
- extstart,extsize);
- if (status == FDISK_SUCCESS) {
- extExists = 1;
- status=fdiskMakeNewLogical(hd, p);
- if (status == FDISK_SUCCESS)
- donesearch = 1;
- }
- }
- } else if (logCreate) {
- logTried = 1;
- if (!extExists) {
- status = FDISK_ERR_NOPEP;
- errsearch = 1;
- } else {
- status=fdiskMakeNewLogical(hd, p);
- if (status == FDISK_SUCCESS)
- donesearch = 1;
- }
- }
- } else {
- printf("Error searching was %d, aborting\n", status);
- return status;
- }
- }
-
- if (donesearch)
- done = 1;
- }
-
- /* did we find an acceptable location? */
- /* if not we SHOULD try reshuffling existing partitions */
- /* but for now we just give up */
- if (!done) {
- return FDISK_ERR_NOFREE;
- }
-
- return FDISK_SUCCESS;
- }
-
-
- /* not sure what this will be good for yet */
- #if 0
-
- /* moves a non-extended primary partition to new location specified in */
- /* the partition p */
- int fdiskMovePrimary( HardDrive *hd, unsigned int num, Partition *p ) {
-
- fdiskSetAttrPartition( hd, num, &p);
-
- }
-
- /* krunch partition table so all moveable partitions form contiguous block */
- /* will not slide logical partitions out of an extended partition, instead */
- /* the extended partition start is slid and logical partitions move inside */
- /* the extended partition. This way the # of primary partition slots used */
- /* is kept constant. */
- /* we try to push available free space towards the start of the disk */
- int fdiskKrunchPartitionTable( HardDrive *hd ) {
-
- unsigned int last, first, cur;
- unsigned int csize, lsize, msize, asize;
- unsigned int cstart, lstart, mstart, astart;
- unsigned int endfree, startfree, sizefree;
- unsigned lastfree;
- int i;
- SpaceMap *freespace;
- SpaceMapEntry testentry;
- Partition tstp;
- Partition *p, *ep;
-
- /* make sure there are any partitions to process */
- if (fdiskLastPartition(hd, &last ) == FDISK_ERR_BADNUM)
- return FDISK_ERR_BADNUM;
-
- /* - look through freespace list */
- /* - if adjacent, movable partition exists, slide to close space */
- /* otherwise, find movable partitions to move to close space */
- /* - if we made any changes, recompute freespace map */
- /* - keep going till we change nothing */
- /* */
- /* First look at primary partitions, shift/relocate them if possible */
- done = 0;
- lastfree = hd->totalsectors;
- freespace = NULL;
- while (!done) {
-
- /* get a freespace map for the drive first */
- fdiskFreeMapGen( hd, &freespace );
- if (!freespace->num)
- break;
-
- /* locate next free space to consider */
- for (i=0; i < freespace->num; i++)
- if (freespace->entry[i].start < lastfree)
- break;
-
- /* couldnt find any more freespace to consider */
- if (i == freespace->num)
- break;
-
- /* locate primary partition closest to freespace on the high side */
- startfree = freespace->entry[i].start;
- sizefree = freespace->entry[i].size;
- endfree = startfree + sizefree - 1;
-
- mindiff = FDISK_SIZE_MAX;
- minnum = 0;
- for (cur=1; cur <=4; cur++) {
- if (fdiskGetAttrPartition( hd, cur, &p))
- continue;
-
- if (p->immutable) {
- free(p);
- continue;
- }
-
- fdiskGetConstraint(&p->start,&cstart,&lstart,&mstart,&astart );
- fdiskGetConstraint(&p->size, &csize, &lsize, &msize, &asize );
-
- if (cstart < startfree) {
- tmpdiff = startfree - cstart;
- if (tmpdiff < mindiff) {
- mindiff = tmpdiff;
- minnum = cur;
- }
- }
- free(p);
- }
-
- /* see if we found anything */
- if ( minnum != 0 ) {
- fdiskGetAttrPartition( hd, minnum, &p);
-
- if (!fdiskIsExtended(p->type.current)) {
- /* its a simple primary partition */
- /* see if we can move the partition and satisfy */
- /* any constraints if may have on its location */
- /* if it works, move the partition and update */
- /* last free considered */
- fdiskGetConstraint(&p->start,&cstart,
- &lstart,&mstart,&astart );
- fdiskGetConstraint(&p->size, &csize,
- &lsize, &msize, &asize );
- startfree = freespace->entry[minnum].start;
- sizefree = freespace->entry[minnum].size;
- endfree = startfree + sizefree - 1;
-
- /* setup new location and round to a cyl boundary */
- /* if rounding makes the partition smaller, move */
- /* start back another cylinder and try again */
- /* primary partitions always start on a cylinder */
- /* boundary (except for the one containing the MBR*/
- testentry.start = endfree - csize;
- fdiskRoundStartToCylinder( hd, &cstart );
- testentry.size = endfree - cstart + 1;
- if (testentry.size < csize)
- testentry.start -= hd->geom.sectors*hd->geom.heads;
- testentry.size = csize;
-
- if (fdiskCheckContraints(hd, &testentry,
- p, PRIMARY ) == FDISK_SUCCESS) {
- fdiskMovePrimary(hd, minnum, p);
- fdiskGetConstraint(&p->start,&cstart,
- &lstart,&mstart,&astart );
- fdiskGetConstraint(&p->size, &csize,
- &lsize, &msize, &asize );
- lastfree = cstart + csize;
- }
- } else {
- /* its a primary extended partition, lots more to do! */
- /* have to also relocate all logical partitions inside */
- if (fdiskCheckContraints(hd, &freespace->entry[i],
- p, EXTENDED ) == FDISK_SUCCESS) {
- fdiskMovePrimaryExtended( hd, minnum, p );
- fdiskGetConstraint(&p->start,&cstart,
- &lstart,&mstart,&astart );
- fdiskGetConstraint(&p->size, &csize,
- &lsize, &msize, &asize );
- lastfree = cstart + csize;
- }
-
- }
- } else {
- done = 1;
- }
-
- /* anything left allocated? */
- if (freespace != NULL) {
- fdiskSpaceMapFree( freespace );
- freespace = NULL;
- }
- }
-
- /* anything left allocated? */
- if (freespace != NULL) {
- fdiskSpaceMapFree( freespace );
- freespace = NULL;
- }
-
- }
- #endif
-
-
- /* given a list of requested partitions, take hdarr as starting point. */
- /* stick partitions into nhdarr */
- /* wecare controls whether we record reason for failures or not */
- int fdiskAutoInsertPartitions( HardDrive **hdarr, unsigned int numhd,
- HardDrive **newhdarr, int wecare,
- PartitionSpec *spec ) {
- unsigned int i;
- int status;
- /* copy existing hard drive structure into the new hard drive struct */
- for (i=0; i < numhd; i++)
- memcpy(newhdarr[i], hdarr[i], sizeof(HardDrive));
-
- /* start inserting the partitions */
- /* set the last alloc error to undef */
- LastAllocStat = ALLOC_UNDEF;
- for (i=0; i<spec->num; i++) {
- if (spec->entry[i].status != REQUEST_ORIGINAL) {
- status = fdiskAutoInsertPartition( newhdarr, numhd,
- &spec->entry[i].partition );
- if (status == FDISK_SUCCESS) {
- spec->entry[i].status = REQUEST_GRANTED;
- if (wecare)
- spec->entry[i].reason = ALLOC_OK;
- } else {
- spec->entry[i].status = REQUEST_DENIED;
- if (wecare)
- spec->entry[i].reason = LastAllocStat;
- }
- }
- }
-
- return FDISK_SUCCESS;
- }
-
- /* */
- /* growing routines */
- /* these routines take an existing array for drives and a partspec */
- /* and grow the partitions marked for growth to fill available space */
-
- /* this should work but is VERY messy!!!!! */
- /* uses internals of partitions and partitions specs too much */
- /* needs to be rewritten to use functions to get/set values */
- int fdiskGrowPartitions( HardDrive **hdarr, unsigned int numhd,
- HardDrive **newhdarr,
- PartitionSpec *spec ) {
-
- PartitionSpec trialspec, startspec, origspec;
- Partition *p;
- unsigned int *freespace, *usedbygrow;
- unsigned int min, max, cur, dif, ldif;
- int j, k, l;
- int statcur;
- float f;
-
- /* copy existing partition spec in a safe place */
- /* we make new copies of the 'names' field, since its malloc'd */
- memcpy(&startspec, spec, sizeof(PartitionSpec));
- for (j=0; j<spec->num; j++) {
- /* copy the name */
- if (spec->entry[j].name)
- startspec.entry[j].name = strdup(spec->entry[j].name);
-
- /* if request was granted, lock partition to drive its on currently */
- if (spec->entry[j].status == REQUEST_GRANTED) {
- startspec.entry[j].status = REQUEST_PENDING;
- p = &startspec.entry[j].partition;
- fdiskDeactivateAllDriveSet( &p->drive );
- fdiskActivateDriveSet( &p->drive, p->drive.current );
- }
- }
-
- /* go thru and weed out the denied partitions */
- for (j=0; j<spec->num; j++)
- if (spec->entry[j].status == REQUEST_DENIED)
- fdiskDeletePartitionSpec(&startspec, spec->entry[j].name);
-
- /* make array of freespace left on each drive */
- freespace = (unsigned int *) alloca(numhd*sizeof(unsigned int));
- usedbygrow = (unsigned int *) alloca(numhd*sizeof(unsigned int));
- for (j=0; j<numhd; j++) {
- freespace[j] = hdarr[j]->totalsectors;
- usedbygrow[j] = 0;
- }
-
- for (j=0; j<startspec.num; j++) {
- p = &startspec.entry[j].partition;
- if (fdiskIsExtended(p->type.current))
- continue;
-
- for (k=0; k<numhd; k++)
- if (hdarr[k]->num == p->drive.current)
- break;
-
- if (k==numhd) /* shouldnt happen */
- continue;
-
- freespace[k] -= p->size.current;
-
- if (!p->size.active || p->size.min == p->size.max || p->immutable)
- continue;
- usedbygrow[k] += p->size.current;
- }
-
- /* now grow them */
- memcpy(&trialspec, &startspec, sizeof(PartitionSpec));
- for (j=0; j<startspec.num; j++) {
- p = &startspec.entry[j].partition;
- if (!p->size.active || p->size.min == p->size.max || p->immutable)
- continue;
-
- for (k=0; k<numhd; k++)
- if (hdarr[k]->num == p->drive.current)
- break;
-
- if (k==numhd) /* shouldnt happen */
- continue;
-
- /* OK, this is the ugliest binary search ever coded. */
- min = 0;
- if (usedbygrow[k] != 0)
- f = ((float)p->size.current/(float)usedbygrow[k]);
- else
- f = 0; /* shouldnt happen */
- max = (unsigned int)((f*(float)freespace[k])+0.5);
- cur = max - (max-min)/2; /* might help with rounding */
- dif = max - min;
- ldif = 0;
-
- while (min != max && ldif != dif) {
- trialspec.entry[j].status = REQUEST_PENDING;
- trialspec.entry[j].partition.size.min =
- startspec.entry[j].partition.size.min + cur;
- statcur = fdiskAutoInsertPartitions(hdarr, numhd, newhdarr, 0,
- &trialspec);
-
- /* check to see if any partitions got lost, if so thats bad */
- for (l=0; l<trialspec.num; l++)
- if (trialspec.entry[l].status == REQUEST_DENIED) {
- statcur = FDISK_ERR_NOFREE;
- break;
- }
-
- if (statcur != FDISK_SUCCESS)
- max = cur;
- else
- min = cur;
-
- cur = max - (max-min)/2;
- ldif = dif;
- dif = max - min;
- }
-
- /* store the final working size in trialspec */
- /* max COULD have failed, so we have to look */
- /* at result of last try with it to see if */
- /* we should use it instead of min. Min val */
- /* SHOULD always be a successful size. */
- trialspec.entry[j].status = REQUEST_PENDING;
- trialspec.entry[j].partition.size.min =
- startspec.entry[j].partition.size.min +
- ((statcur == FDISK_SUCCESS) ? cur : min);
- }
-
- /* we're done, copy into original partition spec and */
- /* insert one last time */
- memcpy(&origspec, spec, sizeof(PartitionSpec));
- for (j=0; j<startspec.num; j++) {
- p = &startspec.entry[j].partition;
- if (!p->size.active || p->size.min == p->size.max || p->immutable)
- continue;
-
- for (k=0; k<spec->num; k++)
- if (!strcmp(trialspec.entry[j].name,spec->entry[k].name))
- break;
-
- if (k == spec->num) /* shouldnt happen */
- continue;
-
- spec->entry[k].partition.size.min=trialspec.entry[j].partition.size.min;
- spec->entry[k].status = REQUEST_PENDING;
- }
-
- fdiskAutoInsertPartitions(hdarr, numhd, newhdarr, 0, spec );
-
- /* now put the 'min' size back to what the user wanted */
- for (j=0; j<spec->num; j++) {
- p = &spec->entry[j].partition;
- if (!p->size.active || p->size.min == p->size.max || p->immutable)
- continue;
-
- spec->entry[j].partition.size.min=origspec.entry[j].partition.size.min;
- }
-
-
- /* now clean up and leave */
- for (j=0; j<startspec.num; j++)
- free(startspec.entry[j].name);
-
- return FDISK_SUCCESS;
- }
-
-
-