fatlite.c

来自「cpc-1631的BSP包for VxWorks操作系统」· C语言 代码 · 共 1,760 行 · 第 1/5 页

C
1,760
字号

  if (!buffer.dirty) {
    long sectorsNeeded = 20;
    checkStatus(vol.tl.defragment(vol.tl.rec,&sectorsNeeded));
  }

  if (sectorNo != buffer.sectorNo || &vol != buffer.owner) {
    const void FAR0 *mappedSector;
#endif
    buffer.sectorNo = sectorNo;
    buffer.owner = &vol;
    if (read) {
      mappedSector = vol.tl.mapSector(vol.tl.rec,sectorNo);
      if (mappedSector)
	tffscpy(buffer.data,mappedSector,SECTOR_SIZE);
      else
	return flSectorNotFound;
    }
    else
      tffsset(buffer.data,0,SECTOR_SIZE);
  }

  buffer.dirty = TRUE;

  return flOK;
}


/*----------------------------------------------------------------------*/
/*		   f i r s t S e c t o r O f C l u s t e r		*/
/*									*/
/* Get sector no. corresponding to cluster no.				*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	cluster		: Cluster no.                                   */
/*                                                                      */
/* Returns:                                                             */
/*	first sector no. of cluster					*/
/*----------------------------------------------------------------------*/

static SectorNo firstSectorOfCluster(Volume vol, unsigned cluster)
{
  return (SectorNo) (cluster - 2) * vol.sectorsPerCluster +
	 vol.firstDataSectorNo;
}


/*----------------------------------------------------------------------*/
/*		       g e t D i r E n t r y    			*/
/*									*/
/* Get a read-only copy of a directory entry.				*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	file		: File belonging to directory entry		*/
/*                                                                      */
/* Returns:                                                             */
/*	dirEntry	: Pointer to directory entry			*/
/*----------------------------------------------------------------------*/

static const DirectoryEntry FAR0 *getDirEntry(File *file)
{
  return (DirectoryEntry FAR0 *) findSector(file->fileVol,file->directorySector) +
	 file->directoryIndex;
}


/*----------------------------------------------------------------------*/
/*		  g e t D i r E n t r y F o r U p d a t e		*/
/*									*/
/* Read a directory sector into the sector buffer and point to an	*/
/* entry, with the intention of modifying it.				*/
/* The buffer will be flushed on operation exit.			*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	file		: File belonging to directory entry		*/
/*                                                                      */
/* Returns:                                                             */
/*	FLStatus	: 0 on success, otherwise failed                */
/*	dirEntry	: Pointer to directory entry in buffer		*/
/*----------------------------------------------------------------------*/

static FLStatus getDirEntryForUpdate(File *file, DirectoryEntry * *dirEntry)
{
  Volume vol = file->fileVol;

  checkStatus(updateSector(file->fileVol,file->directorySector,TRUE));
  *dirEntry = directory + file->directoryIndex;
  buffer.checkPoint = TRUE;

  return flOK;
}


/*----------------------------------------------------------------------*/
/*		  s e t C u r r e n t D a t e T i m e                   */
/*									*/
/* Set current time/date in directory entry                             */
/*                                                                      */
/* Parameters:                                                          */
/*	dirEntry	: Pointer to directory entry                    */
/*                                                                      */
/*----------------------------------------------------------------------*/

static void setCurrentDateTime(DirectoryEntry *dirEntry)
{
  toLE2(dirEntry->updateTime,flCurrentTime());
  toLE2(dirEntry->updateDate,flCurrentDate());
}


/*----------------------------------------------------------------------*/
/*		        g e t F A T e n t r y				*/
/*									*/
/* Get an entry from the FAT. The 1st FAT copy is used.			*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	cluster		: Cluster no. of enrty.				*/
/*                                                                      */
/* Returns:                                                             */
/*	Value of FAT entry.						*/
/*----------------------------------------------------------------------*/

