fcb.c

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

C
738
字号
/*
 *  ReactOS kernel
 *  Copyright (C) 2002, 2004 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/* $Id: fcb.c 21710 2006-04-22 16:36:21Z tretiakov $
 *
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * FILE:             services/fs/cdfs/fcb.c
 * PURPOSE:          CDROM (ISO 9660) filesystem driver
 * PROGRAMMER:       Art Yerkes
 * UPDATE HISTORY:
 */

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

#include "cdfs.h"

#define NDEBUG
#include <debug.h>

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

#define TAG_FCB TAG('I', 'F', 'C', 'B')

#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))


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

static PWCHAR
CdfsGetNextPathElement(PWCHAR FileName)
{
  if (*FileName == L'\0')
    {
      return(NULL);
    }

  while (*FileName != L'\0' && *FileName != L'\\')
    {
      FileName++;
    }

  return(FileName);
}


static VOID
CdfsWSubString(PWCHAR pTarget, const PWCHAR pSource, size_t pLength)
{
  wcsncpy (pTarget, pSource, pLength);
  pTarget [pLength] = L'\0';
}


PFCB
CdfsCreateFCB(PCWSTR FileName)
{
  PFCB Fcb;

  Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB);
  RtlZeroMemory(Fcb, sizeof(FCB));

  if (FileName)
    {
      wcscpy(Fcb->PathName, FileName);
      if (wcsrchr(Fcb->PathName, '\\') != 0)
	{
	  Fcb->ObjectName = wcsrchr(Fcb->PathName, '\\');
	}
      else
	{
	  Fcb->ObjectName = Fcb->PathName;
	}
    }

  ExInitializeResourceLite(&Fcb->MainResource);

  return(Fcb);
}


VOID
CdfsDestroyFCB(PFCB Fcb)
{
  ExDeleteResourceLite(&Fcb->MainResource);

  ExFreePool(Fcb);
}


BOOLEAN
CdfsFCBIsDirectory(PFCB Fcb)
{
  return(Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY);
}


BOOLEAN
CdfsFCBIsRoot(PFCB Fcb)
{
  return(wcscmp(Fcb->PathName, L"\\") == 0);
}


VOID
CdfsGrabFCB(PDEVICE_EXTENSION Vcb,
	    PFCB Fcb)
{
  KIRQL  oldIrql;

  DPRINT("grabbing FCB at %x: %S, refCount:%d\n",
	 Fcb,
	 Fcb->PathName,
	 Fcb->RefCount);

  KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
  Fcb->RefCount++;
  KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
}


VOID
CdfsReleaseFCB(PDEVICE_EXTENSION Vcb,
	       PFCB Fcb)
{
  KIRQL  oldIrql;

  DPRINT("releasing FCB at %x: %S, refCount:%d\n",
	 Fcb,
	 Fcb->PathName,
	 Fcb->RefCount);

  KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
  Fcb->RefCount--;
  if (Fcb->RefCount <= 0 && !CdfsFCBIsDirectory(Fcb))
    {
      RemoveEntryList(&Fcb->FcbListEntry);
      CdfsDestroyFCB(Fcb);
    }
  KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
}


VOID
CdfsAddFCBToTable(PDEVICE_EXTENSION Vcb,
		  PFCB Fcb)
{
  KIRQL  oldIrql;

  KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
  Fcb->DevExt = Vcb;
  InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
  KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
}


PFCB
CdfsGrabFCBFromTable(PDEVICE_EXTENSION Vcb,
		     PUNICODE_STRING FileName)
{
  KIRQL  oldIrql;
  PFCB Fcb;
  PLIST_ENTRY  current_entry;

  KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);

  if (FileName == NULL || FileName->Length == 0 || FileName->Buffer[0] == 0)
    {
      DPRINT("Return FCB for stream file object\n");
      Fcb = Vcb->StreamFileObject->FsContext;
      Fcb->RefCount++;
      KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
      return(Fcb);
    }

  current_entry = Vcb->FcbListHead.Flink;
  while (current_entry != &Vcb->FcbListHead)
    {
      Fcb = CONTAINING_RECORD(current_entry, FCB, FcbListEntry);

      DPRINT("Comparing '%wZ' and '%S'\n", FileName, Fcb->PathName);
      if (_wcsicmp(FileName->Buffer, Fcb->PathName) == 0)
	{
	  Fcb->RefCount++;
	  KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
	  return(Fcb);
	}

      //FIXME: need to compare against short name in FCB here

      current_entry = current_entry->Flink;
    }
  KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);

  return(NULL);
}


