dirwr.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 739 行 · 第 1/2 页

C
739
字号
/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * FILE:             drivers/fs/vfat/dirwr.c
 * PURPOSE:          VFAT Filesystem : write in directory
 *
 */

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

#define NDEBUG
#include "vfat.h"

NTSTATUS
VfatUpdateEntry (PVFATFCB pFcb)
/*
 * update an existing FAT entry
 */
{
  PVOID Context;
  PDIR_ENTRY PinEntry;
  LARGE_INTEGER Offset;
  ULONG SizeDirEntry;
  ULONG dirIndex;

  ASSERT(pFcb);
  ASSERT(pFcb->parentFcb);

  if (pFcb->Flags & FCB_IS_FATX_ENTRY)
  {
    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
    dirIndex = pFcb->startIndex;
  }
  else
  {
    SizeDirEntry = sizeof(FAT_DIR_ENTRY);
    dirIndex = pFcb->dirIndex;
  }

  DPRINT ("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU);

  if (vfatFCBIsRoot(pFcb) || (pFcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
    {
      return STATUS_SUCCESS;
    }

  ASSERT (pFcb->parentFcb);

  Offset.u.HighPart = 0;
  Offset.u.LowPart = dirIndex * SizeDirEntry;
  if (CcPinRead (pFcb->parentFcb->FileObject, &Offset, SizeDirEntry,
      TRUE, &Context, (PVOID*)&PinEntry))
    {
      pFcb->Flags &= ~FCB_IS_DIRTY;
      RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry);
      CcSetDirtyPinnedData(Context, NULL);
      CcUnpinData(Context);
      return STATUS_SUCCESS;
    }
  else
    {
      DPRINT1 ("Failed write to \'%wZ\'.\n", &pFcb->parentFcb->PathNameU);
      return STATUS_UNSUCCESSFUL;
    }
}

BOOLEAN
vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt,
                 PVFATFCB pDirFcb,
                 ULONG nbSlots,
                 PULONG start)
{
/*
 * try to find contiguous entries frees in directory,
 * extend a directory if is neccesary
 */
  LARGE_INTEGER FileOffset;
  ULONG i, count, size, nbFree = 0;
  PDIR_ENTRY pFatEntry;
  PVOID Context = NULL;
  NTSTATUS Status;
  ULONG SizeDirEntry;
  FileOffset.QuadPart = 0;

  if (DeviceExt->Flags & VCB_IS_FATX)
    SizeDirEntry = sizeof(FATX_DIR_ENTRY);
  else
    SizeDirEntry = sizeof(FAT_DIR_ENTRY);

  count = pDirFcb->RFCB.FileSize.u.LowPart / SizeDirEntry;
  size = DeviceExt->FatInfo.BytesPerCluster / SizeDirEntry;
  for (i = 0; i < count; i++, pFatEntry = (PDIR_ENTRY)((ULONG_PTR)pFatEntry + SizeDirEntry))
  {
    if (Context == NULL || (i % size) == 0)
    {
      if (Context)
      {
        CcUnpinData(Context);
      }
      // FIXME: check return value
      CcPinRead (pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster,
                 TRUE, &Context, (PVOID*)&pFatEntry);
      FileOffset.u.LowPart += DeviceExt->FatInfo.BytesPerCluster;
    }
    if (ENTRY_END(DeviceExt, pFatEntry))
    {
      break;
    }
    if (ENTRY_DELETED(DeviceExt, pFatEntry))
    {
      nbFree++;
    }
    else
    {
      nbFree = 0;
    }
    if (nbFree == nbSlots)
    {
      break;
    }
  }
  if (Context)
  {
    CcUnpinData(Context);
    Context = NULL;
  }
  if (nbFree == nbSlots)
  {
    // found enough contiguous free slots
    *start = i - nbSlots + 1;
  }
  else
  {
    *start = i - nbFree;
    if (*start + nbSlots > count)
    {
      LARGE_INTEGER AllocationSize;
      CHECKPOINT;
      // extend the directory
      if (vfatFCBIsRoot(pDirFcb) && DeviceExt->FatInfo.FatType != FAT32)
      {
        // We can't extend a root directory on a FAT12/FAT16/FATX partition
        return FALSE;
      }
      AllocationSize.QuadPart = pDirFcb->RFCB.FileSize.u.LowPart + DeviceExt->FatInfo.BytesPerCluster;
      Status = VfatSetAllocationSizeInformation(pDirFcb->FileObject, pDirFcb,
	                                        DeviceExt, &AllocationSize);
      if (!NT_SUCCESS(Status))
      {
        return FALSE;
      }
      // clear the new dir cluster
      FileOffset.u.LowPart = (ULONG)(pDirFcb->RFCB.FileSize.QuadPart -
                                     DeviceExt->FatInfo.BytesPerCluster);
      CcPinRead (pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster,
                 TRUE, &Context, (PVOID*)&pFatEntry);
      if (DeviceExt->Flags & VCB_IS_FATX)
        memset(pFatEntry, 0xff, DeviceExt->FatInfo.BytesPerCluster);
      else
        RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
    }
    else if (*start + nbSlots < count)
    {
      // clear the entry after the last new entry
      FileOffset.u.LowPart = (*start + nbSlots) * SizeDirEntry;
      CcPinRead (pDirFcb->FileObject, &FileOffset, SizeDirEntry,
                 TRUE, &Context, (PVOID*)&pFatEntry);
      if (DeviceExt->Flags & VCB_IS_FATX)
        memset(pFatEntry, 0xff, SizeDirEntry);
      else
        RtlZeroMemory(pFatEntry, SizeDirEntry);
    }
    if (Context)
    {
      CcSetDirtyPinnedData(Context, NULL);
      CcUnpinData(Context);
    }
  }
  DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots, nbFree, *start);
  return TRUE;
}

