1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package resize_fat::any;
use diagnostics;
use strict;
use vars qw($FREE $FILE $DIRECTORY);
use common qw(:common :constant);
use resize_fat::fat;
use resize_fat::directory;
use resize_fat::dir_entry;
$FREE = 0;
$FILE = 1;
$DIRECTORY = 2;
1;
# returns the number of clusters for a given filesystem type
sub min_cluster_count($) {
my ($fs) = @_;
(1 << $ {{ FAT16 => 12, FAT32 => 12 }}{$fs->{fs_type}}) - 12;
}
sub max_cluster_count($) {
my ($fs) = @_;
2 ** $fs->{fs_type_size} - 11;
}
# calculates the minimum size of a partition, in physical sectors
sub min_size($) {
my ($fs) = @_;
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 :)
my $min_cluster_count = max(2 + $count->{used} + $count->{bad} + $count->{dirs}, min_cluster_count($fs));
$min_cluster_count * divide($fs->{cluster_size}, $SECTORSIZE) +
divide($fs->{cluster_offset}, $SECTORSIZE);
}
# calculates the maximum size of a partition, in physical sectors
sub max_size($) {
my ($fs) = @_;
my $max_cluster_count = min($fs->{nb_fat_entries} - 2, max_cluster_count($fs));
$max_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.
sub flag_clusters {
my ($fs) = @_;
my ($cluster, $entry, $type);
my $f = sub {
($entry) = @_;
$cluster = resize_fat::dir_entry::get_cluster($entry);
if (resize_fat::dir_entry::is_file($entry)) {
$type = $FILE;
} 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;
}
};
$fs->{fat_flag_map} = [ ($FREE) x ($fs->{nb_clusters} + 2) ];
$fs->{clusters}{count}{dirs} = 0;
resize_fat::directory::traverse_all($fs, $f);
}
|