diff options
Diffstat (limited to 'partition.c')
-rw-r--r-- | partition.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/partition.c b/partition.c new file mode 100644 index 0000000..240f0f5 --- /dev/null +++ b/partition.c @@ -0,0 +1,281 @@ +/* Copyright 2021 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see <http://www.gnu.org/licenses/>. + * + * Buffer read/write module + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "partition.h" + +typedef struct Partition_t { + struct Stream_t head; + + mt_off_t offset; /* Offset, in bytes */ + mt_off_t size; /* size, in bytes */ + uint32_t nbSect; /* size, in sectors */ + + uint8_t pos; + + uint8_t sectors; + uint8_t heads; + uint16_t cyclinders; +} Partition_t; + +static __inline__ void print_hsc(hsc *h) +{ + printf(" h=%d s=%d c=%d\n", + head(*h), sector(*h), cyl(*h)); +} + +/* + * Make sure range [ start, end ] does not overlap with partition i + */ +static int overlapCheck(struct partition *partTable, unsigned int i, + uint32_t start, uint32_t end) { + struct partition *partition = &partTable[i]; + if(!partition->sys_ind) + return 0; /* Partition not allocated => ok */ + if(end > BEGIN(partition) && + (start < END(partition) || END(partition) < BEGIN(partition))) + /* overlap */ + return -1; + return 0; +} + +unsigned int findOverlap(struct partition *partTable, unsigned int until, + uint32_t start, uint32_t end) +{ + unsigned int i; + for(i=1; i <= until; i++) + if(overlapCheck(partTable, i, start, end)) + return i; + return 0; +} + + +int consistencyCheck(struct partition *partTable, int doprint, + int verbose, + int *has_activated, uint32_t tot_sectors, + struct device *used_dev UNUSEDP, + unsigned int target_partition) +{ + unsigned int i; + bool inconsistency; + + /* quick consistency check */ + inconsistency = 0; + *has_activated = 0; + for(i=1; i<=4; i++){ + unsigned int j; + struct partition *partition = &partTable[i]; + if(!partition->sys_ind) + continue; + if(partition->boot_ind) + (*has_activated)++; + + if(END(partition) < BEGIN(partition)) { + fprintf(stderr, + "End of partition %d before its begin\n", + i); + } + + if((j = findOverlap(partTable, i-1, + BEGIN(partition), END(partition)))) { + fprintf(stderr, + "Partitions %d and %d overlap\n", + j, i); + inconsistency=1; + } + + if(tot_sectors && END(partition) >tot_sectors) { + fprintf(stderr, + "Partition %d extends beyond end of disk\n", i); + } + + if(doprint && verbose) { + if(i==target_partition) + putchar('*'); + else + putchar(' '); + printf("Partition %d\n",i); + + printf(" active=%x\n", partition->boot_ind); + printf(" start:"); + print_hsc(&partition->start); + printf(" type=0x%x\n", partition->sys_ind); + printf(" end:"); + print_hsc(&partition->end); + printf(" start=%d\n", BEGIN(partition)); + printf(" nr=%d\n", _DWORD(partition->nr_sects)); + printf("\n"); + } + } + return inconsistency; +} + + +static int limit_size(Partition_t *This, mt_off_t start, size_t *len) +{ + if(start > This->size) + return -1; + limitSizeToOffT(len, This->size - start); + return 0; +} + +static ssize_t partition_pread(Stream_t *Stream, char *buf, + mt_off_t start, size_t len) +{ + DeclareThis(Partition_t); + if(limit_size(This, start, &len) < 0) + return -1; + return PREADS(This->head.Next, buf, start+This->offset, len); +} + +static ssize_t partition_pwrite(Stream_t *Stream, char *buf, + mt_off_t start, size_t len) +{ + DeclareThis(Partition_t); + if(limit_size(This, start, &len) < 0) + return -1; + return PWRITES(This->head.Next, buf, start+This->offset, len); +} + +static int partition_data(Stream_t *Stream, time_t *date, mt_off_t *size, + int *type, uint32_t *address) +{ + DeclareThis(Partition_t); + + if(date || type || address) { + int ret = GET_DATA(This->head.Next, date, NULL, type, address); + if(ret < 0) + return ret; + } + if(size) + *size = This->size * 512; + return 0; +} + + +static int partition_geom(Stream_t *Stream, struct device *dev, + UNUSEDP struct device *orig_dev) +{ + DeclareThis(Partition_t); + + if(!dev->tot_sectors) + dev->tot_sectors = This->nbSect; + + return 0; +} + +static Class_t PartitionClass = { + 0, + 0, + partition_pread, + partition_pwrite, + 0, /* flush */ + 0, /* free */ + partition_geom, /* set_geom */ + partition_data, /* get_data */ + 0, /* pre-allocate */ + get_dosConvert_pass_through, /* dos convert */ + 0, /* discard */ +}; + +Stream_t *OpenPartition(Stream_t *Next, struct device *dev, + char *errmsg, mt_off_t *maxSize) { + Partition_t *This; + int has_activated; + unsigned char buf[2048]; + struct partition *partTable=(struct partition *)(buf+ 0x1ae); + uint32_t partOff; + struct partition *partition; + + if(!dev || (dev->partition > 4) || (dev->partition <= 0)) { + fprintf(stderr, + "Invalid partition %d (must be between 1 and 4), ignoring it\n", + dev->partition); + return NULL; + } + + This = New(Partition_t); + if (!This){ + printOom(); + return 0; + } + memset((void*)This, 0, sizeof(Partition_t)); + init_head(&This->head, &PartitionClass, Next); + + + /* read the first sector, or part of it */ + if (force_pread(This->head.Next, (char*) buf, 0, 512) != 512) + goto exit_0; + if( _WORD(buf+510) != 0xaa55) { + /* Not a partition table */ + if(errmsg) + sprintf(errmsg, + "Device does not have a BIOS partition table\n"); + goto exit_0; + } + partition = &partTable[dev->partition]; + if(!partition->sys_ind) { + if(errmsg) + sprintf(errmsg, + "Partition %d does not exist\n", + dev->partition); + goto exit_0; + } + + partOff = BEGIN(partition); + if (maxSize) { + if (partOff > (smt_off_t)(*maxSize >> 9)) { + if(errmsg) + sprintf(errmsg,"init: Big disks not supported"); + goto exit_0; + } + *maxSize -= partOff << 9; + maximize(*maxSize, ((mt_off_t)PART_SIZE(partition)) << 9); + } + + This->offset = (mt_off_t) partOff << 9; + + if(!mtools_skip_check && + consistencyCheck((struct partition *)(buf+0x1ae), 0, 0, + &has_activated, dev->tot_sectors, dev, 0)) { + fprintf(stderr, + "Warning: inconsistent partition table\n"); + fprintf(stderr, + "Possibly unpartitioned device\n"); + fprintf(stderr, + "\n*** Maybe try without partition=%d in " + "device definition ***\n\n", + dev->partition); + fprintf(stderr, + "If this is a PCMCIA card, or a disk " + "partitioned on another computer, this " + "message may be in error: add " + "mtools_skip_check=1 to your .mtoolsrc " + "file to suppress this warning\n"); + } + dev->tot_sectors = This->nbSect = PART_SIZE(partition); + This->size = (mt_off_t) This->nbSect << 9; + return &This->head; + exit_0: + Free(This); + return NULL; +} + |