summaryrefslogtreecommitdiffstats
path: root/perl-install/partition_table_mac.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/partition_table_mac.pm')
-rw-r--r--perl-install/partition_table_mac.pm303
1 files changed, 303 insertions, 0 deletions
diff --git a/perl-install/partition_table_mac.pm b/perl-install/partition_table_mac.pm
new file mode 100644
index 000000000..61e741f4b
--- /dev/null
+++ b/perl-install/partition_table_mac.pm
@@ -0,0 +1,303 @@
+package partition_table_mac;
+
+use diagnostics;
+use strict;
+use vars qw(@ISA);
+
+@ISA = qw(partition_table_raw);
+
+use common qw(:common :system :file :functional);
+use partition_table_raw;
+use partition_table;
+use c;
+
+my %typeToDos = (
+ "Apple_partition_map" => 0x401,
+ "Apple_Driver43" => 0x401,
+ "Apple_Driver_IOKit" => 0x401,
+ "Apple_Patches" => 0x401,
+ "Apple_HFS" => 0x402,
+ "Apple_UNIX_SVR2" => 0x83,
+ "Apple_Free" => 0x0,
+);
+my %typeFromDos = reverse %typeToDos;
+
+
+my ($bz_format, $bz_fields) = list2kv(
+ n => 'bzSig',
+ n => 'bzBlkSize',
+ N => 'bzBlkCnt',
+ n => 'bzDevType',
+ n => 'bzDevID',
+ N => 'bzReserved',
+ n => 'bzDrvrCnt',
+);
+$bz_format = join '', @$bz_format;
+
+
+my ($dd_format, $dd_fields) = list2kv(
+ N => 'ddBlock',
+ n => 'ddSize',
+ n => 'ddType',
+);
+$dd_format = join '', @$dd_format;
+
+
+my ($p_format, $p_fields) = list2kv(
+ n => 'pSig',
+ n => 'pSigPad',
+ N => 'pMapEntry',
+ N => 'pPBlockStart',
+ N => 'pPBlocks',
+
+ a32 => 'pName',
+ a32 => 'pType',
+
+ N => 'pLBlockStart',
+ N => 'pLBlocks',
+ N => 'pFlags',
+ N => 'pBootBlock',
+ N => 'pBootBytes',
+
+ N => 'pAddrs1',
+ N => 'pAddrs2',
+ N => 'pAddrs3',
+ N => 'pAddrs4',
+ N => 'pChecksum',
+
+ a16 => 'pProcID',
+ a128 => 'pBootArgs',
+ a248 => 'pReserved',
+);
+$p_format = join '', @$p_format;
+
+my $magic = 0x4552;
+my $pmagic = 0x504D;
+
+sub adjustStart($$) {
+ my ($hd, $part) = @_;
+}
+sub adjustEnd($$) {
+ my ($hd, $part) = @_;
+}
+
+sub read($$) {
+ my ($hd, $sector) = @_;
+ my $tmp;
+
+ local *F; partition_table_raw::openit($hd, *F) or die "failed to open device";
+ c::lseek_sector(fileno(F), $sector, 0) or die "reading of partition in sector $sector failed";
+
+ sysread F, $tmp, psizeof($bz_format) or die "error while reading bz \(Block Zero\) in sector $sector";
+ my %info; @info{@$bz_fields} = unpack $bz_format, $tmp;
+ my $i;
+
+ foreach $i (0 .. $info{bzDrvrCnt}-1) {
+ sysread F, $tmp, psizeof($dd_format) or die "error while reading driver data in sector $sector";
+ $info{ddMap}[$i] = unpack $dd_format, $tmp;
+ }
+
+ #- check magic number
+ $info{bzSig} == $magic or die "bad magic number";
+
+ my $numparts;
+ c::lseek_sector(fileno(F), $sector, 516) or die "reading of partition in sector $sector failed";
+ sysread F, $tmp, 4 or die "error while reading partition info in sector $sector";
+ $numparts = unpack "N", $tmp;
+
+ my $partmapsize;
+ c::lseek_sector(fileno(F), $sector, 524) or die "reading of partition in sector $sector failed";
+ sysread F, $tmp, 4 or die "error while reading partition info in sector $sector";
+ $partmapsize = ((unpack "N", $tmp) * $info{bzBlkSize}) / psizeof($p_format);
+
+ c::lseek_sector(fileno(F), $sector, 512) or die "reading of partition in sector $sector failed";
+
+ my @pt;
+ for($i=0;$i<$partmapsize;$i++) {
+ my $part;
+ sysread F, $part, psizeof($p_format) or die "error while reading partition info in sector $sector";
+
+ push @pt, map {
+ my %h; @h{@$p_fields} = unpack $p_format, $part;
+ if ($i < $numparts && $h{pSig} eq $pmagic) {
+
+ $h{size} = ($h{pPBlocks} * $info{bzBlkSize}) / 512;
+ $h{start} = ($h{pPBlockStart} * $info{bzBlkSize}) / 512;
+
+ if ($h{pType} =~ /^Apple_UNIX_SVR2/i) {
+ $h{pName} =~ /swap/i ? ($h{type} = 0x82) : ($h{type} = 0x83);
+ } elsif ($h{pType} =~ /^Apple_Free/i) {
+ $h{type} = 0x0;
+ } elsif ($h{pType} =~ /^Apple_HFS/i) {
+ $h{type} = 0x402;
+ } elsif ($h{pType} =~ /^Apple_Partition_Map/i) {
+ $h{type} = 0x401;
+ $h{isMap} = 1;
+ } else {
+ $h{type} = 0x401;
+ };
+ }
+ \%h;
+ } [ $part ];
+ };
+
+ [ @pt ], \%info;
+}
+
+sub write($$$;$) {
+ my ($hd, $sector, $pt, $info) = @_;
+
+ #- handle testing for writing partition table on file only!
+ local *F;
+ if ($::testing) {
+ my $file = "/tmp/partition_table_$hd->{device}";
+ open F, ">$file" or die "error opening test file $file";
+ } else {
+ partition_table_raw::openit($hd, *F, 2) or die "error opening device $hd->{device} for writing";
+ c::lseek_sector(fileno(F), $sector, 0) or return 0;
+ }
+
+ # Find the partition map.
+ my @partstowrite;
+ my $part = $pt->[0];
+ (defined $part->{isMap}) or die "the first partition is not the partition map";
+ push @partstowrite, $part;
+
+ # Now go thru the partitions, sort and fill gaps.
+ my $last;
+ while($part) {
+ $last = $part;
+ $part = &partition_table::next($hd, $part);
+ $part or last;
+
+ if($last->{start} + $last->{size} < $part->{start}) {
+ #There is a gap between partitions. Fill it and move on.
+ push @partstowrite, {
+ type => 0x0,
+ start => $last->{start} + $last->{size},
+ size => $part->{start} - ($last->{start} + $last->{size}),
+ };
+ }
+ push @partstowrite, $part;
+ };
+
+ # now, fill a gap at the end if there is one.
+ if($last->{start} + $last->{size} < $hd->{totalsectors}) {
+ push @partstowrite, {
+ type => 0x0,
+ start => $last->{start} + $last->{size},
+ size => $hd->{totalsectors} - ($last->{start} + $last->{size}),
+ };
+ }
+
+ # Since we didn't create any new drivers, let's try and match up our driver records with out partitons and see if any are missing.
+ my $i;
+ my @ddstowrite;
+ foreach $i ( 0 .. $info->{bzDrvrCnt} - 1) {
+ my $ddBlock = $_->{ddBlock};
+ my $dd = $_;
+ foreach(@partstowrite) {
+ $ddBlock == $_->{pPBlockStart} and push @ddstowrite, $dd;
+ }
+ }
+
+ # Now let's write our first block.
+ syswrite F, pack($bz_format, @$info{@$bz_fields}), psizeof($bz_format) or return 0;
+
+ # ...and now the driver information.
+ foreach $i ( 0 .. $info->{bzDrvrCnt} - 1) {
+ syswrite F, pack($dd_format, $ddstowrite[$i]{@$dd_fields}), psizeof($dd_format) or return 0;
+ }
+ # zero the rest of the data in the first block.
+ foreach $i ( 1 .. (494 - ($info->{bzDrvrCnt} * 8))) {
+ syswrite F, "\0", 1 or return 0;
+ }
+ #c::lseek_sector(fileno(F), $sector, 512) or return 0;
+ # Now, we iterate thru the partstowrite and write them.
+ foreach (@partstowrite) {
+ if (!defined $_->{pSig}) {
+ # The values we need to write to disk are not defined. Let's make them up.
+ $_->{pSig} = $pmagic;
+ $_->{pSigPad} = 0;
+ $_->{pPBlockStart} = ($_->{start} * 512) / $info->{bzBlkSize};
+ $_->{pPBlocks} = ($_->{size} * 512) / $info->{bzBlkSize};
+ $_->{pLBlockStart} = 0;
+ $_->{pLBlocks} = $_->{pPBlocks};
+ $_->{pBootBlock} = 0;
+ $_->{pBootBytes} = 0;
+ $_->{pAddrs1} = 0;
+ $_->{pAddrs2} = 0;
+ $_->{pAddrs3} = 0;
+ $_->{pAddrs4} = 0;
+ $_->{pChecksum} = 0;
+ $_->{pProcID} = "\0";
+ $_->{pBootArgs} = "\0";
+ $_->{pReserved} = "\0";
+
+ if($_->{type} == 0x402) {
+ $_->{pType} = "Apple_HFS";
+ $_->{pName} = "MacOS";
+ $_->{pFlags} = 0x4000037F;
+ } elsif ($_->{type} == 0x401 && $_->{start} == 1) {
+ $_->{pType} = "Apple_Partition_Map";
+ $_->{pName} = "Apple";
+ $_->{pFlags} = 0x33;
+ } elsif ($_->{type} == 0x82) {
+ $_->{pType} = "Apple_UNIX_SVR2";
+ $_->{pName} = "swap";
+ $_->{pFlags} = 0x33;
+ } elsif ($_->{type} == 0x83) {
+ $_->{pType} = "Apple_UNIX_SVR2";
+ $_->{pName} = "Linux Native";
+ $_->{pFlags} = 0x33;
+ } elsif ($_->{type} == 0x0) {
+ $_->{pType} = "Apple_Free";
+ $_->{pName} = "Extra";
+ $_->{pFlags} = 0x31;
+ }
+ };
+ $_->{pMapEntry} = @partstowrite;
+ syswrite F, pack($p_format, @$_{@$p_fields}), psizeof($p_format) or return 0;
+ }
+
+ sync();
+
+ 1;
+}
+
+sub info {
+ my ($hd) = @_;
+
+ # - Build the first block of the drive.
+
+ my $info = {
+ bzSig => $magic,
+ bzBlkSize => 512,
+ bzBlkCnt => $hd->{totalsectors},
+ bzDevType => 0,
+ bzDevID => 0,
+ bzReserved => 0,
+ bzDrvrCnt => 0,
+ };
+
+ $info;
+}
+
+sub clear_raw {
+ my ($hd) = @_;
+ my $pt = { raw => [ ({}) x 63 ], info => info($hd) };
+
+ #- handle special case for partition 1 which is the partition map.
+ my $part = {
+ type => 0x401,
+ start => 1,
+ size => 63,
+ isMap => 1,
+ };
+
+ $pt->{raw}[0] = $part;
+ push @{$pt->{normal}}, $part;
+ $pt;
+}
+
+1;