#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#include <sys/types.h>
#include <sys/dktp/fdisk.h>
#include <sys/fs/pc_fs.h>
#include <sys/fs/pc_dir.h>
#include <sys/fs/pc_label.h>
#include "pcfs_common.h"
#include "fsck_pcfs.h"
#include "pcfs_bpb.h"
extern off64_t FirstClusterOffset;
extern off64_t PartitionOffset;
extern int32_t BytesPerCluster;
extern int32_t TotalClusters;
extern int32_t LastCluster;
extern int32_t RootDirSize;
extern int32_t FATSize;
extern short FATEntrySize;
extern bpb_t TheBIOSParameterBlock;
extern int IsFAT32;
extern int Verbose;
static void
computeFileAreaSize(void)
{
int32_t dataSectors;
int32_t overhead;
BytesPerCluster = TheBIOSParameterBlock.bpb.sectors_per_cluster *
TheBIOSParameterBlock.bpb.bytes_per_sector;
if (TheBIOSParameterBlock.bpb.sectors_in_volume > 0)
dataSectors = TheBIOSParameterBlock.bpb.sectors_in_volume;
else
dataSectors =
TheBIOSParameterBlock.bpb.sectors_in_logical_volume;
overhead = TheBIOSParameterBlock.bpb.resv_sectors;
RootDirSize = TheBIOSParameterBlock.bpb.num_root_entries *
sizeof (struct pcdir);
overhead += RootDirSize / TheBIOSParameterBlock.bpb.bytes_per_sector;
if (TheBIOSParameterBlock.bpb.sectors_per_fat) {
overhead += TheBIOSParameterBlock.bpb.num_fats *
TheBIOSParameterBlock.bpb.sectors_per_fat;
FATSize = TheBIOSParameterBlock.bpb.sectors_per_fat *
TheBIOSParameterBlock.bpb.bytes_per_sector;
} else {
overhead += TheBIOSParameterBlock.bpb.num_fats *
TheBIOSParameterBlock.bpb32.big_sectors_per_fat;
FATSize = TheBIOSParameterBlock.bpb32.big_sectors_per_fat *
TheBIOSParameterBlock.bpb.bytes_per_sector;
}
dataSectors -= overhead;
TotalClusters = dataSectors /
TheBIOSParameterBlock.bpb.sectors_per_cluster;
LastCluster = TotalClusters + FIRST_CLUSTER;
FirstClusterOffset = overhead *
TheBIOSParameterBlock.bpb.bytes_per_sector;
FirstClusterOffset += PartitionOffset;
if (IsFAT32)
FATEntrySize = 32;
else {
if (TotalClusters <= DOS_F12MAXC)
FATEntrySize = 12;
else
FATEntrySize = 16;
}
if (Verbose) {
(void) fprintf(stderr,
gettext("Disk has a file area of %d "
"allocation units,\neach with %d sectors = %llu "
"bytes.\n"), TotalClusters,
TheBIOSParameterBlock.bpb.sectors_per_cluster,
(uint64_t)TotalClusters *
TheBIOSParameterBlock.bpb.sectors_per_cluster *
TheBIOSParameterBlock.bpb.bytes_per_sector);
(void) fprintf(stderr,
gettext("File system overhead of %d sectors.\n"), overhead);
(void) fprintf(stderr,
gettext("The last cluster is %d\n"), LastCluster);
}
}
void
readBPB(int fd)
{
boot_sector_t ubpb;
if (lseek64(fd, PartitionOffset, SEEK_SET) < 0) {
mountSanityCheckFails();
perror(gettext("Cannot seek to start of disk partition"));
(void) close(fd);
exit(7);
}
if (Verbose)
(void) fprintf(stderr,
gettext("Reading BIOS parameter block\n"));
if (read(fd, ubpb.buf, bpsec) < bpsec) {
mountSanityCheckFails();
perror(gettext("Read BIOS parameter block"));
(void) close(fd);
exit(2);
}
if (ltohs(ubpb.mb.signature) != BOOTSECSIG) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bad signature on BPB. Giving up.\n"));
exit(2);
}
#ifdef _BIG_ENDIAN
swap_pack_grabbpb(&TheBIOSParameterBlock, &(ubpb.bs));
#else
(void) memcpy(&(TheBIOSParameterBlock.bpb), &(ubpb.bs.bs_front.bs_bpb),
sizeof (TheBIOSParameterBlock.bpb));
(void) memcpy(&(TheBIOSParameterBlock.ebpb), &(ubpb.bs.bs_ebpb),
sizeof (TheBIOSParameterBlock.ebpb));
#endif
if (TheBIOSParameterBlock.bpb.bytes_per_sector != 512 &&
TheBIOSParameterBlock.bpb.bytes_per_sector != 1024 &&
TheBIOSParameterBlock.bpb.bytes_per_sector != 2048 &&
TheBIOSParameterBlock.bpb.bytes_per_sector != 4096) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bogus bytes per sector value. Giving up.\n"));
exit(2);
}
if (!(ISP2(TheBIOSParameterBlock.bpb.sectors_per_cluster) &&
IN_RANGE(TheBIOSParameterBlock.bpb.sectors_per_cluster,
1, 128))) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bogus sectors per cluster value. Giving up.\n"));
(void) close(fd);
exit(6);
}
if (TheBIOSParameterBlock.bpb.sectors_per_fat == 0) {
#ifdef _BIG_ENDIAN
swap_pack_grab32bpb(&TheBIOSParameterBlock, &(ubpb.bs));
#else
(void) memcpy(&(TheBIOSParameterBlock.bpb32),
&(ubpb.bs32.bs_bpb32),
sizeof (TheBIOSParameterBlock.bpb32));
#endif
IsFAT32 = 1;
}
if (!IsFAT32) {
if ((TheBIOSParameterBlock.bpb.num_root_entries == 0) ||
((TheBIOSParameterBlock.bpb.num_root_entries *
sizeof (struct pcdir)) %
TheBIOSParameterBlock.bpb.bytes_per_sector) != 0) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bogus number of root entries. "
"Giving up.\n"));
exit(2);
}
} else {
if (TheBIOSParameterBlock.bpb.num_root_entries != 0) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bogus number of root entries. "
"Giving up.\n"));
exit(2);
}
}
if (TheBIOSParameterBlock.bpb.num_fats > 4 ||
TheBIOSParameterBlock.bpb.num_fats < 1) {
mountSanityCheckFails();
(void) fprintf(stderr,
gettext("Bogus number of FATs. Giving up.\n"));
exit(2);
}
computeFileAreaSize();
}