Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / TruncFD.pm
1 # Perl subroutine to shorten a floppy image by omitting trailing sectors
2 # that are not in use
3 #
4 # AFAIK works on FAT12 and FAT16. Won't work on FAT32
5 #
6 # 2003.04.28 R. Main.
7 #   Fixes for images with > 65535 sectors
8 #
9 # Placed under GNU Public License by Ken Yap, April 2000
10
11 package TruncFD;
12
13 use strict;
14 use IO::Seekable;
15 use POSIX qw(ceil);
16
17 use constant;
18 use constant DEBUG => 0;
19
20 sub truncfd ($)
21 {
22         my ($file) = @_;
23         my ($nread, $buffer, $cylinders, $clusters, $fatsectors,
24                 $rootdirsectors, @fatents, $i, $lastclus, $clusstart, $lastsector);
25         
26         return -1 if (!defined($file) or !open(F, "$file"));
27         binmode(F);
28         $nread = read(F, $buffer, 512);
29         return -1 if (!defined($nread) or $nread < 512);
30
31         my ($dummy1, $bytepersect, $sectperclus, $resvsectors, $fats, $rootdirents,
32                 $sectors, $dummy2, $sectperfat, $sectpertrk, $heads, $hidsectors,
33                 $bigsectors, $dummy3, $fstype) =
34                 unpack('a11vCvCvvavvvVVa18a5', $buffer);
35         if ($sectors == 0) {
36             $sectors = $bigsectors;
37         }
38         $cylinders = $sectors / ($sectpertrk * $heads);
39         $fatsectors = $fats * $sectperfat;
40         $rootdirsectors = POSIX::ceil(($rootdirents * 32) / $bytepersect);
41         $clusstart  = $resvsectors + $fatsectors + $rootdirsectors;
42         $clusters = int (($sectors - $clusstart) / $sectperclus);
43         return (-s $file) unless $clusters < 65525;
44         $fstype = $clusters < 4085? 'FAT12':'FAT16' if ($fstype ne 'FAT12' && $fstype ne 'FAT16');
45         if (DEBUG) {
46                 print STDERR <<EOF;
47 $fstype filesystem:
48
49 Bytes/sector:           $bytepersect
50 Heads:                  $heads
51 Cylinders:              $cylinders
52 Sectors/cluster:        $sectperclus
53 Clusters:               $clusters
54 Reserved sectors:       $resvsectors
55 Hidden sectors:         $hidsectors
56 Total sectors:          $sectors
57 Sectors/track:          $sectpertrk
58 FATs:                   $fats
59 Sectors/FAT:            $sectperfat
60 FAT sectors:            $fatsectors
61 Root dir entries:       $rootdirents
62 Root dir sectors:       $rootdirsectors
63
64 EOF
65         }
66         return -1 if (!seek(F, $resvsectors * 512, SEEK_SET));
67         $nread = read(F, $buffer, $sectperfat * 512);
68         close(F);
69         return -1 if (!defined($nread));
70         # Default assumption is FAT16
71         # For FAT12
72         if ($fstype eq 'FAT12') {
73                 $buffer =~ s/(...)/$1\x00/sg;
74         }
75         @fatents = unpack("V$clusters", $buffer);
76         # For FAT12 shift bits 23..12 up 4 bits to make it just like FAT16
77         if ($fstype eq 'FAT12') {
78                 foreach $i (0..$#fatents) {
79                         $fatents[$i] = ($fatents[$i] & 0xFFF) | ($fatents[$i] >> 12) << 16;
80                 }
81         }
82         # Make a string of it
83         $buffer = pack("L*", @fatents);
84         # Then extract in little endian format
85         @fatents = unpack("v*", $buffer);
86         $#fatents = $clusters + 1 if (($clusters + 1) < $#fatents);
87         foreach $i (reverse(0..$#fatents)) {
88                 $lastclus = $i, last if ($fatents[$i] != 0);
89         }
90         print STDERR "Last used cluster is $lastclus\n" if (DEBUG);
91         $lastsector = $clusstart + ($lastclus - 1) * $sectperclus;
92         print STDERR "Last used sector is $lastsector\n" if (DEBUG);
93         return ($lastsector * 512);
94 }
95
96 1;