Esempio n. 1
0
NTSTATUS
VfatRead(
    PVFAT_IRP_CONTEXT IrpContext)
{
    NTSTATUS Status;
    PVFATFCB Fcb;
    ULONG Length = 0;
    ULONG ReturnedLength = 0;
    PERESOURCE Resource = NULL;
    LARGE_INTEGER ByteOffset;
    PVOID Buffer;
    ULONG BytesPerSector;

    ASSERT(IrpContext);

    DPRINT("VfatRead(IrpContext %p)\n", IrpContext);

    ASSERT(IrpContext->DeviceObject);

    // This request is not allowed on the main device object
    if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
    {
        DPRINT("VfatRead is called with the main device object.\n");
        Status = STATUS_INVALID_DEVICE_REQUEST;
        goto ByeBye;
    }

    ASSERT(IrpContext->DeviceExt);
    ASSERT(IrpContext->FileObject);
    Fcb = IrpContext->FileObject->FsContext;
    ASSERT(Fcb);

    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
        PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
        IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
        IoSkipCurrentIrpStackLocation(IrpContext->Irp);
        DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart);
        Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
        VfatFreeIrpContext(IrpContext);
        return Status;
    }

    DPRINT("<%wZ>\n", &Fcb->PathNameU);

    ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
    Length = IrpContext->Stack->Parameters.Read.Length;
    BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;

    /* fail if file is a directory and no paged read */
    if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
    {
        Status = STATUS_INVALID_PARAMETER;
        goto ByeBye;
    }

    DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length);

    if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
    {
       Status = STATUS_INVALID_PARAMETER;
       goto ByeBye;
    }

    if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart)
    {
       IrpContext->Irp->IoStatus.Information = 0;
       Status = STATUS_END_OF_FILE;
       goto ByeBye;
    }

    if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
    {
        if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
        {
            DPRINT("%u %u\n", ByteOffset.u.LowPart, Length);
            // non cached read must be sector aligned
            Status = STATUS_INVALID_PARAMETER;
            goto ByeBye;
        }
    }

    if (Length == 0)
    {
        IrpContext->Irp->IoStatus.Information = 0;
        Status = STATUS_SUCCESS;
        goto ByeBye;
    }

    if (Fcb->Flags & FCB_IS_VOLUME)
    {
        Resource = &IrpContext->DeviceExt->DirResource;
    }
    else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
    {
        Resource = &Fcb->PagingIoResource;
    }
    else
    {
        Resource = &Fcb->MainResource;
    }

    if (!ExAcquireResourceSharedLite(Resource,
                                     IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE))
    {
        Resource = NULL;
        Status = STATUS_PENDING;
        goto ByeBye;
    }

    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
    {
        if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
        {
            Status = STATUS_FILE_LOCK_CONFLICT;
            goto ByeBye;
        }
    }

    Buffer = VfatGetUserBuffer(IrpContext->Irp);
    if (!Buffer)
    {
        Status = STATUS_INVALID_USER_BUFFER;
        goto ByeBye;
    }

    if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
        !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
    {
        // cached read
        Status = STATUS_SUCCESS;
        if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
        {
            Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
            Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
        }

        _SEH2_TRY
        {
            if (IrpContext->FileObject->PrivateCacheMap == NULL)
            {
                CcInitializeCacheMap(IrpContext->FileObject,
                                     (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
                                     FALSE,
                                     &(VfatGlobalData->CacheMgrCallbacks),
                                     Fcb);
            }

            if (!CcCopyRead(IrpContext->FileObject,
                            &ByteOffset,
                            Length,
                            (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0,
                            Buffer,
                            &IrpContext->Irp->IoStatus))
            {
                ASSERT((IrpContext->Flags & IRPCONTEXT_CANWAIT) == 0);
                Status = STATUS_PENDING;
                goto ByeBye;
            }
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            Status = _SEH2_GetExceptionCode();
            goto ByeBye;
        }
        _SEH2_END;

        if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
        {
            Status = IrpContext->Irp->IoStatus.Status;
        }
    }
Esempio n. 2
0
static NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext)
{
  NTSTATUS RC = STATUS_SUCCESS;
  long BufferLength = 0;
  PUNICODE_STRING pSearchPattern = NULL;
  FILE_INFORMATION_CLASS FileInformationClass;
  unsigned char *Buffer = NULL;
  PFILE_NAMES_INFORMATION Buffer0 = NULL;
  PVFATFCB pFcb;
  PVFATCCB pCcb;
  BOOLEAN FirstQuery = FALSE;
  BOOLEAN FirstCall = TRUE;
  VFAT_DIRENTRY_CONTEXT DirContext;
  WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
  WCHAR ShortNameBuffer[13];

  PIO_STACK_LOCATION Stack = IrpContext->Stack;

  pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2;
  pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;

  // determine Buffer for result :
  BufferLength = Stack->Parameters.QueryDirectory.Length;
#if 0
  /* Do not probe the user buffer until SEH is available */
  if (IrpContext->Irp->RequestorMode != KernelMode &&
      IrpContext->Irp->MdlAddress == NULL &&
      IrpContext->Irp->UserBuffer != NULL)
    {
      ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
    }
#endif
  Buffer = VfatGetUserBuffer(IrpContext->Irp);

  if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
                                   (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
    {
      RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
      if (NT_SUCCESS(RC))
        {
          RC = STATUS_PENDING;
        }
      return RC;
    }

  /* Obtain the callers parameters */
#ifdef _MSC_VER
  /* HACKHACK: Bug in the MS ntifs.h header:
   * FileName is really a PUNICODE_STRING, not a PSTRING */
  pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
#else
  pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
#endif
  FileInformationClass =
    Stack->Parameters.QueryDirectory.FileInformationClass;
  if (pSearchPattern)
    {
      if (!pCcb->SearchPattern.Buffer)
        {
          FirstQuery = TRUE;
          pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
          pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, pCcb->SearchPattern.MaximumLength, TAG_VFAT);
          if (!pCcb->SearchPattern.Buffer)
            {
              ExReleaseResourceLite(&pFcb->MainResource);
              return STATUS_INSUFFICIENT_RESOURCES;
            }
          RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
          pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
	}
    }
  else if (!pCcb->SearchPattern.Buffer)
    {
      FirstQuery = TRUE;
      pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
      pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_VFAT);
      if (!pCcb->SearchPattern.Buffer)
        {
          ExReleaseResourceLite(&pFcb->MainResource);
          return STATUS_INSUFFICIENT_RESOURCES;
        }
      pCcb->SearchPattern.Buffer[0] = L'*';
      pCcb->SearchPattern.Buffer[1] = 0;
      pCcb->SearchPattern.Length = sizeof(WCHAR);
    }

  if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
    {
      DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
    }
  else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
    {
      DirContext.DirIndex = pCcb->Entry = 0;
    }
  else
    {
      DirContext.DirIndex = pCcb->Entry;
    }

  DPRINT ("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);

  DirContext.LongNameU.Buffer = LongNameBuffer;
  DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
  DirContext.ShortNameU.Buffer = ShortNameBuffer;
  DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);

  while (RC == STATUS_SUCCESS && BufferLength > 0)
    {
      RC = FindFile (IrpContext->DeviceExt, pFcb,
                     &pCcb->SearchPattern, &DirContext, FirstCall);
      pCcb->Entry = DirContext.DirIndex;
      DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext.LongNameU, RC, pCcb->Entry);
      FirstCall = FALSE;
      if (NT_SUCCESS (RC))
        {
          switch (FileInformationClass)
            {
              case FileNameInformation:
                RC = VfatGetFileNameInformation (&DirContext,
                                                 (PFILE_NAMES_INFORMATION) Buffer,
					         BufferLength);
                break;
              case FileDirectoryInformation:
                RC = VfatGetFileDirectoryInformation (&DirContext,
	                                              IrpContext->DeviceExt,
						      (PFILE_DIRECTORY_INFORMATION) Buffer,
						      BufferLength);
                break;
             case FileFullDirectoryInformation:
               RC = VfatGetFileFullDirectoryInformation (&DirContext,
	                                                 IrpContext->DeviceExt,
						         (PFILE_FULL_DIR_INFORMATION) Buffer,
						         BufferLength);
               break;
             case FileBothDirectoryInformation:
               RC = VfatGetFileBothInformation (&DirContext,
	                                        IrpContext->DeviceExt,
					        (PFILE_BOTH_DIR_INFORMATION) Buffer,
					        BufferLength);
               break;
             default:
               RC = STATUS_INVALID_INFO_CLASS;
	    }
          if (RC == STATUS_BUFFER_OVERFLOW)
            {
              break;
            }
	}
      else
        {
          if (FirstQuery)
            {
              RC = STATUS_NO_SUCH_FILE;
            }
          else
            {
              RC = STATUS_NO_MORE_FILES;
            }
          break;
	}
      Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
      Buffer0->FileIndex = DirContext.DirIndex;
      pCcb->Entry = ++DirContext.DirIndex;
      BufferLength -= Buffer0->NextEntryOffset;
      if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
        {
          break;
        }
      Buffer += Buffer0->NextEntryOffset;
    }
  if (Buffer0)
    {
      Buffer0->NextEntryOffset = 0;
      RC = STATUS_SUCCESS;
      IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;

    }
  ExReleaseResourceLite(&pFcb->MainResource);
  return RC;
}
Esempio n. 3
0
NTSTATUS
VfatWrite(
    PVFAT_IRP_CONTEXT IrpContext)
{
    PVFATFCB Fcb;
    PERESOURCE Resource = NULL;
    LARGE_INTEGER ByteOffset;
    LARGE_INTEGER OldFileSize;
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Length = 0;
    PVOID Buffer;
    ULONG BytesPerSector;

    ASSERT(IrpContext);

    DPRINT("VfatWrite(IrpContext %p)\n", IrpContext);

    ASSERT(IrpContext->DeviceObject);

    // This request is not allowed on the main device object
    if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
    {
        DPRINT("VfatWrite is called with the main device object.\n");
        Status = STATUS_INVALID_DEVICE_REQUEST;
        goto ByeBye;
    }

    ASSERT(IrpContext->DeviceExt);
    ASSERT(IrpContext->FileObject);
    Fcb = IrpContext->FileObject->FsContext;
    ASSERT(Fcb);

    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
        PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
        IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
        IoSkipCurrentIrpStackLocation(IrpContext->Irp);
        DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart);
        Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
        VfatFreeIrpContext(IrpContext);
        return Status;
    }

    DPRINT("<%wZ>\n", &Fcb->PathNameU);

    /* fail if file is a directory and no paged read */
    if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
    {
        Status = STATUS_INVALID_PARAMETER;
        goto ByeBye;
    }

    ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
    if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
        ByteOffset.u.HighPart == -1)
    {
        ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
    }
    Length = IrpContext->Stack->Parameters.Write.Length;
    BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;

    if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
    {
        Status = STATUS_INVALID_PARAMETER;
        goto ByeBye;
    }

    if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
        vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1)
    {
        if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
        {
            // we can't extend the FAT, the volume or the root on FAT12/FAT16
            Status = STATUS_END_OF_FILE;
            goto ByeBye;
        }
    }

    if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
    {
        if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
        {
            // non cached write must be sector aligned
            Status = STATUS_INVALID_PARAMETER;
            goto ByeBye;
        }
    }

    if (Length == 0)
    {
        /* FIXME: Update last write time */
        IrpContext->Irp->IoStatus.Information = 0;
        Status = STATUS_SUCCESS;
        goto ByeBye;
    }

    if (IrpContext->Irp->Flags & IRP_PAGING_IO)
    {
        if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
        {
            Status = STATUS_INVALID_PARAMETER;
            goto ByeBye;
        }

        if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
        {
            Length =  ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
        }
    }

    if (Fcb->Flags & FCB_IS_VOLUME)
    {
        Resource = &IrpContext->DeviceExt->DirResource;
    }
    else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
    {
        Resource = &Fcb->PagingIoResource;
    }
    else
    {
        Resource = &Fcb->MainResource;
    }

    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
        if (!ExAcquireResourceSharedLite(Resource,
                                         (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
        {
            Resource = NULL;
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }
    else
    {
        if (!ExAcquireResourceExclusiveLite(Resource,
                                            (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
        {
            Resource = NULL;
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }

    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
    {
        if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
        {
            Status = STATUS_FILE_LOCK_CONFLICT;
            goto ByeBye;
        }
    }

    if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
    {
        if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
        {
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }

    OldFileSize = Fcb->RFCB.FileSize;

    Buffer = VfatGetUserBuffer(IrpContext->Irp);
    if (!Buffer)
    {
        Status = STATUS_INVALID_USER_BUFFER;
        goto ByeBye;
    }


    if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
        !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
    {
        LARGE_INTEGER AllocationSize;
        AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
        Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
                                                  IrpContext->DeviceExt, &AllocationSize);
        if (!NT_SUCCESS (Status))
        {
            goto ByeBye;
        }
    }

    if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
        !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
    {
        // cached write

        if (IrpContext->FileObject->PrivateCacheMap == NULL)
        {
            CcInitializeCacheMap(IrpContext->FileObject,
                                 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
                                 FALSE,
                                 &VfatGlobalData->CacheMgrCallbacks,
                                 Fcb);
        }

        if (ByteOffset.QuadPart > OldFileSize.QuadPart)
        {
            CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
        }

        if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
                        1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
        {
            IrpContext->Irp->IoStatus.Information = Length;
            Status = STATUS_SUCCESS;
        }
        else
        {
            Status = STATUS_UNSUCCESSFUL;
        }
    }
    else
    {
        // non cached write

        if (ByteOffset.QuadPart > OldFileSize.QuadPart)
        {
            CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
        }

        Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
        if (!NT_SUCCESS(Status))
        {
            goto ByeBye;
        }

        Status = VfatWriteFileData(IrpContext, Length, ByteOffset);
        if (NT_SUCCESS(Status))
        {
            IrpContext->Irp->IoStatus.Information = Length;
        }
    }

    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
    {
        if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
        {
            LARGE_INTEGER SystemTime;
            // set dates and times
            KeQuerySystemTime (&SystemTime);
            if (Fcb->Flags & FCB_IS_FATX_ENTRY)
            {
                FsdSystemTimeToDosDateTime(IrpContext->DeviceExt,
                                           &SystemTime, &Fcb->entry.FatX.UpdateDate,
                                           &Fcb->entry.FatX.UpdateTime);
                Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate;
                Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime;
            }
            else
            {
                FsdSystemTimeToDosDateTime(IrpContext->DeviceExt,
                                           &SystemTime, &Fcb->entry.Fat.UpdateDate,
                                           &Fcb->entry.Fat.UpdateTime);
                Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate;
            }
            /* set date and times to dirty */
            Fcb->Flags |= FCB_IS_DIRTY;
        }
    }

ByeBye:
    if (Resource)
    {
        ExReleaseResourceLite(Resource);
    }

    if (Status == STATUS_PENDING)
    {
        Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
        if (NT_SUCCESS(Status))
        {
            Status = VfatQueueRequest(IrpContext);
        }
        else
        {
            IrpContext->Irp->IoStatus.Status = Status;
            IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
            VfatFreeIrpContext(IrpContext);
        }
    }
    else
    {
        IrpContext->Irp->IoStatus.Status = Status;
        if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
            !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
        {
            IrpContext->FileObject->CurrentByteOffset.QuadPart =
                ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
        }

        IoCompleteRequest(IrpContext->Irp,
                          (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
        VfatFreeIrpContext(IrpContext);
    }
    DPRINT("%x\n", Status);
    return Status;
}
Esempio n. 4
0
static
NTSTATUS
DoQuery(
    PVFAT_IRP_CONTEXT IrpContext)
{
    NTSTATUS Status = STATUS_SUCCESS;
    LONG BufferLength = 0;
    PUNICODE_STRING pSearchPattern = NULL;
    FILE_INFORMATION_CLASS FileInformationClass;
    PUCHAR Buffer = NULL;
    PFILE_NAMES_INFORMATION Buffer0 = NULL;
    PVFATFCB pFcb;
    PVFATCCB pCcb;
    BOOLEAN FirstQuery = FALSE;
    BOOLEAN FirstCall = TRUE;
    VFAT_DIRENTRY_CONTEXT DirContext;
    WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
    WCHAR ShortNameBuffer[13];

    PIO_STACK_LOCATION Stack = IrpContext->Stack;

    pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
    pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;

    /* Determine Buffer for result : */
    BufferLength = Stack->Parameters.QueryDirectory.Length;
#if 0
    /* Do not probe the user buffer until SEH is available */
    if (IrpContext->Irp->RequestorMode != KernelMode &&
        IrpContext->Irp->MdlAddress == NULL &&
        IrpContext->Irp->UserBuffer != NULL)
    {
        ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
    }
#endif
    Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);

    if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
                                     BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
    {
        Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
        if (NT_SUCCESS(Status))
            Status = STATUS_PENDING;

        return Status;
    }

    /* Obtain the callers parameters */
#ifdef _MSC_VER
    /* HACKHACK: Bug in the MS ntifs.h header:
     * FileName is really a PUNICODE_STRING, not a PSTRING */
    pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
#else
    pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
#endif
    FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;

    /* Allocate search pattern in case:
     * -> We don't have one already in context
     * -> We have been given an input pattern
     * -> The pattern length is not null
     * -> The pattern buffer is not null
     * Otherwise, we'll fall later and allocate a match all (*) pattern
     */ 
    if (pSearchPattern &&
        pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
    {
        if (!pCcb->SearchPattern.Buffer)
        {
            FirstQuery = TRUE;
            pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
            pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
                                                               pCcb->SearchPattern.MaximumLength,
                                                               TAG_VFAT);
            if (!pCcb->SearchPattern.Buffer)
            {
                ExReleaseResourceLite(&pFcb->MainResource);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
            pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
        }
    }
    else if (!pCcb->SearchPattern.Buffer)
    {
        FirstQuery = TRUE;
        pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
        pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
                                                           2 * sizeof(WCHAR),
                                                           TAG_VFAT);
        if (!pCcb->SearchPattern.Buffer)
        {
            ExReleaseResourceLite(&pFcb->MainResource);
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        pCcb->SearchPattern.Buffer[0] = L'*';
        pCcb->SearchPattern.Buffer[1] = 0;
        pCcb->SearchPattern.Length = sizeof(WCHAR);
    }

    if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
    {
        DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
    }
    else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
    {
        DirContext.DirIndex = pCcb->Entry = 0;
    }
    else
    {
        DirContext.DirIndex = pCcb->Entry;
    }

    DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);

    DirContext.LongNameU.Buffer = LongNameBuffer;
    DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
    DirContext.ShortNameU.Buffer = ShortNameBuffer;
    DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);

    if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
                                        BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
    {
        ExReleaseResourceLite(&pFcb->MainResource);
        return VfatMarkIrpContextForQueue(IrpContext);
    }

    while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
    {
        Status = FindFile(IrpContext->DeviceExt,
                          pFcb,
                          &pCcb->SearchPattern,
                          &DirContext,
                          FirstCall);
        pCcb->Entry = DirContext.DirIndex;

        DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);

        FirstCall = FALSE;
        if (NT_SUCCESS(Status))
        {
            switch (FileInformationClass)
            {
                case FileNameInformation:
                    Status = VfatGetFileNameInformation(&DirContext,
                                                        (PFILE_NAMES_INFORMATION)Buffer,
                                                        BufferLength);
                    break;

                case FileDirectoryInformation:
                    Status = VfatGetFileDirectoryInformation(&DirContext,
                                                             IrpContext->DeviceExt,
                                                             (PFILE_DIRECTORY_INFORMATION)Buffer,
                                                             BufferLength);
                    break;

                case FileFullDirectoryInformation:
                    Status = VfatGetFileFullDirectoryInformation(&DirContext,
                                                                 IrpContext->DeviceExt,
                                                                 (PFILE_FULL_DIR_INFORMATION)Buffer,
                                                                 BufferLength);
                    break;

                case FileBothDirectoryInformation:
                    Status = VfatGetFileBothInformation(&DirContext,
                                                        IrpContext->DeviceExt,
                                                        (PFILE_BOTH_DIR_INFORMATION)Buffer,
                                                        BufferLength);
                    break;

                default:
                    Status = STATUS_INVALID_INFO_CLASS;
                    break;
            }

            if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
                break;
        }
        else
        {
            Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
            break;
        }

        Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
        Buffer0->FileIndex = DirContext.DirIndex;
        pCcb->Entry = ++DirContext.DirIndex;
        BufferLength -= Buffer0->NextEntryOffset;

        if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
            break;

        Buffer += Buffer0->NextEntryOffset;
    }

    if (Buffer0)
    {
        Buffer0->NextEntryOffset = 0;
        Status = STATUS_SUCCESS;
        IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
    }

    ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
    ExReleaseResourceLite(&pFcb->MainResource);

    return Status;
}