/* Raw disk i/o handling the partition tables on a hard drive */ /* */ /* Michael Fulbright June 1997 */ /* Recoded to use new HardDrive structure */ #include #include #include #include #include #include #include #include #include "libfdisk.h" long long llseek(int fd, long long offset, int whence); int fdiskSectorToCHS( HardDrive *hd, unsigned int start, unsigned int *c, unsigned int *h, unsigned int *s ) { *s = start % hd->geom.sectors + 1; start /= hd->geom.sectors; *h = start % hd->geom.heads; start /= hd->geom.heads; *c = start; return FDISK_SUCCESS; } /* move absolute sector position to the next highest cylinder boundary */ /* HOWEVER, if we are within 2 heads of the previous cylinder we dont */ /* round up. This is how partitions with partition tables at the front */ /* work (like LP). */ int fdiskRoundStartToCylinder( HardDrive *hd, unsigned int *start ) { unsigned int m; m = *start % (hd->geom.heads*hd->geom.sectors); if (m > 2*hd->geom.sectors) *start += (hd->geom.heads*hd->geom.sectors) - m; return FDISK_SUCCESS; } /* move absolute sector position to the next lowest cylinder boundary */ int fdiskRoundEndToCylinder( HardDrive *hd, unsigned int *end ) { unsigned int m; if (*end > hd->geom.heads*hd->geom.sectors) { m = (*end % (hd->geom.heads*hd->geom.sectors)); if (m != hd->geom.heads*hd->geom.sectors-1) *end -= m+1; } return FDISK_SUCCESS; } /* these routes return < 0 on system error, errno has error */ /* 0 on success */ /* > 0 on other errors */ /* open device dev, returns allocated HardDrive structure */ /* num is the booting numbers, ie, IDE drives come first, then SCSI, etc */ /* up to caller to set values */ int fdiskOpenDevice(char *dev, unsigned int num, HardDrive **hddev) { int fd; int i; HDGeometry g; HardDrive *hd; *hddev = NULL; /* try to determine everything, if it works then we return */ /* filled in hd_device struct */ fd = open(dev, O_RDWR); if (fd < 0) return -1; if (ioctl(fd, HDIO_GETGEO, &g)) return -1; hd = (HardDrive *) malloc(sizeof(HardDrive)); hd->fd = fd; strncpy(hd->name, dev, MAX_HD_NAMELEN); memcpy(&hd->geom, &g, sizeof(HDGeometry)); hd->totalsectors = hd->geom.sectors*hd->geom.heads*hd->geom.cylinders; *hddev = hd; /* zero out the partition table */ memset(&hd->table, 0, (MAX_PARTITIONS+1)*sizeof(Partition)); memset(&hd->eptable, 0, (MAX_PARTITIONS+1)*sizeof(Partition)); /* set all primaries as available and all extended as unavailable */ for (i=1; i <= MAX_PARTITIONS; i++) { if (i < 5) hd->table[i].status = AVAILABLE; else hd->table[i].status = UNAVAILABLE; /* set all eptable entries as UNAVAILABLE */ hd->eptable[i].status = UNAVAILABLE; } /* no PEP yet! */ hd->pep = 0; hd->num = num; return FDISK_SUCCESS; } /* Note - no error checking (yet) */ int fdiskCloseDevice(HardDrive *hddev) { close(hddev->fd); free(hddev); return FDISK_SUCCESS; } /* cause kernel to re-read partition table */ int fdiskReReadPartitions( HardDrive *hd ) { return ioctl(hd->fd, BLKRRPART); } /* these two routines read/write a Partition Table at the location */ /* specified by the caller */ /* returns a value of FDISK_ERR_BADNUM if no table found at loc */ int fdiskReadPartitionTable(HardDrive *hddev, unsigned int loc, RawPartitionTable **pt ) { int i; long long offset; unsigned int magic; unsigned char b[SECTORSIZE]; RawPartitionTable *t; offset = (long long) loc * (long long) SECTORSIZE; if (llseek(hddev->fd, offset, SEEK_SET) < 0) return -1; if (read(hddev->fd, b, SECTORSIZE) != SECTORSIZE) return -1; /* see if we really got something */ magic = b[PARTMAGOFF]*256 + b[PARTMAGOFF+1]; if (magic != PARTMAGIC) return FDISK_ERR_BADMAGIC; t = (RawPartitionTable *) malloc(sizeof(RawPartitionTable)); for (i=0; i<4; i++) memcpy( &t->entry[i], b+PARTTBLOFF+i*sizeof(RawPartition), sizeof(RawPartition)); *pt = t; return FDISK_SUCCESS; } /* we read the current sector and modify it, in case there is some */ /* boot code there we need to preserve */ /* not sure this is what we want to ALWAYS do */ /* accepts location as the SECTOR OFFSET!!! */ int fdiskWritePartitionTable(HardDrive *hddev, unsigned int loc, RawPartitionTable *pt ) { int i; long long offset; unsigned char b[SECTORSIZE]; #ifdef REALLY_DEBUG printf("seeking to %d and writing partition table\n",loc); print_raw_partition_table(0, pt); #endif offset = (long long) loc * (long long) SECTORSIZE; if (llseek(hddev->fd, offset, SEEK_SET) < 0) return -1; if (read(hddev->fd, b, SECTORSIZE) != SECTORSIZE) return -1; /* move partition data into the sector */ for (i=0; i<4; i++) memcpy( b+PARTTBLOFF+i*sizeof(RawPartition), &pt->entry[i], sizeof(RawPartition)); /* stick the magic on there */ b[PARTMAGOFF ] = PARTMAGIC >> 8; b[PARTMAGOFF+1 ] = PARTMAGIC & 0xff; if (llseek(hddev->fd, offset, SEEK_SET) < 0) return -1; if (write(hddev->fd, b, SECTORSIZE) != SECTORSIZE) return -1; return FDISK_SUCCESS; } int fdiskReadMBR( HardDrive *hddev, RawPartitionTable **pt ) { return fdiskReadPartitionTable(hddev, 0L, pt ); } int fdiskWriteMBR( HardDrive *hddev, RawPartitionTable *pt ) { return fdiskWritePartitionTable( hddev, 0L, pt ); } int fdiskZeroMBR( HardDrive *hddev ) { RawPartitionTable pt; memset(&pt, 0, sizeof(RawPartitionTable)); return fdiskWriteMBR( hddev, &pt ); }