/* 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 . * * 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; }