fat.c

来自「一个类似windows」· C语言 代码 · 共 705 行 · 第 1/2 页

C
705
字号
/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * FILE:             drivers/fs/vfat/fat.c
 * PURPOSE:          VFAT Filesystem
 * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
 *
 */

/* INCLUDES *****************************************************************/

#define NDEBUG
#include "vfat.h"

/* GLOBALS ******************************************************************/

#define  CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
		   (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)

/* FUNCTIONS ****************************************************************/

NTSTATUS
FAT32GetNextCluster(PDEVICE_EXTENSION DeviceExt,
		    ULONG CurrentCluster,
		    PULONG NextCluster)
/*
 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
 *           disk read
 */
{
  PVOID BaseAddress;
  ULONG FATOffset;
  ULONG ChunkSize;
  PVOID Context;
  LARGE_INTEGER Offset;

  ChunkSize = CACHEPAGESIZE(DeviceExt);
  FATOffset = CurrentCluster * sizeof(ULONG);
  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
  if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
  {
    return STATUS_UNSUCCESSFUL;
  }
  CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
  if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
    CurrentCluster = 0xffffffff;
  CcUnpinData(Context);
  *NextCluster = CurrentCluster;
  return (STATUS_SUCCESS);
}

NTSTATUS
FAT16GetNextCluster(PDEVICE_EXTENSION DeviceExt,
		    ULONG CurrentCluster,
		    PULONG NextCluster)
/*
 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
 */
{
  PVOID BaseAddress;
  ULONG FATOffset;
  ULONG ChunkSize;
  PVOID Context;
  LARGE_INTEGER Offset;

  ChunkSize = CACHEPAGESIZE(DeviceExt);
  FATOffset = CurrentCluster * 2;
  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
  if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
  {
    return STATUS_UNSUCCESSFUL;
  }
  CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
  if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
    CurrentCluster = 0xffffffff;
  CcUnpinData(Context);
  *NextCluster = CurrentCluster;
  return (STATUS_SUCCESS);
}

NTSTATUS
FAT12GetNextCluster(PDEVICE_EXTENSION DeviceExt,
		    ULONG CurrentCluster,
		    PULONG NextCluster)
/*
 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
 */
{
  PUSHORT CBlock;
  ULONG Entry;
  PVOID BaseAddress;
  PVOID Context;
  LARGE_INTEGER Offset;


  *NextCluster = 0;

  Offset.QuadPart = 0;
  if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
  {
    return STATUS_UNSUCCESSFUL;
  }
  CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
  if ((CurrentCluster % 2) == 0)
    {
      Entry = *CBlock & 0x0fff;
    }
  else
    {
      Entry = *CBlock >> 4;
    }
//  DPRINT("Entry %x\n",Entry);
  if (Entry >= 0xff8 && Entry <= 0xfff)
    Entry = 0xffffffff;
//  DPRINT("Returning %x\n",Entry);
  *NextCluster = Entry;
  CcUnpinData(Context);
//  return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
  return STATUS_SUCCESS;
}

NTSTATUS
FAT16FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt,
                                 PULONG Cluster)
/*
 * FUNCTION: Finds the first available cluster in a FAT16 table
 */
{
  ULONG FatLength;
  ULONG StartCluster;
  ULONG i, j;
  PVOID BaseAddress;
  ULONG ChunkSize;
  PVOID Context = 0;
  LARGE_INTEGER Offset;
  PUSHORT Block;
  PUSHORT BlockEnd;

  ChunkSize = CACHEPAGESIZE(DeviceExt);
  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
  *Cluster = 0;
  StartCluster = DeviceExt->LastAvailableCluster;

  for (j = 0; j < 2; j++)
  {
    for (i = StartCluster; i < FatLength; )
    {
      Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
      if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
      {
        DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
        return STATUS_UNSUCCESSFUL;
      }
      Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
      BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);

      /* Now process the whole block */
      while (Block < BlockEnd && i < FatLength)
      {
        if (*Block == 0)
        {
          DPRINT("Found available cluster 0x%x\n", i);
          DeviceExt->LastAvailableCluster = *Cluster = i;
          *Block = 0xffff;
          CcSetDirtyPinnedData(Context, NULL);
          CcUnpinData(Context);
          return(STATUS_SUCCESS);
        }

        Block++;
        i++;
      }

      CcUnpinData(Context);
    }
    FatLength = StartCluster;
    StartCluster = 2;
  }
  return(STATUS_DISK_FULL);
}

