fsctl.c

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

C
928
字号

static NTSTATUS
VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
/*
 * FUNCTION: Verify the filesystem
 */
{
  PDEVICE_OBJECT DeviceToVerify;
  NTSTATUS Status = STATUS_SUCCESS;
  FATINFO FatInfo;
  BOOLEAN RecognizedFS;
  PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;

  DPRINT("VfatVerify(IrpContext %x)\n", IrpContext);

  DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
  Status = VfatBlockDeviceIoControl(DeviceToVerify,
				    IOCTL_DISK_CHECK_VERIFY,
				    NULL,
				    0,
				    NULL,
				    0,
				    TRUE);
  DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME;
  if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED)
    {
      DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
      Status = STATUS_WRONG_VOLUME;
    }
  else
    {
      Status = VfatHasFileSystem(DeviceToVerify, &RecognizedFS, &FatInfo);
      if (!NT_SUCCESS(Status) || RecognizedFS == FALSE)
        {
          Status = STATUS_WRONG_VOLUME;
        }
      else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO)))
        {
          /*
           * FIXME:
           *   Preformated floppy disks have very often a serial number of 0000:0000.
           *   We should calculate a crc sum over the sectors from the root directory as secondary volume number.
	   *   Each write to the root directory must update this crc sum.
           */

        }
      else
      	{
      	  Status = STATUS_WRONG_VOLUME;
        }
     }

  return Status;
}


static NTSTATUS
VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
{
   DPRINT("VfatGetVolumeBitmap (IrpContext %x)\n", IrpContext);

   return STATUS_INVALID_DEVICE_REQUEST;
}


static NTSTATUS
VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
{
   PIO_STACK_LOCATION Stack;
   LARGE_INTEGER Vcn;
   PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
   PFILE_OBJECT FileObject;
   ULONG MaxExtentCount;
   PVFATFCB Fcb;
   PDEVICE_EXTENSION DeviceExt;
   ULONG FirstCluster;
   ULONG CurrentCluster;
   ULONG LastCluster;
   NTSTATUS Status;

   DPRINT("VfatGetRetrievalPointers(IrpContext %x)\n", IrpContext);

   DeviceExt = IrpContext->DeviceExt;
   FileObject = IrpContext->FileObject;
   Stack = IrpContext->Stack;
   if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) ||
       Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
   {
      return STATUS_INVALID_PARAMETER;
   }
   if (IrpContext->Irp->UserBuffer == NULL ||
       Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))
   {
      return STATUS_BUFFER_TOO_SMALL;
   }

   Fcb = FileObject->FsContext;

   ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);

   Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn;
   RetrievalPointers = IrpContext->Irp->UserBuffer;

   MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0]));


   if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
   {
      Status = STATUS_INVALID_PARAMETER;
      goto ByeBye;
   }

   CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
   Status = OffsetToCluster(DeviceExt, FirstCluster,
                            Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
			    &CurrentCluster, FALSE);
   if (!NT_SUCCESS(Status))
   {
      goto ByeBye;
   }

   RetrievalPointers->StartingVcn = Vcn;
   RetrievalPointers->ExtentCount = 0;
   RetrievalPointers->Extents[0].Lcn.u.HighPart = 0;
   RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2;
   LastCluster = 0;
   while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount)
   {

      LastCluster = CurrentCluster;
      Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
      Vcn.QuadPart++;
      if (!NT_SUCCESS(Status))
      {
         goto ByeBye;
      }

      if (LastCluster + 1 != CurrentCluster)
      {
	 RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn;
	 RetrievalPointers->ExtentCount++;
	 if (RetrievalPointers->ExtentCount < MaxExtentCount)
	 {
	    RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0;
	    RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2;
	 }
      }
   }

   IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1));
   Status = STATUS_SUCCESS;

ByeBye:
   ExReleaseResourceLite(&Fcb->MainResource);

   return Status;
}

static NTSTATUS
VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
{
   DPRINT("VfatMoveFile(IrpContext %x)\n", IrpContext);

   return STATUS_INVALID_DEVICE_REQUEST;
}

