mirror of
https://abf.rosa.ru/djam/livecd-tools.git
synced 2025-02-23 07:33:00 +00:00
When patching partition table in iso, also update GPT
This commit is contained in:
parent
354d318b40
commit
d1567340b3
1 changed files with 93 additions and 0 deletions
93
rosa-image-fix-x86.pl
Normal file → Executable file
93
rosa-image-fix-x86.pl
Normal file → Executable file
|
@ -4,6 +4,7 @@ use strict;
|
|||
use warnings;
|
||||
|
||||
use Fcntl ':seek';
|
||||
use String::CRC32;
|
||||
|
||||
if (scalar(@ARGV) < 1) {
|
||||
print "Usage: $0 iso-image-file\n";
|
||||
|
@ -15,6 +16,9 @@ my $file;
|
|||
open($file, '+<', $filename) or die "Failed to open file $filename for read-write: $!";
|
||||
binmode($file);
|
||||
|
||||
################################################################################
|
||||
# Fixing MBR
|
||||
|
||||
# Read the first sector (512 bytes) containing the MBR
|
||||
my $mbr;
|
||||
read($file, $mbr, 512) or die "Failed to read the MBR sector: $!";
|
||||
|
@ -43,4 +47,93 @@ substr($mbr, 446, 32) = "\x80" . $partition2 . ("\x00" x 16);
|
|||
# Write the updated MBR back
|
||||
seek($file, 0, SEEK_SET) or die "Failed to position at the beginning of the file: $!";
|
||||
print $file $mbr;
|
||||
|
||||
print "MBR table updated.\n";
|
||||
|
||||
################################################################################
|
||||
# Fixing GPT
|
||||
|
||||
# Auxiliary functions to read/write binary values from/to string consisting of bytes
|
||||
sub getUInt32($$) {
|
||||
# Arguments: source string, offset
|
||||
return unpack("L", substr($_[0], $_[1], 4));
|
||||
}
|
||||
sub getUInt64($$) {
|
||||
# Arguments: source string, offset
|
||||
return unpack("Q", substr($_[0], $_[1], 8));
|
||||
}
|
||||
sub putUInt32($$$) {
|
||||
# Arguments: source/destination string, offset, value
|
||||
substr($_[0], $_[1], 4) = pack("L", $_[2]);
|
||||
}
|
||||
|
||||
# Reading the second sector containing the GPT header
|
||||
my $gpt_header;
|
||||
seek($file, 512, SEEK_SET) or die "Failed to position at the LBA 1: $!";
|
||||
read($file, $gpt_header, 512) or die "Failed to read the GPT sector: $!";
|
||||
if (substr($gpt_header, 0, 8) ne 'EFI PART') {
|
||||
print "No GPT table found, exiting.\n";
|
||||
close($file);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
# Get various data from the header
|
||||
my $gpt_header_size = getUInt32($gpt_header, 0x0c); # Size of the header in bytes (normally, 92)
|
||||
my $gpt_backup_lba = getUInt64($gpt_header, 0x20); # LBA address of the backup GPT header
|
||||
my $gpt_partitions_lba = getUInt64($gpt_header, 0x48); # LBA address of the partitions array
|
||||
my $gpt_partitions_num = getUInt32($gpt_header, 0x50); # Number of partition entries (usually, 128)
|
||||
my $gpt_partition_size = getUInt32($gpt_header, 0x54); # Size of a single partition entry (usually, 128 bytes)
|
||||
|
||||
# Reading the list of partitions
|
||||
my $gpt_part;
|
||||
seek($file, $gpt_partitions_lba * 512, SEEK_SET) or die "Failed to position at the GPT partitions array (LBA $gpt_partitions_lba): $!";
|
||||
read($file, $gpt_part, $gpt_partitions_num * $gpt_partition_size) or die "Failed to read the GPT partitions array: $!";
|
||||
|
||||
# Moving the second partition entry to replace first, and zeroing the second entry
|
||||
substr($gpt_part, 0, $gpt_partition_size) = substr($gpt_part, $gpt_partition_size, $gpt_partition_size);
|
||||
substr($gpt_part, $gpt_partition_size, $gpt_partition_size) = "\x00" x $gpt_partition_size;
|
||||
|
||||
# Update CRC32 for partitions array
|
||||
my $parts_crc32 = crc32($gpt_part);
|
||||
putUInt32($gpt_header, 0x58, $parts_crc32);
|
||||
|
||||
# Update CRC32 for GPT header itself
|
||||
putUInt32($gpt_header, 0x10, 0);
|
||||
putUInt32($gpt_header, 0x10, crc32(substr($gpt_header, 0, $gpt_header_size)));
|
||||
|
||||
# Write the updated GPT header back
|
||||
seek($file, 512, SEEK_SET) or die "Failed to position at the LBA 1: $!";
|
||||
print $file $gpt_header;
|
||||
|
||||
# Write the partitions array
|
||||
seek($file, $gpt_partitions_lba * 512, SEEK_SET) or die "Failed to position at the GPT partitions array (LBA $gpt_partitions_lba): $!";
|
||||
print $file $gpt_part;
|
||||
|
||||
# Read the backup GPT header and get the required fields again
|
||||
seek($file, $gpt_backup_lba * 512, SEEK_SET) or die "Failed to position at the backup GPT header (LBA $gpt_backup_lba): $!";
|
||||
read($file, $gpt_header, 512) or die "Failed to read the backup GPT sector: $!";
|
||||
|
||||
# Do not reread the backup GPT address: it points back to the primary one
|
||||
$gpt_header_size = getUInt32($gpt_header, 0x0c); # Size of the header in bytes (normally, 92)
|
||||
$gpt_partitions_lba = getUInt64($gpt_header, 0x48); # LBA address of the partitions array
|
||||
$gpt_partitions_num = getUInt32($gpt_header, 0x50); # Number of partition entries (usually, 128)
|
||||
$gpt_partition_size = getUInt32($gpt_header, 0x54); # Size of a single partition entry (usually, 128 bytes)
|
||||
|
||||
# Update CRC32 for partitions array
|
||||
putUInt32($gpt_header, 0x58, $parts_crc32);
|
||||
|
||||
# Update CRC32 for GPT header itself
|
||||
putUInt32($gpt_header, 0x10, 0);
|
||||
putUInt32($gpt_header, 0x10, crc32(substr($gpt_header, 0, $gpt_header_size)));
|
||||
|
||||
# Write the partitions array
|
||||
seek($file, $gpt_partitions_lba * 512, SEEK_SET) or die "Failed to position at the GPT partitions array (LBA $gpt_partitions_lba): $!";
|
||||
print $file $gpt_part;
|
||||
|
||||
# Write the backup GPT header
|
||||
seek($file, $gpt_backup_lba * 512, SEEK_SET) or die "Failed to position at the backup GPT header (LBA $gpt_backup_lba): $!";
|
||||
print $file $gpt_header;
|
||||
|
||||
print "GPT table updated.\n";
|
||||
|
||||
close($file);
|
||||
|
|
Loading…
Add table
Reference in a new issue