2 // partition_map.c - partition map routines
4 // Written by Eryk Vershen
8 * Copyright 1996,1997,1998 by Apple Computer, Inc.
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.
31 // for malloc(), calloc() & free()
38 // for strncpy() & strcmp()
40 // for O_RDONLY & O_RDWR
45 #include "partition_map.h"
48 #include "deblock_media.h"
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
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";
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
);
117 partition_map_header
*
118 open_partition_map(char *name
, int *valid_file
, int ask_logical_size
)
121 partition_map_header
* map
;
125 m
= open_pathname_as_media(name
, (rflag
)?O_RDONLY
:O_RDWR
);
127 m
= open_pathname_as_media(name
, O_RDONLY
);
129 error(errno
, "can't open file '%s'", name
);
140 map
= (partition_map_header
*) malloc(sizeof(partition_map_header
));
142 error(errno
, "can't allocate memory for open partition map");
147 map
->writable
= (rflag
)?0:writable
;
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
);
156 map
->misc
= (Block0
*) malloc(PBLOCK_SIZE
);
157 if (map
->misc
== NULL
) {
158 error(errno
, "can't allocate memory for block zero buffer");
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
);
170 map
->physical_block
= map
->misc
->sbBlkSize
;
171 //printf("physical block size is %d\n", map->physical_block);
173 if (ask_logical_size
&& interactive
) {
175 printf("A logical block is %ld bytes: ", size
);
177 get_number_argument("what should be the logical block size? ",
179 size
= (size
/ PBLOCK_SIZE
) * PBLOCK_SIZE
;
180 if (size
< PBLOCK_SIZE
) {
183 map
->logical_block
= size
;
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
205 close_partition_map(map
);
211 close_partition_map(partition_map_header
*map
)
213 partition_map
* entry
;
214 partition_map
* next
;
222 for (entry
= map
->disk_order
; entry
!= NULL
; entry
= next
) {
223 next
= entry
->next_on_disk
;
225 free(entry
->HFS_name
);
234 read_partition_map(partition_map_header
*map
)
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
);
246 error(errno
, "can't allocate memory for disk buffers");
250 if (read_block(map
, 1, (char *)data
) == 0) {
251 error(-1, "Can't read block 1 from '%s'", map
->name
);
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
);
263 } else if (convert_dpme(data
, 1) == 0
264 && data
->dpme_signature
== DPME_SIGNATURE
) {
266 map
->media_size
= (d
* old_logical
) / map
->logical_block
;
269 map
->logical_block
*= 2;
271 if (map
->logical_block
> map
->physical_block
) {
272 error(-1, "No valid block 1 on '%s'", map
->name
);
277 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
279 limit
= data
->dpme_map_entries
;
282 if (add_data_to_map(data
, ix
, map
) == 0) {
293 data
= (DPME
*) malloc(PBLOCK_SIZE
);
295 error(errno
, "can't allocate memory for disk buffers");
299 if (read_block(map
, ix
, (char *)data
) == 0) {
300 error(-1, "Can't read block %u from '%s'", ix
, map
->name
);
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
);
316 write_partition_map(partition_map_header
*map
)
320 partition_map
* entry
;
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);
330 block
= (char *) calloc(1, PBLOCK_SIZE
);
332 result
= write_block(map
, 0, block
);
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
;
345 error(errno
, "Unable to write block %d", i
);
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
) {
353 block
= (char *) malloc(PBLOCK_SIZE
);
355 if (read_block(map
, i
, block
)) {
357 write_block(map
, i
, block
);
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
));
379 error(errno
, "can't allocate memory for map entries");
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
;
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
;
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) {
418 map
= create_partition_map(name
, oldmap
);
422 close_partition_map(oldmap
);
424 add_partition_to_map("Apple", kMapType
,
425 1, (map
->media_size
<= 128? 2: 63), map
);
430 partition_map_header
*
431 create_partition_map(char *name
, partition_map_header
*oldmap
)
434 partition_map_header
* map
;
436 unsigned long default_number
;
437 unsigned long number
;
439 unsigned long multiple
;
441 m
= open_pathname_as_media(name
, (rflag
)?O_RDONLY
:O_RDWR
);
443 error(errno
, "can't open file '%s' for %sing", name
,
444 (rflag
)?"read":"writ");
448 map
= (partition_map_header
*) malloc(sizeof(partition_map_header
));
450 error(errno
, "can't allocate memory for open partition map");
455 map
->writable
= (rflag
)?0:1;
457 map
->disk_order
= NULL
;
458 map
->base_order
= NULL
;
460 if (oldmap
!= NULL
) {
461 size
= oldmap
->physical_block
;
463 size
= media_granularity(m
);
465 m
= open_deblock_media(PBLOCK_SIZE
, m
);
468 printf("A physical block is %ld bytes: ", size
);
470 get_number_argument("what should be the physical block size? ",
472 size
= (size
/ PBLOCK_SIZE
) * PBLOCK_SIZE
;
473 if (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
;
489 printf("A logical block is %ld bytes: ", size
);
491 get_number_argument("what should be the logical block size? ",
493 size
= (size
/ PBLOCK_SIZE
) * PBLOCK_SIZE
;
494 if (size
< PBLOCK_SIZE
) {
499 if (size
> map
->physical_block
) {
500 size
= map
->physical_block
;
503 map
->logical_block
= size
;
505 map
->blocks_in_map
= 0;
506 map
->maximum_in_map
= -1;
508 number
= compute_device_size(map
, oldmap
);
510 printf("size of 'device' is %lu blocks (%d byte blocks): ",
511 number
, map
->logical_block
);
512 default_number
= number
;
515 if (get_number_argument("what should be the size? ",
516 (long *)&number
, default_number
) == 0) {
517 printf("Not a number\n");
521 multiple
= get_multiplier(map
->logical_block
);
523 printf("Bad multiplier\n");
525 } else if (multiple
!= 1) {
526 if (0xFFFFFFFF/multiple
< number
) {
527 printf("Number too large\n");
534 default_number
= kDefault
;
535 } while (number
== 0);
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");
551 sync_device_size(map
);
553 data
= (DPME
*) calloc(1, PBLOCK_SIZE
);
555 error(errno
, "can't allocate memory for disk buffers");
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) {
580 close_partition_map(map
);
586 coerce_block0(partition_map_header
*map
)
594 if (p
->sbSig
!= BLOCK0_SIGNATURE
) {
595 p
->sbSig
= BLOCK0_SIGNATURE
;
596 if (map
->physical_block
== 1) {
597 p
->sbBlkSize
= PBLOCK_SIZE
;
599 p
->sbBlkSize
= map
->physical_block
;
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
)
619 u32 adjusted_base
= 0;
620 u32 adjusted_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
)) {
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
;
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
;
647 limit
= map
->maximum_in_map
;
649 if (map
->blocks_in_map
+ 1 > limit
) {
650 printf("the map is not big enough\n");
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
));
657 if (add_data_to_map(data
, cur
->disk_address
, map
) == 0) {
663 cur
= cur
->next_by_base
;
666 // if it is not Extra then punt
668 || istrncmp(cur
->data
->dpme_type
, kFreeType
, DPISTRLEN
) != 0) {
669 printf("requested base and length is not "
670 "within an existing free partition\n");
673 // figure out what to do and sizes
675 if (data
->dpme_pblock_start
== base
) {
677 if (data
->dpme_pblocks
== length
) {
681 adjusted_base
= base
+ length
;
682 adjusted_length
= data
->dpme_pblocks
- length
;
686 if (data
->dpme_pblock_start
+ data
->dpme_pblocks
== base
+ length
) {
688 adjusted_base
= data
->dpme_pblock_start
;
689 adjusted_length
= base
- adjusted_base
;
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
;
702 limit
= map
->maximum_in_map
;
704 if (map
->blocks_in_map
+ (int)act
> limit
) {
705 printf("the map is not big enough\n");
709 data
= create_data(name
, dptype
, base
, length
);
713 if (act
== kReplace
) {
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) {
724 } else if (act
== kSplit
) {
725 data
= create_data(kFreeName
, kFreeType
, new_base
, new_length
);
727 // insert new with block address equal to this one
728 if (add_data_to_map(data
, cur
->disk_address
, map
) == 0) {
734 // renumber disk addresses
735 renumber_disk_addresses(map
);
743 create_data(const char *name
, const char *dptype
, u32 base
, u32 length
)
747 data
= (DPME
*) calloc(1, PBLOCK_SIZE
);
749 error(errno
, "can't allocate memory for disk buffers");
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
);
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
;
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
786 bzb_init_slice(BZB
*bp
, int slice
)
788 memset(bp
,0,sizeof(BZB
));
789 if ((slice
>= 'A') && (slice
<= 'Z')) {
792 if ((slice
!= 0) && ((slice
< 'a') || (slice
> 'z'))) {
793 error(-1,"Bad bzb slice");
802 strlcpy((char *)bp
->bzb_mount_point
, "/", sizeof(bp
->bzb_mount_point
));
808 bp
->bzb_type
= FSTSFS
;
809 strlcpy((char *)bp
->bzb_mount_point
, "(swap)", sizeof(bp
->bzb_mount_point
));
812 strlcpy((char *)bp
->bzb_mount_point
, "/usr", sizeof(bp
->bzb_mount_point
));
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
;
826 renumber_disk_addresses(partition_map_header
*map
)
831 // reset disk addresses
832 cur
= map
->disk_order
;
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
;
843 compute_device_size(partition_map_header
*map
, partition_map_header
*oldmap
)
846 unsigned long length
;
847 struct hd_geometry geometry
;
852 unsigned long l
, r
, x
= 0;
860 if (fstat(fd
, &info
) < 0) {
861 printf("stat of device failed\n");
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");
873 printf("BLKGETSIZE:size in blocks = %u\n", length
);
876 if (ioctl(fd
, HDIO_GETGEO
, &geometry
) < 0) {
877 printf("get device geometry failed\n");
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");
890 printf("llseek: pos = %d, blocks=%d\n", pos
, pos
/map
->logical_block
);
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
);
901 return (long)(size
/ map
->logical_block
);
906 data
= (char *) malloc(PBLOCK_SIZE
);
908 error(errno
, "can't allocate memory for try buffer");
911 // double till off end
914 while (read_block(map
, r
, data
) != 0) {
921 if (r
>= 0x80000000) {
926 // binary search for end
929 if ((valid
= read_block(map
, x
, data
)) != 0) {
942 // printf("size in blocks = %d\n", x);
951 sync_device_size(partition_map_header
*map
)
962 size
= (d
* map
->logical_block
) / p
->sbBlkSize
;
963 if (p
->sbBlkCount
!= size
) {
964 p
->sbBlkCount
= size
;
970 delete_partition_from_map(partition_map
*entry
)
972 partition_map_header
*map
;
975 if (istrncmp(entry
->data
->dpme_type
, kMapType
, DPISTRLEN
) == 0) {
976 printf("Can't delete entry for the map itself\n");
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) {
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
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
);
1004 if (entry
->contains_driver
) {
1005 remove_driver(entry
); // update block0 if necessary
1008 free(entry
->HFS_name
);
1009 entry
->HFS_kind
= kHFS_not
;
1010 entry
->HFS_name
= 0;
1012 combine_entry(entry
);
1013 map
= entry
->the_map
;
1014 renumber_disk_addresses(map
);
1020 contains_driver(partition_map
*entry
)
1022 partition_map_header
*map
;
1029 map
= entry
->the_map
;
1034 if (p
->sbSig
!= BLOCK0_SIGNATURE
) {
1037 if (map
->logical_block
> p
->sbBlkSize
) {
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
)) {
1059 combine_entry(partition_map
*entry
)
1065 || istrncmp(entry
->data
->dpme_type
, kFreeType
, DPISTRLEN
) != 0) {
1068 if (entry
->next_by_base
!= NULL
) {
1069 p
= entry
->next_by_base
;
1070 if (istrncmp(p
->data
->dpme_type
, kFreeType
, DPISTRLEN
) != 0) {
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
;
1085 entry
->data
->dpme_pblocks
+= p
->data
->dpme_pblocks
;
1086 entry
->data
->dpme_lblocks
= entry
->data
->dpme_pblocks
;
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
;
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
;
1115 entry
->contains_driver
= contains_driver(entry
);
1120 delete_entry(partition_map
*entry
)
1122 partition_map_header
*map
;
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
;
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
;
1142 free(entry
->HFS_name
);
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
) {
1157 cur
= cur
->next_on_disk
;
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) {
1173 cur
= cur
->next_by_base
;
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
) {
1188 cur
= cur
->next_by_base
;
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
);
1201 printf("No such partition\n");
1203 remove_from_disk_order(cur
);
1204 cur
->disk_address
= ix
;
1205 insert_in_disk_order(cur
);
1206 renumber_disk_addresses(map
);
1213 remove_from_disk_order(partition_map
*entry
)
1215 partition_map_header
*map
;
1218 map
= entry
->the_map
;
1219 p
= entry
->next_on_disk
;
1220 if (map
->disk_order
== entry
) {
1221 map
->disk_order
= p
;
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
;
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
;
1247 cur
->prev_on_disk
= entry
;
1249 entry
->prev_on_disk
= NULL
;
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
;
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
;
1278 || entry
->data
->dpme_pblock_start
<= cur
->data
->dpme_pblock_start
) {
1279 map
->base_order
= entry
;
1280 entry
->next_by_base
= cur
;
1282 cur
->prev_by_base
= entry
;
1284 entry
->prev_by_base
= NULL
;
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
;
1305 resize_map(unsigned long new_size
, partition_map_header
*map
)
1307 partition_map
* entry
;
1308 partition_map
* next
;
1312 entry
= find_entry_by_type(kMapType
, map
);
1314 if (entry
== NULL
) {
1315 printf("Couldn't find entry for map!\n");
1318 next
= entry
->next_by_base
;
1321 if (new_size
== entry
->data
->dpme_pblocks
) {
1327 if (new_size
< entry
->data
->dpme_pblocks
) {
1329 || istrncmp(next
->data
->dpme_type
, kFreeType
, DPISTRLEN
) != 0) {
1334 if (new_size
< map
->blocks_in_map
+ incr
) {
1335 printf("New size would be too small\n");
1343 || istrncmp(next
->data
->dpme_type
, kFreeType
, DPISTRLEN
) != 0) {
1344 printf("No free space to expand into\n");
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");
1352 if (new_size
> entry
->data
->dpme_pblocks
+ next
->data
->dpme_pblocks
) {
1353 printf("No enough free space\n");
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
;
1365 remove_driver(partition_map
*entry
)
1367 partition_map_header
*map
;
1375 map
= entry
->the_map
;
1380 if (p
->sbSig
!= BLOCK0_SIGNATURE
) {
1383 if (map
->logical_block
> p
->sbBlkSize
) {
1384 /* this is not supposed to happen, but let's just ignore it. */
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
);
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
);