Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / pdisk / partition_map.c
blob00c9ed670d0f351919924a6843dd0c49dd7c85a3
1 //
2 // partition_map.c - partition map routines
3 //
4 // Written by Eryk Vershen
5 //
7 /*
8 * Copyright 1996,1997,1998 by Apple Computer, Inc.
9 * All Rights Reserved
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.
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.
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.
28 // for *printf()
29 #include <stdio.h>
31 // for malloc(), calloc() & free()
32 #ifndef __linux__
33 #include <stdlib.h>
34 #else
35 #include <malloc.h>
36 #endif
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>
45 #include "partition_map.h"
46 #include "pathname.h"
47 #include "hfs_misc.h"
48 #include "deblock_media.h"
49 #include "io.h"
50 #include "convert.h"
51 #include "util.h"
52 #include "errors.h"
56 // Defines
58 #define APPLE_HFS_FLAGS_VALUE 0x4000037f
59 #define get_align_long(x) (*(x))
60 #define put_align_long(y, x) ((*(x)) = (y))
61 // #define TEST_COMPUTE
65 // Types
70 // Global Constants
72 const char * kFreeType = "Apple_Free";
73 const char * kMapType = "Apple_partition_map";
74 const char * kUnixType = "Apple_UNIX_SVR2";
75 const char * kHFSType = "Apple_HFS";
76 const char * kPatchType = "Apple_Patches";
78 const char * kFreeName = "Extra";
80 enum add_action {
81 kReplace = 0,
82 kAdd = 1,
83 kSplit = 2
87 // Global Variables
89 extern int cflag;
93 // Forward declarations
95 int add_data_to_map(struct dpme *, long, partition_map_header *);
96 int coerce_block0(partition_map_header *map);
97 int contains_driver(partition_map *entry);
98 void combine_entry(partition_map *entry);
99 long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
100 DPME* create_data(const char *name, const char *dptype, u32 base, u32 length);
101 void delete_entry(partition_map *entry);
102 char *get_HFS_name(partition_map *entry, int *kind);
103 void insert_in_base_order(partition_map *entry);
104 void insert_in_disk_order(partition_map *entry);
105 int read_block(partition_map_header *map, unsigned long num, char *buf);
106 int read_partition_map(partition_map_header *map);
107 void remove_driver(partition_map *entry);
108 void remove_from_disk_order(partition_map *entry);
109 void renumber_disk_addresses(partition_map_header *map);
110 void sync_device_size(partition_map_header *map);
111 int write_block(partition_map_header *map, unsigned long num, char *buf);
115 // Routines
117 partition_map_header *
118 open_partition_map(char *name, int *valid_file, int ask_logical_size)
120 MEDIA m;
121 partition_map_header * map;
122 int writable;
123 long size;
125 m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
126 if (m == 0) {
127 m = open_pathname_as_media(name, O_RDONLY);
128 if (m == 0) {
129 error(errno, "can't open file '%s'", name);
130 *valid_file = 0;
131 return NULL;
132 } else {
133 writable = 0;
135 } else {
136 writable = 1;
138 *valid_file = 1;
140 map = (partition_map_header *) malloc(sizeof(partition_map_header));
141 if (map == NULL) {
142 error(errno, "can't allocate memory for open partition map");
143 close_media(m);
144 return NULL;
146 map->name = name;
147 map->writable = (rflag)?0:writable;
148 map->changed = 0;
149 map->written = 0;
150 map->disk_order = NULL;
151 map->base_order = NULL;
153 map->physical_block = media_granularity(m); /* preflight */
154 m = open_deblock_media(PBLOCK_SIZE, m);
155 map->m = m;
156 map->misc = (Block0 *) malloc(PBLOCK_SIZE);
157 if (map->misc == NULL) {
158 error(errno, "can't allocate memory for block zero buffer");
159 close_media(map->m);
160 free(map);
161 return NULL;
162 } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
163 || convert_block0(map->misc, 1)
164 || coerce_block0(map)) {
165 // if I can't read block 0 I might as well give up
166 error(-1, "Can't read block 0 from '%s'", name);
167 close_partition_map(map);
168 return NULL;
170 map->physical_block = map->misc->sbBlkSize;
171 //printf("physical block size is %d\n", map->physical_block);
173 if (ask_logical_size && interactive) {
174 size = PBLOCK_SIZE;
175 printf("A logical block is %ld bytes: ", size);
176 flush_to_newline(0);
177 get_number_argument("what should be the logical block size? ",
178 &size, size);
179 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
180 if (size < PBLOCK_SIZE) {
181 size = PBLOCK_SIZE;
183 map->logical_block = size;
184 } else {
185 map->logical_block = PBLOCK_SIZE;
187 if (map->logical_block > MAXIOSIZE) {
188 map->logical_block = MAXIOSIZE;
190 if (map->logical_block > map->physical_block) {
191 map->physical_block = map->logical_block;
193 map->blocks_in_map = 0;
194 map->maximum_in_map = -1;
195 map->media_size = compute_device_size(map, map);
196 sync_device_size(map);
198 if (read_partition_map(map) < 0) {
199 // some sort of failure reading the map
200 } else {
201 // got it!
203 return map;
205 close_partition_map(map);
206 return NULL;
210 void
211 close_partition_map(partition_map_header *map)
213 partition_map * entry;
214 partition_map * next;
216 if (map == NULL) {
217 return;
220 free(map->misc);
222 for (entry = map->disk_order; entry != NULL; entry = next) {
223 next = entry->next_on_disk;
224 free(entry->data);
225 free(entry->HFS_name);
226 free(entry);
228 close_media(map->m);
229 free(map);
234 read_partition_map(partition_map_header *map)
236 DPME *data;
237 u32 limit;
238 unsigned int ix;
239 int old_logical;
240 double d;
242 //printf("called read_partition_map\n");
243 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
244 data = (DPME *) malloc(PBLOCK_SIZE);
245 if (data == NULL) {
246 error(errno, "can't allocate memory for disk buffers");
247 return -1;
250 if (read_block(map, 1, (char *)data) == 0) {
251 error(-1, "Can't read block 1 from '%s'", map->name);
252 free(data);
253 return -1;
254 } else if (convert_dpme(data, 1)
255 || data->dpme_signature != DPME_SIGNATURE) {
256 old_logical = map->logical_block;
257 map->logical_block = 512;
258 while (map->logical_block <= map->physical_block) {
259 if (read_block(map, 1, (char *)data) == 0) {
260 error(-1, "Can't read block 1 from '%s'", map->name);
261 free(data);
262 return -1;
263 } else if (convert_dpme(data, 1) == 0
264 && data->dpme_signature == DPME_SIGNATURE) {
265 d = map->media_size;
266 map->media_size = (d * old_logical) / map->logical_block;
267 break;
269 map->logical_block *= 2;
271 if (map->logical_block > map->physical_block) {
272 error(-1, "No valid block 1 on '%s'", map->name);
273 free(data);
274 return -1;
277 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
279 limit = data->dpme_map_entries;
280 ix = 1;
281 while (1) {
282 if (add_data_to_map(data, ix, map) == 0) {
283 free(data);
284 return -1;
287 if (ix >= limit) {
288 break;
289 } else {
290 ix++;
293 data = (DPME *) malloc(PBLOCK_SIZE);
294 if (data == NULL) {
295 error(errno, "can't allocate memory for disk buffers");
296 return -1;
299 if (read_block(map, ix, (char *)data) == 0) {
300 error(-1, "Can't read block %u from '%s'", ix, map->name);
301 free(data);
302 return -1;
303 } else if (convert_dpme(data, 1)
304 || (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
305 || (data->dpme_map_entries != limit && dflag == 0)) {
306 error(-1, "Bad data in block %u from '%s'", ix, map->name);
307 free(data);
308 return -1;
311 return 0;
315 void
316 write_partition_map(partition_map_header *map)
318 MEDIA m;
319 char *block;
320 partition_map * entry;
321 int i = 0;
322 int result = 0;
324 m = map->m;
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);
336 if (result == 0) {
337 error(errno, "Unable to write block zero");
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);
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);
359 free(block);
362 #endif
364 if (interactive)
365 printf("The partition table has been altered!\n\n");
367 os_reload_media(map->m);
372 add_data_to_map(struct dpme *data, long ix, partition_map_header *map)
374 partition_map *entry;
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;
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);
392 insert_in_disk_order(entry);
393 insert_in_base_order(entry);
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;
402 return 1;
406 partition_map_header *
407 init_partition_map(char *name, partition_map_header* oldmap)
409 partition_map_header *map;
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;
418 map = create_partition_map(name, oldmap);
419 if (map == NULL) {
420 return oldmap;
422 close_partition_map(oldmap);
424 add_partition_to_map("Apple", kMapType,
425 1, (map->media_size <= 128? 2: 63), map);
426 return map;
430 partition_map_header *
431 create_partition_map(char *name, partition_map_header *oldmap)
433 MEDIA m;
434 partition_map_header * map;
435 DPME *data;
436 unsigned long default_number;
437 unsigned long number;
438 long size;
439 unsigned long multiple;
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;
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;
454 map->name = name;
455 map->writable = (rflag)?0:1;
456 map->changed = 1;
457 map->disk_order = NULL;
458 map->base_order = NULL;
460 if (oldmap != NULL) {
461 size = oldmap->physical_block;
462 } else {
463 size = media_granularity(m);
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;
477 if (map->physical_block > MAXIOSIZE) {
478 map->physical_block = MAXIOSIZE;
480 map->physical_block = size;
481 // printf("block size is %d\n", map->physical_block);
483 if (oldmap != NULL) {
484 size = oldmap->logical_block;
485 } else {
486 size = PBLOCK_SIZE;
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;
498 #if 0
499 if (size > map->physical_block) {
500 size = map->physical_block;
502 #endif
503 map->logical_block = size;
505 map->blocks_in_map = 0;
506 map->maximum_in_map = -1;
508 number = compute_device_size(map, oldmap);
509 if (interactive) {
510 printf("size of 'device' is %lu blocks (%d byte blocks): ",
511 number, map->logical_block);
512 default_number = number;
513 flush_to_newline(0);
514 do {
515 if (get_number_argument("what should be the size? ",
516 (long *)&number, default_number) == 0) {
517 printf("Not a number\n");
518 flush_to_newline(1);
519 number = 0;
520 } else {
521 multiple = get_multiplier(map->logical_block);
522 if (multiple == 0) {
523 printf("Bad multiplier\n");
524 number = 0;
525 } else if (multiple != 1) {
526 if (0xFFFFFFFF/multiple < number) {
527 printf("Number too large\n");
528 number = 0;
529 } else {
530 number *= multiple;
534 default_number = kDefault;
535 } while (number == 0);
537 if (number < 4) {
538 number = 4;
540 printf("new size of 'device' is %lu blocks (%d byte blocks)\n",
541 number, map->logical_block);
543 map->media_size = number;
545 map->misc = (Block0 *) calloc(1, PBLOCK_SIZE);
546 if (map->misc == NULL) {
547 error(errno, "can't allocate memory for block zero buffer");
548 } else {
549 // got it!
550 coerce_block0(map);
551 sync_device_size(map);
553 data = (DPME *) calloc(1, PBLOCK_SIZE);
554 if (data == NULL) {
555 error(errno, "can't allocate memory for disk buffers");
556 } else {
557 // set data into entry
558 data->dpme_signature = DPME_SIGNATURE;
559 data->dpme_map_entries = 1;
560 data->dpme_pblock_start = 1;
561 data->dpme_pblocks = map->media_size - 1;
562 strncpy(data->dpme_name, kFreeName, DPISTRLEN);
563 strncpy(data->dpme_type, kFreeType, DPISTRLEN);
564 data->dpme_lblock_start = 0;
565 data->dpme_lblocks = data->dpme_pblocks;
566 dpme_writable_set(data, 1);
567 dpme_readable_set(data, 1);
568 dpme_bootable_set(data, 0);
569 dpme_in_use_set(data, 0);
570 dpme_allocated_set(data, 0);
571 dpme_valid_set(data, 1);
573 if (add_data_to_map(data, 1, map) == 0) {
574 free(data);
575 } else {
576 return map;
580 close_partition_map(map);
581 return NULL;
586 coerce_block0(partition_map_header *map)
588 Block0 *p;
590 p = map->misc;
591 if (p == NULL) {
592 return 1;
594 if (p->sbSig != BLOCK0_SIGNATURE) {
595 p->sbSig = BLOCK0_SIGNATURE;
596 if (map->physical_block == 1) {
597 p->sbBlkSize = PBLOCK_SIZE;
598 } else {
599 p->sbBlkSize = map->physical_block;
601 p->sbBlkCount = 0;
602 p->sbDevType = 0;
603 p->sbDevId = 0;
604 p->sbData = 0;
605 p->sbDrvrCount = 0;
607 return 0; // we do this simply to make it easier to call this function
612 add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length,
613 partition_map_header *map)
615 partition_map * cur;
616 DPME *data;
617 enum add_action act;
618 int limit;
619 u32 adjusted_base = 0;
620 u32 adjusted_length = 0;
621 u32 new_base = 0;
622 u32 new_length = 0;
624 // find a block that starts includes base and length
625 cur = map->base_order;
626 while (cur != NULL) {
627 if (cur->data->dpme_pblock_start <= base
628 && (base + length) <=
629 (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) {
630 break;
631 } else {
632 // check if request is past end of existing partitions, but on disk
633 if ((cur->next_by_base == NULL) &&
634 (base + length <= map->media_size)) {
635 // Expand final free partition
636 if ((istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) &&
637 base >= cur->data->dpme_pblock_start) {
638 cur->data->dpme_pblocks =
639 map->media_size - cur->data->dpme_pblock_start;
640 break;
642 // create an extra free partition
643 if (base >= cur->data->dpme_pblock_start + cur->data->dpme_pblocks) {
644 if (map->maximum_in_map < 0) {
645 limit = map->media_size;
646 } else {
647 limit = map->maximum_in_map;
649 if (map->blocks_in_map + 1 > limit) {
650 printf("the map is not big enough\n");
651 return 0;
653 data = create_data(kFreeName, kFreeType,
654 cur->data->dpme_pblock_start + cur->data->dpme_pblocks,
655 map->media_size - (cur->data->dpme_pblock_start + cur->data->dpme_pblocks));
656 if (data != NULL) {
657 if (add_data_to_map(data, cur->disk_address, map) == 0) {
658 free(data);
663 cur = cur->next_by_base;
666 // if it is not Extra then punt
667 if (cur == NULL
668 || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
669 printf("requested base and length is not "
670 "within an existing free partition\n");
671 return 0;
673 // figure out what to do and sizes
674 data = cur->data;
675 if (data->dpme_pblock_start == base) {
676 // replace or add
677 if (data->dpme_pblocks == length) {
678 act = kReplace;
679 } else {
680 act = kAdd;
681 adjusted_base = base + length;
682 adjusted_length = data->dpme_pblocks - length;
684 } else {
685 // split or add
686 if (data->dpme_pblock_start + data->dpme_pblocks == base + length) {
687 act = kAdd;
688 adjusted_base = data->dpme_pblock_start;
689 adjusted_length = base - adjusted_base;
690 } else {
691 act = kSplit;
692 new_base = data->dpme_pblock_start;
693 new_length = base - new_base;
694 adjusted_base = base + length;
695 adjusted_length = data->dpme_pblocks - (length + new_length);
698 // if the map will overflow then punt
699 if (map->maximum_in_map < 0) {
700 limit = map->media_size;
701 } else {
702 limit = map->maximum_in_map;
704 if (map->blocks_in_map + (int)act > limit) {
705 printf("the map is not big enough\n");
706 return 0;
709 data = create_data(name, dptype, base, length);
710 if (data == NULL) {
711 return 0;
713 if (act == kReplace) {
714 free(cur->data);
715 cur->data = data;
716 } else {
717 // adjust this block's size
718 cur->data->dpme_pblock_start = adjusted_base;
719 cur->data->dpme_pblocks = adjusted_length;
720 cur->data->dpme_lblocks = adjusted_length;
721 // insert new with block address equal to this one
722 if (add_data_to_map(data, cur->disk_address, map) == 0) {
723 free(data);
724 } else if (act == kSplit) {
725 data = create_data(kFreeName, kFreeType, new_base, new_length);
726 if (data != NULL) {
727 // insert new with block address equal to this one
728 if (add_data_to_map(data, cur->disk_address, map) == 0) {
729 free(data);
734 // renumber disk addresses
735 renumber_disk_addresses(map);
736 // mark changed
737 map->changed = 1;
738 return 1;
742 DPME *
743 create_data(const char *name, const char *dptype, u32 base, u32 length)
745 DPME *data;
747 data = (DPME *) calloc(1, PBLOCK_SIZE);
748 if (data == NULL) {
749 error(errno, "can't allocate memory for disk buffers");
750 } else {
751 // set data into entry
752 data->dpme_signature = DPME_SIGNATURE;
753 data->dpme_map_entries = 1;
754 data->dpme_pblock_start = base;
755 data->dpme_pblocks = length;
756 strncpy(data->dpme_name, name, DPISTRLEN);
757 strncpy(data->dpme_type, dptype, DPISTRLEN);
758 data->dpme_lblock_start = 0;
759 data->dpme_lblocks = data->dpme_pblocks;
760 dpme_init_flags(data);
762 return data;
765 void
766 dpme_init_flags(DPME *data)
768 if (istrncmp(data->dpme_type, kHFSType, DPISTRLEN) == 0) { /* XXX this is gross, fix it! */
769 data->dpme_flags = APPLE_HFS_FLAGS_VALUE;
771 else {
772 dpme_writable_set(data, 1);
773 dpme_readable_set(data, 1);
774 dpme_bootable_set(data, 0);
775 dpme_in_use_set(data, 0);
776 dpme_allocated_set(data, 1);
777 dpme_valid_set(data, 1);
781 /* These bits are appropriate for Apple_UNIX_SVR2 partitions
782 * used by NetBSD. They may be ok for A/UX, but have not been
783 * tested.
785 void
786 bzb_init_slice(BZB *bp, int slice)
788 memset(bp,0,sizeof(BZB));
789 if ((slice >= 'A') && (slice <= 'Z')) {
790 slice += 'a' - 'A';
792 if ((slice != 0) && ((slice < 'a') || (slice > 'z'))) {
793 error(-1,"Bad bzb slice");
794 slice = 0;
796 switch (slice) {
797 case 0:
798 case 'c':
799 return;
800 case 'a':
801 bp->bzb_type = FST;
802 strlcpy((char *)bp->bzb_mount_point, "/", sizeof(bp->bzb_mount_point));
803 bp->bzb_inode = 1;
804 bzb_root_set(bp,1);
805 bzb_usr_set(bp,1);
806 break;
807 case 'b':
808 bp->bzb_type = FSTSFS;
809 strlcpy((char *)bp->bzb_mount_point, "(swap)", sizeof(bp->bzb_mount_point));
810 break;
811 case 'g':
812 strlcpy((char *)bp->bzb_mount_point, "/usr", sizeof(bp->bzb_mount_point));
813 /* Fall through */
814 default:
815 bp->bzb_type = FST;
816 bp->bzb_inode = 1;
817 bzb_usr_set(bp,1);
818 break;
820 bzb_slice_set(bp,0); // XXX NetBSD disksubr.c ignores slice
821 // bzb_slice_set(bp,slice-'a'+1);
822 bp->bzb_magic = BZBMAGIC;
825 void
826 renumber_disk_addresses(partition_map_header *map)
828 partition_map * cur;
829 long ix;
831 // reset disk addresses
832 cur = map->disk_order;
833 ix = 1;
834 while (cur != NULL) {
835 cur->disk_address = ix++;
836 cur->data->dpme_map_entries = map->blocks_in_map;
837 cur = cur->next_on_disk;
842 long
843 compute_device_size(partition_map_header *map, partition_map_header *oldmap)
845 #ifdef TEST_COMPUTE
846 unsigned long length;
847 struct hd_geometry geometry;
848 struct stat info;
849 loff_t pos;
850 #endif
851 char* data;
852 unsigned long l, r, x = 0;
853 long long size;
854 int valid = 0;
855 #ifdef TEST_COMPUTE
856 int fd;
858 fd = map->fd->fd;
859 printf("\n");
860 if (fstat(fd, &info) < 0) {
861 printf("stat of device failed\n");
862 } else {
863 printf("stat: mode = 0%o, type=%s\n", info.st_mode,
864 (S_ISREG(info.st_mode)? "Regular":
865 (S_ISBLK(info.st_mode)?"Block":"Other")));
866 printf("size = %d, blocks = %d\n",
867 info.st_size, info.st_size/map->logical_block);
870 if (ioctl(fd, BLKGETSIZE, &length) < 0) {
871 printf("get device size failed\n");
872 } else {
873 printf("BLKGETSIZE:size in blocks = %u\n", length);
876 if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) {
877 printf("get device geometry failed\n");
878 } else {
879 printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d, total=%d\n",
880 geometry.heads, geometry.sectors,
881 geometry.cylinders, geometry.start,
882 geometry.heads*geometry.sectors*geometry.cylinders);
885 if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) {
886 printf("llseek to end of device failed\n");
887 } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) {
888 printf("llseek to end of device failed on second try\n");
889 } else {
890 printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block);
892 #endif
894 if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) {
895 return (oldmap->misc->sbBlkCount
896 * (oldmap->physical_block / map->logical_block));
899 size = media_total_size(map->m);
900 if (size != 0) {
901 return (long)(size / map->logical_block);
904 // else case
906 data = (char *) malloc(PBLOCK_SIZE);
907 if (data == NULL) {
908 error(errno, "can't allocate memory for try buffer");
909 x = 0;
910 } else {
911 // double till off end
912 l = 0;
913 r = 1024;
914 while (read_block(map, r, data) != 0) {
915 l = r;
916 if (r <= 1024) {
917 r = r * 1024;
918 } else {
919 r = r * 2;
921 if (r >= 0x80000000) {
922 r = 0xFFFFFFFE;
923 break;
926 // binary search for end
927 while (l <= r) {
928 x = (r - l) / 2 + l;
929 if ((valid = read_block(map, x, data)) != 0) {
930 l = x + 1;
931 } else {
932 if (x > 0) {
933 r = x - 1;
934 } else {
935 break;
939 if (valid != 0) {
940 x = x + 1;
942 // printf("size in blocks = %d\n", x);
943 free(data);
946 return x;
950 void
951 sync_device_size(partition_map_header *map)
953 Block0 *p;
954 unsigned long size;
955 double d;
957 p = map->misc;
958 if (p == NULL) {
959 return;
961 d = map->media_size;
962 size = (d * map->logical_block) / p->sbBlkSize;
963 if (p->sbBlkCount != size) {
964 p->sbBlkCount = size;
969 void
970 delete_partition_from_map(partition_map *entry)
972 partition_map_header *map;
973 DPME *data;
975 if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) {
976 printf("Can't delete entry for the map itself\n");
977 return;
979 if (entry->contains_driver) {
980 printf("This program can't install drivers\n");
981 if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) {
982 return;
985 // if past end of disk, delete it completely
986 if (entry->next_by_base == NULL &&
987 entry->data->dpme_pblock_start >= entry->the_map->media_size) {
988 if (entry->contains_driver) {
989 remove_driver(entry); // update block0 if necessary
991 delete_entry(entry);
992 return;
994 // If at end of disk, incorporate extra disk space to partition
995 if (entry->next_by_base == NULL) {
996 entry->data->dpme_pblocks =
997 entry->the_map->media_size - entry->data->dpme_pblock_start;
999 data = create_data(kFreeName, kFreeType,
1000 entry->data->dpme_pblock_start, entry->data->dpme_pblocks);
1001 if (data == NULL) {
1002 return;
1004 if (entry->contains_driver) {
1005 remove_driver(entry); // update block0 if necessary
1007 free(entry->data);
1008 free(entry->HFS_name);
1009 entry->HFS_kind = kHFS_not;
1010 entry->HFS_name = 0;
1011 entry->data = data;
1012 combine_entry(entry);
1013 map = entry->the_map;
1014 renumber_disk_addresses(map);
1015 map->changed = 1;
1020 contains_driver(partition_map *entry)
1022 partition_map_header *map;
1023 Block0 *p;
1024 DDMap *m;
1025 int i;
1026 int f;
1027 u32 start;
1029 map = entry->the_map;
1030 p = map->misc;
1031 if (p == NULL) {
1032 return 0;
1034 if (p->sbSig != BLOCK0_SIGNATURE) {
1035 return 0;
1037 if (map->logical_block > p->sbBlkSize) {
1038 return 0;
1039 } else {
1040 f = p->sbBlkSize / map->logical_block;
1042 if (p->sbDrvrCount > 0) {
1043 m = (DDMap *) p->sbMap;
1044 for (i = 0; i < p->sbDrvrCount; i++) {
1045 start = get_align_long(&m[i].ddBlock);
1046 if (entry->data->dpme_pblock_start <= f*start
1047 && f*(start + m[i].ddSize)
1048 <= (entry->data->dpme_pblock_start
1049 + entry->data->dpme_pblocks)) {
1050 return 1;
1054 return 0;
1058 void
1059 combine_entry(partition_map *entry)
1061 partition_map *p;
1062 u32 end;
1064 if (entry == NULL
1065 || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1066 return;
1068 if (entry->next_by_base != NULL) {
1069 p = entry->next_by_base;
1070 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1071 // next is not free
1072 } else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1073 != p->data->dpme_pblock_start) {
1074 // next is not contiguous (XXX this is bad)
1075 printf("next entry is not contiguous\n");
1076 // start is already minimum
1077 // new end is maximum of two ends
1078 end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1079 if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1080 entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start;
1082 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1083 delete_entry(p);
1084 } else {
1085 entry->data->dpme_pblocks += p->data->dpme_pblocks;
1086 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1087 delete_entry(p);
1090 if (entry->prev_by_base != NULL) {
1091 p = entry->prev_by_base;
1092 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1093 // previous is not free
1094 } else if (p->data->dpme_pblock_start + p->data->dpme_pblocks
1095 != entry->data->dpme_pblock_start) {
1096 // previous is not contiguous (XXX this is bad)
1097 printf("previous entry is not contiguous\n");
1098 // new end is maximum of two ends
1099 end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
1100 if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
1101 end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks;
1103 entry->data->dpme_pblocks = end - p->data->dpme_pblock_start;
1104 // new start is previous entry's start
1105 entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1106 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1107 delete_entry(p);
1108 } else {
1109 entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
1110 entry->data->dpme_pblocks += p->data->dpme_pblocks;
1111 entry->data->dpme_lblocks = entry->data->dpme_pblocks;
1112 delete_entry(p);
1115 entry->contains_driver = contains_driver(entry);
1119 void
1120 delete_entry(partition_map *entry)
1122 partition_map_header *map;
1123 partition_map *p;
1125 map = entry->the_map;
1126 map->blocks_in_map--;
1128 remove_from_disk_order(entry);
1130 p = entry->next_by_base;
1131 if (map->base_order == entry) {
1132 map->base_order = p;
1134 if (p != NULL) {
1135 p->prev_by_base = entry->prev_by_base;
1137 if (entry->prev_by_base != NULL) {
1138 entry->prev_by_base->next_by_base = p;
1141 free(entry->data);
1142 free(entry->HFS_name);
1143 free(entry);
1147 partition_map *
1148 find_entry_by_disk_address(long ix, partition_map_header *map)
1150 partition_map * cur;
1152 cur = map->disk_order;
1153 while (cur != NULL) {
1154 if (cur->disk_address == ix) {
1155 break;
1157 cur = cur->next_on_disk;
1159 return cur;
1163 partition_map *
1164 find_entry_by_type(const char *type_name, partition_map_header *map)
1166 partition_map * cur;
1168 cur = map->base_order;
1169 while (cur != NULL) {
1170 if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) {
1171 break;
1173 cur = cur->next_by_base;
1175 return cur;
1178 partition_map *
1179 find_entry_by_base(u32 base, partition_map_header *map)
1181 partition_map * cur;
1183 cur = map->base_order;
1184 while (cur != NULL) {
1185 if (cur->data->dpme_pblock_start == base) {
1186 break;
1188 cur = cur->next_by_base;
1190 return cur;
1194 void
1195 move_entry_in_map(long old_index, long ix, partition_map_header *map)
1197 partition_map * cur;
1199 cur = find_entry_by_disk_address(old_index, map);
1200 if (cur == NULL) {
1201 printf("No such partition\n");
1202 } else {
1203 remove_from_disk_order(cur);
1204 cur->disk_address = ix;
1205 insert_in_disk_order(cur);
1206 renumber_disk_addresses(map);
1207 map->changed = 1;
1212 void
1213 remove_from_disk_order(partition_map *entry)
1215 partition_map_header *map;
1216 partition_map *p;
1218 map = entry->the_map;
1219 p = entry->next_on_disk;
1220 if (map->disk_order == entry) {
1221 map->disk_order = p;
1223 if (p != NULL) {
1224 p->prev_on_disk = entry->prev_on_disk;
1226 if (entry->prev_on_disk != NULL) {
1227 entry->prev_on_disk->next_on_disk = p;
1229 entry->next_on_disk = NULL;
1230 entry->prev_on_disk = NULL;
1234 void
1235 insert_in_disk_order(partition_map *entry)
1237 partition_map_header *map;
1238 partition_map * cur;
1240 // find position in disk list & insert
1241 map = entry->the_map;
1242 cur = map->disk_order;
1243 if (cur == NULL || entry->disk_address <= cur->disk_address) {
1244 map->disk_order = entry;
1245 entry->next_on_disk = cur;
1246 if (cur != NULL) {
1247 cur->prev_on_disk = entry;
1249 entry->prev_on_disk = NULL;
1250 } else {
1251 for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) {
1252 if (cur->disk_address <= entry->disk_address
1253 && (cur->next_on_disk == NULL
1254 || entry->disk_address <= cur->next_on_disk->disk_address)) {
1255 entry->next_on_disk = cur->next_on_disk;
1256 cur->next_on_disk = entry;
1257 entry->prev_on_disk = cur;
1258 if (entry->next_on_disk != NULL) {
1259 entry->next_on_disk->prev_on_disk = entry;
1261 break;
1268 void
1269 insert_in_base_order(partition_map *entry)
1271 partition_map_header *map;
1272 partition_map * cur;
1274 // find position in base list & insert
1275 map = entry->the_map;
1276 cur = map->base_order;
1277 if (cur == NULL
1278 || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) {
1279 map->base_order = entry;
1280 entry->next_by_base = cur;
1281 if (cur != NULL) {
1282 cur->prev_by_base = entry;
1284 entry->prev_by_base = NULL;
1285 } else {
1286 for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) {
1287 if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start
1288 && (cur->next_by_base == NULL
1289 || entry->data->dpme_pblock_start
1290 <= cur->next_by_base->data->dpme_pblock_start)) {
1291 entry->next_by_base = cur->next_by_base;
1292 cur->next_by_base = entry;
1293 entry->prev_by_base = cur;
1294 if (entry->next_by_base != NULL) {
1295 entry->next_by_base->prev_by_base = entry;
1297 break;
1304 void
1305 resize_map(unsigned long new_size, partition_map_header *map)
1307 partition_map * entry;
1308 partition_map * next;
1309 unsigned int incr;
1311 // find map entry
1312 entry = find_entry_by_type(kMapType, map);
1314 if (entry == NULL) {
1315 printf("Couldn't find entry for map!\n");
1316 return;
1318 next = entry->next_by_base;
1320 // same size
1321 if (new_size == entry->data->dpme_pblocks) {
1322 // do nothing
1323 return;
1326 // make it smaller
1327 if (new_size < entry->data->dpme_pblocks) {
1328 if (next == NULL
1329 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1330 incr = 1;
1331 } else {
1332 incr = 0;
1334 if (new_size < map->blocks_in_map + incr) {
1335 printf("New size would be too small\n");
1336 return;
1338 goto doit;
1341 // make it larger
1342 if (next == NULL
1343 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
1344 printf("No free space to expand into\n");
1345 return;
1347 if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
1348 != next->data->dpme_pblock_start) {
1349 printf("No contiguous free space to expand into\n");
1350 return;
1352 if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) {
1353 printf("No enough free space\n");
1354 return;
1356 doit:
1357 entry->data->dpme_type[0] = 0;
1358 delete_partition_from_map(entry);
1359 add_partition_to_map("Apple", kMapType, 1, new_size, map);
1360 map->maximum_in_map = new_size;
1364 void
1365 remove_driver(partition_map *entry)
1367 partition_map_header *map;
1368 Block0 *p;
1369 DDMap *m;
1370 int i;
1371 int j;
1372 int f;
1373 u32 start;
1375 map = entry->the_map;
1376 p = map->misc;
1377 if (p == NULL) {
1378 return;
1380 if (p->sbSig != BLOCK0_SIGNATURE) {
1381 return;
1383 if (map->logical_block > p->sbBlkSize) {
1384 /* this is not supposed to happen, but let's just ignore it. */
1385 return;
1386 } else {
1388 * compute the factor to convert the block numbers in block0
1389 * into partition map block numbers.
1391 f = p->sbBlkSize / map->logical_block;
1393 if (p->sbDrvrCount > 0) {
1394 m = (DDMap *) p->sbMap;
1395 for (i = 0; i < p->sbDrvrCount; i++) {
1396 start = get_align_long(&m[i].ddBlock);
1398 /* zap the driver if it is wholly contained in the partition */
1399 if (entry->data->dpme_pblock_start <= f*start
1400 && f*(start + m[i].ddSize)
1401 <= (entry->data->dpme_pblock_start
1402 + entry->data->dpme_pblocks)) {
1403 // delete this driver
1404 // by copying down later ones and zapping the last
1405 for (j = i+1; j < p->sbDrvrCount; j++, i++) {
1406 put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock);
1407 m[i].ddSize = m[j].ddSize;
1408 m[i].ddType = m[j].ddType;
1410 put_align_long(0, &m[i].ddBlock);
1411 m[i].ddSize = 0;
1412 m[i].ddType = 0;
1413 p->sbDrvrCount -= 1;
1414 return; /* XXX if we continue we will delete other drivers? */
1421 read_block(partition_map_header *map, unsigned long num, char *buf)
1423 //printf("read block %d\n", num);
1424 return read_media(map->m, ((long long) num) * map->logical_block,
1425 PBLOCK_SIZE, (void *)buf);
1430 write_block(partition_map_header *map, unsigned long num, char *buf)
1432 return write_media(map->m, ((long long) num) * map->logical_block,
1433 PBLOCK_SIZE, (void *)buf);