NTSTATUS
FAT12FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
/*
 * FUNCTION: Finds the first available cluster in a FAT12 table
 */
{
  ULONG FatLength;
  ULONG StartCluster;
  ULONG Entry;
  PUSHORT CBlock;
  ULONG i, j;
  PVOID BaseAddress;
  PVOID Context;
  LARGE_INTEGER Offset;

  FatLength = DeviceExt->FatInfo.NumberOfClusters + 2;
  *Cluster = 0;
  StartCluster = DeviceExt->LastAvailableCluster;
  Offset.QuadPart = 0;
  if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
  {
    DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
    return STATUS_UNSUCCESSFUL;
  }

  for (j = 0; j < 2; j++)
  {
    for (i = StartCluster; i < FatLength; i++)
    {
      CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
      if ((i % 2) == 0)
	   {
	     Entry = *CBlock & 0xfff;
	   }
      else
	   {
	     Entry = *CBlock >> 4;
	   }
      if (Entry == 0)
	   {
	     DPRINT("Found available cluster 0x%x\n", i);
	     DeviceExt->LastAvailableCluster = *Cluster = i;
	     if ((i % 2) == 0)
	       *CBlock = (*CBlock & 0xf000) | 0xfff;
	     else
	       *CBlock = (*CBlock & 0xf) | 0xfff0;
	     CcSetDirtyPinnedData(Context, NULL);
	     CcUnpinData(Context);
	     return(STATUS_SUCCESS);
	   }
    }
    FatLength = StartCluster;
    StartCluster = 2;
  }
  CcUnpinData(Context);
  return (STATUS_DISK_FULL);
}

NTSTATUS
FAT32FindAndMarkAvailableCluster (PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
/*
 * FUNCTION: Finds the first available cluster in a FAT32 table
 */
{
  ULONG FatLength;
  ULONG StartCluster;
  ULONG i, j;
  PVOID BaseAddress;
  ULONG ChunkSize;
  PVOID Context;
  LARGE_INTEGER Offset;
  PULONG Block;
  PULONG BlockEnd;

  ChunkSize = CACHEPAGESIZE(DeviceExt);
  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
  *Cluster = 0;
  StartCluster = DeviceExt->LastAvailableCluster;

  for (j = 0; j < 2; j++)
  {
    for (i = StartCluster; i < FatLength;)
    {
      Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
      if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
      {
        DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
        return STATUS_UNSUCCESSFUL;
      }
      Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
      BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);

      /* Now process the whole block */
      while (Block < BlockEnd && i < FatLength)
      {
        if ((*Block & 0x0fffffff) == 0)
        {
          DPRINT("Found available cluster 0x%x\n", i);
          DeviceExt->LastAvailableCluster = *Cluster = i;
          *Block = 0x0fffffff;
          CcSetDirtyPinnedData(Context, NULL);
          CcUnpinData(Context);
          return(STATUS_SUCCESS);
        }

        Block++;
        i++;
      }

      CcUnpinData(Context);
    }
    FatLength = StartCluster;
    StartCluster = 2;
  }
  return (STATUS_DISK_FULL);
}

static NTSTATUS
FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
/*
 * FUNCTION: Counts free cluster in a FAT12 table
 */
{
  ULONG Entry;
  PVOID BaseAddress;
  ULONG ulCount = 0;
  ULONG i;
  ULONG numberofclusters;
  LARGE_INTEGER Offset;
  PVOID Context;
  PUSHORT CBlock;

  Offset.QuadPart = 0;
  if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
  {
    return STATUS_UNSUCCESSFUL;
  }

  numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;

  for (i = 2; i < numberofclusters; i++)
    {
    CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
      if ((i % 2) == 0)
	{
      Entry = *CBlock & 0x0fff;
	}
      else
	{
      Entry = *CBlock >> 4;
	}
      if (Entry == 0)
	ulCount++;
    }

  CcUnpinData(Context);
  DeviceExt->AvailableClusters = ulCount;
  DeviceExt->AvailableClustersValid = TRUE;

  return(STATUS_SUCCESS);
}


static NTSTATUS
FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
/*
 * FUNCTION: Counts free clusters in a FAT16 table
 */
{
  PUSHORT Block;
  PUSHORT BlockEnd;
  PVOID BaseAddress = NULL;

⌨️ 快捷键说明

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