static NTSTATUS
FATAddEntry (PDEVICE_EXTENSION DeviceExt,
	     PUNICODE_STRING NameU,
	     PVFATFCB* Fcb,
	     PVFATFCB ParentFcb,
	     ULONG RequestedOptions,
	     UCHAR ReqAttr)
/*
  create a new FAT entry
*/
{
  PVOID Context = NULL;
  PFAT_DIR_ENTRY pFatEntry;
  slot *pSlots;
  USHORT nbSlots = 0, j, posCar;
  PUCHAR Buffer;
  BOOLEAN needTilde = FALSE, needLong = FALSE;
  BOOLEAN lCaseBase = FALSE, uCaseBase, lCaseExt = FALSE, uCaseExt;
  ULONG CurrentCluster;
  LARGE_INTEGER SystemTime, FileOffset;
  NTSTATUS Status = STATUS_SUCCESS;
  ULONG size;
  long i;

  OEM_STRING NameA;
  CHAR aName[13];
  BOOLEAN IsNameLegal;
  BOOLEAN SpacesFound;

  VFAT_DIRENTRY_CONTEXT DirContext;
  WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
  WCHAR ShortNameBuffer[13];

  DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU);

  DirContext.LongNameU = *NameU;

  nbSlots = (DirContext.LongNameU.Length / sizeof(WCHAR) + 12) / 13 + 1;	//nb of entry needed for long name+normal entry
  DPRINT ("NameLen= %d, nbSlots =%d\n", DirContext.LongNameU.Length / sizeof(WCHAR), nbSlots);
  Buffer = ExAllocatePool (NonPagedPool, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
  if (Buffer == NULL)
  {
    return STATUS_INSUFFICIENT_RESOURCES;
  }
  RtlZeroMemory (Buffer, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
  pSlots = (slot *) Buffer;

  NameA.Buffer = aName;
  NameA.Length = 0;
  NameA.MaximumLength = sizeof(aName);

  DirContext.ShortNameU.Buffer = ShortNameBuffer;
  DirContext.ShortNameU.Length = 0;
  DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);

  RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));

  IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound);

  if (!IsNameLegal || SpacesFound)
    {
      GENERATE_NAME_CONTEXT NameContext;
      VFAT_DIRENTRY_CONTEXT SearchContext;
      WCHAR ShortSearchName[13];
      needTilde = TRUE;
      needLong = TRUE;
      RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));
      SearchContext.LongNameU.Buffer = LongNameBuffer;
      SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
      SearchContext.ShortNameU.Buffer = ShortSearchName;
      SearchContext.ShortNameU.MaximumLength = sizeof(ShortSearchName);

      for (i = 0; i < 100; i++)
        {
          RtlGenerate8dot3Name(&DirContext.LongNameU, FALSE, &NameContext, &DirContext.ShortNameU);
          DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
	  SearchContext.DirIndex = 0;
          Status = FindFile (DeviceExt, ParentFcb, &DirContext.ShortNameU, &SearchContext, TRUE);
          if (!NT_SUCCESS(Status))
            {
	      break;
            }
        }
      if (i == 100) /* FIXME : what to do after this ? */
        {
          ExFreePool (Buffer);
          CHECKPOINT;
          return STATUS_UNSUCCESSFUL;
        }
      IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA, &SpacesFound);
      aName[NameA.Length]=0;
    }
  else
    {
      aName[NameA.Length] = 0;
      for (posCar = 0; posCar < DirContext.LongNameU.Length / sizeof(WCHAR); posCar++)
        {
          if (DirContext.LongNameU.Buffer[posCar] == L'.')
	    {
	      break;
	    }
        }
      /* check if the name and the extension contains upper case characters */
      RtlDowncaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE);
      DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
      uCaseBase = wcsncmp(DirContext.LongNameU.Buffer,
	                  DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;
      if (posCar < DirContext.LongNameU.Length/sizeof(WCHAR))
        {
	  i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
	  uCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
	                     DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
        }
      else
        {
          uCaseExt = FALSE;
        }
      /* check if the name and the extension contains lower case characters */
      RtlUpcaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE);
      DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
      lCaseBase = wcsncmp(DirContext.LongNameU.Buffer,
	                  DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;
      if (posCar < DirContext.LongNameU.Length / sizeof(WCHAR))
        {
	  i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
	  lCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
	                     DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
        }
      else
        {
	  lCaseExt = FALSE;
        }
      if ((lCaseBase && uCaseBase) || (lCaseExt && uCaseExt))
        {
          needLong = TRUE;
        }
    }
  DPRINT ("'%s', '%wZ', needTilde=%d, needLong=%d\n",
          aName, &DirContext.LongNameU, needTilde, needLong);
  memset(DirContext.DirEntry.Fat.ShortName, ' ', 11);
  for (i = 0; i < 8 && aName[i] && aName[i] != '.'; i++)
    {
      DirContext.DirEntry.Fat.Filename[i] = aName[i];
    }
  if (aName[i] == '.')
    {
      i++;
      for (j = 8; j < 11 && aName[i]; j++, i++)
        {
          DirContext.DirEntry.Fat.Filename[j] = aName[i];
        }
    }
  if (DirContext.DirEntry.Fat.Filename[0] == 0xe5)
    {
      DirContext.DirEntry.Fat.Filename[0] = 0x05;
    }

  if (needLong)
    {
      RtlCopyMemory(LongNameBuffer, DirContext.LongNameU.Buffer, DirContext.LongNameU.Length);
      DirContext.LongNameU.Buffer = LongNameBuffer;
      DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
      DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
      memset(DirContext.LongNameU.Buffer + DirContext.LongNameU.Length / sizeof(WCHAR) + 1, 0xff,
	     DirContext.LongNameU.MaximumLength - DirContext.LongNameU.Length - sizeof(WCHAR));
    }
  else
    {
      nbSlots = 1;
      if (lCaseBase)
        {
	  DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE;
        }
      if (lCaseExt)
        {
	  DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT;
        }
    }

  DPRINT ("dos name=%11.11s\n", DirContext.DirEntry.Fat.Filename);

  /* set attributes */
  DirContext.DirEntry.Fat.Attrib = ReqAttr;
  if (RequestedOptions & FILE_DIRECTORY_FILE)
    {
      DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
    }
  /* set dates and times */

⌨️ 快捷键说明

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