/******************************************************************************* * * * 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 */