summaryrefslogtreecommitdiffstats
path: root/perl-install/resize_fat
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/resize_fat')
-rw-r--r--perl-install/resize_fat/any.pm7
-rw-r--r--perl-install/resize_fat/c_rewritten.xs100
-rw-r--r--perl-install/resize_fat/dir_entry.pm4
-rw-r--r--perl-install/resize_fat/directory.pm14
-rw-r--r--perl-install/resize_fat/fat.pm50
-rw-r--r--perl-install/resize_fat/io.pm2
-rw-r--r--perl-install/resize_fat/main.pm13
7 files changed, 126 insertions, 64 deletions
diff --git a/perl-install/resize_fat/any.pm b/perl-install/resize_fat/any.pm
index ff0045d0b..252caed4b 100644
--- a/perl-install/resize_fat/any.pm
+++ b/perl-install/resize_fat/any.pm
@@ -54,12 +54,11 @@ sub max_size($) {
divide($fs->{cluster_offset}, $SECTORSIZE);
}
-#- fills in $fs->{fat_flag_map}.
+#- 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 $fat_flag_map = "\0" x ($fs->{nb_clusters} + 2);
my $f = sub {
($entry) = @_;
@@ -71,11 +70,11 @@ sub flag_clusters {
$type = $DIRECTORY;
} else { return }
- my $nb = resize_fat::c_rewritten::checkFat($fat_flag_map, $cluster, $type, $entry->{name});
+ my $nb = resize_fat::c_rewritten::checkFat($cluster, $type, $entry->{name});
$nb_dirs += $nb if $type == $DIRECTORY;
0;
};
+ resize_fat::c_rewritten::allocate_fat_flag($fs->{nb_clusters} + 2);
resize_fat::directory::traverse_all($fs, $f);
- $fs->{fat_flag_map} = $fat_flag_map;
$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 a42f3d133..388f8b9ea 100644
--- a/perl-install/resize_fat/c_rewritten.xs
+++ b/perl-install/resize_fat/c_rewritten.xs
@@ -4,8 +4,10 @@
/* set by scan_fat, used by next */
short *fat = NULL;
+char *fat_flag_map = NULL;
+unsigned int *fat_remap = NULL;
+int fat_remap_size;
int type_size, nb_clusters, bad_cluster_value;
-char *fat_flag_map;
unsigned int next(unsigned int cluster) {
short *p = fat + type_size * cluster;
@@ -13,19 +15,63 @@ unsigned int next(unsigned int cluster) {
return type_size == 1 ? *p : *((unsigned int *) p);
}
+void set_next(unsigned int cluster, unsigned int val) {
+ short *p = fat + type_size * cluster;
+ if (cluster > nb_clusters + 2) croak("fat::set_next: cluster %d outside filesystem", cluster);
+ type_size == 1 ? *p : *((unsigned int *) p) = val;
+}
+
MODULE = resize_fat::c_rewritten PACKAGE = resize_fat::c_rewritten
+void
+read_fat(fd, offset, size, magic)
+ int fd
+ int offset
+ int size
+ unsigned char magic
+ PPCODE:
+{
+ fat = (short *) malloc(size);
+ if (lseek(fd, offset, SEEK_SET) != offset ||
+ read(fd, fat, size) != size) {
+ free(fat); fat = NULL;
+ croak("reading FAT failed");
+ }
+ if (magic != *(unsigned char *) fat) {
+ free(fat); fat = NULL;
+ croak("FAT has invalid signature");
+ }
+}
+
void
-scan_fat(fat_, nb_clusters_, type_size_)
- char *fat_
+write_fat(fd, size)
+ int fd
+ int size
+ PPCODE:
+{
+ if (write(fd, fat, size) != size) croak("write_fat: write failed");
+}
+
+void
+free_all()
+ PPCODE:
+#define FREE(p) if (p) free(p), p = NULL;
+ FREE(fat);
+ FREE(fat_flag_map);
+ FREE(fat_remap);
+#undef FREE
+
+void
+scan_fat(nb_clusters_, type_size_)
int nb_clusters_
int type_size_
PPCODE:
+{
unsigned int v;
int free = 0, bad = 0, used = 0;
short *p;
- fat = (short*) fat_; type_size = type_size_; nb_clusters = nb_clusters_;
+ type_size = type_size_; nb_clusters = nb_clusters_;
bad_cluster_value = type_size ? 0xffffff7 : 0xfff7;
if (type_size % 16) fprintf(stderr, "unable to handle type_size"), exit(1);
@@ -42,6 +88,7 @@ scan_fat(fat_, nb_clusters_, type_size_)
PUSHs(sv_2mortal(newSViv(free)));
PUSHs(sv_2mortal(newSViv(bad)));
PUSHs(sv_2mortal(newSViv(used)));
+}
unsigned int
next(unused, cluster)
@@ -52,15 +99,27 @@ next(unused, cluster)
OUTPUT:
RETVAL
+void
+set_next(unused, cluster, val)
+ void *unused
+ unsigned int cluster
+ unsigned int val
+ CODE:
+ set_next(cluster, val);
+
+void
+allocate_fat_flag(size)
+ int size
+ CODE:
+ fat_flag_map = malloc(size);
+
int
-checkFat(fat_flag_map_, cluster, type, name)
- char *fat_flag_map_
+checkFat(cluster, type, name)
unsigned int cluster
int type
char *name
CODE:
int nb = 0;
- fat_flag_map = fat_flag_map_;
for (; cluster < bad_cluster_value; cluster = next(cluster)) {
if (cluster == 0) croak("Bad FAT: unterminated chain for %s\n", name);
@@ -88,3 +147,30 @@ set_flag(cluster, flag)
CODE:
fat_flag_map[cluster] = flag;
+void
+allocate_fat_remap(size)
+ int size
+ CODE:
+ fat_remap_size = size / 4;
+ fat_remap = (unsigned int *) malloc(size);
+
+unsigned int
+fat_remap(cluster)
+ unsigned int cluster
+ CODE:
+ if (cluster >= bad_cluster_value) {
+ RETVAL = cluster; /* special cases */
+ } else {
+ if (fat_remap == NULL) croak("fat_remap NULL in fat_remap");
+ if (cluster >= fat_remap_size) croak("cluster %d >= %d in fat_remap", cluster, fat_remap_size);
+ RETVAL = fat_remap[cluster];
+ }
+ OUTPUT:
+ RETVAL
+
+void
+set_fat_remap(cluster, val)
+ unsigned int cluster
+ unsigned int val
+ CODE:
+ fat_remap[cluster] = val;
diff --git a/perl-install/resize_fat/dir_entry.pm b/perl-install/resize_fat/dir_entry.pm
index 0739b0951..be3bd436a 100644
--- a/perl-install/resize_fat/dir_entry.pm
+++ b/perl-install/resize_fat/dir_entry.pm
@@ -51,12 +51,12 @@ sub is_special_entry($) {
#- return true if entry has been modified
sub remap {
- my ($fat_remap, $entry) = @_;
+ my ($entry) = @_;
is_special_entry($entry) and return;
my $cluster = get_cluster($entry);
- my $new_cluster = $fat_remap->[$cluster];
+ my $new_cluster = resize_fat::c_rewritten::fat_remap($cluster);
#-print "remapping cluster ", get_first_cluster($fs, $entry), " to $new_cluster";
diff --git a/perl-install/resize_fat/directory.pm b/perl-install/resize_fat/directory.pm
index f62203e50..22d2a1fae 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 ($fs, $directory, $f) = @_;
+sub traverse($$) {
+ my ($directory, $f) = @_;
for (my $i = 0;; $i++) {
my $raw = \substr($directory, $i * $psizeof_format, $psizeof_format);
@@ -58,7 +58,7 @@ sub traverse_all($$) {
&$f($entry);
resize_fat::dir_entry::is_directory($entry)
- and traverse($fs, 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)), $traverse_all);
undef; #- no need to write back (cf traverse)
};
@@ -66,14 +66,14 @@ 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($fs, $directory, $traverse_all);
+ traverse($directory, $traverse_all);
+ $traverse_all = undef; #- circular reference is no good for perl's poor GC :(
}
#- function used by construct_dir_tree to translate the `cluster' fields in each
#- directory entry
-sub remap {
+sub remap($$) {
my ($fs, $directory) = @_;
-
- traverse($fs->{fat_remap}, $directory, sub { resize_fat::dir_entry::remap($fs->{fat_remap}, $_[0]) });
+ traverse($directory, \&resize_fat::dir_entry::remap);
}
diff --git a/perl-install/resize_fat/fat.pm b/perl-install/resize_fat/fat.pm
index 67c64165c..83426471a 100644
--- a/perl-install/resize_fat/fat.pm
+++ b/perl-install/resize_fat/fat.pm
@@ -12,17 +12,10 @@ use resize_fat::c_rewritten;
sub read($) {
my ($fs) = @_;
- @{$fs->{fats}} = map {
- my $fat = eval { resize_fat::io::read($fs, $fs->{fat_offset} + $_ * $fs->{fat_size}, $fs->{fat_size}) };
- $@ and die "reading fat #$_ failed";
- vec($fat, 0, 8) == $fs->{media} or die "FAT $_ has invalid signature";
- $fat;
- } (0 .. $fs->{nb_fats} - 1);
-
- $fs->{fat} = $fs->{fats}[0];
+ resize_fat::c_rewritten::read_fat(fileno $fs->{fd}, $fs->{fat_offset}, $fs->{fat_size}, $fs->{media});
@{$fs->{clusters}{count}}{qw(free bad used)} =
- resize_fat::c_rewritten::scan_fat($fs->{fat}, $fs->{nb_clusters}, $fs->{fs_type_size});
+ resize_fat::c_rewritten::scan_fat($fs->{nb_clusters}, $fs->{fs_type_size});
}
sub write($) {
@@ -30,7 +23,7 @@ sub write($) {
sysseek $fs->{fd}, $fs->{fat_offset}, 0 or die "write_fat: seek failed";
foreach (1..$fs->{nb_fats}) {
- syswrite $fs->{fd}, $fs->{fat} or die "write_fat: write failed";
+ resize_fat::c_rewritten::write_fat(fileno $fs->{fd}, $fs->{fat_size});
}
}
@@ -43,7 +36,7 @@ sub write($) {
sub allocate_remap {
my ($fs, $cut_point) = @_;
my ($cluster, $new_cluster);
- my $remap = sub { $fs->{fat_remap}[$cluster] = $new_cluster; };
+ my $remap = sub { resize_fat::c_rewritten::set_fat_remap($cluster, $new_cluster) };
my $get_new = sub {
$new_cluster = get_free($fs);
0 < $new_cluster && $new_cluster < $cut_point or die "no free clusters";
@@ -51,7 +44,8 @@ sub allocate_remap {
#-log::ld("resize_fat: [$cluster,", &next($fs, $cluster), "...]->$new_cluster...");
};
- $fs->{fat_remap}[0] = 0;
+ resize_fat::c_rewritten::allocate_fat_remap($fs->{fat_size});
+
$fs->{last_free_cluster} = 2;
for ($cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) {
if ($cluster < $cut_point) {
@@ -76,30 +70,19 @@ sub update {
for (my $cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) {
if (resize_fat::c_rewritten::flag($cluster)) {
my $old_next = &next($fs, $cluster);
- my $new = $fs->{fat_remap}[$cluster];
- my $new_next = $fs->{fat_remap}[$old_next];
+ my $new = resize_fat::c_rewritten::fat_remap($cluster);
+ my $new_next = resize_fat::c_rewritten::fat_remap($old_next);
set_available($fs, $cluster);
is_eof($old_next) ?
set_eof($fs, $new) :
- set_next($fs, $new, $new_next);
+ set_next ($fs, $new, $new_next);
}
}
}
-#- - compares the two FATs (one's a backup that should match) - skips first entry
-#- - its just a signature (already checked above) NOTE: checks for cross-linking
-#- are done in count.c
-sub check($) {
- my ($fs) = @_;
- return;
- foreach (@{$fs->{fats}}) {
- $_ eq $fs->{fats}[0] or die "FAT tables do not match";
- }
-}
-
sub endianness16($) { (($_[0] & 0xff) << 8) + ($_[0] >> 8); }
sub endianness($$) {
my ($val, $nb_bits) = @_;
@@ -113,18 +96,9 @@ sub endianness($$) {
$r;
}
-#-sub next($$) {
-#- my ($fs, $cluster) = @_;
-#- $cluster > $fs->{nb_clusters} + 2 and die "fat::next: cluster $cluster outside filesystem";
-#- endianness(vec($fs->{fat}, $cluster, $fs->{fs_type_size}), $fs->{fs_type_size});
-#-}
*next = \&resize_fat::c_rewritten::next;
+*set_next = \&resize_fat::c_rewritten::set_next;
-sub set_next($$$) {
- my ($fs, $cluster, $new_v) = @_;
- $cluster > $fs->{nb_clusters} + 2 and die "fat::set_next: cluster $cluster outside filesystem";
- vec($fs->{fat}, $cluster, $fs->{fs_type_size}) = endianness($new_v, $fs->{fs_type_size});
-}
sub get_free($) {
@@ -143,7 +117,7 @@ sub is_eof($) {
}
sub set_eof($$) {
my ($fs, $cluster) = @_;
- set_next($fs, $cluster, $resize_fat::bad_cluster_value + 1);
+ set_next ($fs, $cluster, $resize_fat::bad_cluster_value + 1);
}
#- returns true if <cluster> is empty. Note that this includes bad clusters.
@@ -159,5 +133,5 @@ sub is_available($) {
}
sub set_available($$) {
my ($fs, $cluster) = @_;
- set_next($fs, $cluster, 0);
+ set_next ($fs, $cluster, 0);
}
diff --git a/perl-install/resize_fat/io.pm b/perl-install/resize_fat/io.pm
index 8cf21d929..cbe0033ca 100644
--- a/perl-install/resize_fat/io.pm
+++ b/perl-install/resize_fat/io.pm
@@ -10,7 +10,7 @@ use resize_fat::fat;
sub read($$$) {
my ($fs, $pos, $size) = @_;
- my $buf;
+ my $buf = "\0" x $size;
sysseek $fs->{fd}, $pos, 0 or die "seeking to byte #$pos failed on device $fs->{fs_name}";
sysread $fs->{fd}, $buf, $size or die "reading at byte #$pos failed on device $fs->{fs_name}";
$buf;
diff --git a/perl-install/resize_fat/main.pm b/perl-install/resize_fat/main.pm
index 762d18bca..ade04122c 100644
--- a/perl-install/resize_fat/main.pm
+++ b/perl-install/resize_fat/main.pm
@@ -45,12 +45,13 @@ sub new($$$) {
resize_fat::boot_sector::read($fs);
$resize_fat::isFAT32 and eval { resize_fat::info_sector::read($fs) };
resize_fat::fat::read($fs);
- resize_fat::fat::check($fs);
resize_fat::any::flag_clusters($fs);
bless $fs, $type;
}
+sub DESTROY { resize_fat::c_rewritten::free_all() }
+
#- copy all clusters >= <start_cluster> to a new place on the partition, less
#- than <start_cluster>. Only copies files, not directories.
#- (use of buffer needed because the seeks slow like hell the hard drive)
@@ -65,7 +66,9 @@ sub copy_clusters {
};
for (; $cluster < $fs->{nb_clusters} + 2; $cluster++) {
resize_fat::c_rewritten::flag($cluster) == $resize_fat::any::FILE or next;
- push @buffer, $fs->{fat_remap}[$cluster], resize_fat::io::read_cluster($fs, $cluster);
+ push @buffer,
+ resize_fat::c_rewritten::fat_remap($cluster),
+ resize_fat::io::read_cluster($fs, $cluster);
@buffer > 50 and &$flush();
}
&$flush();
@@ -85,8 +88,8 @@ sub construct_dir_tree {
resize_fat::c_rewritten::flag($cluster) == $resize_fat::any::DIRECTORY or next;
resize_fat::io::write_cluster($fs,
- $fs->{fat_remap}[$cluster],
- resize_fat::directory::remap($fs, resize_fat::io::read_cluster($fs, $cluster)));
+ resize_fat::c_rewritten::fat_remap($cluster),
+ resize_fat::directory::remap($fs, resize_fat::io::read_cluster($fs, $cluster)));
}
sync();
@@ -101,7 +104,7 @@ sub construct_dir_tree {
my $cluster = $fs->{fat32_root_dir_cluster};
resize_fat::io::write_cluster($fs,
- $fs->{fat_remap}[$cluster],
+ resize_fat::c_rewritten::fat_remap($cluster),
resize_fat::directory::remap($fs, resize_fat::io::read_cluster($fs, $cluster)));
} else {
resize_fat::io::write($fs, $fs->{root_dir_offset}, $fs->{root_dir_size},