// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Package bootrecord describes the first sectors of a partition, which hold filesystem metadata.
package bootrecord

import (
	"errors"
	"unsafe"

	"github.com/golang/glog"

	"go.fuchsia.dev/fuchsia/src/lib/thinfs/thinio"
)

const (
	// NumReservedClusters describes how many cluster numbers are reserved (FAT[0] and FAT[1]).
	NumReservedClusters uint32 = 2

	// BootrecordSize is the size of a bootrecord
	BootrecordSize = 512
)

// Bootrecord describes the underlying boot record, independent of FAT type.
type Bootrecord struct {
	t      FATType
	device *thinio.Conductor

	// Cached values which have been pulled from the bootrecord on disk.
	totalSectors      uint32
	sectorSize        uint32 // In bytes
	clusterSize       uint32 // In bytes
	sectorsPerCluster uint32
	numUsableClusters uint32
	sectorsPerFAT     uint32
	reservedSectors   uint32
	numFATs           uint32
	firstDataSector   uint32
	mirroringActive   bool
	primaryFAT        uint32

	// FAT32 exclusive
	rootCluster  uint32
	fsInfoOffset int64

	// FAT12/16 exclusive
	numRootEntriesMax uint32
}

// Type returns the type of the underlying Bootrecord.
func (b *Bootrecord) Type() FATType {
	return b.t
}

// FATEntrySize returns the size (in bytes) of a single entry in the FAT.
func (b *Bootrecord) FATEntrySize() uint32 {
	switch b.t {
	case FAT32:
		return 4
	case FAT16:
		return 2
	default:
		panic("Not supported")
	}
}

// ClusterSize returns the size of a single cluster.
// The size of a single cluster should be a power of two multiple of the sector size.
func (b *Bootrecord) ClusterSize() uint32 {
	return b.clusterSize
}

// ClusterInValidRange checks that the cluster is in a valid range.
// It does not access the entry corresponding to the cluster.
func (b *Bootrecord) ClusterInValidRange(cluster uint32) bool {
	minCluster := NumReservedClusters
	maxCluster := minCluster + b.NumUsableClusters()
	return (minCluster <= cluster && cluster <= maxCluster)
}

// VolumeSize returns the size of all sectors allocated to the FAT filesystem.
func (b *Bootrecord) VolumeSize() int64 {
	return int64(b.totalSectors) * int64(b.sectorSize)
}

// FsInfoOffset returns the offset in the device of the FS Info structure,
// or an error if the value is invalid.
func (b *Bootrecord) FsInfoOffset() (int64, error) {
	if b.fsInfoOffset == 0 {
		return 0, errors.New("Missing/Invalid FS Info structure")
	}
	return b.fsInfoOffset, nil
}

// MirroringInfo describes if mirroring is necessary.
//
// If mirroring is active, returns "true", along with the number of FATs which need to be mirrored.
// If mirroring is disabled, returns "false", along with the primary FAT which should be used.
func (b *Bootrecord) MirroringInfo() (active bool, numFATs, primary uint32) {
	return b.mirroringActive, b.numFATs, b.primaryFAT
}

// ClusterLocationFATPrimary returns device offset for a particular cluster index in the primary
// File Allocation Table.
func (b *Bootrecord) ClusterLocationFATPrimary(cluster uint32) int64 {
	indexFAT := b.primaryFAT
	return b.ClusterLocationFAT(indexFAT, cluster)
}

// ClusterLocationFAT returns device offset for a particular cluster index in an arbitrary File
// Allocation Table.
func (b *Bootrecord) ClusterLocationFAT(indexFAT, cluster uint32) int64 {
	offsetOfFAT := (b.reservedSectors + indexFAT*b.sectorsPerFAT) * b.sectorSize
	offsetInsideFAT := cluster * b.FATEntrySize()
	return int64(offsetOfFAT + offsetInsideFAT)
}

// ClusterLocationData returns the device offset for a cluster's data.
func (b *Bootrecord) ClusterLocationData(cluster uint32) int64 {
	clusterSector := ((cluster - 2) * b.sectorsPerCluster) + b.firstDataSector
	return int64(clusterSector) * int64(b.sectorSize)
}

// NumUsableClusters returns the number of non-reserved sectors.
func (b *Bootrecord) NumUsableClusters() uint32 {
	return b.numUsableClusters
}

