1 //
2 // partition_map.c - partition map routines
3 //
4 // Written by Eryk Vershen
5 //
6
7 /*
8 * Copyright 1996,1997,1998 by Apple Computer, Inc.
9 * All Rights Reserved
10 *
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both the copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE.
20 *
21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 */
27
28 // for *printf()
29 #include <stdio.h>
30
31 // for malloc(), calloc() & free()
32 #ifndef __linux__
33 #include <stdlib.h>
34 #else
35 #include <malloc.h>
36 #endif
37
38 // for strncpy() & strcmp()
39 #include <string.h>
40 // for O_RDONLY & O_RDWR
41 #include <fcntl.h>
42 // for errno
43 #include <errno.h>
44
45 #include <inttypes.h>
46
47 #include "partition_map.h"
48 #include "pathname.h"
49 #include "hfs_misc.h"
50 #include "deblock_media.h"
51 #include "io.h"
52 #include "convert.h"
53 #include "util.h"
54 #include "errors.h"
55
56
57 //
58 // Defines
59 //
60 #define APPLE_HFS_FLAGS_VALUE 0x4000037f
61 #define get_align_long(x) (*(x))
62 #define put_align_long(y, x) ((*(x)) = (y))
63 // #define TEST_COMPUTE
64
65
66 //
67 // Types
68 //
69
70
71 //
72 // Global Constants
73 //
74 const char * kFreeType = "Apple_Free";
75 const char * kMapType = "Apple_partition_map";
76 const char * kUnixType = "Apple_UNIX_SVR2";
77 const char * kHFSType = "Apple_HFS";
78 const char * kPatchType = "Apple_Patches";
79
80 const char * kFreeName = "Extra";
81
82 enum add_action {
83 kReplace = 0,
84 kAdd = 1,
85 kSplit = 2
86 };
87
88 //
89 // Global Variables
90 //
91 extern int cflag;
92
93
94 //
95 // Forward declarations
96 //
97 int add_data_to_map(struct dpme *, long, partition_map_header *);
98 int coerce_block0(partition_map_header *map);
99 int contains_driver(partition_map *entry);
100 void combine_entry(partition_map *entry);
101 long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
102 DPME* create_data(const char *name, const char *dptype, uint32_t base, uint32_t length);
103 void delete_entry(partition_map *entry);
104 char *get_HFS_name(partition_map *entry, int *kind);
105 void insert_in_base_order(partition_map *entry);
106 void insert_in_disk_order(partition_map *entry);
107 int read_block(partition_map_header *map, uint32_t num, char *buf);
108 int read_partition_map(partition_map_header *map);
109 void remove_driver(partition_map *entry);
110 void remove_from_disk_order(partition_map *entry);
111 void renumber_disk_addresses(partition_map_header *map);
112 void sync_device_size(partition_map_header *map);
113 int write_block(partition_map_header *map, uint32_t num, char *buf);
114
115
116 //
117 // Routines
118 //
119 partition_map_header *
open_partition_map(char * name,int * valid_file,int ask_logical_size)120 open_partition_map(char *name, int *valid_file, int ask_logical_size)
121 {
122 MEDIA m;
123 partition_map_header * map;
124 int writable;
125 long size;
126
127 m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
128 if (m == 0) {
129 m = open_pathname_as_media(name, O_RDONLY);
130 if (m == 0) {
131 error(errno, "can't open file '%s'", name);
132 *valid_file = 0;
133 return NULL;
134 } else {
135 writable = 0;
136 }
137 } else {
138 writable = 1;
139 }
140 *valid_file = 1;
141
142 map = (partition_map_header *) malloc(sizeof(partition_map_header));
143 if (map == NULL) {
144 error(errno, "can't allocate memory for open partition map");
145 close_media(m);
146 return NULL;
147 }
148 map->name = name;
149 map->writable = (rflag)?0:writable;
150 map->changed = 0;
151 map->written = 0;
152 map->disk_order = NULL;
153 map->base_order = NULL;
154
155 map->physical_block = media_granularity(m); /* preflight */
156 m = open_deblock_media(PBLOCK_SIZE, m);
157 map->m = m;
158 map->misc = (Block0 *) malloc(PBLOCK_SIZE);
159 if (map->misc == NULL) {
160 error(errno, "can't allocate memory for block zero buffer");
161 close_media(map->m);
162 free(map);
163 return NULL;
164 } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
165 || convert_block0(map->misc, 1)
166 || coerce_block0(map)) {
167 // if I can't read block 0 I might as well give up
168 error(-1, "Can't read block 0 from '%s'", name);
169 close_partition_map(map);
170 return NULL;
171 }
172 map->physical_block = map->misc->sbBlkSize;
173 //printf("physical block size is %d\n", map->physical_block);
174
175 if (ask_logical_size && interactive) {
176 size = PBLOCK_SIZE;
177 printf("A logical block is %ld bytes: ", size);
178 flush_to_newline(0);
179 get_number_argument("what should be the logical block size? ",
180 &size, size);
181 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
182 if (size < PBLOCK_SIZE) {
183 size = PBLOCK_SIZE;
184 }
185 map->logical_block = size;
186 } else {
187 map->logical_block = PBLOCK_SIZE;
188 }
189 if (map->logical_block > MAXIOSIZE) {
190 map->logical_block = MAXIOSIZE;
191 }
192 if (map->logical_block > map->physical_block) {
193 map->physical_block = map->logical_block;
194 }
195 map->blocks_in_map = 0;
196 map->maximum_in_map = -1;
197 map->media_size = compute_device_size(map, map);
198 sync_device_size(map);
199
200 if (read_partition_map(map) < 0) {
201 // some sort of failure reading the map
202 } else {
203 // got it!
204 ;
205 return map;
206 }
207 close_partition_map(map);
208 return NULL;
209 }
210
211
212 void
close_partition_map(partition_map_header * map)213 close_partition_map(partition_map_header *map)
214 {
215 partition_map * entry;
216 partition_map * next;
217
218 if (map == NULL) {
219 return;
220 }
221
222 free(map->misc);
223
224 for (entry = map->disk_order; entry != NULL; entry = next) {
225 next = entry->next_on_disk;
226 free(entry->data);
227 free(entry->HFS_name);
228 free(entry);
229 }
230 close_media(map->m);
231 free(map);
232 }
233
234
235 int
read_partition_map(partition_map_header * map)236 read_partition_map(partition_map_header *map)
237 {
238 DPME *data;
239 uint32_t limit;
240 uint32_t ix;
241 int old_logical;
242 double d;
243
244 //printf("called read_partition_map\n");
245 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
246 data = (DPME *) malloc(PBLOCK_SIZE);
247 if (data == NULL) {
248 error(errno, "can't allocate memory for disk buffers");
249 return -1;
250 }
251
252 if (read_block(map, 1, (char *)data) == 0) {
253 error(-1, "Can't read block 1 from '%s'", map->name);
254 free(data);
255 return -1;
256 } else if (convert_dpme(data, 1)
257 || data->dpme_signature != DPME_SIGNATURE) {
258 old_logical = map->logical_block;
259 map->logical_block = 512;
260 while (map->logical_block <= map->physical_block) {
261 if (read_block(map, 1, (char *)data) == 0) {
262 error(-1, "Can't read block 1 from '%s'", map->name);
263 free(data);
264 return -1;
265 } else if (convert_dpme(data, 1) == 0
266 && data->dpme_signature == DPME_SIGNATURE) {
267 d = map->media_size;
268 map->media_size = (d * old_logical) / map->logical_block;
269 break;
270 }
271 map->logical_block *= 2;
272 }
273 if (map->logical_block > map->physical_block) {
274 error(-1, "No valid block 1 on '%s'", map->name);
275 free(data);
276 return -1;
277 }
278 }
279 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
280
281 limit = data->dpme_map_entries;
282 ix = 1;
283 while (1) {
284 if (add_data_to_map(data, ix, map) == 0) {
285 free(data);
286 return -1;
287 }
288
289 if (ix >= limit) {
290 break;
291 } else {
292 ix++;
293 }
294
295 data = (DPME *) malloc(PBLOCK_SIZE);
296 if (data == NULL) {
297 error(errno, "can't allocate memory for disk buffers");
298 return -1;
299 }
300
301 if (read_block(map, ix, (char *)data) == 0) {
302 error(-1, "Can't read block %u from '%s'", ix, map->name);
303 free(data);
304 return -1;
305 } else if (convert_dpme(data, 1)
306 || (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
307 || (data->dpme_map_entries != limit && dflag == 0)) {
308 error(-1, "Bad data in block %u from '%s'", ix, map->name);
309 free(data);
310 return -1;
311 }
312 }
313 return 0;
314 }
315
316
317 void
write_partition_map(partition_map_header * map)318 write_partition_map(partition_map_header *map)
319 {
320 char *block;
321 partition_map * entry;
322 int i = 0;
323 int result = 0;
324
325 if (map->misc != NULL) {
326 convert_block0(map->misc, 0);
327 result = write_block(map, 0, (char *)map->misc);
328 convert_block0(map->misc, 1);
329 } else {
330 block = (char *) calloc(1, PBLOCK_SIZE);
331 if (block != NULL) {
332 result = write_block(map, 0, block);
333 free(block);
334 }
335 }
336 if (result == 0) {
337 error(errno, "Unable to write block zero");
338 }
339 for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
340 convert_dpme(entry->data, 0);
341 result = write_block(map, entry->disk_address, (char *)entry->data);
342 convert_dpme(entry->data, 1);
343 i = entry->disk_address;
344 if (result == 0) {
345 error(errno, "Unable to write block %d", i);
346 }
347 }
348
349 #ifdef __linux__
350 // zap the block after the map (if possible) to get around a bug.
351 if (map->maximum_in_map > 0 && i < map->maximum_in_map) {
352 i += 1;
353 block = (char *) malloc(PBLOCK_SIZE);
354 if (block != NULL) {
355 if (read_block(map, i, block)) {
356 block[0] = 0;
357 write_block(map, i, block);
358 }
359 free(block);
360 }
361 }
362 #endif
363
364 if (interactive)
365 printf("The partition table has been altered!\n\n");
366
367 os_reload_media(map->m);
368 }
369
370
371 int
add_data_to_map(struct dpme * data,long ix,partition_map_header * map)372 add_data_to_map(struct dpme *data, long ix, partition_map_header *map)
373 {
374 partition_map *entry;
375
376 //printf("add data %d to map\n", ix);
377 entry = (partition_map *) malloc(sizeof(partition_map));
378 if (entry == NULL) {
379 error(errno, "can't allocate memory for map entries");
380 return 0;
381 }
382 entry->next_on_disk = NULL;
383 entry->prev_on_disk = NULL;
384 entry->next_by_base = NULL;
385 entry->prev_by_base = NULL;
386 entry->disk_address = ix;
387 entry->the_map = map;
388 entry->data = data;
389 entry->contains_driver = contains_driver(entry);
390 entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind);
391
392 insert_in_disk_order(entry);
393 insert_in_base_order(entry);
394
395 map->blocks_in_map++;
396 if (map->maximum_in_map < 0) {
397 if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) {
398 map->maximum_in_map = data->dpme_pblocks;
399 }
400 }
401
402 return 1;
403 }
404
405
406 partition_map_header *
init_partition_map(char * name,partition_map_header * oldmap)407 init_partition_map(char *name, partition_map_header* oldmap)
408 {
409 partition_map_header *map;
410
411 if (oldmap != NULL) {
412 printf("map already exists\n");
413 if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) {
414 return oldmap;
415 }
416 }
417
418 map = create_partition_map(name, oldmap);
419 if (map == NULL) {
420 return oldmap;
421 }
422 close_partition_map(oldmap);
423
424 add_partition_to_map("Apple", kMapType,
425 1, (map->media_size <= 128? 2: 63), map);
426 return map;
427 }
428
429
430 partition_map_header *
create_partition_map(char * name,partition_map_header * oldmap)431 create_partition_map(char *name, partition_map_header *oldmap)
432 {
433 MEDIA m;
434 partition_map_header * map;
435 DPME *data;
436 uint32_t default_number;
437 uint32_t number;
438 long size;
439 uint32_t multiple;
440
441 m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
442 if (m == 0) {
443 error(errno, "can't open file '%s' for %sing", name,
444 (rflag)?"read":"writ");
445 return NULL;
446 }
447
448 map = (partition_map_header *) malloc(sizeof(partition_map_header));
449 if (map == NULL) {
450 error(errno, "can't allocate memory for open partition map");
451 close_media(m);
452 return NULL;
453 }
454 map->name = name;
455 map->writable = (rflag)?0:1;
456 map->changed = 1;
457 map->disk_order = NULL;
458 map->base_order = NULL;
459
460 if (oldmap != NULL) {
461 size = oldmap->physical_block;
462 } else {
463 size = media_granularity(m);
464 }
465 m = open_deblock_media(PBLOCK_SIZE, m);
466 map->m = m;
467 if (interactive) {
468 printf("A physical block is %ld bytes: ", size);
469 flush_to_newline(0);
470 get_number_argument("what should be the physical block size? ",
471 &size, size);
472 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
473 if (size < PBLOCK_SIZE) {
474 size = PBLOCK_SIZE;
475 }
476 }
477 if (map->physical_block > MAXIOSIZE) {
478 map->physical_block = MAXIOSIZE;
479 }
480 map->physical_block = size;
481 // printf("block size is %d\n", map->physical_block);
482
483 if (oldmap != NULL) {
484 size = oldmap->logical_block;
485 } else {
486 size = PBLOCK_SIZE;
487 }
488 if (interactive) {
489 printf("A logical block is %ld bytes: ", size);
490 flush_to_newline(0);
491 get_number_argument("what should be the logical block size? ",
492 &size, size);
493 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
494 if (size < PBLOCK_SIZE) {
495 size = PBLOCK_SIZE;
496 }
497 }
498 #if 0
499 if (size > map->physical_block) {
500 size = map->physical_block;
501 }
502 #endif
503 map->logical_block = size;
504
505 map->blocks_in_map = 0;
506 map->maximum_in_map = -1;
507
508 number = compute_device_size(map, oldmap);
509 if (interactive) {
510 printf("size of 'device' is %"PRIu32" blocks (%d byte blocks): ",
511 number, map->logical_block);
512 default_number = number;
513 flush_to_newline(0);
514 do {
515 long long_number = number;
516 if (get_number_argument("what should be the size? ",
517 &long_number, default_number) == 0) {
518 printf("Not a number\n");
519 flush_to_newline(1);
520 number = 0;
521 } else {
522 number = long_number;
523 multiple = get_multiplier(map->logical_block);
524 if (multiple == 0) {
525 printf("Bad multiplier\n");
526 number = 0;
527 } else if (multiple != 1) {
528 if (0xFFFFFFFF/multiple < number) {
529 printf("Number too large\n");
530 number = 0;
531 } else {
532 number *= multiple;
533 }
534 }
535 }
536 default_number = kDefault;
537 } while (number == 0);
538
539 if (number < 4) {
540 number = 4;
541 }
542 printf("new size of 'device' is %"PRIu32" blocks (%d byte blocks)\n",
543 number, map->logical_block);
544 }
545 map->media_size = number;
546
547 map->misc = (Block0 *) calloc(1, PBLOCK_SIZE);
548 if (map->misc == NULL) {
549 error(errno, "can't allocate memory for block zero buffer");
550 } else {
551 // got it!
552 coerce_block0(map);
553 sync_device_size(map);
554
555 data = (DPME *) calloc(1, PBLOCK_SIZE);
556 if (data == NULL) {
557 error(errno, "can't allocate memory for disk buffers");
558 } else {
559 // set data into entry
560 data->dpme_signature = DPME_SIGNATURE;
561 data->dpme_map_entries = 1;
562 data->dpme_pblock_start = 1;
563 data->dpme_pblocks = map->media_size - 1;
564 strncpy(data->dpme_name, kFreeName, DPISTRLEN);
565 strncpy(data->dpme_type, kFreeType, DPISTRLEN);
566 data->dpme_lblock_start = 0;
567 data->dpme_lblocks = data->dpme_pblocks;
568 dpme_writable_set(data, 1);
569 dpme_readable_set(data, 1);
570 dpme_bootable_set(data, 0);
571 dpme_in_use_set(data, 0);
572 dpme_allocated_set(data, 0);
573 dpme_valid_set(data, 1);
574
575 if (add_data_to_map(data, 1, map) == 0) {
576 free(data);
577 } else {
578 return map;
579 }
580 }
581 }
582 close_partition_map(map);
583 return NULL;
584 }
585
586
587 int
coerce_block0(partition_map_header * map)588 coerce_block0(partition_map_header *map)
589 {
590 Block0 *p;
591
592 p = map->misc;
593 if (p == NULL) {
594 return 1;
595 }
596 if (p->sbSig != BLOCK0_SIGNATURE) {
597 p->sbSig = BLOCK0_SIGNATURE;
598 if (map->physical_block == 1) {
599 p->sbBlkSize = PBLOCK_SIZE;
600 } else {
601 p->sbBlkSize = map->physical_block;
602 }
603 p->sbBlkCount = 0;
604 p->sbDevType = 0;
605 p->sbDevId = 0;
606 p->sbData = 0;
607 p->sbDrvrCount = 0;
608 }
609 return 0; // we do this simply to make it easier to call this function
610 }
611
612
613 int
add_partition_to_map(const char * name,const char * dptype,uint32_t base,uint32_t length,partition_map_header * map)614 add_partition_to_map(const char *name, const char *dptype, uint32_t base, uint32_t length,
615 partition_map_header *map)
616 {
617 partition_map * cur;
618 DPME *data;
619 enum add_action act;
620 int limit;
621 uint32_t adjusted_base = 0;
622 uint32_t adjusted_length = 0;
623 uint32_t new_base = 0;
624 uint32_t new_length = 0;
625
626 // find a block that starts includes base and length
627 cur = map->base_order;
628 while (cur != NULL) {
629 if (cur->data->dpme_pblock_start <= base
630 && (base + length) <=
631 (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) {
632 break;
633 } else {
634 // check if request is past end of existing partitions, but on disk
635 if ((cur->next_by_base == NULL) &&
636 (base + length <= map->media_size)) {
637 // Expand final free partition
638 if ((istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) &&
639 base >= cur->data->dpme_pblock_start) {
640 cur->data->dpme_pblocks =
641 map->media_size - cur->data->dpme_pblock_start;
642 break;
643 }
644 // create an extra free partition
645 if (base >= cur->data->dpme_pblock_start + cur->data->dpme_pblocks) {
646 if (map->maximum_in_map < 0) {
647 limit = map->media_size;
648 } else {
649 limit = map->maximum_in_map;
650 }
651 if (map->blocks_in_map + 1 > limit) {
652 printf("the map is not big enough\n");
653 return 0;
654 }
655 data = create_data(kFreeName, kFreeType,
656 cur->data->dpme_pblock_start + cur->data->dpme_pblocks,
657 map->media_size - (cur->data->dpme_pblock_start + cur->data->dpme_pblocks));
658 if (data != NULL) {
659 if (add_data_to_map(data, cur->disk_address, map) == 0) {
660 free(data);
661 }
662 }
663 }
664 }
665 cur = cur->next_by_base;
666 }
667 }
668 // if it is not Extra then punt
669 if (cur == NULL
670 || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
671 printf("requested base and length is not "
672 "within an existing free partition\n");
673 return 0;
674 }
675 // figure out what to do and sizes
676 data = cur->data;
677 if (data->dpme_pblock_start == base) {
678 // replace or add
679 if (data->dpme_pblocks == length) {
680 act = kReplace;
681 } else {
682 act = kAdd;
683 adjusted_base = base + length;
684 adjusted_length = data->dpme_pblocks - length;
685 }
686 } else {
687 // split or add
688 if (data->dpme_pblock_start + data->dpme_pblocks == base + length) {
689 act = kAdd;
690 adjusted_base = data->dpme_pblock_start;
691 adjusted_length = base - adjusted_base;
692 } else {
693 act = kSplit;
694 new_base = data->dpme_pblock_start;
695 new_length = base - new_base;
696 adjusted_base = base + length;
697 adjusted_length = data->dpme_pblocks - (length + new_length);
698 }
699 }
700 // if the map will overflow then punt
701 if (map->maximum_in_map < 0) {
702 limit = map->media_size;
703 } else {
704 limit = map->maximum_in_map;
705 }
706 if (map->blocks_in_map + (int)act > limit) {
707 printf("the map is not big enough\n");
708 return 0;
709 }
710
711 data = create_data(name, dptype, base, length);
712 if (data == NULL) {
713 return 0;
714 }
715 if (act == kReplace) {
716 free(cur->data);
717 cur->data = data;
718 } else {
719 // adjust this block's size
720 cur->data->dpme_pblock_start = adjusted_base;
721 cur->data->dpme_pblocks = adjusted_length;
722 cur->data->dpme_lblocks = adjusted_length;
723 // insert new with block address equal to this one
724 if (add_data_to_map(data, cur->disk_address, map) == 0) {
725 free(data);
726 } else if (act == kSplit) {
727 data = create_data(kFreeName, kFreeType, new_base, new_length);
728 if (data != NULL) {
729 // insert new with block address equal to this one
730 if (add_data_to_map(data, cur->disk_address, map) == 0) {
731 free(data);
732 }
733 }
734 }
735 }
736 // renumber disk addresses
737 renumber_disk_addresses(map);
738 // mark changed
739 map->changed = 1;
740 return 1;
741 }
742
743
744 DPME *
create_data(const char * name,const char * dptype,uint32_t base,uint32_t length)745 create_data(const char *name, const char *dptype, uint32_t base, uint32_t length)
746 {
747 DPME *data;
748
749 data = (DPME *) calloc(1, PBLOCK_SIZE);
750 if (data == NULL) {
751 error(errno, "can't allocate memory for disk buffers");
752 } else {
753 // set data into entry
754 data->dpme_signature = DPME_SIGNATURE;
755 data->dpme_map_entries = 1;
756 data->dpme_pblock_start = base;
757 data->dpme_pblocks = length;
758 strncpy(data->dpme_name, name, DPISTRLEN);
759 strncpy(data->dpme_type, dptype, DPISTRLEN);
760 data->dpme_lblock_start = 0;
761 data->dpme_lblocks = data->dpme_pblocks;
762 dpme_init_flags(data);
763 }
764 return data;
765 }
766
767 void
dpme_init_flags(DPME * data)768 dpme_init_flags(DPME *data)
769 {
770 if (istrncmp(data->dpme_type, kHFSType, DPISTRLEN) == 0) { /* XXX this is gross, fix it! */
771 data->dpme_flags = APPLE_HFS_FLAGS_VALUE;
772 }
773 else {
774 dpme_writable_set(data, 1);
775 dpme_readable_set(data, 1);
776 dpme_bootable_set(data, 0);
777 dpme_in_use_set(data, 0);
778 dpme_allocated_set(data, 1);
779 dpme_valid_set(data, 1);
780 }
781 }
782
783 /* These bits are appropriate for Apple_UNIX_SVR2 partitions
784 * used by NetBSD. They may be ok for A/UX, but have not been
785 * tested.
786 */
787 void
bzb_init_slice(BZB * bp,int slice)788 bzb_init_slice(BZB *bp, int slice)
789 {
790 memset(bp,0,sizeof(BZB));
791 if ((slice >= 'A') && (slice <= 'Z')) {
792 slice += 'a' - 'A';
793 }
794 if ((slice != 0) && ((slice < 'a') || (slice > 'z'))) {
795 error(-1,"Bad bzb slice");
796 slice = 0;
797 }
798 switch (slice) {
799 case 0:
800 case 'c':
801 return;
802 case 'a':
803 bp->bzb_type = FST;
804 strlcpy((char *)bp->bzb_mount_point, "/", sizeof(bp->bzb_mount_point));
805 bp->bzb_inode = 1;
806 bzb_root_set(bp,1);
807 bzb_usr_set(bp,1);
808 break;
809 case 'b':
810 bp->bzb_type = FSTSFS;
811 strlcpy((char *)bp->bzb_mount_point, "(swap)", sizeof(bp->bzb_mount_point));
812 break;
813 case 'g':
814 strlcpy((char *)bp->bzb_mount_point, "/usr", sizeof(bp->bzb_mount_point));
815 /* Fall through */
816 default:
817 bp->bzb_type = FST;
818 bp->bzb_inode = 1;
819 bzb_usr_set(bp,1);
820 break;
821 }
822 bzb_slice_set(bp,0); // XXX NetBSD disksubr.c ignores slice
823 // bzb_slice_set(bp,slice-'a'+1);
824 bp->bzb_magic = BZBMAGIC;
825 }
826
827 void
renumber_disk_addresses(partition_map_header * map)828 renumber_disk_addresses(partition_map_header *map)
829 {
830 partition_map * cur;
831 long ix;
832
833 // reset disk addresses
834 cur = map->disk_order;
835 ix = 1;
836 while (cur != NULL) {
837 cur->disk_address = ix++;
838 cur->data->dpme_map_entries = map->blocks_in_map;
839 cur = cur->next_on_disk;
840 }
841 }
842
843
844 long
compute_device_size(partition_map_header * map,partition_map_header * oldmap)845 compute_device_size(partition_map_header *map, partition_map_header *oldmap)
846 {
847 #ifdef TEST_COMPUTE
848 uint32_t length;
849 struct hd_geometry geometry;
850 struct stat info;
851 loff_t pos;
852 #endif
853 char* data;
854 uint32_t l, r, x = 0;
855 long long size;
856 int valid = 0;
857 #ifdef TEST_COMPUTE
858 int fd;
859
860 fd = map->fd->fd;
861 printf("\n");
862 if (fstat(fd, &info) < 0) {
863 printf("stat of device failed\n");
864 } else {
865 printf("stat: mode = 0%o, type=%s\n", info.st_mode,
866 (S_ISREG(info.st_mode)? "Regular":
867 (S_ISBLK(info.st_mode)?"Block":"Other")));
868 printf("size = %d, blocks = %d\n",
869 info.st_size, info.st_size/map->logical_block);
870 }
871
872 if (ioctl(fd, BLKGETSIZE, &length) < 0) {
873 printf("get device size failed\n");
874 } else {
875 printf("BLKGETSIZE:size in blocks = %u\n", length);
876 }
877
878 if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) {
879 printf("get device geometry failed\n");
880 } else {
881 printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d, total=%d\n",
882 geometry.heads, geometry.sectors,
883 geometry.cylinders, geometry.start,
884 geometry.heads*geometry.sectors*geometry.cylinders);
885 }
886
887 if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) {
888 printf("llseek to end of device failed\n");
889 } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) {
890 printf("llseek to end of device failed on second try\n");
891 } else {
892 printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block);
893 }
894 #endif
895
896 if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) {
897 return (oldmap->misc->sbBlkCount
898 * (oldmap->physical_block / map->logical_block));
899 }
900
901 size = media_total_size(map->m);
902 if (size != 0) {
903 return (long)(size / map->logical_block);
904 }
905
906 // else case
907
908 data = (char *) malloc(PBLOCK_SIZE);
909 if (data == NULL) {
910 error(errno, "can't allocate memory for try buffer");
911 x = 0;
912 } else {
913 // double till off end
914 l = 0;
915 r = 1024;
916 while (read_block(map, r, data) != 0) {
917 l = r;
918 if (r <= 1024) {
919 r = r * 1024;
920 } else {
921 r = r * 2;
922 }
923 if (r >= 0x80000000) {
924 r = 0xFFFFFFFE;
925 break;
926 }
927 }
928 // binary search for end
929 while (l <= r) {
930 x = (r - l) / 2 + l;
931 if ((valid = read_block(map, x, data)) != 0) {
932 l = x + 1;
933 } else {
934 if (x > 0) {
935 r = x - 1;
936 } else {
937 break;
938 }
939 }
940 }
941 if (valid != 0) {
942 x = x + 1;
943 }
944 // printf("size in blocks = %d\n", x);
945 free(data);
946 }
947
948 return x;
949 }
950
951
952 void
sync_device_size(partition_map_header * map)953 sync_device_size(partition_map_header *map)
954 {
955 Block0 *p;
956 uint32_t size;
957 double d;
958
959 p = map->misc;
960 if (p == NULL) {
961 return;
962 }
963 d = map->media_size;
964 size = (d * map->logical_block) / p->sbBlkSize;
965 if (p->sbBlkCount != size) {
966 p->sbBlkCount = size;
967 }
968 }
969
970
971 void
delete_partition_from_map(partition_map * entry)972 delete_partition_from_map(partition_map *entry)
973 {
974 partition_map_header *map;
975 DPME *data;
976
977 if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) {
978 printf("Can't delete entry for the map itself\n");
979 return;
980 }
981 if (entry->contains_driver) {
982 printf("This program can't install drivers\n");
983 if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) {
984 return;
985 }
986 }
987 // if past end of disk, delete it completely
988 if (entry->next_by_base == NULL &&
989 entry->data->dpme_pblock_start >= entry->the_map->media_size) {
990 if (entry->contains_driver) {
991 remove_driver(entry); // update block0 if necessary
992 }
993 delete_entry(entry);
994 return;
995 }
996 // If at end of disk, incorporate extra disk space to partition
997 if (entry->next_by_base == NULL) {
998 entry->data->dpme_pblocks =
999 entry->the_map->media_size - entry->data->dpme_pblock_start;
1000 }
1001 data = create_data(kFreeName, kFreeType,
1002 entry->data->dpme_pblock_start, entry->data->dpme_pblocks);
1003 if (data == NULL) {
1004 return;
1005 }
1006 if (entry->contains_driver) {
1007 remove_driver(entry); // update block0 if necessary
1008 }
1009 free(entry->data);
1010 free(entry->HFS_name);
1011 entry->HFS_kind = kHFS_not;
1012 entry->HFS_name = 0;
1013 entry->data = data;
1014 combine_entry(entry);
1015 map = entry->the_map;
1016 renumber_disk_addresses(map);
1017 map->changed = 1;
1018 }
1019
1020
1021 int
contains_driver(partition_map * entry)1022 contains_driver(partition_map *entry)
1023 {
1024 partition_map_header *map;
1025 Block0 *p;
1026 DDMap *m;
1027 int i;
1028 int f;
1029 uint32_t start;
1030
1031 map = entry->the_map;
1032 p = map->misc;
1033 if (p == NULL) {
1034 return 0;
1035 }
1036 if (p->sbSig != BLOCK0_SIGNATURE) {
1037 return 0;
1038 }
1039 if (map->logical_block > p->sbBlkSize) {
1040 return 0;
1041 } else {
1042 f = p->sbBlkSize / map->logical_block;
1043 }
1044 if (p->sbDrvrCount > 0) {
1045 m = (DDMap *) p->sbMap;
1046 for (i = 0; i < p->sbDrvrCount; i++) {
1047 start = get_align_long(&m[i].ddBlock);
1048 if (entry->data->dpme_pblock_start <= f*start
1049 && f*(start + m[i].ddSize)
1050 <= (entry->data->dpme_pblock_start
1051 + entry->data->dpme_pblocks)) {
1052 return 1;
1053 }
1054 }
1055 }
1056 return 0;
1057 }
1058
1059
1060 void
combine_entry(partition_map * entry)1061 combine_entry(partition_map *entry)
1062 {
1063 partition_map *p;
1064 uint32_t end;
1065
1066 if (entry == NULL
1067 || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1068 return;
1069 }
1070 if (entry->next_by_base != NULL) {
1071 p = entry->next_by_base;
1072 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1073 // next is not free
1074 } else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1075 != p->data->dpme_pblock_start) {
1076 // next is not contiguous (XXX this is bad)
1077 printf("next entry is not contiguous\n");
1078 // start is already minimum
1079 // new end is maximum of two ends
1080 end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1081 if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1082 entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start;
1083 }
1084 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1085 delete_entry(p);
1086 } else {
1087 entry->data->dpme_pblocks += p->data->dpme_pblocks;
1088 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1089 delete_entry(p);
1090 }
1091 }
1092 if (entry->prev_by_base != NULL) {
1093 p = entry->prev_by_base;
1094 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1095 // previous is not free
1096 } else if (p->data->dpme_pblock_start + p->data->dpme_pblocks
1097 != entry->data->dpme_pblock_start) {
1098 // previous is not contiguous (XXX this is bad)
1099 printf("previous entry is not contiguous\n");
1100 // new end is maximum of two ends
1101 end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1102 if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1103 end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks;
1104 }
1105 entry->data->dpme_pblocks = end - p->data->dpme_pblock_start;
1106 // new start is previous entry's start
1107 entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1108 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1109 delete_entry(p);
1110 } else {
1111 entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1112 entry->data->dpme_pblocks += p->data->dpme_pblocks;
1113 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1114 delete_entry(p);
1115 }
1116 }
1117 entry->contains_driver = contains_driver(entry);
1118 }
1119
1120
1121 void
delete_entry(partition_map * entry)1122 delete_entry(partition_map *entry)
1123 {
1124 partition_map_header *map;
1125 partition_map *p;
1126
1127 map = entry->the_map;
1128 map->blocks_in_map--;
1129
1130 remove_from_disk_order(entry);
1131
1132 p = entry->next_by_base;
1133 if (map->base_order == entry) {
1134 map->base_order = p;
1135 }
1136 if (p != NULL) {
1137 p->prev_by_base = entry->prev_by_base;
1138 }
1139 if (entry->prev_by_base != NULL) {
1140 entry->prev_by_base->next_by_base = p;
1141 }
1142
1143 free(entry->data);
1144 free(entry->HFS_name);
1145 free(entry);
1146 }
1147
1148
1149 partition_map *
find_entry_by_disk_address(int32_t ix,partition_map_header * map)1150 find_entry_by_disk_address(int32_t ix, partition_map_header *map)
1151 {
1152 partition_map * cur;
1153
1154 cur = map->disk_order;
1155 while (cur != NULL) {
1156 if (cur->disk_address == ix) {
1157 break;
1158 }
1159 cur = cur->next_on_disk;
1160 }
1161 return cur;
1162 }
1163
1164
1165 partition_map *
find_entry_by_type(const char * type_name,partition_map_header * map)1166 find_entry_by_type(const char *type_name, partition_map_header *map)
1167 {
1168 partition_map * cur;
1169
1170 cur = map->base_order;
1171 while (cur != NULL) {
1172 if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) {
1173 break;
1174 }
1175 cur = cur->next_by_base;
1176 }
1177 return cur;
1178 }
1179
1180 partition_map *
find_entry_by_base(uint32_t base,partition_map_header * map)1181 find_entry_by_base(uint32_t base, partition_map_header *map)
1182 {
1183 partition_map * cur;
1184
1185 cur = map->base_order;
1186 while (cur != NULL) {
1187 if (cur->data->dpme_pblock_start == base) {
1188 break;
1189 }
1190 cur = cur->next_by_base;
1191 }
1192 return cur;
1193 }
1194
1195
1196 void
move_entry_in_map(int32_t old_index,int32_t ix,partition_map_header * map)1197 move_entry_in_map(int32_t old_index, int32_t ix, partition_map_header *map)
1198 {
1199 partition_map * cur;
1200
1201 cur = find_entry_by_disk_address(old_index, map);
1202 if (cur == NULL) {
1203 printf("No such partition\n");
1204 } else {
1205 remove_from_disk_order(cur);
1206 cur->disk_address = ix;
1207 insert_in_disk_order(cur);
1208 renumber_disk_addresses(map);
1209 map->changed = 1;
1210 }
1211 }
1212
1213
1214 void
remove_from_disk_order(partition_map * entry)1215 remove_from_disk_order(partition_map *entry)
1216 {
1217 partition_map_header *map;
1218 partition_map *p;
1219
1220 map = entry->the_map;
1221 p = entry->next_on_disk;
1222 if (map->disk_order == entry) {
1223 map->disk_order = p;
1224 }
1225 if (p != NULL) {
1226 p->prev_on_disk = entry->prev_on_disk;
1227 }
1228 if (entry->prev_on_disk != NULL) {
1229 entry->prev_on_disk->next_on_disk = p;
1230 }
1231 entry->next_on_disk = NULL;
1232 entry->prev_on_disk = NULL;
1233 }
1234
1235
1236 void
insert_in_disk_order(partition_map * entry)1237 insert_in_disk_order(partition_map *entry)
1238 {
1239 partition_map_header *map;
1240 partition_map * cur;
1241
1242 // find position in disk list & insert
1243 map = entry->the_map;
1244 cur = map->disk_order;
1245 if (cur == NULL || entry->disk_address <= cur->disk_address) {
1246 map->disk_order = entry;
1247 entry->next_on_disk = cur;
1248 if (cur != NULL) {
1249 cur->prev_on_disk = entry;
1250 }
1251 entry->prev_on_disk = NULL;
1252 } else {
1253 for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) {
1254 if (cur->disk_address <= entry->disk_address
1255 && (cur->next_on_disk == NULL
1256 || entry->disk_address <= cur->next_on_disk->disk_address)) {
1257 entry->next_on_disk = cur->next_on_disk;
1258 cur->next_on_disk = entry;
1259 entry->prev_on_disk = cur;
1260 if (entry->next_on_disk != NULL) {
1261 entry->next_on_disk->prev_on_disk = entry;
1262 }
1263 break;
1264 }
1265 }
1266 }
1267 }
1268
1269
1270 void
insert_in_base_order(partition_map * entry)1271 insert_in_base_order(partition_map *entry)
1272 {
1273 partition_map_header *map;
1274 partition_map * cur;
1275
1276 // find position in base list & insert
1277 map = entry->the_map;
1278 cur = map->base_order;
1279 if (cur == NULL
1280 || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) {
1281 map->base_order = entry;
1282 entry->next_by_base = cur;
1283 if (cur != NULL) {
1284 cur->prev_by_base = entry;
1285 }
1286 entry->prev_by_base = NULL;
1287 } else {
1288 for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) {
1289 if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start
1290 && (cur->next_by_base == NULL
1291 || entry->data->dpme_pblock_start
1292 <= cur->next_by_base->data->dpme_pblock_start)) {
1293 entry->next_by_base = cur->next_by_base;
1294 cur->next_by_base = entry;
1295 entry->prev_by_base = cur;
1296 if (entry->next_by_base != NULL) {
1297 entry->next_by_base->prev_by_base = entry;
1298 }
1299 break;
1300 }
1301 }
1302 }
1303 }
1304
1305
1306 void
resize_map(uint32_t new_size,partition_map_header * map)1307 resize_map(uint32_t new_size, partition_map_header *map)
1308 {
1309 partition_map * entry;
1310 partition_map * next;
1311 uint32_t incr;
1312
1313 // find map entry
1314 entry = find_entry_by_type(kMapType, map);
1315
1316 if (entry == NULL) {
1317 printf("Couldn't find entry for map!\n");
1318 return;
1319 }
1320 next = entry->next_by_base;
1321
1322 // same size
1323 if (new_size == entry->data->dpme_pblocks) {
1324 // do nothing
1325 return;
1326 }
1327
1328 // make it smaller
1329 if (new_size < entry->data->dpme_pblocks) {
1330 if (next == NULL
1331 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1332 incr = 1;
1333 } else {
1334 incr = 0;
1335 }
1336 if (new_size < map->blocks_in_map + incr) {
1337 printf("New size would be too small\n");
1338 return;
1339 }
1340 goto doit;
1341 }
1342
1343 // make it larger
1344 if (next == NULL
1345 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1346 printf("No free space to expand into\n");
1347 return;
1348 }
1349 if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1350 != next->data->dpme_pblock_start) {
1351 printf("No contiguous free space to expand into\n");
1352 return;
1353 }
1354 if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) {
1355 printf("No enough free space\n");
1356 return;
1357 }
1358 doit:
1359 entry->data->dpme_type[0] = 0;
1360 delete_partition_from_map(entry);
1361 add_partition_to_map("Apple", kMapType, 1, new_size, map);
1362 map->maximum_in_map = new_size;
1363 }
1364
1365
1366 void
remove_driver(partition_map * entry)1367 remove_driver(partition_map *entry)
1368 {
1369 partition_map_header *map;
1370 Block0 *p;
1371 DDMap *m;
1372 int i;
1373 int j;
1374 int f;
1375 uint32_t start;
1376
1377 map = entry->the_map;
1378 p = map->misc;
1379 if (p == NULL) {
1380 return;
1381 }
1382 if (p->sbSig != BLOCK0_SIGNATURE) {
1383 return;
1384 }
1385 if (map->logical_block > p->sbBlkSize) {
1386 /* this is not supposed to happen, but let's just ignore it. */
1387 return;
1388 } else {
1389 /*
1390 * compute the factor to convert the block numbers in block0
1391 * into partition map block numbers.
1392 */
1393 f = p->sbBlkSize / map->logical_block;
1394 }
1395 if (p->sbDrvrCount > 0) {
1396 m = (DDMap *) p->sbMap;
1397 for (i = 0; i < p->sbDrvrCount; i++) {
1398 start = get_align_long(&m[i].ddBlock);
1399
1400 /* zap the driver if it is wholly contained in the partition */
1401 if (entry->data->dpme_pblock_start <= f*start
1402 && f*(start + m[i].ddSize)
1403 <= (entry->data->dpme_pblock_start
1404 + entry->data->dpme_pblocks)) {
1405 // delete this driver
1406 // by copying down later ones and zapping the last
1407 for (j = i+1; j < p->sbDrvrCount; j++, i++) {
1408 put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock);
1409 m[i].ddSize = m[j].ddSize;
1410 m[i].ddType = m[j].ddType;
1411 }
1412 put_align_long(0, &m[i].ddBlock);
1413 m[i].ddSize = 0;
1414 m[i].ddType = 0;
1415 p->sbDrvrCount -= 1;
1416 return; /* XXX if we continue we will delete other drivers? */
1417 }
1418 }
1419 }
1420 }
1421
1422 int
read_block(partition_map_header * map,uint32_t num,char * buf)1423 read_block(partition_map_header *map, uint32_t num, char *buf)
1424 {
1425 //printf("read block %d\n", num);
1426 return read_media(map->m, ((long long) num) * map->logical_block,
1427 PBLOCK_SIZE, (void *)buf);
1428 }
1429
1430
1431 int
write_block(partition_map_header * map,uint32_t num,char * buf)1432 write_block(partition_map_header *map, uint32_t num, char *buf)
1433 {
1434 return write_media(map->m, ((long long) num) * map->logical_block,
1435 PBLOCK_SIZE, (void *)buf);
1436 }
1437