windows-nt/Source/XPSP1/NT/drivers/storage/tffsport/fatfilt.c

1521 lines
50 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*******************************************************************************
* *
* M-Systems Confidential *
* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 *
* All Rights Reserved *
* *
*******************************************************************************
* *
* NOTICE OF M-SYSTEMS OEM *
* SOFTWARE LICENSE AGREEMENT *
* *
* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE AGREEMENT *
* BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT FOR THE SPECIFIC *
* TERMS AND CONDITIONS OF USE, OR CONTACT M-SYSTEMS FOR LICENSE *
* ASSISTANCE: *
* E-MAIL = info@m-sys.com *
* *
*******************************************************************************
* *
* *
* Module: FATFILT *
* *
* This module implements installable FAT12/16 filters. It supports up to *
* SOCKETS sockets, with up to MAX_TL_PARTITIONS disks per socket. *
* Each disk can contain up to FL_MAX_PARTS_PER_DISK partitions on it, with *
* maximum depth of partition nesting in extended partitions equal to *
* MAX_PARTITION_DEPTH. *
* *
* In order for this module to work, disks must be abs.mounted rather then *
* mounted. In latter case, this module won't detect any of disk's *
* partitions, and won't install FAT filters. *
* *
* This module uses more then 512 bytes of stack space in case if MALLOC is *
* not enabled. *
* *
*******************************************************************************/
/*
* $Log: V:/Flite/archives/TrueFFS5/Src/FATFILT.C_V $
*
* Rev 1.10 Jan 17 2002 23:00:14 oris
* Changed debug print added \r.
*
* Rev 1.9 Sep 15 2001 23:45:50 oris
* Changed BIG_ENDIAN to FL_BIG_ENDIAN
*
* Rev 1.8 Jun 17 2001 16:39:10 oris
* Improved documentation and remove warnings.
*
* Rev 1.7 May 16 2001 21:17:18 oris
* Added the FL_ prefix to the following defines: MALLOC and FREE.
*
* Rev 1.6 May 01 2001 14:21:02 oris
* Remove warnings.
*
* Rev 1.5 Apr 30 2001 18:00:10 oris
* Added casting to remove warrnings.
*
* Rev 1.4 Apr 24 2001 17:07:32 oris
* Missing casting of MALLOC calls.
*
* Rev 1.3 Apr 10 2001 23:54:24 oris
* FL_MAX_DISKS_PER_SOCKET changed to MAX_TL_PARTITIONS.
*
* Rev 1.2 Apr 09 2001 15:00:42 oris
* Change static allocation to dynamic allocations.
* Renamed flffCheck back to ffCheckBeforeWrite to be backwards compatible with OSAK 4.2.
*
* Rev 1.1 Apr 01 2001 07:51:16 oris
* New implementation of fat filter.
*
* Rev 1.0 19 Feb 2001 21:14:14 andreyk
* Initial revision.
*/
/*
* Includes
*/
#include "fatfilt.h"
#include "blockdev.h"
#include "flflash.h"
#include "bddefs.h"
#if defined(ABS_READ_WRITE) && !defined(FL_READ_ONLY)
/*
* Module configuration
*/
#define FL_INCLUDE_FAT_MONITOR /* undefine it to remove FAT filter code */
/*
* Defines
*/
/* extract pointer to user's buffer from IOreq */
#ifdef SCATTER_GATHER
#define FLBUF(ioreq,i) (*((char FAR1 **)((ioreq)->irData) + (int)(i)))
#else
#define FLBUF(ioreq,i) ((char FAR1 *)(ioreq->irData) + (SECTOR_SIZE * ((int)(i))))
#endif
/* extract socket# and disk# from TFFS handle */
#define H2S(handle) (((int)(handle)) & 0xf)
#define H2D(handle) ((((int)(handle)) >> 4) & 0xf)
/* construct TFFS handle from socket# and disk# */
#define SD2H(socNo,diskNo) ((int)((((diskNo) & 0xf) << 4) | ((socNo) & 0xf)))
/* unformatted ("raw") disk partition */
#define FL_RAW_PART (-1)
/*
* Local routines
*/
static FLStatus reset (void);
static FLStatus discardDisk (int handle);
static FLStatus newDisk (int handle);
static FLStatus parseDisk (int handle);
static FLStatus discardDiskParts (FLffDisk *pd);
static FLStatus addDiskPart (FLffDisk *pd, int partNo);
static FLStatus addNewDiskPart (FLffDisk *pd);
static FLBoolean isPartTableWrite (FLffDisk *pd, IOreq FAR2 *ioreq);
static FLStatus isExtPartPresent (char FAR1 *buf, SectorNo *nextExtPartSec);
#ifdef FL_INCLUDE_FAT_MONITOR
static FLStatus partEnableFF (FLffVol* pv);
static FLStatus partFreeDelClusters (FLffVol *pv, SectorNo secNo, char FAR1 *newFAT);
#endif
/*
* Local data
*/
/* module reset flag */
static FLBoolean resetDone = FALSE;
/* disks (BDTL partitions in OSAK terminology) */
static FLffDisk* ffDisk[SOCKETS][MAX_TL_PARTITIONS] = { { NULL } };
#ifndef FL_MALLOC
/*
* WARNING: Large static arrays !
*
* sizeof(ffAllDisks[x][y]) is 64 bytes.
* sizeof(ffAllParts[x][y][z]) is 40 bytes.
*
*/
static FLffDisk ffAllDisks[SOCKETS][MAX_TL_PARTITIONS];
static FLffVol ffAllParts[SOCKETS][MAX_TL_PARTITIONS][FL_MAX_PARTS_PER_DISK];
#endif /* FL_MALLOC */
static const char zeroes[SECTOR_SIZE] = {0};
/* --------------------------------------------------------------------------- *
* *
* d i s c a r d D i s k P a r t s *
* *
* Discard all the partition info (if any) associated with particular disk. *
* *
* Parameters: *
* pd : disk (BDTL volume) *
* *
* Returns: *
* Always flOK. *
* *
* --------------------------------------------------------------------------- */
static FLStatus discardDiskParts ( FLffDisk * pd )
{
register int i;
if (pd != NULL) {
for (i = 0; i < FL_MAX_PARTS_PER_DISK; i++) {
#ifdef FL_MALLOC
if (pd->part[i] != NULL)
FL_FREE(pd->part[i]);
#endif
pd->part[i] = NULL;
}
pd->parts = 0;
}
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* a d d D i s k P a r t *
* *
* If there is partition record #partNo associated with the disk, discard *
* this info. Attach new partition record #partNo. *
* *
* Parameters: *
* pd : disk (BDTL volume) *
* partNo : partition (0 ... FL_MAX_PARTS_PER_DISK-1) *
* *
* Returns: *
* flOK if success, otherwise respective error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus addDiskPart ( FLffDisk * pd,
int partNo )
{
FLffVol * pv;
FLStatus status;
int socNo, diskNo;
/* arg. sanity check */
if ((pd == NULL) || (partNo >= FL_MAX_PARTS_PER_DISK))
return flBadDriveHandle;
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(pd->handle);
diskNo = H2D(pd->handle);
if ((socNo >= SOCKETS) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
status = flNotEnoughMemory;
#ifdef FL_MALLOC
pv = (FLffVol *)FL_MALLOC( sizeof(FLffVol) );
#else
pv = &ffAllParts[socNo][diskNo][partNo];
#endif
if (pv != NULL) {
/* initialize fields in struct FLffDisk to safe values */
pv->handle = pd->handle;
pv->type = FL_RAW_PART;
pv->flags = 0;
pv->ffEnabled = FALSE; /* turn off FAT minitor */
pv->sectors = (SectorNo) 0;
pv->firstFATsecNo = (SectorNo) -1; /* none */
pv->lastFATsecNo = pv->firstFATsecNo; /* none */
pv->firstDataSecNo = (SectorNo) 0;
pv->clusterSize = (unsigned) 0;
#ifdef FL_MALLOC
if( pd->part[partNo] != NULL )
FL_FREE(pd->part[partNo]);
#endif
pd->part[partNo] = pv;
status = flOK;
}
return status;
}
/* --------------------------------------------------------------------------- *
* *
* a d d N e w D i s k P a r t *
* *
* Add one more partition record to the disk. *
* *
* Parameters: *
* pd : disk (BDTL volume) *
* *
* Returns: *
* flOK if success, otherwise respective error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus addNewDiskPart ( FLffDisk * pd )
{
if (pd->parts < FL_MAX_PARTS_PER_DISK) {
checkStatus( addDiskPart (pd, pd->parts) );
pd->parts++;
}
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* d i s c a r d D i s k *
* *
* Remove disk record (with all the associated partition records). *
* *
* Parameters: *
* handle : TFFS handle *
* *
* Returns: *
* flOK if success, otherwise respective error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus discardDisk ( int handle )
{
int socNo, diskNo;
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(handle);
diskNo = H2D(handle);
if ((socNo >= SOCKETS) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
if( ffDisk[socNo][diskNo] != NULL ) {
/* discard associated partition info */
(void) discardDiskParts( ffDisk[socNo][diskNo] );
#ifdef FL_MALLOC
/* release disk's scratch buffer */
if( (ffDisk[socNo][diskNo])->buf != NULL)
FL_FREE( (ffDisk[socNo][diskNo])->buf );
FL_FREE( ffDisk[socNo][diskNo] );
#endif
ffDisk[socNo][diskNo] = NULL;
}
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* n e w D i s k *
* *
* Discard existing disk record (if any), and create new one. *
* *
* Parameters: *
* handle : TFFS handle *
* *
* Returns: *
* flOK if success, otherwise respective error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus newDisk ( int handle )
{
int socNo, diskNo;
int i;
FLffDisk * pd;
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(handle);
diskNo = H2D(handle);
if ((socNo >= SOCKETS) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* discard current disk and associated partition info (if any) */
checkStatus( discardDisk(handle) );
#ifdef FL_MALLOC
pd = (FLffDisk *) FL_MALLOC( sizeof(FLffDisk) );
if (pd == NULL)
return flNotEnoughMemory;
/* allocate and attach disk's scratch buffer */
pd->buf = (char *)FL_MALLOC( SECTOR_SIZE );
if (pd->buf == NULL) {
FL_FREE (pd);
return flNotEnoughMemory;
}
#else /* !FL_MALLOC */
pd = &ffAllDisks[socNo][diskNo];
#endif /* FL_MALLOC */
pd->handle = handle;
pd->ffstate = flStateNotInitialized;
/* don't know partition layout yet */
pd->parts = 0;
for (i = 0; i < FL_MAX_PARTS_PER_DISK; i++)
pd->part[i] = NULL;
/* watch Master Boot Record for update */
pd->secToWatch = (SectorNo) 0;
ffDisk[socNo][diskNo] = pd;
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* i s P a r t T a b l e W r i t e *
* *
* Check if any of the sectors specified by 'ioreq' points to Master Boot *
* Record or next extended partition in the extended partitions list. *
* *
* Parameters: *
* pd : pointer to disk structure *
* ioreq : standard I/O request *
* *
* Returns: *
* TRUE if write to MBR or extended partition list is detected, otherwise *
* FALSE *
* *
* --------------------------------------------------------------------------- */
static FLBoolean isPartTableWrite ( FLffDisk * pd,
IOreq FAR2 * ioreq )
{
register long i;
if (pd != NULL) {
for (i = (long)0; i < ioreq->irSectorCount; i++) {
if( (ioreq->irSectorNo + i) == (long)pd->secToWatch )
return TRUE;
}
}
return FALSE;
}
/* --------------------------------------------------------------------------- *
* *
* i s E x t P a r t P r e s e n t *
* *
* Check if extended partition persent in the partition table. If it is, *
* calculate the sector # where next partition table will be written to. *
* *
* Parameters: *
* buf : partition table *
* nextExtPartSec : sector where next partition table will be written to *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus isExtPartPresent ( char FAR1 * buf,
SectorNo * nextExtPartSec )
{
Partition FAR1 * p;
register int i;
/* does it look like partition table ? */
if (LE2(((PartitionTable FAR1 *) buf)->signature) != PARTITION_SIGNATURE)
return flBadFormat;
/* if extended. part. present, get sector# that will contain next part. in list */
p = &( ((PartitionTable FAR1 *) buf)->ptEntry[0] );
for (i = 0; i < FL_PART_TBL_ENTRIES; i++, p++) {
if (p->type == EX_PARTIT) {
*nextExtPartSec = (SectorNo) UNAL4( (void *) p[i].startingSectorOfPartition );
return flOK;
}
}
/* no extended partition found */
return flFileNotFound;
}
/* --------------------------------------------------------------------------- *
* *
* r e s e t *
* *
* Resets this software module to it's initial state upon boot. *
* *
* Parameters: *
* none *
* *
* Returns: *
* flOK in case of success, otherwise respective error code *
* *
* --------------------------------------------------------------------------- */
static FLStatus reset (void)
{
int iSoc, iDisk;
for (iSoc = 0; iSoc < SOCKETS; iSoc++) {
/* discard existing disk structures for that socket */
for (iDisk = 0; iDisk < MAX_TL_PARTITIONS; iDisk++)
(void) discardDisk( SD2H(iSoc, iDisk) );
/* pre-allocate disk structure for first disk of every socket */
checkStatus( newDisk(SD2H(iSoc, 0)) );
}
resetDone = TRUE;
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* p a r s e D i s k *
* *
* Read partition table(s), install and enable FAT filters on all FAT12/16 *
* partitions. *
* *
* Parameters: *
* handle : TFFS handle *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* NOTE: This routine uses disk's scratch buffer. *
* *
* --------------------------------------------------------------------------- */
static FLStatus parseDisk ( int handle )
{
int socNo, diskNo;
SectorNo extPartStartSec, sec;
int i, depth;
int type;
FLffDisk * pd;
FLffVol * pv;
Partition * pp;
IOreq ioreq;
#ifdef FL_MALLOC
char * buf;
#else
char buf[SECTOR_SIZE];
#endif
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(handle);
diskNo = H2D(handle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* if disk structure hasn't been allocated yet, do it now */
if (ffDisk[socNo][diskNo] == NULL)
checkStatus( newDisk(handle) );
pd = ffDisk[socNo][diskNo];
#ifdef FL_MALLOC
/* make sure scratch buffer is available */
if (pd->buf == NULL)
return flBufferingError;
buf = pd->buf;
#endif /* FL_MALLOC */
/* discard obsolete disk's partition info */
(void) discardDiskParts (pd);
/* read Master Boot Record */
ioreq.irHandle = handle;
ioreq.irSectorNo = (SectorNo) 0;
ioreq.irSectorCount = (SectorNo) 1;
ioreq.irData = (void FAR1 *) buf;
checkStatus( flAbsRead(&ioreq) );
/* is it MBR indeed ? */
if (LE2(((PartitionTable *) buf)->signature) != PARTITION_SIGNATURE)
return flPartitionNotFound;
/* do primary partitions only (we will do extended partitions later) */
pp = &( ((PartitionTable *) buf)->ptEntry[0] );
for (i = 0; i < FL_PART_TBL_ENTRIES; i++, pp++) {
if( pp->type == ((char)0) ) /* skip empty slot */
continue;
if( pp->type == ((char)EX_PARTIT) ) /* skip extended partition */
continue;
/* primary partition found (not necessarily FAT12/16) */
if( addNewDiskPart(pd) != flOK )
break;
pv = pd->part[pd->parts - 1];
/* remember partition's type, and where it starts */
pv->type = (int) pp->type;
pv->startSecNo = (SectorNo) UNAL4( (void *) pp->startingSectorOfPartition );
}
/* do extended partitions in depth */
for (i = 0; i < FL_PART_TBL_ENTRIES; i++) {
/* re-read Master Boot Record */
ioreq.irHandle = handle;
ioreq.irSectorNo = (SectorNo) 0;
ioreq.irSectorCount = (SectorNo) 1;
ioreq.irData = (void FAR1 *) buf;
checkStatus( flAbsRead(&ioreq) );
/* is it MBR indeed ? */
if (LE2(((PartitionTable *) buf)->signature) != PARTITION_SIGNATURE)
return flOK;
/* pick up next extended partition in MBR */
pp = &( ((PartitionTable *) buf)->ptEntry[i] );
if( pp->type == ((char)EX_PARTIT) ) {
/* remember where extended partition starts */
extPartStartSec = (SectorNo) UNAL4( (void *) pp->startingSectorOfPartition );
/* follow the list of partition tables */
sec = extPartStartSec;
for (depth = 0; depth < MAX_PARTITION_DEPTH; depth++) {
/* read next partition table in the list */
ioreq.irHandle = handle;
ioreq.irSectorNo = sec;
ioreq.irSectorCount = (SectorNo) 1;
ioreq.irData = (void FAR1 *) buf;
checkStatus( flAbsRead(&ioreq) );
/* is it valid partition table ? */
if (LE2(((PartitionTable *) buf)->signature) != PARTITION_SIGNATURE)
break;
/* if 1st entry is zero, it's the end of part. table list */
pp = &( ((PartitionTable *) buf)->ptEntry[0] );
if( pp->type == ((char)0) )
break;
/* Take this partition. Remember it's type, and where it starts */
if( addNewDiskPart(pd) != flOK )
break;
pv = pd->part[pd->parts - 1];
pv->type = (int) pp->type;
pv->startSecNo =
(SectorNo) UNAL4( (void *) pp->startingSectorOfPartition) + sec;
/* 2nd entry must be extended partition */
pp = &( ((PartitionTable *) buf)->ptEntry[1] );
if( pp->type != ((char)EX_PARTIT) )
break;
/* sector where next part. table in the list resides */
sec = extPartStartSec +
(SectorNo) UNAL4( (void *) pp->startingSectorOfPartition );
} /* for(depth) */
}
} /* for(i) */
#ifdef FL_INCLUDE_FAT_MONITOR
/* turn on FAT filters on FAT12/16 partition(s) */
if (pd->parts > 0) {
for (i = 0; i < pd->parts; i++) {
pv = pd->part[i];
type = pv->type;
/*
* WARNING : Routine partEnableFF() uses disk's scratch buffer !
*/
if((type == FAT12_PARTIT) || (type == FAT16_PARTIT) || (type == DOS4_PARTIT))
partEnableFF (pv);
}
}
#endif /* FL_INCLUDE_FAT_MONITOR */
/* watch for MBR (sector #0) update */
pd->secToWatch = (SectorNo) 0;
pd->ffstate = flStateInitialized;
return flOK;
}
#ifdef FL_INCLUDE_FAT_MONITOR
/* --------------------------------------------------------------------------- *
* *
* p a r t E n a b l e F F *
* *
* Installs and enables FAT filter on partition. *
* *
* Parameters: *
* pv : disk partition (filesystem volume) *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* NOTE: This routine uses disk's scratch buffer. *
* *
* --------------------------------------------------------------------------- */
static FLStatus partEnableFF ( FLffVol * pv )
{
int socNo, diskNo;
FLffDisk * pd;
BPB * bpb;
SectorNo sectors;
SectorNo rootDirSecNo;
SectorNo rootDirSectors;
SectorNo sectorsPerFAT;
unsigned maxCluster;
int partNo;
IOreq ioreq;
#ifdef FL_MALLOC
char * buf;
#else
char buf[SECTOR_SIZE];
#endif
/* arg. sanity check */
if (pv == NULL)
return flBadDriveHandle;
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(pv->handle);
diskNo = H2D(pv->handle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* check if 'pv' belongs to this disk */
pd = ffDisk[socNo][diskNo];
if (pd == NULL)
return flBadDriveHandle;
for (partNo = 0; partNo < pd->parts; partNo++) {
if (pd->part[partNo] == pv)
break;
}
if (partNo >= pd->parts)
return flBadDriveHandle;
#ifdef FL_MALLOC
/* make sure scratch buffer is available */
if (pd->buf == NULL)
return flBufferingError;
buf = pd->buf;
#endif /* FL_MALLOC */
/* make sure FAT filter is off on this partition */
pv->ffEnabled = FALSE;
pv->firstFATsecNo = (SectorNo) -1;
pv->lastFATsecNo = pv->firstFATsecNo;
pv->clusterSize = (unsigned) 0;
/* read the BPB */
ioreq.irHandle = pv->handle;
ioreq.irSectorNo = pv->startSecNo;
ioreq.irSectorCount = (SectorNo) 1;
ioreq.irData = (void FAR1 *) buf;
checkStatus( flAbsRead(&ioreq) );
/* Does it look like DOS bootsector ? */
bpb = &( ((DOSBootSector *) buf)->bpb );
if( !((bpb->jumpInstruction[0] == 0xe9)
||
((bpb->jumpInstruction[0] == 0xeb) && (bpb->jumpInstruction[2] == 0x90)))) {
return flNonFATformat;
}
/* Do we handle this sector size ? */
if (UNAL2(bpb->bytesPerSector) != SECTOR_SIZE)
return flFormatNotSupported;
/*
* Is it a bogus BPB (leftover from previous disk partitioning) ?
* Check that there is no overlap with next partition (if one exists).
*/
sectors = UNAL2(bpb->totalSectorsInVolumeDOS3);
if (sectors == (SectorNo)0)
sectors = (SectorNo) LE4(bpb->totalSectorsInVolume);
if ((partNo+1 < pd->parts) && (pd->part[partNo+1] != NULL)) {
if( sectors > (pd->part[partNo+1])->startSecNo - pv->startSecNo )
return flNonFATformat;
}
/* number of sectors in partition as reported by BPB */
pv->sectors = sectors;
/* valid BPB; get the rest of partition info from it */
pv->firstFATsecNo = pv->startSecNo + (SectorNo)( LE2(bpb->reservedSectors) );
sectorsPerFAT = (SectorNo) LE2(bpb->sectorsPerFAT);
pv->lastFATsecNo = pv->firstFATsecNo + sectorsPerFAT - (SectorNo)1;
rootDirSecNo = pv->firstFATsecNo + (sectorsPerFAT * bpb->noOfFATS);
rootDirSectors = (SectorNo)1 + (SectorNo)
(((UNAL2(bpb->rootDirectoryEntries) * DIRECTORY_ENTRY_SIZE) - 1) / SECTOR_SIZE);
pv->firstDataSecNo = rootDirSecNo + rootDirSectors;
pv->clusterSize = bpb->sectorsPerCluster;
/* decide which type of FAT is it */
maxCluster = (unsigned)1 + (unsigned)
((pv->sectors - (pv->firstDataSecNo - pv->startSecNo)) / pv->clusterSize);
if (maxCluster < 4085) {
pv->flags |= VOLUME_12BIT_FAT; /* 12-bit FAT */
#ifndef FAT_12BIT
DEBUG_PRINT(("Debug: FAT_12BIT must be defined.\r\n"));
return flFormatNotSupported;
#endif
}
/* turn on FAT filter on this partition */
pv->ffEnabled = TRUE;
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* p a r t F r e e D e l C l u s t e r s *
* *
* Compare the new contents of the specified FAT sector against the old *
* one on the disk. If any freed clusters are found, issue 'sector delete' *
* calls for all sectors that are occupied by these freed clusters. *
* *
* Parameters: *
* pv : disk partition (filesystem volume) *
* secNo : abs. sector # of the FAT sector *
* newFAT : new contents of this FAT sector *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* NOTE: This routine uses disk's scratch buffer. *
* *
* --------------------------------------------------------------------------- */
static FLStatus partFreeDelClusters ( FLffVol * pv,
SectorNo secNo,
char FAR1 * newFAT)
{
FLffDisk * pd;
int socNo, diskNo;
unsigned short oldFATentry, newFATentry;
SectorNo iSec;
unsigned firstCluster;
IOreq ioreq;
int offset;
int iPart;
#ifdef FAT_12BIT
int halfBytes;
#endif
#ifdef FL_MALLOC
char * oldFAT;
#else
char oldFAT[SECTOR_SIZE];
#endif
/* arg. sanity check */
if (pv == NULL)
return flBadDriveHandle;
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(pv->handle);
diskNo = H2D(pv->handle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* check if 'pv' belongs to this disk */
pd = ffDisk[socNo][diskNo];
if (pd == NULL)
return flBadDriveHandle;
for (iPart = 0; iPart < pd->parts; iPart++) {
if (pd->part[iPart] == pv)
break;
}
if (iPart >= pd->parts)
return flBadDriveHandle;
#ifdef FL_MALLOC
/* make sure scratch buffer is available */
if (pd->buf == NULL)
return flBufferingError;
oldFAT = pd->buf;
#endif /* FL_MALLOC */
/* read in the FAT sector from the disk */
ioreq.irHandle = pv->handle;
ioreq.irSectorNo = secNo;
ioreq.irSectorCount = 1;
ioreq.irData = (void FAR1 *) oldFAT;
checkStatus( flAbsRead(&ioreq) );
#ifdef FAT_12BIT
/* size of FAT entry in half-bytes */
halfBytes = ((pv->flags & VOLUME_12BIT_FAT) ? 3 : 4);
/* starting cluster */
if (halfBytes == 3) {
firstCluster =
((((unsigned)(secNo - pv->firstFATsecNo)) * (2 * SECTOR_SIZE)) + 2) / 3;
}
else {
firstCluster = ((unsigned)(secNo - pv->firstFATsecNo)) * (SECTOR_SIZE / 2);
}
/* staring data sector */
iSec = (((SectorNo)firstCluster - 2) * pv->clusterSize) + pv->firstDataSecNo;
offset = (firstCluster * ((unsigned) halfBytes)) & ((2 * SECTOR_SIZE) - 1);
/*
* Find if any clusters were logically deleted, and if so, delete them.
*
* NOTE: We are skipping over 12-bit FAT entries which span more than
* one sector.
*/
for (; offset < ((2 * SECTOR_SIZE) - 2);
offset += halfBytes, iSec += pv->clusterSize) {
#ifdef FL_BIG_ENDIAN
oldFATentry = LE2( *(LEushort FAR0 *)(oldFAT + (offset / 2)) );
newFATentry = LE2( *(LEushort FAR1 *)(newFAT + (offset / 2)) );
#else
oldFATentry = UNAL2( *(Unaligned FAR0 *)(oldFAT + (offset / 2)) );
newFATentry = UNAL2( *(Unaligned FAR1 *)(newFAT + (offset / 2)) );
#endif /* FL_BIG_ENDIAN */
if (offset & 1) {
oldFATentry >>= 4;
newFATentry >>= 4;
}
else {
if (halfBytes == 3) {
oldFATentry &= 0xfff;
newFATentry &= 0xfff;
}
}
#else /* !FAT_12BIT */
firstCluster = ((unsigned) (secNo - pv->firstFATsecNo) * (SECTOR_SIZE / 2));
iSec = pv->firstDataSecNo +
(((SectorNo)(firstCluster - (unsigned)2)) * pv->clusterSize);
/* Find if any clusters were logically deleted, and if so, delete them */
for (offset = 0; offset < SECTOR_SIZE; offset += 2, iSec += pv->clusterSize) {
oldFATentry = LE2( *(LEushort FAR0 *)(oldFAT + offset) );
newFATentry = LE2( *(LEushort FAR1 *)(newFAT + offset) );
#endif /* FAT_12BIT */
if ((oldFATentry != FAT_FREE) && (newFATentry == FAT_FREE)) {
ioreq.irHandle = pv->handle;
ioreq.irSectorNo = iSec;
ioreq.irSectorCount = pv->clusterSize;
checkStatus( flAbsDelete(&ioreq) );
}
}
return flOK;
}
#endif /* FL_INCLUDE_FAT_MONITOR */
/* --------------------------------------------------------------------------- *
* *
* f f C h e c k B e f o r e W r i t e *
* *
* Catch all the FAT updates. Detect disk partitioning operation, track it *
* to completion, re-read partition tables, and re-install FAT filters on *
* all FAT12/16 partitions. *
* *
* Parameters: *
* ioreq : standard I/O request to be checked *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* --------------------------------------------------------------------------- */
FLStatus ffCheckBeforeWrite ( IOreq FAR2 * ioreq )
{
int socNo, diskNo;
FLffDisk * pd;
FLffVol * pv;
long iSec;
int iPart;
IOreq ioreq2;
char FAR1 * usrBuf;
/* if module hasn't been reset yet, do it now */
if (resetDone == FALSE)
(void) reset();
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(ioreq->irHandle);
diskNo = H2D(ioreq->irHandle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* if disk structure hasn't been allocated yet, do it now */
if (ffDisk[socNo][diskNo] == NULL)
checkStatus( newDisk((int)ioreq->irHandle) );
pd = ffDisk[socNo][diskNo];
/* read partition table(s) and install FAT filters is needed */
if (pd->ffstate == flStateNotInitialized)
checkStatus( parseDisk((int)ioreq->irHandle) );
/* catch writes to MBR, and track the whole disk partitioning operations */
while( isPartTableWrite(pd, ioreq) == TRUE ) {
/* disk re-partitioning is in progress */
if( pd->secToWatch == (SectorNo)0 ) {
/* it's write to MBR, so trash BPBs in all disk's partitions */
if (pd->parts > 0) {
for (iPart = 0; iPart < pd->parts; iPart++) {
ioreq2.irHandle = ioreq->irHandle;
ioreq2.irSectorNo = (pd->part[iPart])->startSecNo;
ioreq2.irSectorCount = (SectorNo) 1;
ioreq2.irData = (void FAR1 *) zeroes;
(void) flAbsWrite(&ioreq2);
}
}
}
/* keep FAT filters disabled while disk partitioning is in progress */
pd->ffstate = flStateInitInProgress;
/* partition table which is about to be written to disk */
usrBuf = FLBUF( ioreq, (pd->secToWatch - ioreq->irSectorNo) );
switch( isExtPartPresent(usrBuf, &(pd->secToWatch)) ) {
case flOK:
/*
* Found valid partition table with extended partition.
* The pd->secToWatch has been updated to point to the
* sector where next partition table will be written to.
*/
continue;
case flFileNotFound:
/*
* Valid partition table, but no extended partition in it.
* Partitioning has been completed. Set pd->ffstate to
* 'flStateNotInitialized' to initiate parsing of partition
* table(s) and FAT filter installation next time this routine
* is called.
*/
pd->ffstate = flStateNotInitialized;
break;
case flBadFormat:
default:
/* No valid partition table. */
break;
}
return flOK;
}
#ifdef FL_INCLUDE_FAT_MONITOR
/* check for FAT update */
if (pd->ffstate == flStateInitialized) {
/* NOTE: We can handle 'write' request that spans disk partition boundaries */
for (iSec = ioreq->irSectorNo;
iSec < (ioreq->irSectorNo + ioreq->irSectorCount); iSec++) {
for (iPart = 0; iPart < pd->parts; iPart++) {
pv = pd->part[iPart];
/* we monitor only FAT12/16 partitions */
if ((pv->type != FAT12_PARTIT) && (pv->type != FAT16_PARTIT) &&
(pv->type != DOS4_PARTIT))
continue;
/* FAT filters can be disabled on individual partitions */
if (pv->ffEnabled != TRUE)
continue;
if ((iSec >= (long)pv->firstFATsecNo) && (iSec <= (long)pv->lastFATsecNo)) {
/* compare new and old contents of FAT sectors(s) */
usrBuf = FLBUF( ioreq, (iSec - ioreq->irSectorNo) );
checkStatus( partFreeDelClusters(pv, iSec, usrBuf) );
}
}
}
}
#endif /* FL_INCLUDE_FAT_MONITOR */
return flOK;
}
/* --------------------------------------------------------------------------- *
* *
* f l f f C o n t r o l *
* *
* Enable/disable/install FAT filters. See comments inside the routine for *
* the list of supported operations. *
* *
* Parameters: *
* handle : TFFS handle *
* partNo : partition # (0 .. FL_MAX_PARTS_PER_DISK) *
* state : see list of supported operations below *
* *
* Returns: *
* flOK on success, otherwise error code *
* *
* --------------------------------------------------------------------------- *
* *
* The following FAT monitor control requests are supported: *
* *
* state : flStateNotInitialized *
* partNo : [0 ... pd->parts-1] *
* action : turn off FAT monitor on specified partition *
* *
* state : flStateNotInitialized *
* partNo : < 0 *
* action : turn off FAT monitor on all partitions *
* *
* state : flStateInitialized *
* partNo : [0 ... pd->parts-1] *
* action : if FAT monitor has been installed on specified partition, *
* turn it on *
* *
* state : flStateInitInProgress *
* partNo : ignored *
* action : re-read partition table(s), and install FAT filters on all *
* partitions *
* *
* --------------------------------------------------------------------------- */
FLStatus flffControl ( int handle,
int partNo,
FLState state )
{
int socNo, diskNo;
FLffDisk * pd;
int i;
FLStatus status;
/* if module hasn't been reset yet, do it now */
if (resetDone == FALSE)
(void) reset();
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(handle);
diskNo = H2D(handle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return flBadDriveHandle;
/* if disk structure hasn't been allocated yet, do it now */
if (ffDisk[socNo][diskNo] == NULL)
checkStatus( newDisk(handle) );
pd = ffDisk[socNo][diskNo];
/* abort if disk re-partitioning is in progress */
if (pd->ffstate == flStateInitInProgress)
return flDriveNotReady;
/* read partition table(s) and install FAT filters is needed */
if (pd->ffstate == flStateNotInitialized) {
if (state == flStateNotInitialized)
return flOK;
checkStatus( parseDisk(handle) );
}
/* check 'partNo' arguement for sanity */
if ((partNo >= pd->parts) || (partNo >= FL_MAX_PARTS_PER_DISK))
return flBadDriveHandle;
/* do requested operation */
status = flBadParameter;
switch (state) {
case flStateInitInProgress:
/* read partition table(s), install FAT filters on all partitions */
pd->ffstate = flStateNotInitialized;
status = parseDisk(handle);
break;
case flStateNotInitialized:
/* turn off FAT monitor */
if (partNo < 0) { /* all partitions */
for (i = 0; i < FL_MAX_PARTS_PER_DISK; i++) {
if (pd->part[i] != NULL)
(pd->part[i])->ffEnabled = FALSE;
}
}
else { /* specified partition */
if (pd->part[partNo] != NULL)
(pd->part[partNo])->ffEnabled = FALSE;
}
status = flOK;
break;
#ifdef FL_INCLUDE_FAT_MONITOR
case flStateInitialized:
/* turn on FAT monitor */
if ((pd->ffstate == flStateInitialized) && (partNo >= 0)) {
if (pd->part[partNo] != NULL) {
switch( (pd->part[partNo])->type ) {
case FAT12_PARTIT:
case FAT16_PARTIT:
case DOS4_PARTIT:
(pd->part[partNo])->ffEnabled = TRUE;
status = flOK;
break;
case FL_RAW_PART:
DEBUG_PRINT(("Debug: can't ctrl non-existent partition.\r\n"));
break;
default:
DEBUG_PRINT(("Debug: can't ctrl non-FAT12/16 partition.\r\n"));
break;
}
}
}
break;
#endif /* FL_INCLUDE_FAT_MONITOR */
} /* switch(state) */
return status;
}
/* --------------------------------------------------------------------------- *
* *
* f l f f I n f o *
* *
* Obtain complete partition info for specified disk. *
* *
* Parameters: *
* handle : TFFS handle *
* *
* Returns: *
* NULL if error, otherwise pointer to partitioning info *
* *
* --------------------------------------------------------------------------- */
FLffDisk * flffInfo ( int handle )
{
int socNo, diskNo;
FLffDisk * pd;
/* if module hasn't been reset yet, do it now */
if (resetDone == FALSE)
(void) reset();
/* break TFFS handle into socket# and disk#, and do sanity check */
socNo = H2S(handle);
diskNo = H2D(handle);
if ((socNo >= ((int) noOfSockets)) || (diskNo >= MAX_TL_PARTITIONS))
return NULL;
/* if disk structure hasn't been allocated yet, do it now */
if (ffDisk[socNo][diskNo] == NULL) {
if( newDisk(handle) != flOK )
return NULL;
}
pd = ffDisk[socNo][diskNo];
/* read partition table(s) and install FAT filters is needed */
if (pd->ffstate == flStateNotInitialized) {
if( parseDisk(handle) != flOK )
return NULL;
}
return pd;
}
#endif /* ABS_READ_WRITE && FL_READ_ONLY */