static unsigned getFATentry(Volume vol, unsigned cluster)
{
  LEushort FAR0 *fat16Sector;

  unsigned fatSectorNo = vol.firstFATSectorNo;
#ifdef FAT_12BIT
  if (vol.flags & VOLUME_12BIT_FAT)
    fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
  else
#endif
    fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);

#ifndef SINGLE_BUFFER
  if (!buffer.dirty) {
    /* If the buffer is free, use it to store this FAT sector */
    updateSector(&vol,fatSectorNo,TRUE);
    buffer.dirty = FALSE;
  }
#endif
  fat16Sector = (LEushort FAR0 *) findSector(&vol,fatSectorNo);

#ifdef FAT_12BIT
  if (vol.flags & VOLUME_12BIT_FAT) {
    unsigned char FAR0 *fat12Sector = (unsigned char FAR0 *) fat16Sector;
    unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
    unsigned char firstByte = fat12Sector[halfByteOffset / 2];
    halfByteOffset += 2;
    if (halfByteOffset >= SECTOR_SIZE * 2) {
      /* Entry continues on the next sector. What a mess */
      halfByteOffset -= SECTOR_SIZE * 2;
      fat12Sector = (unsigned char FAR0 *) findSector(&vol,fatSectorNo + 1);
    }
    if (halfByteOffset & 1)
      return ((firstByte & 0xf0) >> 4) + (fat12Sector[halfByteOffset / 2] << 4);
    else
      return firstByte + ((fat12Sector[halfByteOffset / 2] & 0xf) << 8);
  }
  else
#endif
    return LE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)]);
}


/*----------------------------------------------------------------------*/
/*		         s e t F A T e n t r y				*/
/*									*/
/* Writes a new value to a given FAT cluster entry.                     */
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	cluster		: Cluster no. of enrty.				*/
/*	entry		: New value of FAT entry.			*/
/*                                                                      */
/* Returns:                                                             */
/*	FLStatus	: 0 on success, otherwise failed                */
/*----------------------------------------------------------------------*/

static FLStatus setFATentry(Volume vol, unsigned cluster, unsigned entry)
{
  LEushort *fat16Sector;

  unsigned fatSectorNo = vol.firstFATSectorNo;
#ifdef FAT_12BIT
  if (vol.flags & VOLUME_12BIT_FAT)
    fatSectorNo += (cluster * 3) >> (SECTOR_SIZE_BITS + 1);
  else
#endif
    fatSectorNo += cluster >> (SECTOR_SIZE_BITS - 1);

  checkStatus(updateSector(&vol,fatSectorNo,TRUE));
  fat16Sector = (LEushort *) buffer.data;

#ifdef FAT_12BIT
  if (vol.flags & VOLUME_12BIT_FAT) {
    unsigned char *fat12Sector = (unsigned char *) buffer.data;
    unsigned halfByteOffset = (cluster * 3) & (SECTOR_SIZE * 2 - 1);
    if (halfByteOffset & 1) {
      fat12Sector[halfByteOffset / 2] &= 0xf;
      fat12Sector[halfByteOffset / 2] |= (entry & 0xf) << 4;
    }
    else
      fat12Sector[halfByteOffset / 2] = entry;
    halfByteOffset += 2;
    if (halfByteOffset >= SECTOR_SIZE * 2) {
      /* Entry continues on the next sector. What a mess */
      halfByteOffset -= SECTOR_SIZE * 2;
      fatSectorNo++;
      checkStatus(updateSector(&vol,fatSectorNo,TRUE));
    }
    if (halfByteOffset & 1)
      fat12Sector[halfByteOffset / 2] = entry >> 4;
    else {
      fat12Sector[halfByteOffset / 2] &= 0xf0;
      fat12Sector[halfByteOffset / 2] |= (entry & 0x0f00) >> 8;
    }
  }
  else
#endif
    toLE2(fat16Sector[cluster & (SECTOR_SIZE / 2 - 1)],entry);

  return flOK;
}


