diff options
Diffstat (limited to 'perl-install/resize_fat')
-rw-r--r-- | perl-install/resize_fat/Makefile | 16 | ||||
-rw-r--r-- | perl-install/resize_fat/README | 4 | ||||
-rw-r--r-- | perl-install/resize_fat/any.pm | 97 | ||||
-rw-r--r-- | perl-install/resize_fat/boot_sector.pm | 76 | ||||
-rw-r--r-- | perl-install/resize_fat/c_rewritten.pm | 2 | ||||
-rw-r--r-- | perl-install/resize_fat/c_rewritten.xs | 195 | ||||
-rw-r--r-- | perl-install/resize_fat/dir_entry.pm | 29 | ||||
-rw-r--r-- | perl-install/resize_fat/directory.pm | 45 | ||||
-rw-r--r-- | perl-install/resize_fat/fat.pm | 87 | ||||
-rw-r--r-- | perl-install/resize_fat/info_sector.pm | 17 | ||||
-rw-r--r-- | perl-install/resize_fat/io.pm | 29 | ||||
-rw-r--r-- | perl-install/resize_fat/main.pm | 141 |
12 files changed, 480 insertions, 258 deletions
diff --git a/perl-install/resize_fat/Makefile b/perl-install/resize_fat/Makefile index 34c257a4e..a82ca8441 100644 --- a/perl-install/resize_fat/Makefile +++ b/perl-install/resize_fat/Makefile @@ -1,12 +1,10 @@ -PRODUCT = libresize -TARSOURCE = $(PRODUCT).tar.bz2 +.PHONY: clean -.PHONY: clean tar +c_rewritten: %: %.xs + test -e Makefile_c || perl Makefile.PL + $(MAKE) -f Makefile_c LD_RUN_PATH= + rm -f ../auto/resize_fat ; ln -s ../resize_fat/blib/arch/auto ../auto/resize_fat clean: - rm -f *~ TAGS $(TARSOURCE) - -tar: clean - cp -f ../common.pm . - cd .. ; tar cfy $(TARSOURCE) $(PRODUCT) ; mv $(TARSOURCE) $(PRODUCT) - rm -f common.pm + test ! -e Makefile_c || $(MAKE) -f Makefile_c clean + rm -f *~ *.o diff --git a/perl-install/resize_fat/README b/perl-install/resize_fat/README index 2910c06c3..1c4798c82 100644 --- a/perl-install/resize_fat/README +++ b/perl-install/resize_fat/README @@ -1,5 +1,7 @@ -just do ./resize.pm and look at usage. +TODO: +resize_fat::fat::update($fs) should be called before doing undoable things +(before the sync in construct_dir_tree) BUGS: no known bugs :) diff --git a/perl-install/resize_fat/any.pm b/perl-install/resize_fat/any.pm index d78a342be..3844e1c16 100644 --- a/perl-install/resize_fat/any.pm +++ b/perl-install/resize_fat/any.pm @@ -1,49 +1,79 @@ -package resize_fat::any; +package resize_fat::any; # $Id$ 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; use resize_fat::directory; 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; -# returns the number of clusters for a given filesystem type +#- returns the number of clusters for a given filesystem type sub min_cluster_count($) { my ($fs) = @_; - (1 << $ {{ FAT16 => 12, FAT32 => 16 }}{$fs->{fs_type}}) - 12; + (1 << $ {{ FAT16 => 12, FAT32 => 12 }}{$fs->{fs_type}}) - 12; } sub max_cluster_count($) { my ($fs) = @_; - $resize_fat::bad_cluster_value - 2; + (1 << $ {{ FAT16 => 16, FAT32 => 28 }}{$fs->{fs_type}}) - 11; } -# calculates the minimum size of a partition, in physical sectors +#- 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(-$_) } + die "any: empty FAT table of $fs->{nb_clusters} clusters"; +} +#- 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(-$_) } + + #- Oh at this point there are no unmoveable blocks! + 2; +} + +#- calculates the minimum size of a partition, in physical sectors sub min_size($) { my ($fs) = @_; - my $count = $fs->{clusters}->{count}; + my $count = $fs->{clusters}{count}; - # directories are both in `used' and `dirs', so are counted twice - # 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 :) + #- directories are both in `used' and `dirs', so are counted twice + #- 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, last_unmoveable($fs)); + + my $size = $min_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) + + divide($fs->{cluster_offset}, $SECTORSIZE) + + 64*1024*1024 / $SECTORSIZE; #- help with such more sectors (ie 64Mb). + + #- help zindozs again with 512Mb+ at least else partition is ignored. + if ($resize_fat::isFAT32) { + $size = max($size, 524*1024*1024 / $SECTORSIZE); + } + $size; - $min_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) + - divide($fs->{cluster_offset}, $SECTORSIZE); } -# calculates the maximum size of a partition, in physical sectors +#- calculates the maximum size of a partition, in physical sectors sub max_size($) { my ($fs) = @_; @@ -52,31 +82,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(last_used($fs), min_cluster_count($fs)); + + $used_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) + + divide($fs->{cluster_offset}, $SECTORSIZE); +} -# fills in $fs->{fat_flag_map}. -# Each FAT entry is flagged as either FREE, FILE or DIRECTORY. +#- 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); + 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 } - for (; !resize_fat::fat::is_eof($cluster); $cluster = resize_fat::fat::next($fs, $cluster)) { - $cluster == 0 and die "Bad FAT: unterminated chain for $entry->{name}\n"; - $fs->{fat_flag_map}->[$cluster] and die "Bad FAT: cluster $cluster is cross-linked for $entry->{name}\n"; - $fs->{fat_flag_map}->[$cluster] = $type; - $fs->{clusters}->{count}->{dirs}++ if $type == $DIRECTORY; - } + my $nb = resize_fat::c_rewritten::checkFat($cluster, $type, "$curr_dir_name/$entry->{name}"); + print "resize_fat:flag_clusters: check fat returned $nb of type $type for $curr_dir_name/$entry->{name}\n"; + $nb_dirs += $nb if $type == $DIRECTORY; + 0; }; - $fs->{fat_flag_map} = [ ($FREE) x ($fs->{nb_clusters} + 2) ]; - $fs->{clusters}->{count}->{dirs} = 0; + + #- this must call allocate_fat_flag that zeroes the buffer allocated. + resize_fat::c_rewritten::allocate_fat_flag($fs->{nb_clusters} + 2); + resize_fat::directory::traverse_all($fs, $f); + $fs->{clusters}{count}{dirs} = $nb_dirs; } diff --git a/perl-install/resize_fat/boot_sector.pm b/perl-install/resize_fat/boot_sector.pm index c236b1617..4ed4a73f7 100644 --- a/perl-install/resize_fat/boot_sector.pm +++ b/perl-install/resize_fat/boot_sector.pm @@ -1,69 +1,73 @@ -package resize_fat::boot_sector; +package resize_fat::boot_sector; # $Id$ use diagnostics; use strict; -use common qw(:common :system :constant); +use common qw(:common :system :constant :functional); use resize_fat::io; use resize_fat::any; use resize_fat::directory; +#- Oops, this will be unresizable on big-endian machine. trapped by signature. my $format = "a3 a8 S C S C S S C S S S I I I S S I S S a458 S"; my @fields = ( - 'boot_jump', # boot strap short or near jump - 'system_id', # Name - can be used to special case partition manager volumes - 'sector_size', # bytes per logical sector - 'cluster_size_in_sectors', # sectors/cluster - 'nb_reserved', # reserved sectors - 'nb_fats', # number of FATs - 'nb_root_dir_entries', # number of root directory entries - 'small_nb_sectors', # number of sectors: big_nb_sectors supersedes - 'media', # media code - 'fat16_fat_length', # sectors/FAT for FAT12/16 + 'boot_jump', #- boot strap short or near jump + 'system_id', #- Name - can be used to special case partition manager volumes + 'sector_size', #- bytes per logical sector + 'cluster_size_in_sectors', #- sectors/cluster + 'nb_reserved', #- reserved sectors + 'nb_fats', #- number of FATs + 'nb_root_dir_entries', #- number of root directory entries + 'small_nb_sectors', #- number of sectors: big_nb_sectors supersedes + 'media', #- media code + 'fat16_fat_length', #- sectors/FAT for FAT12/16 'sectors_per_track', 'nb_heads', - 'nb_hidden', # (unused) - 'big_nb_sectors', # number of sectors (if small_nb_sectors == 0) - -# FAT32-only entries - 'fat32_fat_length', # size of FAT in sectors - 'fat32_flags', # bit8: fat mirroring, - # low4: active fat - 'fat32_version', # minor * 256 + major + 'nb_hidden', #- (unused) + 'big_nb_sectors', #- number of sectors (if small_nb_sectors == 0) + +#- FAT32-only entries + 'fat32_fat_length', #- size of FAT in sectors + 'fat32_flags', #- bit8: fat mirroring, + #- low4: active fat + 'fat32_version', #- minor * 256 + major 'fat32_root_dir_cluster', 'info_offset_in_sectors', 'fat32_backup_sector', -# Common again... - 'boot_code', # Boot code (or message) - 'boot_sign', # 0xAA55 +#- Common again... + 'boot_code', #- Boot code (or message) + 'boot_sign', #- 0xAA55 ); 1; -# trimfs_init_boot_sector() - reads in the boot sector - gets important info out -# of boot sector, and puts in main structure - performs sanity checks - returns 1 -# on success, 0 on failureparameters: filesystem an empty structure to fill. +#- trimfs_init_boot_sector() - reads in the boot sector - gets important info out +#- of boot sector, and puts in main structure - performs sanity checks - returns 1 +#- on success, 0 on failureparameters: filesystem an empty structure to fill. sub read($) { my ($fs) = @_; - + my $boot = eval { resize_fat::io::read($fs, 0, $SECTORSIZE) }; $@ and die "reading boot sector failed on device $fs->{fs_name}"; @{$fs}{@fields} = unpack $format, $boot; $fs->{nb_sectors} = $fs->{small_nb_sectors} || $fs->{big_nb_sectors}; - $fs->{cluster_size} = $fs->{cluster_size_in_sectors} * $fs->{sector_size}; + $fs->{cluster_size} = $fs->{cluster_size_in_sectors} * $fs->{sector_size}; - $fs->{boot_sign} == 0xAA55 or die "Invalid signature for a MS-based filesystem."; - $fs->{nb_fats} == 2 or die "Weird number of FATs: $fs->{nb_fats}, not 2.", + $fs->{boot_sign} == 0xAA55 or die "Invalid signature for a MS-based filesystem.\n"; $fs->{nb_sectors} < 32 and die "Too few sectors for viable file system\n"; + $fs->{nb_fats} == 2 or cdie "Weird number of FATs: $fs->{nb_fats}, not 2.\n"; + $fs->{sector_size} == 512 or cdie "Strange sector_size != 512\n"; if ($fs->{fat16_fat_length}) { - # asserting FAT16, will be verified later on + #- asserting FAT16, will be verified later on + $resize_fat::isFAT32 = 0; $fs->{fs_type} = 'FAT16'; $fs->{fs_type_size} = 16; $fs->{fat_length} = $fs->{fat16_fat_length}; + $resize_fat::bad_cluster_value = 0xfff7; #- 2**16 - 1 } else { $resize_fat::isFAT32 = 1; $fs->{fs_type} = 'FAT32'; @@ -72,9 +76,9 @@ sub read($) { $fs->{nb_root_dir_entries} = 0; $fs->{info_offset} = $fs->{info_offset_in_sectors} * $fs->{sector_size}; + $resize_fat::bad_cluster_value = 0x0ffffff7; } - $resize_fat::bad_cluster_value = (1 << $fs->{fs_type_size}) - 9; - + $fs->{fat_offset} = $fs->{nb_reserved} * $fs->{sector_size}; $fs->{fat_size} = $fs->{fat_length} * $fs->{sector_size}; $fs->{root_dir_offset} = $fs->{fat_offset} + $fs->{fat_size} * $fs->{nb_fats}; @@ -83,12 +87,12 @@ sub read($) { $fs->{nb_fat_entries} = divide($fs->{fat_size}, $fs->{fs_type_size} / 8); - # - 2 because clusters 0 & 1 doesn't exist + #- - 2 because clusters 0 & 1 doesn't exist $fs->{nb_clusters} = divide($fs->{nb_sectors} * $fs->{sector_size} - $fs->{cluster_offset}, $fs->{cluster_size}) - 2; $fs->{dir_entries_per_cluster} = divide($fs->{cluster_size}, psizeof($format)); - $fs->{nb_clusters} >= resize_fat::any::min_cluster_count($fs) or die "error: not enough sectors for a $fs->{fs_type}\n"; +#- $fs->{nb_clusters} >= resize_fat::any::min_cluster_count($fs) or die "error: not enough sectors for a $fs->{fs_type}\n"; $fs->{nb_clusters} < resize_fat::any::max_cluster_count($fs) or die "error: too many sectors for a $fs->{fs_type}\n"; } @@ -99,7 +103,7 @@ sub write($) { eval { resize_fat::io::write($fs, 0, $SECTORSIZE, $boot) }; $@ and die "writing the boot sector failed on device $fs->{fs_name}"; if ($resize_fat::isFAT32) { - # write backup + #- write backup eval { resize_fat::io::write($fs, $fs->{fat32_backup_sector} * $SECTORSIZE, $SECTORSIZE, $boot) }; $@ and die "writing the backup boot sector (#$fs->{fat32_backup_sector}) failed on device $fs->{fs_name}"; } diff --git a/perl-install/resize_fat/c_rewritten.pm b/perl-install/resize_fat/c_rewritten.pm index 1f5f505c7..d74ecb5d3 100644 --- a/perl-install/resize_fat/c_rewritten.pm +++ b/perl-install/resize_fat/c_rewritten.pm @@ -1,4 +1,4 @@ -package resize_fat::c_rewritten; +package resize_fat::c_rewritten; # $Id$ use strict; use vars qw($VERSION @ISA); diff --git a/perl-install/resize_fat/c_rewritten.xs b/perl-install/resize_fat/c_rewritten.xs index a42f3d133..92361097d 100644 --- a/perl-install/resize_fat/c_rewritten.xs +++ b/perl-install/resize_fat/c_rewritten.xs @@ -4,31 +4,105 @@ /* 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; + +void free_all() { +#define FREE(p) if (p) free(p), p = NULL; + FREE(fat); + FREE(fat_flag_map); + FREE(fat_remap); +#undef FREE +} unsigned int next(unsigned int cluster) { short *p = fat + type_size * cluster; - if (cluster > nb_clusters + 2) croak("fat::next: cluster %d outside filesystem", cluster); + if (!fat) { + free_all(); + croak("fat::next: trying to use null pointer"); + } + if (cluster >= nb_clusters + 2) { + free_all(); + croak("fat::next: cluster %d outside filesystem", 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 (!fat) { + free_all(); + croak("fat::set_next: trying to use null pointer"); + } + if (cluster >= nb_clusters + 2) { + free_all(); + 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 (!fat) { + free_all(); + croak("read_fat: not enough memory"); + } + if (lseek(fd, offset, SEEK_SET) != offset || + read(fd, fat, size) != size) { + free_all(); + croak("read_fat: reading FAT failed"); + } + if (magic != *(unsigned char *) fat) { + free_all(); + croak("read_fat: 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) { + free_all(); + croak("write_fat: write failed"); + } +} + +void +free_all() + PPCODE: + free_all(); + +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_; - bad_cluster_value = type_size ? 0xffffff7 : 0xfff7; + type_size = type_size_; nb_clusters = nb_clusters_; + bad_cluster_value = type_size == 32 ? 0x0ffffff7 : 0xfff7; - if (type_size % 16) fprintf(stderr, "unable to handle type_size"), exit(1); + if (type_size % 16) { + free_all(); + croak("scan_fat: unable to handle FAT%d", type_size); + } type_size /= 16; for (p = fat + 2 * type_size; p < fat + type_size * (nb_clusters + 2); p += type_size) { @@ -42,6 +116,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,20 +127,49 @@ 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 = calloc(size, 1); + if (!fat_flag_map) { + free_all(); + croak("allocate_fat_flag: not enough memory"); + } + 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_; + if (!fat_flag_map) { + free_all(); + croak("Bad FAT: trying to use null pointer"); + } 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 (cluster == 0) { + free_all(); + croak("Bad FAT: unterminated chain for %s\n", name); + } + if (cluster >= nb_clusters + 2) { + free_all(); + croak("Bad FAT: chain outside filesystem for %s\n", name); + } + if (fat_flag_map[cluster]) { + free_all(); + croak("Bad FAT: cluster %d is cross-linked for %s\n", cluster, name); + } fat_flag_map[cluster] = type; nb++; } @@ -77,6 +181,14 @@ unsigned int flag(cluster) unsigned int cluster CODE: + if (!fat_flag_map) { + free_all(); + croak("Bad FAT: trying to use null pointer"); + } + if (cluster >= nb_clusters + 2) { + free_all(); + croak("Bad FAT: going outside filesystem"); + } RETVAL = fat_flag_map[cluster]; OUTPUT: RETVAL @@ -86,5 +198,62 @@ set_flag(cluster, flag) unsigned int cluster int flag CODE: + if (!fat_flag_map) { + free_all(); + croak("Bad FAT: trying to use null pointer"); + } + if (cluster >= nb_clusters + 2) { + free_all(); + croak("Bad FAT: going outside filesystem"); + } fat_flag_map[cluster] = flag; +void +allocate_fat_remap(size) + int size + CODE: + fat_remap_size = size; + fat_remap = (unsigned int *) calloc(size, sizeof(unsigned int *)); + if (!fat_remap) { + free_all(); + croak("allocate_fat_remap: not enough memory"); + } + +unsigned int +fat_remap(cluster) + unsigned int cluster + CODE: + if (!fat_remap) { + free_all(); + croak("fat_remap: trying to use null pointer"); + } + if (cluster >= bad_cluster_value) { + RETVAL = cluster; /* special cases */ + } else { + if (cluster >= fat_remap_size) { + free_all(); + croak("fat_remap: 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: + if (!fat_remap) { + free_all(); + croak("set_fat_remap: trying to use null pointer"); + } + if (cluster >= fat_remap_size) { + free_all(); + croak("set_fat_remap: cluster %d >= %d in set_fat_remap", cluster, fat_remap_size); + } + if (val < bad_cluster_value && val >= fat_remap_size) { + free_all(); + croak("set_fat_remap: remapping cluster %d to cluster %d >= %d in set_fat_remap", cluster, val, fat_remap_size); + } + fat_remap[cluster] = val; diff --git a/perl-install/resize_fat/dir_entry.pm b/perl-install/resize_fat/dir_entry.pm index fa5ebb344..b39c72094 100644 --- a/perl-install/resize_fat/dir_entry.pm +++ b/perl-install/resize_fat/dir_entry.pm @@ -1,10 +1,14 @@ -package resize_fat::dir_entry; +package resize_fat::dir_entry; # $Id$ use diagnostics; 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; @@ -13,7 +17,7 @@ my $DIRECTORY_ATTR = 0x10; sub get_cluster($) { my ($entry) = @_; - $entry->{first_cluster} + ($resize_fat::isFAT32 ? $entry->{first_cluster_high} * 65536 : 0); + $entry->{first_cluster} + ($resize_fat::isFAT32 ? $entry->{first_cluster_high} * (1 << 16) : 0); } sub set_cluster($$) { my ($entry, $val) = @_; @@ -21,14 +25,14 @@ sub set_cluster($$) { $entry->{first_cluster_high} = $val >> 16 if $resize_fat::isFAT32; } -sub is_directory_raw($) { +sub is_unmoveable($) { my ($entry) = @_; - !is_special_entry($entry) && $entry->{attributes} & $DIRECTORY_ATTR; + $entry->{attributes} & $HIDDEN_ATTR || $entry->{attributes} & $SYSTEM_ATTR; } sub is_directory($) { my ($entry) = @_; - is_directory_raw($entry) && $entry->{name} !~ /^\.\.? /; + $entry->{attributes} & $DIRECTORY_ATTR && $entry->{name} !~ /^\.\.? / && !is_special_entry($entry); } sub is_volume($) { @@ -46,7 +50,7 @@ sub is_special_entry($) { my ($entry) = @_; my ($c) = unpack "C", $entry->{name}; - # skip empty slots, deleted files, and 0xF6?? (taken from kernel) + #- skip empty slots, deleted files, and 0xF6?? (taken from kernel) $c == 0 || $c == $DELETED_FLAG || $c == 0xF6 and return 1; $entry->{attributes} == $VFAT_ATTR and return 1; @@ -54,18 +58,19 @@ sub is_special_entry($) { } -# return true if entry has been modified +#- return true if entry has been modified +#- curr_dir_name is added to contains current directory name, "" for root. sub remap { - my ($fat_remap, $entry) = @_; - + my ($curr_dir_name, $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"; + #-print "remapping cluster ", get_cluster($entry), " to $new_cluster"; - $new_cluster == $cluster and return; # no need to modify + $new_cluster == $cluster and return; #- no need to modify set_cluster($entry, $new_cluster); 1; diff --git a/perl-install/resize_fat/directory.pm b/perl-install/resize_fat/directory.pm index ab8ec5328..beb780bcf 100644 --- a/perl-install/resize_fat/directory.pm +++ b/perl-install/resize_fat/directory.pm @@ -1,4 +1,4 @@ -package resize_fat::directory; +package resize_fat::directory; # $Id$ use diagnostics; use strict; @@ -14,35 +14,36 @@ my @fields = ( 'extension', 'attributes', 'is_upper_case_name', - 'creation_time_low', # milliseconds + 'creation_time_low', #- milliseconds 'creation_time_high', 'creation_date', 'access_date', - 'first_cluster_high', # for FAT32 + 'first_cluster_high', #- for FAT32 'time', 'date', 'first_cluster', 'length', ); +my $psizeof_format = psizeof($format); 1; -sub entry_size { psizeof($format) } +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 +#- 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) = @_; + my ($directory, $curr_dir_name, $f) = @_; - for (my $i = 0; 1; $i++) { - my $raw = \substr($directory, $i * psizeof($format), psizeof($format)); + for (my $i = 0;; $i++) { + my $raw = \substr($directory, $i * $psizeof_format, $psizeof_format); - # empty entry means end of directory + #- empty entry means end of directory $$raw =~ /^\0*$/ and return $directory; my $entry; @{$entry}{@fields} = unpack $format, $$raw; - &$f($entry) + &$f($curr_dir_name, $entry) and $$raw = pack $format, @{$entry}{@fields}; } $directory; @@ -52,27 +53,27 @@ 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($fs, resize_fat::io::read_file($fs, resize_fat::dir_entry::get_cluster($entry)), $traverse_all); + resize_fat::dir_entry::is_directory($entry) + 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) + undef; #- no need to write back (cf traverse) }; 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); + undef $traverse_all; #- 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 { +#- function used by construct_dir_tree to translate the `cluster' fields in each +#- directory entry +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 2b64bd6f7..31643f0a3 100644 --- a/perl-install/resize_fat/fat.pm +++ b/perl-install/resize_fat/fat.pm @@ -1,34 +1,21 @@ -package resize_fat::fat; +package resize_fat::fat; # $Id$ use diagnostics; use strict; use resize_fat::any; use resize_fat::io; +use resize_fat::c_rewritten; 1; 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); + resize_fat::c_rewritten::read_fat(fileno $fs->{fd}, $fs->{fat_offset}, $fs->{fat_size}, $fs->{media}); - $fs->{fat} = $fs->{fats}->[0]; - - my ($free, $bad, $used) = (0, 0, 0); - - for (my $i = 2; $i < $fs->{nb_clusters} + 2; $i++) { - my $cluster = &next($fs, $i); - if ($cluster == 0) { $free++; } - elsif ($cluster == $resize_fat::bad_cluster_value) { $bad++; } - else { $used++; } - } - @{$fs->{clusters}->{count}}{qw(free bad used)} = ($free, $bad, $used); + @{$fs->{clusters}{count}}{qw(free bad used)} = + resize_fat::c_rewritten::scan_fat($fs->{nb_clusters}, $fs->{fs_type_size}); } sub write($) { @@ -36,32 +23,34 @@ 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}, $fs->{fat_size} or die "write_fat: write failed"; + resize_fat::c_rewritten::write_fat(fileno $fs->{fd}, $fs->{fat_size}); } } -# allocates where all the clusters will be moved to. Clusters before cut_point -# remain in the same position, however cluster that are part of a directory are -# moved regardless (this is a mechanism to prevent data loss) (cut_point is the -# first cluster that won't occur in the new fs) +#- allocates where all the clusters will be moved to. Clusters before cut_point +#- remain in the same position, however cluster that are part of a directory are +#- moved regardless (this is a mechanism to prevent data loss) (cut_point is the +#- first cluster that won't occur in the new fs) 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"; - set_eof($fs, $new_cluster); # mark as used - #log::ld("resize_fat: [$cluster,", &next($fs, $cluster), "...]->$new_cluster..."); + set_eof($fs, $new_cluster); #- mark as used + #-log::ld("resize_fat: [$cluster,", &next($fs, $cluster), "...]->$new_cluster..."); }; - $fs->{fat_remap}->[0] = 0; + #- this must call allocate_fat_remap that zeroes the buffer allocated. + resize_fat::c_rewritten::allocate_fat_remap($fs->{nb_clusters} + 2); + $fs->{last_free_cluster} = 2; for ($cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) { if ($cluster < $cut_point) { - if ($fs->{fat_flag_map}->[$cluster] == $resize_fat::any::DIRECTORY) { + if (resize_fat::c_rewritten::flag($cluster) == $resize_fat::any::DIRECTORY) { &$get_new(); } else { $new_cluster = $cluster; @@ -75,36 +64,26 @@ sub allocate_remap { } -# updates the fat for the resized filesystem +#- updates the fat for the resized filesystem sub update { my ($fs) = @_; for (my $cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) { - if ($fs->{fat_flag_map}->[$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) = @_; - 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) = @_; @@ -118,17 +97,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($) { @@ -140,28 +111,28 @@ sub get_free($) { die "no free clusters"; } -# returns true if <cluster> represents an EOF marker +#- returns true if <cluster> represents an EOF marker sub is_eof($) { my ($cluster) = @_; $cluster >= $resize_fat::bad_cluster_value; } 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. +#- returns true if <cluster> is empty. Note that this includes bad clusters. sub is_empty($) { my ($cluster) = @_; $cluster == 0 || $cluster == $resize_fat::bad_cluster_value; } -# returns true if <cluster> is available. +#- returns true if <cluster> is available. sub is_available($) { my ($cluster) = @_; $cluster == 0; } sub set_available($$) { my ($fs, $cluster) = @_; - set_next($fs, $cluster, 0); + set_next ($fs, $cluster, 0); } diff --git a/perl-install/resize_fat/info_sector.pm b/perl-install/resize_fat/info_sector.pm index c46ae15fc..1d9c1690a 100644 --- a/perl-install/resize_fat/info_sector.pm +++ b/perl-install/resize_fat/info_sector.pm @@ -1,4 +1,4 @@ -package resize_fat::info_sector; +package resize_fat::info_sector; # $Id$ use diagnostics; use strict; @@ -6,12 +6,13 @@ use strict; use common qw(:system); use resize_fat::io; +#- Oops, this will be unresizable on big-endian machine. trapped by signature. my $format = "a484 I I I a16"; my @fields = ( 'unused', - 'signature', # should be 0x61417272 - 'free_clusters', # -1 for unknown - 'next_cluster', # most recently allocated cluster + 'signature', #- should be 0x61417272 + 'free_clusters', #- -1 for unknown + 'next_cluster', #- most recently allocated cluster 'unused2', ); @@ -20,15 +21,15 @@ my @fields = ( sub read($) { my ($fs) = @_; - my $info = resize_fat::io::read($fs, $fs->{offset}, psizeof($format)); + my $info = resize_fat::io::read($fs, $fs->{info_offset}, psizeof($format)); @{$fs->{info_sector}}{@fields} = unpack $format, $info; - $fs->{info_sector}->{signature} == 0x61417272 or die "Invalid information sector signature\n"; + $fs->{info_sector}{signature} == 0x61417272 or die "Invalid information sector signature\n"; } sub write($) { my ($fs) = @_; - $fs->{info_sector}->{free_clusters} = $fs->{clusters}->{count}->{free}; - $fs->{info_sector}->{next_cluster} = 2; + $fs->{info_sector}{free_clusters} = $fs->{clusters}->{count}->{free}; + $fs->{info_sector}{next_cluster} = 2; my $info = pack $format, @{$fs->{info_sector}}{@fields}; diff --git a/perl-install/resize_fat/io.pm b/perl-install/resize_fat/io.pm index 8ffaa8355..7643a0953 100644 --- a/perl-install/resize_fat/io.pm +++ b/perl-install/resize_fat/io.pm @@ -1,16 +1,18 @@ -package resize_fat::io; +package resize_fat::io; # $Id$ use diagnostics; use strict; use resize_fat::fat; +use c; 1; sub read($$$) { my ($fs, $pos, $size) = @_; - my $buf; + print "reading $size bytes at $pos\n"; + 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; @@ -18,36 +20,31 @@ sub read($$$) { sub write($$$$) { my ($fs, $pos, $size, $buf) = @_; sysseek $fs->{fd}, $pos, 0 or die "seeking to byte #$pos failed on device $fs->{fs_name}"; - syswrite $fs->{fd}, $buf, $size or die "writing at byte #$pos failed on device $fs->{fs_name}"; + syswrite $fs->{fd}, $buf or die "writing at byte #$pos failed on device $fs->{fs_name}"; } sub read_cluster($$) { my ($fs, $cluster) = @_; my $buf; + my $pos = $fs->{cluster_offset} / 512 + $cluster * ($fs->{cluster_size} / 512); - eval { - $buf = &read($fs, - $fs->{cluster_offset} + $cluster * $fs->{cluster_size}, - $fs->{cluster_size}); - }; @$ and die "reading cluster #$cluster failed on device $fs->{fs_name}"; + c::lseek_sector(fileno $fs->{fd}, $pos, 0) or die "seeking to sector #$pos failed on device $fs->{fs_name}"; + sysread $fs->{fd}, $buf, $fs->{cluster_size} or die "reading at sector #$pos failed on device $fs->{fs_name}"; $buf; } sub write_cluster($$$) { my ($fs, $cluster, $buf) = @_; + my $pos = $fs->{cluster_offset} / 512 + $cluster * ($fs->{cluster_size} / 512); - eval { - &write($fs, - $fs->{cluster_offset} + $cluster * $fs->{cluster_size}, - $fs->{cluster_size}, - $buf); - }; @$ and die "writing cluster #$cluster failed on device $fs->{fs_name}"; + c::lseek_sector(fileno $fs->{fd}, $pos, 0) or die "seeking to sector #$pos failed on device $fs->{fs_name}"; + syswrite $fs->{fd}, $buf or die "writing at sector #$pos failed on device $fs->{fs_name}"; } sub read_file($$) { my ($fs, $cluster) = @_; my $buf = ''; - for (; !resize_fat::fat::is_eof($cluster); $cluster = resize_fat::fat::next($fs, $cluster)) { + for (; !resize_fat::fat::is_eof($cluster); $cluster = resize_fat::fat::next ($fs, $cluster)) { $cluster == 0 and die "Bad FAT: unterminated chain\n"; $buf .= read_cluster($fs, $cluster); } @@ -70,5 +67,5 @@ sub open($) { check_mounted($fs->{device}); sysopen F, $fs->{fs_name}, 2 or sysopen F, $fs->{fs_name}, 0 or die "error opening device $fs->{fs_name} for writing\n"; - $fs->{fd} = \*F; + $fs->{fd} = *F; } diff --git a/perl-install/resize_fat/main.pm b/perl-install/resize_fat/main.pm index 2d5f4f969..dc1a65e65 100644 --- a/perl-install/resize_fat/main.pm +++ b/perl-install/resize_fat/main.pm @@ -1,6 +1,25 @@ #!/usr/bin/perl -package resize_fat::main; +# DiskDrake +# Copyright (C) 1999 MandrakeSoft (pixel@linux-mandrake.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This is mainly a perl rewrite of the work of Andrew Clausen (libresize) + +package resize_fat::main; # $Id$ use diagnostics; use strict; @@ -15,79 +34,86 @@ use resize_fat::fat; use resize_fat::any; -#@ARGV == 2 or die "usage: fatresize <device> <size>\n <size> = 100 means `resize to 100Mb'\n <size> = +10 means `keep 10Mb of free space'\n"; -# -#my $fs = init($ARGV[0]); -#resize($fs, $ARGV[1]); - 1; -# - reads in the boot sector/partition info., and tries to make some sense of it +#- - reads in the boot sector/partition info., and tries to make some sense of it sub new($$$) { my ($type, $device, $fs_name) = @_; my $fs = { device => $device, fs_name => $fs_name } ; - resize_fat::io::open($fs); - 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); - + eval { + resize_fat::io::open($fs); + resize_fat::boot_sector::read($fs); + $resize_fat::isFAT32 and eval { resize_fat::info_sector::read($fs) }; + resize_fat::fat::read($fs); + resize_fat::any::flag_clusters($fs); + }; + if ($@) { + close $fs->{fd}; + die; + } bless $fs, $type; } -# 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) +sub DESTROY { + my ($fs) = @_; + close $fs->{fd}; + 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) sub copy_clusters { my ($fs, $cluster) = @_; my @buffer; - my $flush = sub { - while (@buffer) { + my $flush = sub { + while (@buffer) { my $cluster = shift @buffer; resize_fat::io::write_cluster($fs, $cluster, shift @buffer); } }; for (; $cluster < $fs->{nb_clusters} + 2; $cluster++) { - $fs->{fat_flag_map}->[$cluster] == $resize_fat::any::FILE or next; - push @buffer, $fs->{fat_remap}->[$cluster], resize_fat::io::read_cluster($fs, $cluster); + resize_fat::c_rewritten::flag($cluster) == $resize_fat::any::FILE or next; + push @buffer, + resize_fat::c_rewritten::fat_remap($cluster), + resize_fat::io::read_cluster($fs, $cluster); @buffer > 50 and &$flush(); } &$flush(); } -# Constructs the new directory tree to match the new file locations. +#- Constructs the new directory tree to match the new file locations. sub construct_dir_tree { my ($fs) = @_; - if ($resize_fat::isFAT32) { - # fat32's root must remain in the first 64k clusters - # so don't set it as DIRECTORY, it will be specially handled - $fs->{fat_flag_map}->[$fs->{fat32_root_dir_cluster}] = $resize_fat::any::FREE; + if ($resize_fat::isFAT32) { + #- fat32's root must remain in the first 64k clusters + #- so don't set it as DIRECTORY, it will be specially handled + resize_fat::c_rewritten::set_flag($fs->{fat32_root_dir_cluster}, $resize_fat::any::FREE); } for (my $cluster = 2; $cluster < $fs->{nb_clusters} + 2; $cluster++) { - $fs->{fat_flag_map}->[$cluster] == $resize_fat::any::DIRECTORY or next; + 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::io::write_cluster($fs, + resize_fat::c_rewritten::fat_remap($cluster), + resize_fat::directory::remap($fs, resize_fat::io::read_cluster($fs, $cluster))); } sync(); - # until now, only free clusters have been written. it's a null operation if we stop here. - # it means no corruption :) + #- until now, only free clusters have been written. it's a null operation if we stop here. + #- it means no corruption :) # - # now we must be as fast as possible! + #- now we must be as fast as possible! - # remapping non movable root directory + #- remapping non movable root directory if ($resize_fat::isFAT32) { my $cluster = $fs->{fat32_root_dir_cluster}; - resize_fat::io::write_cluster($fs, - $fs->{fat_remap}->[$cluster], + resize_fat::io::write_cluster($fs, + 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}, @@ -97,44 +123,50 @@ 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 -# - checks boundaries before starting -# - copies all data beyond new_cluster_count behind the frontier +#- resize +#- - size is in sectors +#- - checks boundaries before starting +#- - copies all data beyond new_cluster_count behind the frontier sub resize { my ($fs, $size) = @_; my ($min, $max) = (min_size($fs), max_size($fs)); - $size += $min if $size =~ /^\+/; $size >= $min or die "Minimum filesystem size is $min sectors"; $size <= $max or die "Maximum filesystem size is $max sectors"; - log::l("resize_fat: Partition size fill be ", $size * $SECTORSIZE >> 20, "Mb (well exactly ${size} sectors)"); + log::l("resize_fat: Partition size will be ". ($size * $SECTORSIZE >> 20) ."Mb (well exactly ${size} sectors)"); 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}; + $fs->{clusters}{count}->{free} = + $fs->{nb_clusters} - $fs->{clusters}{count}->{used} - $fs->{clusters}->{count}->{bad} - 2; $fs->{system_id} = 'was here!'; $fs->{small_nb_sectors} = 0; @@ -144,9 +176,10 @@ sub resize { resize_fat::boot_sector::write($fs); - $resize_fat::isFAT32 and eval { resize_fat::info_sector::write($fs) }; # doesn't matter if this fails - its pretty useless! + $resize_fat::isFAT32 and eval { resize_fat::info_sector::write($fs) }; #- doesn't matter if this fails - its pretty useless! sync(); + close $fs->{fd}; log::l("resize_fat: done"); } |