finfo.c

来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 940 行 · 第 1/2 页

C
940
字号
		      PDEVICE_OBJECT DeviceObject,
		      PFILE_ALL_INFORMATION Info,
		      PULONG BufferLength)
/*
 * FUNCTION: Retrieve the all file information
 */
{
  NTSTATUS Status;
  ULONG InitialBufferLength = *BufferLength;

  ASSERT(Info);
  ASSERT(Fcb);

  if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
    return(STATUS_BUFFER_OVERFLOW);

  /* Basic Information */
  Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
  if (!NT_SUCCESS(Status)) return Status;
  /* Standard Information */
  Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
  if (!NT_SUCCESS(Status)) return Status;
  /* Internal Information */
  Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
  if (!NT_SUCCESS(Status)) return Status;
  /* EA Information */
  Info->EaInformation.EaSize = 0;
  /* Access Information: The IO-Manager adds this information */
  /* Position Information */
  Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
  if (!NT_SUCCESS(Status)) return Status;
  /* Mode Information: The IO-Manager adds this information */
  /* Alignment Information: The IO-Manager adds this information */
  /* Name Information */
  Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
  if (!NT_SUCCESS(Status)) return Status;

  *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));

  return STATUS_SUCCESS;
}

static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
{
   if (Size > 0)
   {
      Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
   }
   else
   {
      Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
   }
   if (!vfatFCBIsDirectory(Fcb))
   {
      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
         Fcb->entry.FatX.FileSize = Size;
      else
         Fcb->entry.Fat.FileSize = Size;
   }
   Fcb->RFCB.FileSize.QuadPart = Size;
   Fcb->RFCB.ValidDataLength.QuadPart = Size;

   if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
   {
      CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
   }
}

