diff options
Diffstat (limited to 'perl-install/resize_fat')
-rw-r--r-- | perl-install/resize_fat/any.pm | 7 | ||||
-rw-r--r-- | perl-install/resize_fat/c_rewritten.xs | 100 | ||||
-rw-r--r-- | perl-install/resize_fat/dir_entry.pm | 4 | ||||
-rw-r--r-- | perl-install/resize_fat/directory.pm | 14 | ||||
-rw-r--r-- | perl-install/resize_fat/fat.pm | 50 | ||||
-rw-r--r-- | perl-install/resize_fat/io.pm | 2 | ||||
-rw-r--r-- | perl-install/resize_fat/main.pm | 13 |
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}, |