#ifdef USE_ROS_CC_AND_FS
static NTSTATUS
VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext)
{
   PDEVICE_EXTENSION DeviceExt;
   PROS_QUERY_LCN_MAPPING LcnQuery;
   PIO_STACK_LOCATION Stack;

   DPRINT("VfatRosQueryLcnMapping(IrpContext %x)\n", IrpContext);

   DeviceExt = IrpContext->DeviceExt;
   Stack = IrpContext->Stack;
   if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL ||
       Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING))
   {
      return STATUS_BUFFER_TOO_SMALL;
   }
   LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer);
   LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector;
   IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING);
   return(STATUS_SUCCESS);
}
#endif

static NTSTATUS
VfatIsVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
{
   PULONG Flags;

   DPRINT("VfatIsVolumeDirty(IrpContext %x)\n", IrpContext);

   if (IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength != sizeof(ULONG))
      return STATUS_INVALID_BUFFER_SIZE;
   else if (!IrpContext->Irp->AssociatedIrp.SystemBuffer)
      return STATUS_INVALID_USER_BUFFER;

   Flags = (PULONG)IrpContext->Irp->AssociatedIrp.SystemBuffer;
   *Flags = 0;

   if (IrpContext->DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY
      && !(IrpContext->DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY))
   {
      *Flags |= VOLUME_IS_DIRTY;
   }

   return STATUS_SUCCESS;
}

static NTSTATUS
VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
{
   ULONG eocMark;
   PDEVICE_EXTENSION DeviceExt;
   NTSTATUS Status = STATUS_SUCCESS;

   DPRINT("VfatMarkVolumeDirty(IrpContext %x)\n", IrpContext);
   DeviceExt = IrpContext->DeviceExt;

   if (!(DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY))
   {
      Status = GetNextCluster(DeviceExt, 1, &eocMark);
      if (NT_SUCCESS(Status))
      {
         /* unset clean shutdown bit */
         eocMark &= ~DeviceExt->CleanShutBitMask;
         Status = WriteCluster(DeviceExt, 1, eocMark);
      }
   }

   DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY;

   return Status;
}

NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
/*
 * FUNCTION: File system control
 */
{

   NTSTATUS Status;

   DPRINT("VfatFileSystemControl(IrpContext %x)\n", IrpContext);

   ASSERT(IrpContext);
   ASSERT(IrpContext->Irp);
   ASSERT(IrpContext->Stack);

   IrpContext->Irp->IoStatus.Information = 0;

   switch (IrpContext->MinorFunction)
   {
      case IRP_MN_USER_FS_REQUEST:
         switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode)
	 {
	    case FSCTL_GET_VOLUME_BITMAP:
               Status = VfatGetVolumeBitmap(IrpContext);
	       break;
	    case FSCTL_GET_RETRIEVAL_POINTERS:
               Status = VfatGetRetrievalPointers(IrpContext);
	       break;
	    case FSCTL_MOVE_FILE:
	       Status = VfatMoveFile(IrpContext);
	       break;
#ifdef USE_ROS_CC_AND_FS
 	    case FSCTL_ROS_QUERY_LCN_MAPPING:
	       Status = VfatRosQueryLcnMapping(IrpContext);
	       break;
#endif
	    case FSCTL_IS_VOLUME_DIRTY:
	       Status = VfatIsVolumeDirty(IrpContext);
	       break;
	    case FSCTL_MARK_VOLUME_DIRTY:
	       Status = VfatMarkVolumeDirty(IrpContext);
	       break;
	    default:
	       Status = STATUS_INVALID_DEVICE_REQUEST;
	 }
	 break;

      case IRP_MN_MOUNT_VOLUME:
         Status = VfatMount(IrpContext);
	 break;

      case IRP_MN_VERIFY_VOLUME:
	DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n");
	 Status = VfatVerify(IrpContext);
	 break;

      default:
	   DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction);
	   Status = STATUS_INVALID_DEVICE_REQUEST;
	   break;
   }

   IrpContext->Irp->IoStatus.Status = Status;

   IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
   VfatFreeIrpContext(IrpContext);
   return (Status);
}

⌨️ 快捷键说明

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