blob: 240f0f59619c1606ceafdaffdd1c46dfc4ea13a1 [file] [log] [blame]
Yi Kong39bbd962022-01-09 19:41:38 +08001/* Copyright 2021 Alain Knaff.
2 * This file is part of mtools.
3 *
4 * Mtools is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Mtools is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Buffer read/write module
18 */
19
20#include "sysincludes.h"
21#include "msdos.h"
22#include "mtools.h"
23#include "partition.h"
24
25typedef struct Partition_t {
26 struct Stream_t head;
27
28 mt_off_t offset; /* Offset, in bytes */
29 mt_off_t size; /* size, in bytes */
30 uint32_t nbSect; /* size, in sectors */
31
32 uint8_t pos;
33
34 uint8_t sectors;
35 uint8_t heads;
36 uint16_t cyclinders;
37} Partition_t;
38
39static __inline__ void print_hsc(hsc *h)
40{
41 printf(" h=%d s=%d c=%d\n",
42 head(*h), sector(*h), cyl(*h));
43}
44
45/*
46 * Make sure range [ start, end ] does not overlap with partition i
47 */
48static int overlapCheck(struct partition *partTable, unsigned int i,
49 uint32_t start, uint32_t end) {
50 struct partition *partition = &partTable[i];
51 if(!partition->sys_ind)
52 return 0; /* Partition not allocated => ok */
53 if(end > BEGIN(partition) &&
54 (start < END(partition) || END(partition) < BEGIN(partition)))
55 /* overlap */
56 return -1;
57 return 0;
58}
59
60unsigned int findOverlap(struct partition *partTable, unsigned int until,
61 uint32_t start, uint32_t end)
62{
63 unsigned int i;
64 for(i=1; i <= until; i++)
65 if(overlapCheck(partTable, i, start, end))
66 return i;
67 return 0;
68}
69
70
71int consistencyCheck(struct partition *partTable, int doprint,
72 int verbose,
73 int *has_activated, uint32_t tot_sectors,
74 struct device *used_dev UNUSEDP,
75 unsigned int target_partition)
76{
77 unsigned int i;
78 bool inconsistency;
79
80 /* quick consistency check */
81 inconsistency = 0;
82 *has_activated = 0;
83 for(i=1; i<=4; i++){
84 unsigned int j;
85 struct partition *partition = &partTable[i];
86 if(!partition->sys_ind)
87 continue;
88 if(partition->boot_ind)
89 (*has_activated)++;
90
91 if(END(partition) < BEGIN(partition)) {
92 fprintf(stderr,
93 "End of partition %d before its begin\n",
94 i);
95 }
96
97 if((j = findOverlap(partTable, i-1,
98 BEGIN(partition), END(partition)))) {
99 fprintf(stderr,
100 "Partitions %d and %d overlap\n",
101 j, i);
102 inconsistency=1;
103 }
104
105 if(tot_sectors && END(partition) >tot_sectors) {
106 fprintf(stderr,
107 "Partition %d extends beyond end of disk\n", i);
108 }
109
110 if(doprint && verbose) {
111 if(i==target_partition)
112 putchar('*');
113 else
114 putchar(' ');
115 printf("Partition %d\n",i);
116
117 printf(" active=%x\n", partition->boot_ind);
118 printf(" start:");
119 print_hsc(&partition->start);
120 printf(" type=0x%x\n", partition->sys_ind);
121 printf(" end:");
122 print_hsc(&partition->end);
123 printf(" start=%d\n", BEGIN(partition));
124 printf(" nr=%d\n", _DWORD(partition->nr_sects));
125 printf("\n");
126 }
127 }
128 return inconsistency;
129}
130
131
132static int limit_size(Partition_t *This, mt_off_t start, size_t *len)
133{
134 if(start > This->size)
135 return -1;
136 limitSizeToOffT(len, This->size - start);
137 return 0;
138}
139
140static ssize_t partition_pread(Stream_t *Stream, char *buf,
141 mt_off_t start, size_t len)
142{
143 DeclareThis(Partition_t);
144 if(limit_size(This, start, &len) < 0)
145 return -1;
146 return PREADS(This->head.Next, buf, start+This->offset, len);
147}
148
149static ssize_t partition_pwrite(Stream_t *Stream, char *buf,
150 mt_off_t start, size_t len)
151{
152 DeclareThis(Partition_t);
153 if(limit_size(This, start, &len) < 0)
154 return -1;
155 return PWRITES(This->head.Next, buf, start+This->offset, len);
156}
157
158static int partition_data(Stream_t *Stream, time_t *date, mt_off_t *size,
159 int *type, uint32_t *address)
160{
161 DeclareThis(Partition_t);
162
163 if(date || type || address) {
164 int ret = GET_DATA(This->head.Next, date, NULL, type, address);
165 if(ret < 0)
166 return ret;
167 }
168 if(size)
169 *size = This->size * 512;
170 return 0;
171}
172
173
174static int partition_geom(Stream_t *Stream, struct device *dev,
175 UNUSEDP struct device *orig_dev)
176{
177 DeclareThis(Partition_t);
178
179 if(!dev->tot_sectors)
180 dev->tot_sectors = This->nbSect;
181
182 return 0;
183}
184
185static Class_t PartitionClass = {
186 0,
187 0,
188 partition_pread,
189 partition_pwrite,
190 0, /* flush */
191 0, /* free */
192 partition_geom, /* set_geom */
193 partition_data, /* get_data */
194 0, /* pre-allocate */
195 get_dosConvert_pass_through, /* dos convert */
196 0, /* discard */
197};
198
199Stream_t *OpenPartition(Stream_t *Next, struct device *dev,
200 char *errmsg, mt_off_t *maxSize) {
201 Partition_t *This;
202 int has_activated;
203 unsigned char buf[2048];
204 struct partition *partTable=(struct partition *)(buf+ 0x1ae);
205 uint32_t partOff;
206 struct partition *partition;
207
208 if(!dev || (dev->partition > 4) || (dev->partition <= 0)) {
209 fprintf(stderr,
210 "Invalid partition %d (must be between 1 and 4), ignoring it\n",
211 dev->partition);
212 return NULL;
213 }
214
215 This = New(Partition_t);
216 if (!This){
217 printOom();
218 return 0;
219 }
220 memset((void*)This, 0, sizeof(Partition_t));
221 init_head(&This->head, &PartitionClass, Next);
222
223
224 /* read the first sector, or part of it */
225 if (force_pread(This->head.Next, (char*) buf, 0, 512) != 512)
226 goto exit_0;
227 if( _WORD(buf+510) != 0xaa55) {
228 /* Not a partition table */
229 if(errmsg)
230 sprintf(errmsg,
231 "Device does not have a BIOS partition table\n");
232 goto exit_0;
233 }
234 partition = &partTable[dev->partition];
235 if(!partition->sys_ind) {
236 if(errmsg)
237 sprintf(errmsg,
238 "Partition %d does not exist\n",
239 dev->partition);
240 goto exit_0;
241 }
242
243 partOff = BEGIN(partition);
244 if (maxSize) {
245 if (partOff > (smt_off_t)(*maxSize >> 9)) {
246 if(errmsg)
247 sprintf(errmsg,"init: Big disks not supported");
248 goto exit_0;
249 }
250 *maxSize -= partOff << 9;
251 maximize(*maxSize, ((mt_off_t)PART_SIZE(partition)) << 9);
252 }
253
254 This->offset = (mt_off_t) partOff << 9;
255
256 if(!mtools_skip_check &&
257 consistencyCheck((struct partition *)(buf+0x1ae), 0, 0,
258 &has_activated, dev->tot_sectors, dev, 0)) {
259 fprintf(stderr,
260 "Warning: inconsistent partition table\n");
261 fprintf(stderr,
262 "Possibly unpartitioned device\n");
263 fprintf(stderr,
264 "\n*** Maybe try without partition=%d in "
265 "device definition ***\n\n",
266 dev->partition);
267 fprintf(stderr,
268 "If this is a PCMCIA card, or a disk "
269 "partitioned on another computer, this "
270 "message may be in error: add "
271 "mtools_skip_check=1 to your .mtoolsrc "
272 "file to suppress this warning\n");
273 }
274 dev->tot_sectors = This->nbSect = PART_SIZE(partition);
275 This->size = (mt_off_t) This->nbSect << 9;
276 return &This->head;
277 exit_0:
278 Free(This);
279 return NULL;
280}
281