NTSTATUS
VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
				 PVFATFCB Fcb,
				 PDEVICE_EXTENSION DeviceExt,
				 PLARGE_INTEGER AllocationSize)
{
  ULONG OldSize;
  ULONG Cluster, FirstCluster;
  NTSTATUS Status;

  ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
  ULONG NewSize = AllocationSize->u.LowPart;
  ULONG NCluster;
  BOOLEAN AllocSizeChanged = FALSE;

  DPRINT("VfatSetAllocationSizeInformation()\n");

  if (Fcb->Flags & FCB_IS_FATX_ENTRY)
    OldSize = Fcb->entry.FatX.FileSize;
  else
    OldSize = Fcb->entry.Fat.FileSize;
  if (AllocationSize->u.HighPart > 0)
  {
    return STATUS_INVALID_PARAMETER;
  }
  if (OldSize == NewSize)
    {
      return(STATUS_SUCCESS);
    }

  FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);

  if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
  {
    AllocSizeChanged = TRUE;
    if (FirstCluster == 0)
    {
      Fcb->LastCluster = Fcb->LastOffset = 0;
      Status = NextCluster (DeviceExt, FirstCluster, &FirstCluster, TRUE);
      if (!NT_SUCCESS(Status))
      {
	DPRINT1("NextCluster failed. Status = %x\n", Status);
	return Status;
      }
      if (FirstCluster == 0xffffffff)
      {
         return STATUS_DISK_FULL;
      }
      Status = OffsetToCluster(DeviceExt, FirstCluster,
                               ROUND_DOWN(NewSize - 1, ClusterSize),
                               &NCluster, TRUE);
      if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
      {
         /* disk is full */
         NCluster = Cluster = FirstCluster;
         Status = STATUS_SUCCESS;
         while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
         {
            Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
            WriteCluster (DeviceExt, Cluster, 0);
            Cluster = NCluster;
         }
         return STATUS_DISK_FULL;
      }
      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
      {
         Fcb->entry.FatX.FirstCluster = FirstCluster;
      }
      else
      {
        if (DeviceExt->FatInfo.FatType == FAT32)
        {
          Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
          Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
        }
        else
        {
            ASSERT((FirstCluster >> 16) == 0);
            Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
        }
      }
    }
    else
    {
#if 0 /* FIXME */
       if (Fcb->LastCluster > 0)
       {
          if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
          {
             Cluster = Fcb->LastCluster;
             Status = STATUS_SUCCESS;
          }
          else
          {
             Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
                                      Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset,
                                      &Cluster, FALSE);
          }
       }
       else
       {
          Status = OffsetToCluster(DeviceExt, FirstCluster,
                                   Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
                                   &Cluster, FALSE);
       }
       if (!NT_SUCCESS(Status))
       {
          return Status;
       }

       if (Fcb->LastCluster == 0)
       {
          Fcb->LastCluster = Cluster;
          Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
       }

       /* FIXME: Check status */
       /* Cluster points now to the last cluster within the chain */
       Status = OffsetToCluster(DeviceExt, Cluster,
	                        ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
                                &NCluster, TRUE);
#else
       Status = OffsetToCluster(DeviceExt, FirstCluster,
	                        ROUND_DOWN(NewSize - 1, ClusterSize),
                                &Cluster, TRUE);
       NCluster = Cluster;
#endif
       if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
       {
	  /* disk is full */
	  NCluster = Cluster;
          Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
	  WriteCluster(DeviceExt, Cluster, 0xffffffff);
	  Cluster = NCluster;
          while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
	  {
	    Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
            WriteCluster (DeviceExt, Cluster, 0);
	    Cluster = NCluster;
	  }
	  return STATUS_DISK_FULL;
       }
    }
    UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
  }
  else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
  {
    AllocSizeChanged = TRUE;
    /* FIXME: Use the cached cluster/offset better way. */
    Fcb->LastCluster = Fcb->LastOffset = 0;
    UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
    if (NewSize > 0)
    {
      Status = OffsetToCluster(DeviceExt, FirstCluster,
	          ROUND_DOWN(NewSize - 1, ClusterSize),
		  &Cluster, FALSE);

      NCluster = Cluster;
      Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
      WriteCluster(DeviceExt, Cluster, 0xffffffff);
      Cluster = NCluster;
    }
    else
    {
      if (Fcb->Flags & FCB_IS_FATX_ENTRY)
      {
         Fcb->entry.FatX.FirstCluster = 0;
      }
      else
      {
        if (DeviceExt->FatInfo.FatType == FAT32)
        {
          Fcb->entry.Fat.FirstCluster = 0;
          Fcb->entry.Fat.FirstClusterHigh = 0;
        }
        else
        {
            Fcb->entry.Fat.FirstCluster = 0;
        }
      }

      NCluster = Cluster = FirstCluster;
      Status = STATUS_SUCCESS;
    }
    while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
    {
       Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
       WriteCluster (DeviceExt, Cluster, 0);
       Cluster = NCluster;
    }
  }
  else
  {
     UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
  }
  /* Update the on-disk directory entry */
  Fcb->Flags |= FCB_IS_DIRTY;
  if (AllocSizeChanged)
    {
      VfatUpdateEntry(Fcb);
    }
  return STATUS_SUCCESS;
}

NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
/*
 * FUNCTION: Retrieve the specified file information
 */
{
  FILE_INFORMATION_CLASS FileInformationClass;
  PVFATFCB FCB = NULL;

  NTSTATUS RC = STATUS_SUCCESS;
  PVOID SystemBuffer;
  ULONG BufferLength;

  /* PRECONDITION */
  ASSERT(IrpContext);

  /* INITIALIZATION */
  FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
  FCB = (PVFATFCB) IrpContext->FileObject->FsContext;

  DPRINT("VfatQueryInformation is called for '%s'\n",
         FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);


  SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
  BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;

  if (!(FCB->Flags & FCB_IS_PAGE_FILE))
  {
     if (!ExAcquireResourceSharedLite(&FCB->MainResource,
                                      (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
     {
        return VfatQueueRequest (IrpContext);
     }
  }


  switch (FileInformationClass)
    {
    case FileStandardInformation:
      RC = VfatGetStandardInformation(FCB,
				      SystemBuffer,
				      &BufferLength);
      break;
    case FilePositionInformation:
      RC = VfatGetPositionInformation(IrpContext->FileObject,
				      FCB,
				      IrpContext->DeviceObject,
				      SystemBuffer,
				      &BufferLength);
      break;
    case FileBasicInformation:
      RC = VfatGetBasicInformation(IrpContext->FileObject,
				   FCB,
				   IrpContext->DeviceObject,
				   SystemBuffer,
				   &BufferLength);
      break;
    case FileNameInformation:
      RC = VfatGetNameInformation(IrpContext->FileObject,
				  FCB,
				  IrpContext->DeviceObject,
				  SystemBuffer,
				  &BufferLength);
      break;
    case FileInternalInformation:
      RC = VfatGetInternalInformation(FCB,
				      SystemBuffer,
				      &BufferLength);
      break;
    case FileNetworkOpenInformation:
      RC = VfatGetNetworkOpenInformation(FCB,
					 IrpContext->DeviceExt,
					 SystemBuffer,
					 &BufferLength);
      break;
    case FileAllInformation:
      RC = VfatGetAllInformation(IrpContext->FileObject,
				 FCB,
				 IrpContext->DeviceObject,
				 SystemBuffer,
				 &BufferLength);
      break;

    case FileEaInformation:
      RC = VfatGetEaInformation(IrpContext->FileObject,
				FCB,
				IrpContext->DeviceObject,
				SystemBuffer,
				&BufferLength);
      break;

    case FileAlternateNameInformation:
      RC = STATUS_NOT_IMPLEMENTED;
      break;
    default:
      RC = STATUS_NOT_SUPPORTED;
    }

  if (!(FCB->Flags & FCB_IS_PAGE_FILE))
  {
     ExReleaseResourceLite(&FCB->MainResource);
  }
  IrpContext->Irp->IoStatus.Status = RC;
  if (NT_SUCCESS(RC))
    IrpContext->Irp->IoStatus.Information =
      IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
  else
    IrpContext->Irp->IoStatus.Information = 0;
  IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
  VfatFreeIrpContext(IrpContext);

  return RC;
}

NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
/*
 * FUNCTION: Retrieve the specified file information
 */
{
  FILE_INFORMATION_CLASS FileInformationClass;
  PVFATFCB FCB = NULL;
  NTSTATUS RC = STATUS_SUCCESS;
  PVOID SystemBuffer;
  BOOLEAN CanWait = (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0;

  /* PRECONDITION */
  ASSERT(IrpContext);

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

  /* INITIALIZATION */
  FileInformationClass =
    IrpContext->Stack->Parameters.SetFile.FileInformationClass;
  FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
  SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;

  DPRINT("VfatSetInformation is called for '%s'\n",
         FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);

  DPRINT("FileInformationClass %d\n", FileInformationClass);
  DPRINT("SystemBuffer %x\n", SystemBuffer);

  if (!(FCB->Flags & FCB_IS_PAGE_FILE))
    {
      if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
                                          (BOOLEAN)CanWait))
	{
	  return(VfatQueueRequest (IrpContext));
	}
    }

  switch (FileInformationClass)
    {
    case FilePositionInformation:
      RC = VfatSetPositionInformation(IrpContext->FileObject,
				      SystemBuffer);
      break;
    case FileDispositionInformation:
      RC = VfatSetDispositionInformation(IrpContext->FileObject,
					 FCB,
					 IrpContext->DeviceObject,
					 SystemBuffer);
      break;
    case FileAllocationInformation:
    case FileEndOfFileInformation:
      RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
					    FCB,
					    IrpContext->DeviceExt,
					    (PLARGE_INTEGER)SystemBuffer);
      break;
    case FileBasicInformation:
      RC = VfatSetBasicInformation(IrpContext->FileObject,
				   FCB,
				   IrpContext->DeviceExt,
				   SystemBuffer);
      break;
    case FileRenameInformation:
      RC = STATUS_NOT_IMPLEMENTED;
      break;
    default:
      RC = STATUS_NOT_SUPPORTED;
    }

  if (!(FCB->Flags & FCB_IS_PAGE_FILE))
  {
     ExReleaseResourceLite(&FCB->MainResource);
  }

  IrpContext->Irp->IoStatus.Status = RC;
  IrpContext->Irp->IoStatus.Information = 0;
  IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
  VfatFreeIrpContext(IrpContext);

  return RC;
}

/* EOF */

⌨️ 快捷键说明

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