summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perl-install/fs.pm2
-rw-r--r--perl-install/partition_table_raw.pm16
-rw-r--r--perl-install/resize_fat/any.pm47
-rw-r--r--perl-install/resize_fat/c_rewritten.xs2
-rw-r--r--perl-install/resize_fat/dir_entry.pm12
-rw-r--r--perl-install/resize_fat/directory.pm16
-rw-r--r--perl-install/resize_fat/fat.pm4
-rw-r--r--perl-install/resize_fat/main.pm28
8 files changed, 94 insertions, 33 deletions
diff --git a/perl-install/fs.pm b/perl-install/fs.pm
index 3920de74b..c3f960cd8 100644
--- a/perl-install/fs.pm
+++ b/perl-install/fs.pm
@@ -280,7 +280,7 @@ sub write_fstab($;$$) {
mkdir "$prefix/$mntpoint", 0755 or log::l("failed to mkdir $prefix/$mntpoint: $!");
eval { devices::make("$prefix/dev/$device") };
- [ "/dev/$device", $mntpoint, "vfat", "user,exec,conv=auto", 0, 0 ];
+ [ "/dev/$device", $mntpoint, "vfat", "user,exec,conv=binary", 0, 0 ];
} grep { isFat($_) &&
! exists $new{"/dev/$_->{device}"} } @$fstab;
diff --git a/perl-install/partition_table_raw.pm b/perl-install/partition_table_raw.pm
index e48cddce0..2acd60004 100644
--- a/perl-install/partition_table_raw.pm
+++ b/perl-install/partition_table_raw.pm
@@ -48,12 +48,20 @@ sub adjustStart($$) {
sub adjustEnd($$) {
my ($hd, $part) = @_;
my $end = $part->{start} + $part->{size};
- my $end2 = round_down($end, cylinder_size($hd));
- unless ($part->{start} < $end2) {
- $end2 = round_up($end, cylinder_size($hd));
- }
+ my $end2 = round_up($end, cylinder_size($hd));
+ $end2 = $hd->{geom}{cylinders} * cylinder_size($hd) if $end2 > $hd->{geom}{cylinders} * cylinder_size($hd);
$part->{size} = $end2 - $part->{start};
}
+#- previous version of adjustEnd, should check for numbers about partition start/end.
+#sub adjustEnd($$) {
+# my ($hd, $part) = @_;
+# my $end = $part->{start} + $part->{size};
+# my $end2 = round_down($end, cylinder_size($hd));
+# unless ($part->{start} < $end2) {
+# $end2 = round_up($end, cylinder_size($hd));
+# }
+# $part->{size} = $end2 - $part->{start};
+#}
sub get_geometry($) {
my ($dev) = @_;
diff --git a/perl-install/resize_fat/any.pm b/perl-install/resize_fat/any.pm
index 252caed4b..47f15558b 100644
--- a/perl-install/resize_fat/any.pm
+++ b/perl-install/resize_fat/any.pm
@@ -2,7 +2,7 @@ package resize_fat::any;
use diagnostics;
use strict;
-use vars qw($FREE $FILE $DIRECTORY);
+use vars qw($FREE $FILE $DIRECTORY $UNMOVEABLE);
use common qw(:common :constant);
use resize_fat::fat;
@@ -11,9 +11,10 @@ use resize_fat::dir_entry;
use resize_fat::c_rewritten;
-$FREE = 0;
-$FILE = 1;
-$DIRECTORY = 2;
+$FREE = 0;
+$FILE = 1;
+$DIRECTORY = 2;
+$UNMOVEABLE = 8;
1;
@@ -31,6 +32,23 @@ sub max_cluster_count($) {
+#- patch to get the function last_used that return the last used cluster of a fs.
+sub last_used($) {
+ my ($fs) = @_;
+
+ #- count in negative so absolute value count back to 2.
+ foreach (-($fs->{nb_clusters}+1)..-2) { return -$_ if resize_fat::c_rewritten::flag(-$_) }
+ return 2;
+}
+#- patch to get the function last_unmoveable that return the last unmoveable cluster of a fs.
+sub last_unmoveable($) {
+ my ($fs) = @_;
+
+ #- count in negative so absolute value count back to 2.
+ foreach (-($fs->{nb_clusters}+1)..-2) { return -$_ if 0x8 & resize_fat::c_rewritten::flag(-$_) }
+ return 2;
+}
+
#- calculates the minimum size of a partition, in physical sectors
sub min_size($) {
my ($fs) = @_;
@@ -40,6 +58,7 @@ sub min_size($) {
#- It's done on purpose since we're moving all directories. So at the worse
#- moment, 2 directories are there, but that way nothing wrong can happen :)
my $min_cluster_count = max(2 + $count->{used} + $count->{bad} + $count->{dirs}, min_cluster_count($fs));
+ $min_cluster_count = max($min_cluster_count, 2 + last_unmoveable($fs));
$min_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) +
divide($fs->{cluster_offset}, $SECTORSIZE);
@@ -53,28 +72,42 @@ sub max_size($) {
$max_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) +
divide($fs->{cluster_offset}, $SECTORSIZE);
}
+#- calculates used size in order to avoid modifying anything.
+sub used_size($) {
+ my ($fs) = @_;
+
+ my $used_cluster_count = max(2 + last_used($fs), min_cluster_count($fs));
+
+ $used_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) +
+ divide($fs->{cluster_offset}, $SECTORSIZE);
+}
#- fills in fat_flag_map in c_rewritten.
#- Each FAT entry is flagged as either FREE, FILE or DIRECTORY.
sub flag_clusters {
my ($fs) = @_;
- my ($cluster, $entry, $type, $nb_dirs);
+ my ($cluster, $curr_dir_name, $entry, $type, $nb_dirs);
my $f = sub {
- ($entry) = @_;
+ ($curr_dir_name, $entry) = @_;
$cluster = resize_fat::dir_entry::get_cluster($entry);
if (resize_fat::dir_entry::is_file($entry)) {
$type = $FILE;
+ $type |= $UNMOVEABLE if resize_fat::dir_entry::is_unmoveable($entry);
} elsif (resize_fat::dir_entry::is_directory($entry)) {
$type = $DIRECTORY;
} else { return }
- my $nb = resize_fat::c_rewritten::checkFat($cluster, $type, $entry->{name});
+ my $nb = resize_fat::c_rewritten::checkFat($cluster, $type, "$curr_dir_name/$entry->{name}");
$nb_dirs += $nb if $type == $DIRECTORY;
0;
};
resize_fat::c_rewritten::allocate_fat_flag($fs->{nb_clusters} + 2);
+
+ #- patch to reset contents of memory allocated by allocate_fat_flag
+ foreach (0..$fs->{nb_clusters} + 1) { resize_fat::c_rewritten::set_flag($_, 0) }
+
resize_fat::directory::traverse_all($fs, $f);
$fs->{clusters}{count}{dirs} = $nb_dirs;
}
diff --git a/perl-install/resize_fat/c_rewritten.xs b/perl-install/resize_fat/c_rewritten.xs
index 388f8b9ea..5aebb1ffb 100644
--- a/perl-install/resize_fat/c_rewritten.xs
+++ b/perl-install/resize_fat/c_rewritten.xs
@@ -124,7 +124,7 @@ checkFat(cluster, type, name)
for (; cluster < bad_cluster_value; cluster = next(cluster)) {
if (cluster == 0) croak("Bad FAT: unterminated chain for %s\n", name);
- if (fat_flag_map[cluster]) croak("Bad FAT: cluster $cluster is cross-linked for %s\n", name);
+ if (fat_flag_map[cluster]) croak("Bad FAT: cluster %d is cross-linked for %s\n", cluster, name);
fat_flag_map[cluster] = type;
nb++;
}
diff --git a/perl-install/resize_fat/dir_entry.pm b/perl-install/resize_fat/dir_entry.pm
index be3bd436a..390659b0e 100644
--- a/perl-install/resize_fat/dir_entry.pm
+++ b/perl-install/resize_fat/dir_entry.pm
@@ -5,6 +5,10 @@ use strict;
my $DELETED_FLAG = 0xe5;
+
+my $READ_ONLY_ATTR = 0x01;
+my $HIDDEN_ATTR = 0x02;
+my $SYSTEM_ATTR = 0x04;
my $VOLUME_LABEL_ATTR = 0x08;
my $VFAT_ATTR = 0x0f;
my $DIRECTORY_ATTR = 0x10;
@@ -21,6 +25,11 @@ sub set_cluster($$) {
$entry->{first_cluster_high} = $val >> 16 if $resize_fat::isFAT32;
}
+sub is_unmoveable($) {
+ my ($entry) = @_;
+ $entry->{attributes} & $HIDDEN_ATTR || $entry->{attributes} & $SYSTEM_ATTR;
+}
+
sub is_directory($) {
my ($entry) = @_;
$entry->{attributes} & $DIRECTORY_ATTR && $entry->{name} !~ /^\.\.? / && !is_special_entry($entry);
@@ -50,8 +59,9 @@ sub is_special_entry($) {
#- return true if entry has been modified
+#- curr_dir_name is added to contains current directory name, "" for root.
sub remap {
- my ($entry) = @_;
+ my ($curr_dir_name, $entry) = @_;
is_special_entry($entry) and return;
diff --git a/perl-install/resize_fat/directory.pm b/perl-install/resize_fat/directory.pm
index cdce4be88..1bc1014c6 100644
--- a/perl-install/resize_fat/directory.pm
+++ b/perl-install/resize_fat/directory.pm
@@ -32,8 +32,8 @@ sub entry_size { $psizeof_format }
#- call `f' for each entry of the directory
#- if f return true, then modification in the entry are taken back
-sub traverse($$) {
- my ($directory, $f) = @_;
+sub traverse($$$) {
+ my ($directory, $curr_dir_name, $f) = @_;
for (my $i = 0;; $i++) {
my $raw = \substr($directory, $i * $psizeof_format, $psizeof_format);
@@ -43,7 +43,7 @@ sub traverse($$) {
my $entry; @{$entry}{@fields} = unpack $format, $$raw;
- &$f($entry)
+ &$f($curr_dir_name, $entry)
and $$raw = pack $format, @{$entry}{@fields};
}
$directory;
@@ -53,12 +53,12 @@ sub traverse_all($$) {
my ($fs, $f) = @_;
my $traverse_all; $traverse_all = sub {
- my ($entry) = @_;
+ my ($curr_dir_name, $entry) = @_;
- &$f($entry);
+ &$f($curr_dir_name, $entry);
resize_fat::dir_entry::is_directory($entry)
- and traverse(resize_fat::io::read_file($fs, resize_fat::dir_entry::get_cluster($entry)), $traverse_all);
+ and traverse(resize_fat::io::read_file($fs, resize_fat::dir_entry::get_cluster($entry)), "$curr_dir_name/$entry->{name}", $traverse_all);
undef; #- no need to write back (cf traverse)
};
@@ -66,7 +66,7 @@ sub traverse_all($$) {
my $directory = $resize_fat::isFAT32 ?
resize_fat::io::read_file($fs, $fs->{fat32_root_dir_cluster}) :
resize_fat::io::read($fs, $fs->{root_dir_offset}, $fs->{root_dir_size});
- traverse($directory, $traverse_all);
+ traverse($directory, "", $traverse_all);
undef $traverse_all; #- circular reference is no good for perl's poor GC :(
}
@@ -75,5 +75,5 @@ sub traverse_all($$) {
#- directory entry
sub remap($$) {
my ($fs, $directory) = @_;
- traverse($directory, \&resize_fat::dir_entry::remap);
+ traverse($directory, "", \&resize_fat::dir_entry::remap);
}
diff --git a/perl-install/resize_fat/fat.pm b/perl-install/resize_fat/fat.pm
index 83426471a..33572624a 100644
--- a/perl-install/resize_fat/fat.pm
+++ b/perl-install/resize_fat/fat.pm
@@ -46,6 +46,10 @@ sub allocate_remap {
resize_fat::c_rewritten::allocate_fat_remap($fs->{fat_size});
+ #- patch to reset contents of memory allocated by allocate_fat_remap
+ #- divide by 4 because fat_size is in bytes.
+ foreach (0..$fs->{fat_size}/4 - 1) { resize_fat::c_rewritten::set_fat_remap($_, 0) }
+
$fs->{last_free_cluster} = 2;
for ($cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) {
if ($cluster < $cut_point) {
diff --git a/perl-install/resize_fat/main.pm b/perl-install/resize_fat/main.pm
index ac2fffaa2..bac7f8ad1 100644
--- a/perl-install/resize_fat/main.pm
+++ b/perl-install/resize_fat/main.pm
@@ -114,6 +114,7 @@ sub construct_dir_tree {
sub min_size($) { &resize_fat::any::min_size }
sub max_size($) { &resize_fat::any::max_size }
+sub used_size($) { &resize_fat::any::used_size }
#- resize
#- - size is in sectors
@@ -124,7 +125,6 @@ sub resize {
my ($min, $max) = (min_size($fs), max_size($fs));
-
$size += $min if $size =~ /^\+/;
$size >= $min or die "Minimum filesystem size is $min sectors";
@@ -134,24 +134,30 @@ sub resize {
my $new_data_size = $size * $SECTORSIZE - $fs->{cluster_offset};
my $new_nb_clusters = divide($new_data_size, $fs->{cluster_size});
+ my $used_size = used_size($fs);
- log::l("resize_fat: Allocating new clusters");
- resize_fat::fat::allocate_remap($fs, $new_nb_clusters);
+ log::l("resize_fat: Break point for moving files is ". ($used_size * $SECTORSIZE >> 20) ." Mb ($used_size sectors)");
+ if ($size < $used_size) {
+ log::l("resize_fat: Allocating new clusters");
+ resize_fat::fat::allocate_remap($fs, $new_nb_clusters);
- log::l("resize_fat: Copying files");
- copy_clusters($fs, $new_nb_clusters);
+ log::l("resize_fat: Copying files");
+ copy_clusters($fs, $new_nb_clusters);
- log::l("resize_fat: Copying directories");
- construct_dir_tree($fs);
+ log::l("resize_fat: Copying directories");
+ construct_dir_tree($fs);
- log::l("Writing new FAT...");
- resize_fat::fat::update($fs);
- resize_fat::fat::write($fs);
+ log::l("Writing new FAT...");
+ resize_fat::fat::update($fs);
+ resize_fat::fat::write($fs);
+ } else {
+ log::l("resize_fat: Nothing need to be moved");
+ }
$fs->{nb_sectors} = $size;
$fs->{nb_clusters} = $new_nb_clusters;
$fs->{clusters}{count}->{free} =
- $fs->{nb_clusters} - $fs->{clusters}{count}->{used} - $fs->{clusters}->{count}->{bad} - 2;
+ $fs->{nb_clusters} - $fs->{clusters}{count}->{used} - $fs->{clusters}->{count}->{bad} - 2;
$fs->{system_id} = 'was here!';
$fs->{small_nb_sectors} = 0;