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 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
# Perl subroutine to shorten a floppy image by omitting trailing sectors
# that are not in use
#
# AFAIK works on FAT12 and FAT16. Won't work on FAT32
#
# 2003.04.28 R. Main.
# Fixes for images with > 65535 sectors
#
# Placed under GNU Public License by Ken Yap, April 2000
package TruncFD;
use strict;
use IO::Seekable;
use POSIX qw(ceil);
use constant;
use constant DEBUG => 0;
sub truncfd ($)
{
my ($file) = @_;
my ($nread, $buffer, $cylinders, $clusters, $fatsectors,
$rootdirsectors, @fatents, $i, $lastclus, $clusstart, $lastsector);
return -1 if (!defined($file) or !open(F, "$file"));
binmode(F);
$nread = read(F, $buffer, 512);
return -1 if (!defined($nread) or $nread < 512);
my ($dummy1, $bytepersect, $sectperclus, $resvsectors, $fats, $rootdirents,
$sectors, $dummy2, $sectperfat, $sectpertrk, $heads, $hidsectors,
$bigsectors, $dummy3, $fstype) =
unpack('a11vCvCvvavvvVVa18a5', $buffer);
if ($sectors == 0) {
$sectors = $bigsectors;
}
$cylinders = $sectors / ($sectpertrk * $heads);
$fatsectors = $fats * $sectperfat;
$rootdirsectors = POSIX::ceil(($rootdirents * 32) / $bytepersect);
$clusstart = $resvsectors + $fatsectors + $rootdirsectors;
$clusters = int (($sectors - $clusstart) / $sectperclus);
return (-s $file) unless $clusters < 65525;
$fstype = $clusters < 4085? 'FAT12':'FAT16' if ($fstype ne 'FAT12' && $fstype ne 'FAT16');
if (DEBUG) {
print STDERR <<EOF;
$fstype filesystem:
Bytes/sector: $bytepersect
Heads: $heads
Cylinders: $cylinders
Sectors/cluster: $sectperclus
Clusters: $clusters
Reserved sectors: $resvsectors
Hidden sectors: $hidsectors
Total sectors: $sectors
Sectors/track: $sectpertrk
FATs: $fats
Sectors/FAT: $sectperfat
FAT sectors: $fatsectors
Root dir entries: $rootdirents
Root dir sectors: $rootdirsectors
EOF
}
return -1 if (!seek(F, $resvsectors * 512, SEEK_SET));
$nread = read(F, $buffer, $sectperfat * 512);
close(F);
return -1 if (!defined($nread));
# Default assumption is FAT16
# For FAT12
if ($fstype eq 'FAT12') {
$buffer =~ s/(...)/$1\x00/sg;
}
@fatents = unpack("V$clusters", $buffer);
# For FAT12 shift bits 23..12 up 4 bits to make it just like FAT16
if ($fstype eq 'FAT12') {
foreach $i (0..$#fatents) {
$fatents[$i] = ($fatents[$i] & 0xFFF) | ($fatents[$i] >> 12) << 16;
}
}
# Make a string of it
$buffer = pack("L*", @fatents);
# Then extract in little endian format
@fatents = unpack("v*", $buffer);
$#fatents = $clusters + 1 if (($clusters + 1) < $#fatents);
foreach $i (reverse(0..$#fatents)) {
$lastclus = $i, last if ($fatents[$i] != 0);
}
print STDERR "Last used cluster is $lastclus\n" if (DEBUG);
$lastsector = $clusstart + ($lastclus - 1) * $sectperclus;
print STDERR "Last used sector is $lastsector\n" if (DEBUG);
return ($lastsector * 512);
}
1;
|