NTSTATUS
CdfsFCBInitializeCache(PVCB Vcb,
		       PFCB Fcb)
{
  PFILE_OBJECT FileObject;
  NTSTATUS Status;
  PCCB  newCCB;

  FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);

  newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB);
  if (newCCB == NULL)
    {
      return(STATUS_INSUFFICIENT_RESOURCES);
    }
  RtlZeroMemory(newCCB,
		sizeof(CCB));

  FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
  FileObject->FsContext = Fcb;
  FileObject->FsContext2 = newCCB;
  newCCB->PtrFileObject = FileObject;
  Fcb->FileObject = FileObject;
  Fcb->DevExt = Vcb;

#ifdef USE_ROS_AND_FS
  Status = CcRosInitializeFileCache(FileObject,
				    PAGE_SIZE);
  if (!NT_SUCCESS(Status))
    {
      DbgPrint("CcRosInitializeFileCache failed\n");
      KEBUGCHECK(0);
    }
#else
  Status = STATUS_SUCCESS;
  CcInitializeCacheMap(FileObject,
                       (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
		       FALSE,
		       NULL,
		       NULL);
#endif

  ObDereferenceObject(FileObject);
  Fcb->Flags |= FCB_CACHE_INITIALIZED;

  return(Status);
}


PFCB
CdfsMakeRootFCB(PDEVICE_EXTENSION Vcb)
{
  PFCB Fcb;

  Fcb = CdfsCreateFCB(L"\\");

  Fcb->Entry.DataLengthL = Vcb->CdInfo.RootSize;
  Fcb->Entry.ExtentLocationL = Vcb->CdInfo.RootStart;
  Fcb->Entry.FileFlags = FILE_FLAG_DIRECTORY;
  Fcb->IndexNumber.QuadPart = 0LL;
  Fcb->RefCount = 1;
  Fcb->DirIndex = 0;
  Fcb->RFCB.FileSize.QuadPart = Vcb->CdInfo.RootSize;
  Fcb->RFCB.ValidDataLength.QuadPart = Vcb->CdInfo.RootSize;
  Fcb->RFCB.AllocationSize.QuadPart = Vcb->CdInfo.RootSize;

  CdfsFCBInitializeCache(Vcb, Fcb);
  CdfsAddFCBToTable(Vcb, Fcb);
  CdfsGrabFCB(Vcb, Fcb);

  return(Fcb);
}


PFCB
CdfsOpenRootFCB(PDEVICE_EXTENSION Vcb)
{
  UNICODE_STRING FileName;
  PFCB Fcb;

  RtlInitUnicodeString(&FileName, L"\\");

  Fcb = CdfsGrabFCBFromTable(Vcb,
			     &FileName);
  if (Fcb == NULL)
    {
      Fcb = CdfsMakeRootFCB(Vcb);
    }

  return(Fcb);
}


static VOID
CdfsGetDirEntryName(PDEVICE_EXTENSION DeviceExt,
		    PDIR_RECORD Record,
		    PWSTR Name)
/*
 * FUNCTION: Retrieves the file name from a directory record.
 */
{
  if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
    {
      wcscpy(Name, L".");
    }
  else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
    {
      wcscpy(Name, L"..");
    }
  else
    {
      if (DeviceExt->CdInfo.JolietLevel == 0)
	{
	  ULONG i;

	  for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
	    Name[i] = (WCHAR)Record->FileId[i];
	  Name[i] = 0;
	}
      else
	{
	  CdfsSwapString(Name,
			 Record->FileId,
			 Record->FileIdLength);
	}
    }

  DPRINT("Name '%S'\n", Name);
}


NTSTATUS
CdfsMakeFCBFromDirEntry(PVCB Vcb,
			PFCB DirectoryFCB,
			PWSTR LongName,
			PWSTR ShortName,
			PDIR_RECORD Record,
			ULONG DirectorySector,
			ULONG DirectoryOffset,
			PFCB * fileFCB)
{
  WCHAR pathName[MAX_PATH];
  PFCB rcFCB;
  ULONG Size;

  if (LongName [0] != 0 && wcslen (DirectoryFCB->PathName) +
        sizeof(WCHAR) + wcslen (LongName) > MAX_PATH)
    {
      return(STATUS_OBJECT_NAME_INVALID);
    }

  wcscpy(pathName, DirectoryFCB->PathName);
  if (!CdfsFCBIsRoot(DirectoryFCB))
    {
      wcscat(pathName, L"\\");
    }

⌨️ 快捷键说明

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