// RootCluster returns the cluster number of the root directory. Returns an error if the root
// directory is not found in a cluster (as is the case for FAT12 and FAT16).
func (b *Bootrecord) RootCluster() uint32 {
	switch b.t {
	case FAT32:
		return b.rootCluster
	case FAT16, FAT12:
		panic("Root cluster does not exist outside FAT32")
	default:
		panic("Unsupported FAT version")
	}
}

// RootReservedInfo provides information for the root directory on FAT12 and FAT16 filesystems.
func (b *Bootrecord) RootReservedInfo() (offsetStart int64, numRootEntriesMax int64) {
	switch b.t {
	case FAT32:
		panic("Root is not in the reserved region for FAT32")
	case FAT16, FAT12:
		offsetStart = int64(b.sectorSize * (b.reservedSectors + (b.numFATs * b.sectorsPerFAT)))
		numRootEntriesMax = int64(b.numRootEntriesMax)
		return
	default:
		panic("Unsupported FAT version")
	}
}

// New returns a new Bootrecord described by the first 512 bytes of a partition.
// Returns an error if the first 512 bytes of the partition do not match a known (or supported) FAT
// version.
func New(d *thinio.Conductor) (*Bootrecord, error) {
	glog.V(1).Info("Creating a New bootrecord")
	buf := make([]byte, BootrecordSize)
	_, err := d.ReadAt(buf, 0)
	if err != nil {
		return nil, err
	}

	// One of these is valid, the other is not. We need to discover which is which.
	small := *(*brSmall)(unsafe.Pointer(&buf[0]))
	large := *(*brLarge)(unsafe.Pointer(&buf[0]))

	// This is not the "official way" to determine the FAT type, but it lets us distinguish betwen
	// the small and large types of FATs. We'll guess the type now, and continue validating it
	// later.
	sizeClassLarge := large.bpb.guessFATType()

	var fatType FATType
	var bpb *bpbShared
	var firstDataSector uint32
	if sizeClassLarge {
		// Probably FAT32.
		if err := large.Validate(); err != nil {
			return nil, err
		}
		fatType = FAT32
		bpb = &large.bpb
		firstDataSector = large.FirstDataSector()
	} else {
		// Probably FAT12/16.
		if fatType, err = small.Validate(); err != nil {
			return nil, err
		}
		bpb = &small.bpb
		firstDataSector = small.FirstDataSector()
	}

	br := &Bootrecord{
		t:      fatType,
		device: d,
	}

	br.totalSectors = bpb.TotalSectors()
	br.sectorSize = bpb.BytesPerSec()
	br.sectorsPerCluster = bpb.SectorsPerCluster()
	br.clusterSize = br.sectorsPerCluster * br.sectorSize
	br.numUsableClusters = bpb.TotalClusters(firstDataSector) - NumReservedClusters
	br.firstDataSector = firstDataSector
	br.reservedSectors = bpb.NumSectorsReserved()
	br.numFATs = bpb.NumFATs()

	switch br.t {
	case FAT32:
		glog.V(1).Info("Loading a FAT32 bootrecord")
		br.sectorsPerFAT = large.bpbExtended.SectorsPerFAT32()
		br.mirroringActive, br.primaryFAT = large.bpbExtended.MirroringInfo()
		br.rootCluster = large.bpbExtended.RootCluster()
		fsInfoSector := large.bpbExtended.FsInfoSector()
		if 0 < fsInfoSector && fsInfoSector < br.reservedSectors {
			// Only use fsInfoSector if it is in the "reserved sector" region.
			br.fsInfoOffset = int64(large.bpbExtended.FsInfoSector() * br.sectorSize)
		}

		if !br.ClusterInValidRange(br.rootCluster) {
			return nil, errors.New("Invalid root cluster")
		}
	case FAT16:
		glog.V(1).Info("Loading a FAT16 bootrecord")
		br.sectorsPerFAT = small.bpb.SectorsPerFAT16()
		// Mirroring assumed to be active on FAT16.
		br.mirroringActive = true
		br.primaryFAT = 0
		br.numRootEntriesMax = small.bpb.NumRootEntries()
	default:
		// At the moment, FAT12 is unsupported.
		glog.V(1).Info("Cannot load unsupported FAT type")
		return nil, errors.New("Unsupported version of FAT")
	}

	if d.DeviceSize() < br.VolumeSize() {
		return nil, errors.New("Cannot load filesystem: expects more sectors than device provides")
	}
	return br, nil
}