/*----------------------------------------------------------------------*/
/*		        a l l o c a t e C l u s t e r			*/
/*									*/
/* Allocates a new cluster for a file and adds it to a FAT chain or     */
/* marks it in a directory entry.					*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	file		: File to extend. It should be positioned at    */
/*			  end-of-file.					*/
/*                                                                      */
/* Returns:                                                             */
/*	FLStatus	: 0 on success, otherwise failed                */
/*----------------------------------------------------------------------*/

static FLStatus allocateCluster(File *file)
{
  Volume vol = file->fileVol;
  unsigned originalRover;

  if (file->flags & FILE_READ_ONLY)
    return flNoWriteAccess;

  /* Look for a free cluster. Start at the allocation rover */
  originalRover = vol.allocationRover;

  do {
    vol.allocationRover++;
    if (vol.allocationRover > vol.maxCluster)
      vol.allocationRover = 2;	/* wraparound to start of volume */
    if (vol.allocationRover == originalRover)
      return flNoSpaceInVolume;
  } while (getFATentry(&vol,vol.allocationRover) != FAT_FREE);

  /* Found a free cluster. Mark it as an end of chain */
  checkStatus(setFATentry(&vol,vol.allocationRover,FAT_LAST_CLUSTER));

  /* Mark previous cluster or directory to point to it */
  if (file->currentCluster == 0) {
    DirectoryEntry *dirEntry;
    checkStatus(getDirEntryForUpdate(file,&dirEntry));

    toLE2(dirEntry->startingCluster,vol.allocationRover);
    setCurrentDateTime(dirEntry);
  }
  else
    checkStatus(setFATentry(&vol,file->currentCluster,vol.allocationRover));

  /* Set our new current cluster */
  file->currentCluster = vol.allocationRover;

  return flOK;
}


/*----------------------------------------------------------------------*/
/*		     g e t S e c t o r A n d O f f s e t		*/
/*									*/
/* Based on the current position of a file, gets a sector number and    */
/* offset in the sector that marks the file's current position.		*/
/* If the position is at the end-of-file, and the file is opened for    */
/* write, this routine will extend the file by allocating a new cluster.*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*                                                                      */
/* Returns:                                                             */
/*	FLStatus	: 0 on success, otherwise failed                */
/*----------------------------------------------------------------------*/

static FLStatus getSectorAndOffset(File *file,
				 SectorNo *sectorNo,
				 unsigned *offsetInSector)
{
  Volume vol = file->fileVol;
  unsigned offsetInCluster =
	      (unsigned) file->currentPosition & (vol.bytesPerCluster - 1);
  if (offsetInCluster == 0) {	/* This cluster is finished. Get next */
    if (file->flags & FILE_IS_ROOT_DIR) {
      if (file->currentPosition >= file->fileSize)
	return flRootDirectoryFull;
    }
    else {
      if (file->currentPosition >= file->fileSize) {
	checkStatus(allocateCluster(file));
      }
      else {
	unsigned nextCluster;

	if (file->currentCluster == 0)
	  nextCluster = LE2(getDirEntry(file)->startingCluster);
	else
	  nextCluster = getFATentry(&vol,file->currentCluster);
	if (nextCluster < 2 || nextCluster > vol.maxCluster)
	  /* We have a bad file size, or the FAT is bad */
	  return flInvalidFATchain;
	file->currentCluster = nextCluster;
      }
    }
  }

  *offsetInSector = offsetInCluster & (SECTOR_SIZE - 1);
  if (file->flags & FILE_IS_ROOT_DIR)
    *sectorNo = vol.rootDirectorySectorNo +
		      (SectorNo) (file->currentPosition >> SECTOR_SIZE_BITS);
  else
    *sectorNo = firstSectorOfCluster(&vol,file->currentCluster) +
		      (SectorNo) (offsetInCluster >> SECTOR_SIZE_BITS);

  return flOK;
}


/*----------------------------------------------------------------------*/
/*		        c l o s e F i l e				*/
/*									*/
/* Closes an open file, records file size and dates in directory and    */
/* releases file handle.						*/
/*                                                                      */
/* Parameters:                                                          */
/*	vol		: Pointer identifying drive			*/
/*	file		: File to close.		                */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?