]>
Commit | Line | Data |
---|---|---|
e2ee9178 DB |
1 | /* |
2 | * Many, many hands. | |
3 | * Specific DOS label file - Davidlohr Bueso <dave@gnu.org> | |
4 | */ | |
5 | ||
6 | #include <unistd.h> | |
9dea2923 | 7 | #include <ctype.h> |
e2ee9178 DB |
8 | |
9 | #include "nls.h" | |
10 | #include "xalloc.h" | |
11 | #include "randutils.h" | |
12 | #include "common.h" | |
13 | #include "fdisk.h" | |
14 | #include "fdiskdoslabel.h" | |
15 | ||
9dea2923 | 16 | #define set_hsc(h,s,c,sector) { \ |
24cd580b DB |
17 | s = sector % cxt->geom.sectors + 1; \ |
18 | sector /= cxt->geom.sectors; \ | |
19 | h = sector % cxt->geom.heads; \ | |
20 | sector /= cxt->geom.heads; \ | |
21 | c = sector & 0xff; \ | |
22 | s |= (sector >> 2) & 0xc0; \ | |
9dea2923 DB |
23 | } |
24 | ||
e53ced85 | 25 | #define alignment_required (grain != cxt->sector_size) |
9dea2923 | 26 | |
96f817fb | 27 | struct pte ptes[MAXIMUM_PARTS]; |
24def09d | 28 | sector_t extended_offset; |
96f817fb KZ |
29 | int ext_index; |
30 | ||
e53ced85 | 31 | static int get_nonexisting_partition(struct fdisk_context *cxt, int warn, int max) |
9dea2923 DB |
32 | { |
33 | int pno = -1; | |
34 | int i; | |
35 | int dflt = 0; | |
36 | ||
37 | for (i = 0; i < max; i++) { | |
38 | struct pte *pe = &ptes[i]; | |
39 | struct partition *p = pe->part_table; | |
40 | ||
41 | if (p && is_cleared_partition(p)) { | |
42 | if (pno >= 0) { | |
43 | dflt = pno + 1; | |
44 | goto not_unique; | |
45 | } | |
46 | pno = i; | |
47 | } | |
48 | } | |
49 | if (pno >= 0) { | |
50 | printf(_("Selected partition %d\n"), pno+1); | |
51 | return pno; | |
52 | } | |
53 | printf(_("All primary partitions have been defined already!\n")); | |
54 | return -1; | |
55 | ||
56 | not_unique: | |
e53ced85 | 57 | return get_partition_dflt(cxt, warn, max, dflt); |
9dea2923 DB |
58 | } |
59 | ||
60 | ||
e2ee9178 | 61 | /* Allocate a buffer and read a partition table sector */ |
24def09d | 62 | static void read_pte(struct fdisk_context *cxt, int pno, sector_t offset) |
e2ee9178 DB |
63 | { |
64 | struct pte *pe = &ptes[pno]; | |
65 | ||
66 | pe->offset = offset; | |
e53ced85 | 67 | pe->sectorbuffer = xmalloc(cxt->sector_size); |
7737f698 | 68 | read_sector(cxt, offset, pe->sectorbuffer); |
e2ee9178 DB |
69 | pe->changed = 0; |
70 | pe->part_table = pe->ext_pointer = NULL; | |
71 | } | |
72 | ||
73 | static void dos_write_mbr_id(unsigned char *b, unsigned int id) | |
74 | { | |
75 | store4_little_endian(&b[440], id); | |
76 | } | |
77 | ||
78 | static unsigned int dos_read_mbr_id(const unsigned char *b) | |
79 | { | |
80 | return read4_little_endian(&b[440]); | |
81 | } | |
82 | ||
83 | static void clear_partition(struct partition *p) | |
84 | { | |
85 | if (!p) | |
86 | return; | |
87 | p->boot_ind = 0; | |
88 | p->head = 0; | |
89 | p->sector = 0; | |
90 | p->cyl = 0; | |
91 | p->sys_ind = 0; | |
92 | p->end_head = 0; | |
93 | p->end_sector = 0; | |
94 | p->end_cyl = 0; | |
95 | set_start_sect(p,0); | |
96 | set_nr_sects(p,0); | |
97 | } | |
98 | ||
e53ced85 | 99 | void dos_init(struct fdisk_context *cxt) |
e2ee9178 DB |
100 | { |
101 | int i; | |
102 | ||
103 | disklabel = DOS_LABEL; | |
104 | partitions = 4; | |
105 | ext_index = 0; | |
106 | extended_offset = 0; | |
107 | ||
108 | for (i = 0; i < 4; i++) { | |
109 | struct pte *pe = &ptes[i]; | |
110 | ||
38b36353 | 111 | pe->part_table = pt_offset(cxt->mbr, i); |
e2ee9178 DB |
112 | pe->ext_pointer = NULL; |
113 | pe->offset = 0; | |
38b36353 | 114 | pe->sectorbuffer = cxt->mbr; |
e2ee9178 DB |
115 | pe->changed = 0; |
116 | } | |
117 | ||
24cd580b | 118 | warn_geometry(cxt); |
e53ced85 DB |
119 | warn_limits(cxt); |
120 | warn_alignment(cxt); | |
e2ee9178 DB |
121 | } |
122 | ||
7737f698 | 123 | static void read_extended(struct fdisk_context *cxt, int ext) |
e2ee9178 DB |
124 | { |
125 | int i; | |
126 | struct pte *pex; | |
127 | struct partition *p, *q; | |
128 | ||
129 | ext_index = ext; | |
130 | pex = &ptes[ext]; | |
131 | pex->ext_pointer = pex->part_table; | |
132 | ||
133 | p = pex->part_table; | |
134 | if (!get_start_sect(p)) { | |
135 | fprintf(stderr, | |
136 | _("Bad offset in primary extended partition\n")); | |
137 | return; | |
138 | } | |
139 | ||
140 | while (IS_EXTENDED (p->sys_ind)) { | |
141 | struct pte *pe = &ptes[partitions]; | |
142 | ||
143 | if (partitions >= MAXIMUM_PARTS) { | |
144 | /* This is not a Linux restriction, but | |
145 | this program uses arrays of size MAXIMUM_PARTS. | |
146 | Do not try to `improve' this test. */ | |
147 | struct pte *pre = &ptes[partitions-1]; | |
148 | ||
149 | fprintf(stderr, | |
150 | _("Warning: omitting partitions after #%d.\n" | |
151 | "They will be deleted " | |
152 | "if you save this partition table.\n"), | |
153 | partitions); | |
154 | clear_partition(pre->ext_pointer); | |
155 | pre->changed = 1; | |
156 | return; | |
157 | } | |
158 | ||
7737f698 | 159 | read_pte(cxt, partitions, extended_offset + get_start_sect(p)); |
e2ee9178 DB |
160 | |
161 | if (!extended_offset) | |
162 | extended_offset = get_start_sect(p); | |
163 | ||
164 | q = p = pt_offset(pe->sectorbuffer, 0); | |
165 | for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) { | |
166 | if (IS_EXTENDED (p->sys_ind)) { | |
167 | if (pe->ext_pointer) | |
168 | fprintf(stderr, | |
169 | _("Warning: extra link " | |
170 | "pointer in partition table" | |
171 | " %d\n"), partitions + 1); | |
172 | else | |
173 | pe->ext_pointer = p; | |
174 | } else if (p->sys_ind) { | |
175 | if (pe->part_table) | |
176 | fprintf(stderr, | |
177 | _("Warning: ignoring extra " | |
178 | "data in partition table" | |
179 | " %d\n"), partitions + 1); | |
180 | else | |
181 | pe->part_table = p; | |
182 | } | |
183 | } | |
184 | ||
185 | /* very strange code here... */ | |
186 | if (!pe->part_table) { | |
187 | if (q != pe->ext_pointer) | |
188 | pe->part_table = q; | |
189 | else | |
190 | pe->part_table = q + 1; | |
191 | } | |
192 | if (!pe->ext_pointer) { | |
193 | if (q != pe->part_table) | |
194 | pe->ext_pointer = q; | |
195 | else | |
196 | pe->ext_pointer = q + 1; | |
197 | } | |
198 | ||
199 | p = pe->ext_pointer; | |
200 | partitions++; | |
201 | } | |
202 | ||
203 | /* remove empty links */ | |
204 | remove: | |
205 | for (i = 4; i < partitions; i++) { | |
206 | struct pte *pe = &ptes[i]; | |
207 | ||
208 | if (!get_nr_sects(pe->part_table) && | |
209 | (partitions > 5 || ptes[4].part_table->sys_ind)) { | |
210 | printf(_("omitting empty partition (%d)\n"), i+1); | |
211 | dos_delete_partition(i); | |
212 | goto remove; /* numbering changed */ | |
213 | } | |
214 | } | |
215 | } | |
216 | ||
38b36353 | 217 | void dos_print_mbr_id(struct fdisk_context *cxt) |
e2ee9178 | 218 | { |
38b36353 | 219 | printf(_("Disk identifier: 0x%08x\n"), dos_read_mbr_id(cxt->mbr)); |
e2ee9178 DB |
220 | } |
221 | ||
e53ced85 | 222 | void create_doslabel(struct fdisk_context *cxt) |
e2ee9178 DB |
223 | { |
224 | unsigned int id; | |
225 | ||
226 | /* random disk signature */ | |
c544aa2c | 227 | random_get_bytes(&id, sizeof(id)); |
e2ee9178 DB |
228 | |
229 | fprintf(stderr, _("Building a new DOS disklabel with disk identifier 0x%08x.\n"), id); | |
230 | ||
e53ced85 | 231 | dos_init(cxt); |
38b36353 | 232 | fdisk_mbr_zeroize(cxt); |
e2ee9178 DB |
233 | set_all_unchanged(); |
234 | set_changed(0); | |
235 | ||
236 | /* Generate an MBR ID for this disk */ | |
38b36353 | 237 | dos_write_mbr_id(cxt->mbr, id); |
e2ee9178 DB |
238 | |
239 | /* Put MBR signature */ | |
38b36353 | 240 | write_part_table_flag(cxt->mbr); |
e2ee9178 DB |
241 | } |
242 | ||
38b36353 | 243 | void dos_set_mbr_id(struct fdisk_context *cxt) |
e2ee9178 DB |
244 | { |
245 | unsigned long new_id; | |
246 | char *ep; | |
247 | char ps[64]; | |
248 | ||
249 | snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "), | |
38b36353 | 250 | dos_read_mbr_id(cxt->mbr)); |
e2ee9178 DB |
251 | |
252 | if (read_chars(ps) == '\n') | |
253 | return; | |
254 | ||
255 | new_id = strtoul(line_ptr, &ep, 0); | |
256 | if (*ep != '\n') | |
257 | return; | |
258 | ||
38b36353 | 259 | dos_write_mbr_id(cxt->mbr, new_id); |
e2ee9178 | 260 | MBRbuffer_changed = 1; |
38b36353 | 261 | dos_print_mbr_id(cxt); |
e2ee9178 DB |
262 | } |
263 | ||
264 | void dos_delete_partition(int i) | |
265 | { | |
266 | struct pte *pe = &ptes[i]; | |
267 | struct partition *p = pe->part_table; | |
268 | struct partition *q = pe->ext_pointer; | |
269 | ||
270 | /* Note that for the fifth partition (i == 4) we don't actually | |
271 | decrement partitions. */ | |
272 | ||
273 | if (i < 4) { | |
274 | if (IS_EXTENDED (p->sys_ind) && i == ext_index) { | |
275 | partitions = 4; | |
276 | ptes[ext_index].ext_pointer = NULL; | |
277 | extended_offset = 0; | |
278 | } | |
279 | clear_partition(p); | |
280 | } else if (!q->sys_ind && i > 4) { | |
281 | /* the last one in the chain - just delete */ | |
282 | --partitions; | |
283 | --i; | |
284 | clear_partition(ptes[i].ext_pointer); | |
285 | ptes[i].changed = 1; | |
286 | } else { | |
287 | /* not the last one - further ones will be moved down */ | |
288 | if (i > 4) { | |
289 | /* delete this link in the chain */ | |
290 | p = ptes[i-1].ext_pointer; | |
291 | *p = *q; | |
292 | set_start_sect(p, get_start_sect(q)); | |
293 | set_nr_sects(p, get_nr_sects(q)); | |
294 | ptes[i-1].changed = 1; | |
295 | } else if (partitions > 5) { /* 5 will be moved to 4 */ | |
296 | /* the first logical in a longer chain */ | |
297 | struct pte *pe = &ptes[5]; | |
298 | ||
299 | if (pe->part_table) /* prevent SEGFAULT */ | |
300 | set_start_sect(pe->part_table, | |
301 | get_partition_start(pe) - | |
302 | extended_offset); | |
303 | pe->offset = extended_offset; | |
304 | pe->changed = 1; | |
305 | } | |
306 | ||
307 | if (partitions > 5) { | |
308 | partitions--; | |
309 | while (i < partitions) { | |
310 | ptes[i] = ptes[i+1]; | |
311 | i++; | |
312 | } | |
313 | } else | |
314 | /* the only logical: clear only */ | |
315 | clear_partition(ptes[i].part_table); | |
316 | } | |
317 | } | |
318 | ||
7737f698 | 319 | int check_dos_label(struct fdisk_context *cxt) |
e2ee9178 DB |
320 | { |
321 | int i; | |
322 | ||
38b36353 | 323 | if (!valid_part_table_flag(cxt->mbr)) |
e2ee9178 DB |
324 | return 0; |
325 | ||
e53ced85 | 326 | dos_init(cxt); |
e2ee9178 DB |
327 | |
328 | for (i = 0; i < 4; i++) { | |
329 | struct pte *pe = &ptes[i]; | |
330 | ||
331 | if (IS_EXTENDED (pe->part_table->sys_ind)) { | |
332 | if (partitions != 4) | |
333 | fprintf(stderr, _("Ignoring extra extended " | |
334 | "partition %d\n"), i + 1); | |
335 | else | |
7737f698 | 336 | read_extended(cxt, i); |
e2ee9178 DB |
337 | } |
338 | } | |
339 | ||
340 | for (i = 3; i < partitions; i++) { | |
341 | struct pte *pe = &ptes[i]; | |
342 | ||
343 | if (!valid_part_table_flag(pe->sectorbuffer)) { | |
344 | fprintf(stderr, | |
345 | _("Warning: invalid flag 0x%04x of partition " | |
346 | "table %d will be corrected by w(rite)\n"), | |
347 | part_table_flag(pe->sectorbuffer), i + 1); | |
348 | pe->changed = 1; | |
349 | } | |
350 | } | |
351 | ||
352 | return 1; | |
353 | } | |
354 | ||
355 | /* | |
356 | * Avoid warning about DOS partitions when no DOS partition was changed. | |
357 | * Here a heuristic "is probably dos partition". | |
358 | * We might also do the opposite and warn in all cases except | |
359 | * for "is probably nondos partition". | |
360 | */ | |
361 | int is_dos_partition(int t) | |
362 | { | |
363 | return (t == 1 || t == 4 || t == 6 || | |
364 | t == 0x0b || t == 0x0c || t == 0x0e || | |
365 | t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 || | |
366 | t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 || | |
367 | t == 0xc1 || t == 0xc4 || t == 0xc6); | |
368 | } | |
9dea2923 | 369 | |
e53ced85 DB |
370 | static void set_partition(struct fdisk_context *cxt, |
371 | int i, int doext, sector_t start, | |
24def09d | 372 | sector_t stop, int sysid) |
9dea2923 DB |
373 | { |
374 | struct partition *p; | |
24def09d | 375 | sector_t offset; |
9dea2923 DB |
376 | |
377 | if (doext) { | |
378 | p = ptes[i].ext_pointer; | |
379 | offset = extended_offset; | |
380 | } else { | |
381 | p = ptes[i].part_table; | |
382 | offset = ptes[i].offset; | |
383 | } | |
384 | p->boot_ind = 0; | |
385 | p->sys_ind = sysid; | |
386 | set_start_sect(p, start - offset); | |
387 | set_nr_sects(p, stop - start + 1); | |
388 | ||
389 | if (!doext) | |
e53ced85 | 390 | print_partition_size(cxt, i + 1, start, stop, sysid); |
9dea2923 | 391 | |
24cd580b DB |
392 | if (dos_compatible_flag && (start/(cxt->geom.sectors*cxt->geom.heads) > 1023)) |
393 | start = cxt->geom.heads*cxt->geom.sectors*1024 - 1; | |
9dea2923 | 394 | set_hsc(p->head, p->sector, p->cyl, start); |
24cd580b DB |
395 | if (dos_compatible_flag && (stop/(cxt->geom.sectors*cxt->geom.heads) > 1023)) |
396 | stop = cxt->geom.heads*cxt->geom.sectors*1024 - 1; | |
9dea2923 DB |
397 | set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); |
398 | ptes[i].changed = 1; | |
399 | } | |
400 | ||
24def09d DB |
401 | static sector_t get_unused_start(int part_n, sector_t start, |
402 | sector_t first[], sector_t last[]) | |
9dea2923 DB |
403 | { |
404 | int i; | |
405 | ||
406 | for (i = 0; i < partitions; i++) { | |
24def09d | 407 | sector_t lastplusoff; |
9dea2923 DB |
408 | |
409 | if (start == ptes[i].offset) | |
410 | start += sector_offset; | |
411 | lastplusoff = last[i] + ((part_n < 4) ? 0 : sector_offset); | |
412 | if (start >= first[i] && start <= lastplusoff) | |
413 | start = lastplusoff + 1; | |
414 | } | |
415 | ||
416 | return start; | |
417 | } | |
418 | ||
e53ced85 DB |
419 | static sector_t align_lba_in_range(struct fdisk_context *cxt, |
420 | sector_t lba, sector_t start, sector_t stop) | |
9dea2923 | 421 | { |
e53ced85 DB |
422 | start = align_lba(cxt, start, ALIGN_UP); |
423 | stop = align_lba(cxt, stop, ALIGN_DOWN); | |
9dea2923 | 424 | |
e53ced85 | 425 | lba = align_lba(cxt, lba, ALIGN_NEAREST); |
9dea2923 DB |
426 | |
427 | if (lba < start) | |
428 | return start; | |
429 | else if (lba > stop) | |
430 | return stop; | |
431 | return lba; | |
432 | } | |
433 | ||
e53ced85 | 434 | void dos_add_partition(struct fdisk_context *cxt, int n, int sys) |
9dea2923 DB |
435 | { |
436 | char mesg[256]; /* 48 does not suffice in Japanese */ | |
437 | int i, read = 0; | |
438 | struct partition *p = ptes[n].part_table; | |
439 | struct partition *q = ptes[ext_index].part_table; | |
24def09d | 440 | sector_t start, stop = 0, limit, temp, |
9dea2923 DB |
441 | first[partitions], last[partitions]; |
442 | ||
443 | if (p && p->sys_ind) { | |
444 | printf(_("Partition %d is already defined. Delete " | |
445 | "it before re-adding it.\n"), n + 1); | |
446 | return; | |
447 | } | |
448 | fill_bounds(first, last); | |
449 | if (n < 4) { | |
450 | start = sector_offset; | |
618882d6 | 451 | if (display_in_cyl_units || !cxt->total_sectors) |
24cd580b | 452 | limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1; |
9dea2923 | 453 | else |
618882d6 | 454 | limit = cxt->total_sectors - 1; |
9dea2923 DB |
455 | |
456 | if (limit > UINT_MAX) | |
457 | limit = UINT_MAX; | |
458 | ||
459 | if (extended_offset) { | |
460 | first[ext_index] = extended_offset; | |
461 | last[ext_index] = get_start_sect(q) + | |
462 | get_nr_sects(q) - 1; | |
463 | } | |
464 | } else { | |
465 | start = extended_offset + sector_offset; | |
466 | limit = get_start_sect(q) + get_nr_sects(q) - 1; | |
467 | } | |
468 | if (display_in_cyl_units) | |
469 | for (i = 0; i < partitions; i++) | |
470 | first[i] = (cround(first[i]) - 1) * units_per_sector; | |
471 | ||
472 | snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR)); | |
473 | do { | |
24def09d | 474 | sector_t dflt, aligned; |
9dea2923 DB |
475 | |
476 | temp = start; | |
477 | dflt = start = get_unused_start(n, start, first, last); | |
478 | ||
479 | /* the default sector should be aligned and unused */ | |
480 | do { | |
e53ced85 | 481 | aligned = align_lba_in_range(cxt, dflt, dflt, limit); |
9dea2923 DB |
482 | dflt = get_unused_start(n, aligned, first, last); |
483 | } while (dflt != aligned && dflt > aligned && dflt < limit); | |
484 | ||
485 | if (dflt >= limit) | |
486 | dflt = start; | |
487 | if (start > limit) | |
488 | break; | |
489 | if (start >= temp+units_per_sector && read) { | |
490 | printf(_("Sector %llu is already allocated\n"), temp); | |
491 | temp = start; | |
492 | read = 0; | |
493 | } | |
494 | if (!read && start == temp) { | |
24def09d | 495 | sector_t i = start; |
9dea2923 | 496 | |
e53ced85 | 497 | start = read_int(cxt, cround(i), cround(dflt), cround(limit), |
9dea2923 DB |
498 | 0, mesg); |
499 | if (display_in_cyl_units) { | |
500 | start = (start - 1) * units_per_sector; | |
501 | if (start < i) start = i; | |
502 | } | |
503 | read = 1; | |
504 | } | |
505 | } while (start != temp || !read); | |
506 | if (n > 4) { /* NOT for fifth partition */ | |
507 | struct pte *pe = &ptes[n]; | |
508 | ||
509 | pe->offset = start - sector_offset; | |
510 | if (pe->offset == extended_offset) { /* must be corrected */ | |
511 | pe->offset++; | |
512 | if (sector_offset == 1) | |
513 | start++; | |
514 | } | |
515 | } | |
516 | ||
517 | for (i = 0; i < partitions; i++) { | |
518 | struct pte *pe = &ptes[i]; | |
519 | ||
520 | if (start < pe->offset && limit >= pe->offset) | |
521 | limit = pe->offset - 1; | |
522 | if (start < first[i] && limit >= first[i]) | |
523 | limit = first[i] - 1; | |
524 | } | |
525 | if (start > limit) { | |
526 | printf(_("No free sectors available\n")); | |
527 | if (n > 4) | |
528 | partitions--; | |
529 | return; | |
530 | } | |
531 | if (cround(start) == cround(limit)) { | |
532 | stop = limit; | |
533 | } else { | |
534 | int is_suffix_used = 0; | |
535 | ||
536 | snprintf(mesg, sizeof(mesg), | |
537 | _("Last %1$s, +%2$s or +size{K,M,G}"), | |
538 | str_units(SINGULAR), str_units(PLURAL)); | |
539 | ||
e53ced85 DB |
540 | stop = read_int_with_suffix(cxt, |
541 | cround(start), cround(limit), cround(limit), | |
542 | cround(start), mesg, &is_suffix_used); | |
9dea2923 DB |
543 | if (display_in_cyl_units) { |
544 | stop = stop * units_per_sector - 1; | |
545 | if (stop >limit) | |
546 | stop = limit; | |
547 | } | |
548 | ||
549 | if (is_suffix_used && alignment_required) { | |
550 | /* the last sector has not been exactly requested (but | |
551 | * defined by +size{K,M,G} convention), so be smart | |
552 | * and align the end of the partition. The next | |
553 | * partition will start at phy.block boundary. | |
554 | */ | |
e53ced85 | 555 | stop = align_lba_in_range(cxt, stop, start, limit) - 1; |
9dea2923 DB |
556 | if (stop > limit) |
557 | stop = limit; | |
558 | } | |
559 | } | |
560 | ||
e53ced85 | 561 | set_partition(cxt, n, 0, start, stop, sys); |
9dea2923 | 562 | if (n > 4) |
e53ced85 | 563 | set_partition(cxt, n - 1, 1, ptes[n].offset, stop, EXTENDED); |
9dea2923 DB |
564 | |
565 | if (IS_EXTENDED (sys)) { | |
566 | struct pte *pe4 = &ptes[4]; | |
567 | struct pte *pen = &ptes[n]; | |
568 | ||
569 | ext_index = n; | |
570 | pen->ext_pointer = p; | |
571 | pe4->offset = extended_offset = start; | |
e53ced85 | 572 | pe4->sectorbuffer = xcalloc(1, cxt->sector_size); |
9dea2923 DB |
573 | pe4->part_table = pt_offset(pe4->sectorbuffer, 0); |
574 | pe4->ext_pointer = pe4->part_table + 1; | |
575 | pe4->changed = 1; | |
576 | partitions = 5; | |
577 | } | |
578 | } | |
579 | ||
e53ced85 | 580 | static void add_logical(struct fdisk_context *cxt) |
9dea2923 DB |
581 | { |
582 | if (partitions > 5 || ptes[4].part_table->sys_ind) { | |
583 | struct pte *pe = &ptes[partitions]; | |
584 | ||
e53ced85 | 585 | pe->sectorbuffer = xcalloc(1, cxt->sector_size); |
9dea2923 DB |
586 | pe->part_table = pt_offset(pe->sectorbuffer, 0); |
587 | pe->ext_pointer = pe->part_table + 1; | |
588 | pe->offset = 0; | |
589 | pe->changed = 1; | |
590 | partitions++; | |
591 | } | |
592 | printf(_("Adding logical partition %d\n"), partitions); | |
e53ced85 | 593 | dos_add_partition(cxt, partitions - 1, LINUX_NATIVE); |
9dea2923 DB |
594 | } |
595 | ||
596 | /* | |
597 | * Ask the user for new partition type information (logical, extended). | |
598 | * This function calls the actual partition adding logic - dos_add_partition. | |
599 | */ | |
e53ced85 | 600 | void dos_new_partition(struct fdisk_context *cxt) |
9dea2923 DB |
601 | { |
602 | int i, free_primary = 0; | |
603 | ||
604 | for (i = 0; i < 4; i++) | |
605 | free_primary += !ptes[i].part_table->sys_ind; | |
606 | ||
607 | if (!free_primary && partitions >= MAXIMUM_PARTS) { | |
608 | printf(_("The maximum number of partitions has been created\n")); | |
609 | return; | |
610 | } | |
611 | ||
612 | if (!free_primary) { | |
613 | if (extended_offset) { | |
614 | printf(_("All primary partitions are in use\n")); | |
e53ced85 | 615 | add_logical(cxt); |
9dea2923 DB |
616 | } else |
617 | printf(_("If you want to create more than four partitions, you must replace a\n" | |
618 | "primary partition with an extended partition first.\n")); | |
619 | } else if (partitions >= MAXIMUM_PARTS) { | |
620 | printf(_("All logical partitions are in use\n")); | |
621 | printf(_("Adding a primary partition\n")); | |
e53ced85 | 622 | dos_add_partition(cxt, get_partition(cxt, 0, 4), LINUX_NATIVE); |
9dea2923 DB |
623 | } else { |
624 | char c, dflt, line[LINE_LENGTH]; | |
625 | ||
626 | dflt = (free_primary == 1 && !extended_offset) ? 'e' : 'p'; | |
627 | snprintf(line, sizeof(line), | |
628 | _("Partition type:\n" | |
629 | " p primary (%d primary, %d extended, %d free)\n" | |
630 | "%s\n" | |
631 | "Select (default %c): "), | |
632 | 4 - (extended_offset ? 1 : 0) - free_primary, extended_offset ? 1 : 0, free_primary, | |
633 | extended_offset ? _(" l logical (numbered from 5)") : _(" e extended"), | |
634 | dflt); | |
635 | ||
636 | c = tolower(read_chars(line)); | |
637 | if (c == '\n') { | |
638 | c = dflt; | |
639 | printf(_("Using default response %c\n"), c); | |
640 | } | |
641 | if (c == 'p') { | |
e53ced85 | 642 | int i = get_nonexisting_partition(cxt, 0, 4); |
9dea2923 | 643 | if (i >= 0) |
e53ced85 | 644 | dos_add_partition(cxt, i, LINUX_NATIVE); |
9dea2923 DB |
645 | return; |
646 | } else if (c == 'l' && extended_offset) { | |
e53ced85 | 647 | add_logical(cxt); |
9dea2923 DB |
648 | return; |
649 | } else if (c == 'e' && !extended_offset) { | |
e53ced85 | 650 | int i = get_nonexisting_partition(cxt, 0, 4); |
9dea2923 | 651 | if (i >= 0) |
e53ced85 | 652 | dos_add_partition(cxt, i, EXTENDED); |
9dea2923 DB |
653 | return; |
654 | } else | |
655 | printf(_("Invalid partition type `%c'\n"), c); | |
656 | } | |
657 | } | |
0dc13a38 | 658 | |
7737f698 | 659 | void dos_write_table(struct fdisk_context *cxt) |
0dc13a38 DB |
660 | { |
661 | int i; | |
662 | ||
663 | /* MBR (primary partitions) */ | |
664 | if (!MBRbuffer_changed) { | |
665 | for (i = 0; i < 4; i++) | |
666 | if (ptes[i].changed) | |
667 | MBRbuffer_changed = 1; | |
668 | } | |
669 | if (MBRbuffer_changed) { | |
38b36353 DB |
670 | write_part_table_flag(cxt->mbr); |
671 | write_sector(cxt, 0, cxt->mbr); | |
0dc13a38 DB |
672 | } |
673 | /* EBR (logical partitions) */ | |
674 | for (i = 4; i < partitions; i++) { | |
675 | struct pte *pe = &ptes[i]; | |
676 | ||
677 | if (pe->changed) { | |
678 | write_part_table_flag(pe->sectorbuffer); | |
7737f698 | 679 | write_sector(cxt, pe->offset, pe->sectorbuffer); |
0dc13a38 DB |
680 | } |
681 | } | |
682 | } |