/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: drivers/fs/vfat/finfo.c
+ * FILE: drivers/filesystems/fastfat/finfo.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
* Herve Poussineau (reactos@poussine.freesurf.fr)
+ * Pierre Schweitzer (pierre@reactos.org)
*
*/
/* INCLUDES *****************************************************************/
-#define NDEBUG
#include "vfat.h"
+#define NDEBUG
+#include <debug.h>
+
+#define NASSERTS_RENAME
+
/* GLOBALS ******************************************************************/
const char* FileInformationClassNames[] =
{
- "??????",
- "FileDirectoryInformation",
- "FileFullDirectoryInformation",
- "FileBothDirectoryInformation",
- "FileBasicInformation",
- "FileStandardInformation",
- "FileInternalInformation",
- "FileEaInformation",
- "FileAccessInformation",
- "FileNameInformation",
- "FileRenameInformation",
- "FileLinkInformation",
- "FileNamesInformation",
- "FileDispositionInformation",
- "FilePositionInformation",
- "FileFullEaInformation",
- "FileModeInformation",
- "FileAlignmentInformation",
- "FileAllInformation",
- "FileAllocationInformation",
- "FileEndOfFileInformation",
- "FileAlternateNameInformation",
- "FileStreamInformation",
- "FilePipeInformation",
- "FilePipeLocalInformation",
- "FilePipeRemoteInformation",
- "FileMailslotQueryInformation",
- "FileMailslotSetInformation",
- "FileCompressionInformation",
- "FileObjectIdInformation",
- "FileCompletionInformation",
- "FileMoveClusterInformation",
- "FileQuotaInformation",
- "FileReparsePointInformation",
- "FileNetworkOpenInformation",
- "FileAttributeTagInformation",
- "FileTrackingInformation",
- "FileIdBothDirectoryInformation",
- "FileIdFullDirectoryInformation",
- "FileValidDataLengthInformation",
- "FileShortNameInformation",
- "FileMaximumInformation"
+ "??????",
+ "FileDirectoryInformation",
+ "FileFullDirectoryInformation",
+ "FileBothDirectoryInformation",
+ "FileBasicInformation",
+ "FileStandardInformation",
+ "FileInternalInformation",
+ "FileEaInformation",
+ "FileAccessInformation",
+ "FileNameInformation",
+ "FileRenameInformation",
+ "FileLinkInformation",
+ "FileNamesInformation",
+ "FileDispositionInformation",
+ "FilePositionInformation",
+ "FileFullEaInformation",
+ "FileModeInformation",
+ "FileAlignmentInformation",
+ "FileAllInformation",
+ "FileAllocationInformation",
+ "FileEndOfFileInformation",
+ "FileAlternateNameInformation",
+ "FileStreamInformation",
+ "FilePipeInformation",
+ "FilePipeLocalInformation",
+ "FilePipeRemoteInformation",
+ "FileMailslotQueryInformation",
+ "FileMailslotSetInformation",
+ "FileCompressionInformation",
+ "FileObjectIdInformation",
+ "FileCompletionInformation",
+ "FileMoveClusterInformation",
+ "FileQuotaInformation",
+ "FileReparsePointInformation",
+ "FileNetworkOpenInformation",
+ "FileAttributeTagInformation",
+ "FileTrackingInformation",
+ "FileIdBothDirectoryInformation",
+ "FileIdFullDirectoryInformation",
+ "FileValidDataLengthInformation",
+ "FileShortNameInformation",
+ "FileMaximumInformation"
};
/* FUNCTIONS ****************************************************************/
-static NTSTATUS
-VfatGetStandardInformation(PVFATFCB FCB,
- PFILE_STANDARD_INFORMATION StandardInfo,
- PULONG BufferLength)
/*
* FUNCTION: Retrieve the standard file information
*/
+NTSTATUS
+VfatGetStandardInformation(
+ PVFATFCB FCB,
+ PFILE_STANDARD_INFORMATION StandardInfo,
+ PULONG BufferLength)
{
+ if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
+ return STATUS_BUFFER_OVERFLOW;
- if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
- return STATUS_BUFFER_OVERFLOW;
+ /* PRECONDITION */
+ ASSERT(StandardInfo != NULL);
+ ASSERT(FCB != NULL);
- /* PRECONDITION */
- ASSERT(StandardInfo != NULL);
- ASSERT(FCB != NULL);
-
- if (vfatFCBIsDirectory(FCB))
+ if (vfatFCBIsDirectory(FCB))
{
- StandardInfo->AllocationSize.QuadPart = 0;
- StandardInfo->EndOfFile.QuadPart = 0;
- StandardInfo->Directory = TRUE;
+ StandardInfo->AllocationSize.QuadPart = 0;
+ StandardInfo->EndOfFile.QuadPart = 0;
+ StandardInfo->Directory = TRUE;
}
- else
+ else
{
- StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
- StandardInfo->EndOfFile = FCB->RFCB.FileSize;
- StandardInfo->Directory = FALSE;
+ StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
+ StandardInfo->EndOfFile = FCB->RFCB.FileSize;
+ StandardInfo->Directory = FALSE;
}
- StandardInfo->NumberOfLinks = 1;
- StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
+ StandardInfo->NumberOfLinks = 1;
+ StandardInfo->DeletePending = BooleanFlagOn(FCB->Flags, FCB_DELETE_PENDING);
- *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
- return(STATUS_SUCCESS);
+ *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatSetPositionInformation(PFILE_OBJECT FileObject,
- PFILE_POSITION_INFORMATION PositionInfo)
+static
+NTSTATUS
+VfatSetPositionInformation(
+ PFILE_OBJECT FileObject,
+ PFILE_POSITION_INFORMATION PositionInfo)
{
- DPRINT ("FsdSetPositionInformation()\n");
+ DPRINT("FsdSetPositionInformation()\n");
- DPRINT ("PositionInfo %p\n", PositionInfo);
- DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
+ DPRINT("PositionInfo %p\n", PositionInfo);
+ DPRINT("Setting position %u\n", PositionInfo->CurrentByteOffset.u.LowPart);
- FileObject->CurrentByteOffset.QuadPart =
- PositionInfo->CurrentByteOffset.QuadPart;
+ FileObject->CurrentByteOffset.QuadPart =
+ PositionInfo->CurrentByteOffset.QuadPart;
- return (STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatGetPositionInformation(PFILE_OBJECT FileObject,
- PVFATFCB FCB,
- PDEVICE_OBJECT DeviceObject,
- PFILE_POSITION_INFORMATION PositionInfo,
- PULONG BufferLength)
+static
+NTSTATUS
+VfatGetPositionInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_POSITION_INFORMATION PositionInfo,
+ PULONG BufferLength)
{
- UNREFERENCED_PARAMETER(FileObject);
- UNREFERENCED_PARAMETER(FCB);
- UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(FileObject);
+ UNREFERENCED_PARAMETER(FCB);
+ UNREFERENCED_PARAMETER(DeviceExt);
- DPRINT ("VfatGetPositionInformation()\n");
+ DPRINT("VfatGetPositionInformation()\n");
- if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
- return STATUS_BUFFER_OVERFLOW;
+ if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
+ return STATUS_BUFFER_OVERFLOW;
- PositionInfo->CurrentByteOffset.QuadPart =
- FileObject->CurrentByteOffset.QuadPart;
+ PositionInfo->CurrentByteOffset.QuadPart =
+ FileObject->CurrentByteOffset.QuadPart;
- DPRINT("Getting position %I64x\n",
- PositionInfo->CurrentByteOffset.QuadPart);
+ DPRINT("Getting position %I64x\n",
+ PositionInfo->CurrentByteOffset.QuadPart);
- *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
- return(STATUS_SUCCESS);
+ *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatSetBasicInformation(PFILE_OBJECT FileObject,
- PVFATFCB FCB,
- PDEVICE_EXTENSION DeviceExt,
- PFILE_BASIC_INFORMATION BasicInfo)
+static
+NTSTATUS
+VfatSetBasicInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_BASIC_INFORMATION BasicInfo)
+{
+ ULONG NotifyFilter;
+
+ DPRINT("VfatSetBasicInformation()\n");
+
+ ASSERT(NULL != FileObject);
+ ASSERT(NULL != FCB);
+ ASSERT(NULL != DeviceExt);
+ ASSERT(NULL != BasicInfo);
+ /* Check volume label bit */
+ ASSERT(0 == (*FCB->Attributes & _A_VOLID));
+
+ NotifyFilter = 0;
+
+ if (BasicInfo->FileAttributes != 0)
+ {
+ UCHAR Attributes;
+
+ Attributes = (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_ARCHIVE |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_READONLY));
+
+ if (vfatFCBIsDirectory(FCB))
+ {
+ if (BooleanFlagOn(BasicInfo->FileAttributes, FILE_ATTRIBUTE_TEMPORARY))
+ {
+ DPRINT("Setting temporary attribute on a directory!\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Attributes |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else
+ {
+ if (BooleanFlagOn(BasicInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
+ {
+ DPRINT("Setting directory attribute on a file!\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (Attributes != *FCB->Attributes)
+ {
+ *FCB->Attributes = Attributes;
+ DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ }
+ }
+
+ if (vfatVolumeIsFatX(DeviceExt))
+ {
+ if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->CreationTime,
+ &FCB->entry.FatX.CreationDate,
+ &FCB->entry.FatX.CreationTime);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
+ }
+
+ if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->LastAccessTime,
+ &FCB->entry.FatX.AccessDate,
+ &FCB->entry.FatX.AccessTime);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
+ }
+
+ if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->LastWriteTime,
+ &FCB->entry.FatX.UpdateDate,
+ &FCB->entry.FatX.UpdateTime);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
+ }
+ }
+ else
+ {
+ if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->CreationTime,
+ &FCB->entry.Fat.CreationDate,
+ &FCB->entry.Fat.CreationTime);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
+ }
+
+ if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->LastAccessTime,
+ &FCB->entry.Fat.AccessDate,
+ NULL);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
+ }
+
+ if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+ {
+ FsdSystemTimeToDosDateTime(DeviceExt,
+ &BasicInfo->LastWriteTime,
+ &FCB->entry.Fat.UpdateDate,
+ &FCB->entry.Fat.UpdateTime);
+ NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
+ }
+ }
+
+ VfatUpdateEntry(DeviceExt, FCB);
+
+ if (NotifyFilter != 0)
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ NotifyFilter,
+ FILE_ACTION_MODIFIED);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+VfatGetBasicInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_BASIC_INFORMATION BasicInfo,
+ PULONG BufferLength)
{
- DPRINT("VfatSetBasicInformation()\n");
+ UNREFERENCED_PARAMETER(FileObject);
+
+ DPRINT("VfatGetBasicInformation()\n");
- ASSERT(NULL != FileObject);
- ASSERT(NULL != FCB);
- ASSERT(NULL != DeviceExt);
- ASSERT(NULL != BasicInfo);
- /* Check volume label bit */
- ASSERT(0 == (*FCB->Attributes & _A_VOLID));
+ if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
+ return STATUS_BUFFER_OVERFLOW;
- if (FCB->Flags & FCB_IS_FATX_ENTRY)
- {
- if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+ if (vfatVolumeIsFatX(DeviceExt))
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->CreationTime,
- &FCB->entry.FatX.CreationDate,
- &FCB->entry.FatX.CreationTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.FatX.CreationDate,
+ FCB->entry.FatX.CreationTime,
+ &BasicInfo->CreationTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.FatX.AccessDate,
+ FCB->entry.FatX.AccessTime,
+ &BasicInfo->LastAccessTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.FatX.UpdateDate,
+ FCB->entry.FatX.UpdateTime,
+ &BasicInfo->LastWriteTime);
+ BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
+ }
+ else
+ {
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.Fat.CreationDate,
+ FCB->entry.Fat.CreationTime,
+ &BasicInfo->CreationTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.Fat.AccessDate,
+ 0,
+ &BasicInfo->LastAccessTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ FCB->entry.Fat.UpdateDate,
+ FCB->entry.Fat.UpdateTime,
+ &BasicInfo->LastWriteTime);
+ BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
}
- if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+ BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
+ /* Synthesize FILE_ATTRIBUTE_NORMAL */
+ if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_ARCHIVE |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_READONLY)))
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->LastAccessTime,
- &FCB->entry.FatX.AccessDate,
- &FCB->entry.FatX.AccessTime);
+ DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
+ BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
}
+ DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
+
+ *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
+ return STATUS_SUCCESS;
+}
+
- if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+static
+NTSTATUS
+VfatSetDispositionInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_DISPOSITION_INFORMATION DispositionInfo)
+{
+ DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
+
+ ASSERT(DeviceExt != NULL);
+ ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
+ ASSERT(FCB != NULL);
+
+ if (!DispositionInfo->DeleteFile)
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->LastWriteTime,
- &FCB->entry.FatX.UpdateDate,
- &FCB->entry.FatX.UpdateTime);
+ /* undelete the file */
+ FCB->Flags &= ~FCB_DELETE_PENDING;
+ FileObject->DeletePending = FALSE;
+ return STATUS_SUCCESS;
}
- }
- else
- {
- if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+
+ if (BooleanFlagOn(FCB->Flags, FCB_DELETE_PENDING))
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->CreationTime,
- &FCB->entry.Fat.CreationDate,
- &FCB->entry.Fat.CreationTime);
+ /* stream already marked for deletion. just update the file object */
+ FileObject->DeletePending = TRUE;
+ return STATUS_SUCCESS;
}
- if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+ if (vfatFCBIsReadOnly(FCB))
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->LastAccessTime,
- &FCB->entry.Fat.AccessDate,
- NULL);
+ return STATUS_CANNOT_DELETE;
}
- if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+ if (vfatFCBIsRoot(FCB) ||
+ (FCB->LongNameU.Length == sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.') ||
+ (FCB->LongNameU.Length == 2 * sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.' && FCB->LongNameU.Buffer[1] == L'.'))
{
- FsdSystemTimeToDosDateTime(DeviceExt,
- &BasicInfo->LastWriteTime,
- &FCB->entry.Fat.UpdateDate,
- &FCB->entry.Fat.UpdateTime);
+ /* we cannot delete a '.', '..' or the root directory */
+ return STATUS_ACCESS_DENIED;
}
- }
- if (BasicInfo->FileAttributes)
- {
- *FCB->Attributes = (unsigned char)((*FCB->Attributes &
- (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
- (BasicInfo->FileAttributes &
- (FILE_ATTRIBUTE_ARCHIVE |
- FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_HIDDEN |
- FILE_ATTRIBUTE_READONLY)));
- DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
- }
+ if (!MmFlushImageSection (FileObject->SectionObjectPointer, MmFlushForDelete))
+ {
+ /* can't delete a file if its mapped into a process */
+
+ DPRINT("MmFlushImageSection returned FALSE\n");
+ return STATUS_CANNOT_DELETE;
+ }
+
+ if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(DeviceExt, FCB))
+ {
+ /* can't delete a non-empty directory */
+
+ return STATUS_DIRECTORY_NOT_EMPTY;
+ }
- VfatUpdateEntry(FCB);
+ /* all good */
+ FCB->Flags |= FCB_DELETE_PENDING;
+ FileObject->DeletePending = TRUE;
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
static NTSTATUS
-VfatGetBasicInformation(PFILE_OBJECT FileObject,
- PVFATFCB FCB,
- PDEVICE_OBJECT DeviceObject,
- PFILE_BASIC_INFORMATION BasicInfo,
- PULONG BufferLength)
+vfatPrepareTargetForRename(
+ IN PDEVICE_EXTENSION DeviceExt,
+ IN PVFATFCB * ParentFCB,
+ IN PUNICODE_STRING NewName,
+ IN BOOLEAN ReplaceIfExists,
+ IN PUNICODE_STRING ParentName,
+ OUT PBOOLEAN Deleted)
{
- PDEVICE_EXTENSION DeviceExt;
-
- UNREFERENCED_PARAMETER(FileObject);
-
- DPRINT("VfatGetBasicInformation()\n");
-
- DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
- if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
- return STATUS_BUFFER_OVERFLOW;
-
- if (FCB->Flags & FCB_IS_FATX_ENTRY)
- {
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.FatX.CreationDate,
- FCB->entry.FatX.CreationTime,
- &BasicInfo->CreationTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.FatX.AccessDate,
- FCB->entry.FatX.AccessTime,
- &BasicInfo->LastAccessTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.FatX.UpdateDate,
- FCB->entry.FatX.UpdateTime,
- &BasicInfo->LastWriteTime);
- BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
- }
- else
- {
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.Fat.CreationDate,
- FCB->entry.Fat.CreationTime,
- &BasicInfo->CreationTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.Fat.AccessDate,
- 0,
- &BasicInfo->LastAccessTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- FCB->entry.Fat.UpdateDate,
- FCB->entry.Fat.UpdateTime,
- &BasicInfo->LastWriteTime);
- BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
- }
-
- BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
- /* Synthesize FILE_ATTRIBUTE_NORMAL */
- if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
- FILE_ATTRIBUTE_ARCHIVE |
- FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_HIDDEN |
- FILE_ATTRIBUTE_READONLY)))
- {
- DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
- BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
- }
- DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
-
- *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
- return(STATUS_SUCCESS);
+ NTSTATUS Status;
+ PVFATFCB TargetFcb;
+
+ DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt, ParentFCB, NewName, ReplaceIfExists, ParentName);
+
+ *Deleted = FALSE;
+ /* Try to open target */
+ Status = vfatGetFCBForFile(DeviceExt, ParentFCB, &TargetFcb, NewName);
+ /* If it exists */
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName, TargetFcb->Flags);
+ /* Check whether we are allowed to replace */
+ if (ReplaceIfExists)
+ {
+ /* If that's a directory or a read-only file, we're not allowed */
+ if (vfatFCBIsDirectory(TargetFcb) || vfatFCBIsReadOnly(TargetFcb))
+ {
+ DPRINT("And this is a readonly file!\n");
+ vfatReleaseFCB(DeviceExt, *ParentFCB);
+ *ParentFCB = NULL;
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ return STATUS_OBJECT_NAME_COLLISION;
+ }
+
+
+ /* If we still have a file object, close it. */
+ if (TargetFcb->FileObject)
+ {
+ if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
+ {
+ DPRINT("MmFlushImageSection failed.\n");
+ vfatReleaseFCB(DeviceExt, *ParentFCB);
+ *ParentFCB = NULL;
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TargetFcb->FileObject->DeletePending = TRUE;
+ VfatCloseFile(DeviceExt, TargetFcb->FileObject);
+ }
+
+ /* If we are here, ensure the file isn't open by anyone! */
+ if (TargetFcb->OpenHandleCount != 0)
+ {
+ DPRINT("There are still open handles for this file.\n");
+ vfatReleaseFCB(DeviceExt, *ParentFCB);
+ *ParentFCB = NULL;
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ return STATUS_ACCESS_DENIED;
+ }
+
+ /* Effectively delete old file to allow renaming */
+ DPRINT("Effectively deleting the file.\n");
+ VfatDelEntry(DeviceExt, TargetFcb, NULL);
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ *Deleted = TRUE;
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ vfatReleaseFCB(DeviceExt, *ParentFCB);
+ *ParentFCB = NULL;
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ return STATUS_OBJECT_NAME_COLLISION;
+ }
+ }
+ else if (*ParentFCB != NULL)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Failure */
+ return Status;
}
+static
+BOOLEAN
+IsThereAChildOpened(PVFATFCB FCB)
+{
+ PLIST_ENTRY Entry;
+ PVFATFCB VolFCB;
-static NTSTATUS
-VfatSetDispositionInformation(PFILE_OBJECT FileObject,
- PVFATFCB FCB,
- PDEVICE_OBJECT DeviceObject,
- PFILE_DISPOSITION_INFORMATION DispositionInfo)
+ for (Entry = FCB->ParentListHead.Flink; Entry != &FCB->ParentListHead; Entry = Entry->Flink)
+ {
+ VolFCB = CONTAINING_RECORD(Entry, VFATFCB, ParentListEntry);
+ if (VolFCB->OpenHandleCount != 0)
+ {
+ ASSERT(VolFCB->parentFcb == FCB);
+ DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB->PathNameU, VolFCB->RefCount, VolFCB->OpenHandleCount);
+ return TRUE;
+ }
+
+ if (vfatFCBIsDirectory(VolFCB) && !IsListEmpty(&VolFCB->ParentListHead))
+ {
+ if (IsThereAChildOpened(VolFCB))
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static
+VOID
+VfatRenameChildFCB(
+ PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB FCB)
{
-#if DBG
- PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
+ PLIST_ENTRY Entry;
+ PVFATFCB Child;
+
+ if (IsListEmpty(&FCB->ParentListHead))
+ return;
+
+ for (Entry = FCB->ParentListHead.Flink; Entry != &FCB->ParentListHead; Entry = Entry->Flink)
+ {
+ NTSTATUS Status;
+
+ Child = CONTAINING_RECORD(Entry, VFATFCB, ParentListEntry);
+ DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child->PathNameU, Child->RefCount, FCB->RefCount);
+
+ Status = vfatSetFCBNewDirName(DeviceExt, Child, FCB);
+ if (!NT_SUCCESS(Status))
+ continue;
+
+ if (vfatFCBIsDirectory(Child))
+ {
+ VfatRenameChildFCB(DeviceExt, Child);
+ }
+ }
+}
+
+/*
+ * FUNCTION: Set the file name information
+ */
+static
+NTSTATUS
+VfatSetRenameInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_RENAME_INFORMATION RenameInfo,
+ PFILE_OBJECT TargetFileObject)
+{
+#ifdef NASSERTS_RENAME
+#pragma push_macro("ASSERT")
+#undef ASSERT
+#define ASSERT(x) ((VOID) 0)
+#endif
+ NTSTATUS Status;
+ UNICODE_STRING NewName;
+ UNICODE_STRING SourcePath;
+ UNICODE_STRING SourceFile;
+ UNICODE_STRING NewPath;
+ UNICODE_STRING NewFile;
+ PFILE_OBJECT RootFileObject;
+ PVFATFCB RootFCB;
+ UNICODE_STRING RenameInfoString;
+ PVFATFCB ParentFCB;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE TargetHandle;
+ BOOLEAN DeletedTarget;
+ ULONG OldReferences, NewReferences;
+ PVFATFCB OldParent;
+
+ DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject, FCB, DeviceExt, RenameInfo, TargetFileObject);
+
+ /* Disallow renaming root */
+ if (vfatFCBIsRoot(FCB))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ OldReferences = FCB->parentFcb->RefCount;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(OldReferences);
+#endif
+
+ /* If we are performing relative opening for rename, get FO for getting FCB and path name */
+ if (RenameInfo->RootDirectory != NULL)
+ {
+ /* We cannot tolerate relative opening with a full path */
+ if (RenameInfo->FileName[0] == L'\\')
+ {
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ Status = ObReferenceObjectByHandle(RenameInfo->RootDirectory,
+ FILE_READ_DATA,
+ *IoFileObjectType,
+ ExGetPreviousMode(),
+ (PVOID *)&RootFileObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ RootFCB = RootFileObject->FsContext;
+ }
+
+ RtlInitEmptyUnicodeString(&NewName, NULL, 0);
+ ParentFCB = NULL;
+
+ if (TargetFileObject == NULL)
+ {
+ /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
+ * information supplied by the user
+ */
+
+ /* First, setup a string we'll work on */
+ RenameInfoString.Length = RenameInfo->FileNameLength;
+ RenameInfoString.MaximumLength = RenameInfo->FileNameLength;
+ RenameInfoString.Buffer = RenameInfo->FileName;
+
+ /* Check whether we have FQN */
+ if (RenameInfoString.Length > 6 * sizeof(WCHAR))
+ {
+ if (RenameInfoString.Buffer[0] == L'\\' && RenameInfoString.Buffer[1] == L'?' &&
+ RenameInfoString.Buffer[2] == L'?' && RenameInfoString.Buffer[3] == L'\\' &&
+ RenameInfoString.Buffer[5] == L':' && (RenameInfoString.Buffer[4] >= L'A' &&
+ RenameInfoString.Buffer[4] <= L'Z'))
+ {
+ /* If so, open its target directory */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &RenameInfoString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL, NULL);
+
+ Status = IoCreateFile(&TargetHandle,
+ FILE_WRITE_DATA | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT,
+ NULL, 0,
+ CreateFileTypeNone,
+ NULL,
+ IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ /* Get its FO to get the FCB */
+ Status = ObReferenceObjectByHandle(TargetHandle,
+ FILE_WRITE_DATA,
+ *IoFileObjectType,
+ KernelMode,
+ (PVOID *)&TargetFileObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(TargetHandle);
+ goto Cleanup;
+ }
+
+ /* Are we working on the same volume? */
+ if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
+ {
+ ObDereferenceObject(TargetFileObject);
+ ZwClose(TargetHandle);
+ TargetFileObject = NULL;
+ Status = STATUS_NOT_SAME_DEVICE;
+ goto Cleanup;
+ }
+ }
+ }
+
+ NewName.Length = 0;
+ NewName.MaximumLength = RenameInfo->FileNameLength;
+ if (RenameInfo->RootDirectory != NULL)
+ {
+ NewName.MaximumLength += sizeof(WCHAR) + RootFCB->PathNameU.Length;
+ }
+ else if (RenameInfo->FileName[0] != L'\\')
+ {
+ /* We don't have full path, and we don't have root directory:
+ * => we move inside the same directory
+ */
+ NewName.MaximumLength += sizeof(WCHAR) + FCB->DirNameU.Length;
+ }
+ else if (TargetFileObject != NULL)
+ {
+ /* We had a FQN:
+ * => we need to use its correct path
+ */
+ NewName.MaximumLength += sizeof(WCHAR) + ((PVFATFCB)TargetFileObject->FsContext)->PathNameU.Length;
+ }
+
+ NewName.Buffer = ExAllocatePoolWithTag(NonPagedPool, NewName.MaximumLength, TAG_VFAT);
+ if (NewName.Buffer == NULL)
+ {
+ if (TargetFileObject != NULL)
+ {
+ ObDereferenceObject(TargetFileObject);
+ ZwClose(TargetHandle);
+ TargetFileObject = NULL;
+ }
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ if (RenameInfo->RootDirectory != NULL)
+ {
+ /* Here, copy first absolute and then append relative */
+ RtlCopyUnicodeString(&NewName, &RootFCB->PathNameU);
+ NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
+ NewName.Length += sizeof(WCHAR);
+ RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
+ }
+ else if (RenameInfo->FileName[0] != L'\\')
+ {
+ /* Here, copy first work directory and then append filename */
+ RtlCopyUnicodeString(&NewName, &FCB->DirNameU);
+ NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
+ NewName.Length += sizeof(WCHAR);
+ RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
+ }
+ else if (TargetFileObject != NULL)
+ {
+ /* Here, copy first path name and then append filename */
+ RtlCopyUnicodeString(&NewName, &((PVFATFCB)TargetFileObject->FsContext)->PathNameU);
+ NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
+ NewName.Length += sizeof(WCHAR);
+ RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
+ }
+ else
+ {
+ /* Here we should have full path, so simply copy it */
+ RtlCopyUnicodeString(&NewName, &RenameInfoString);
+ }
+
+ /* Do we have to cleanup some stuff? */
+ if (TargetFileObject != NULL)
+ {
+ ObDereferenceObject(TargetFileObject);
+ ZwClose(TargetHandle);
+ TargetFileObject = NULL;
+ }
+ }
+ else
+ {
+ /* At that point, we shouldn't care about whether we are relative opening
+ * Target FO FCB should already have full path
+ */
+
+ /* Before constructing string, just make a sanity check (just to be sure!) */
+ if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
+ {
+ Status = STATUS_NOT_SAME_DEVICE;
+ goto Cleanup;
+ }
+
+ NewName.Length = 0;
+ NewName.MaximumLength = TargetFileObject->FileName.Length + ((PVFATFCB)TargetFileObject->FsContext)->PathNameU.Length + sizeof(WCHAR);
+ NewName.Buffer = ExAllocatePoolWithTag(NonPagedPool, NewName.MaximumLength, TAG_VFAT);
+ if (NewName.Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ RtlCopyUnicodeString(&NewName, &((PVFATFCB)TargetFileObject->FsContext)->PathNameU);
+ NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
+ NewName.Length += sizeof(WCHAR);
+ RtlAppendUnicodeStringToString(&NewName, &TargetFileObject->FileName);
+ }
+
+ /* Explode our paths to get path & filename */
+ vfatSplitPathName(&FCB->PathNameU, &SourcePath, &SourceFile);
+ DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath, &SourceFile);
+ vfatSplitPathName(&NewName, &NewPath, &NewFile);
+ DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath, &NewFile);
+
+ if (vfatFCBIsDirectory(FCB) && !IsListEmpty(&FCB->ParentListHead))
+ {
+ if (IsThereAChildOpened(FCB))
+ {
+ Status = STATUS_ACCESS_DENIED;
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
+ goto Cleanup;
+ }
+ }
+
+ /* Are we working in place? */
+ if (FsRtlAreNamesEqual(&SourcePath, &NewPath, TRUE, NULL))
+ {
+ if (FsRtlAreNamesEqual(&SourceFile, &NewFile, FALSE, NULL))
+ {
+ Status = STATUS_SUCCESS;
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
+ goto Cleanup;
+ }
+
+ if (FsRtlAreNamesEqual(&SourceFile, &NewFile, TRUE, NULL))
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ FILE_ACTION_RENAMED_OLD_NAME);
+ Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ FILE_ACTION_RENAMED_NEW_NAME);
+ }
+ }
+ else
+ {
+ /* Try to find target */
+ ParentFCB = FCB->parentFcb;
+ vfatGrabFCB(DeviceExt, ParentFCB);
+ Status = vfatPrepareTargetForRename(DeviceExt,
+ &ParentFCB,
+ &NewFile,
+ RenameInfo->ReplaceIfExists,
+ &NewPath,
+ &DeletedTarget);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(OldReferences == FCB->parentFcb->RefCount - 1);
+ ASSERT(OldReferences == ParentFCB->RefCount - 1);
+ goto Cleanup;
+ }
+
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ (DeletedTarget ? FILE_ACTION_REMOVED : FILE_ACTION_RENAMED_OLD_NAME));
+ Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, FALSE);
+ if (NT_SUCCESS(Status))
+ {
+ if (DeletedTarget)
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
+ FILE_ACTION_MODIFIED);
+ }
+ else
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ FILE_ACTION_RENAMED_NEW_NAME);
+ }
+ }
+ }
+
+ ASSERT(OldReferences == FCB->parentFcb->RefCount - 1); // extra grab
+ ASSERT(OldReferences == ParentFCB->RefCount - 1); // extra grab
+ }
+ else
+ {
+
+ /* Try to find target */
+ ParentFCB = NULL;
+ OldParent = FCB->parentFcb;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(OldParent);
+#endif
+ Status = vfatPrepareTargetForRename(DeviceExt,
+ &ParentFCB,
+ &NewName,
+ RenameInfo->ReplaceIfExists,
+ &NewPath,
+ &DeletedTarget);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
+ goto Cleanup;
+ }
+
+ NewReferences = ParentFCB->RefCount;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(NewReferences);
#endif
- DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
-
- ASSERT(DeviceExt != NULL);
- ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
- ASSERT(FCB != NULL);
-
- if (!DispositionInfo->DeleteFile)
- {
- /* undelete the file */
- FCB->Flags &= ~FCB_DELETE_PENDING;
- FileObject->DeletePending = FALSE;
- return STATUS_SUCCESS;
- }
-
- if (FCB->Flags & FCB_DELETE_PENDING)
- {
- /* stream already marked for deletion. just update the file object */
- FileObject->DeletePending = TRUE;
- return STATUS_SUCCESS;
- }
-
- if (*FCB->Attributes & FILE_ATTRIBUTE_READONLY)
- {
- return STATUS_CANNOT_DELETE;
- }
-
- if (vfatFCBIsRoot(FCB) ||
- (FCB->LongNameU.Length == sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.') ||
- (FCB->LongNameU.Length == 2 * sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.' && FCB->LongNameU.Buffer[1] == L'.'))
- {
- // we cannot delete a '.', '..' or the root directory
- return STATUS_ACCESS_DENIED;
- }
-
-
- if (!MmFlushImageSection (FileObject->SectionObjectPointer, MmFlushForDelete))
- {
- /* can't delete a file if its mapped into a process */
-
- DPRINT("MmFlushImageSection returned FALSE\n");
- return STATUS_CANNOT_DELETE;
- }
-
- if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(FCB))
- {
- /* can't delete a non-empty directory */
-
- return STATUS_DIRECTORY_NOT_EMPTY;
- }
-
- /* all good */
- FCB->Flags |= FCB_DELETE_PENDING;
- FileObject->DeletePending = TRUE;
-
- return STATUS_SUCCESS;
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ FILE_ACTION_REMOVED);
+ Status = VfatMoveEntry(DeviceExt, FCB, &NewFile, ParentFCB);
+ if (NT_SUCCESS(Status))
+ {
+ if (DeletedTarget)
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
+ FILE_ACTION_MODIFIED);
+ }
+ else
+ {
+ vfatReportChange(DeviceExt,
+ FCB,
+ (vfatFCBIsDirectory(FCB) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+ FILE_ACTION_ADDED);
+ }
+ }
+ }
+
+ if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
+ {
+ VfatRenameChildFCB(DeviceExt, FCB);
+ }
+
+ ASSERT(OldReferences == OldParent->RefCount + 1); // removed file
+ ASSERT(NewReferences == ParentFCB->RefCount - 1); // new file
+Cleanup:
+ if (ParentFCB != NULL) vfatReleaseFCB(DeviceExt, ParentFCB);
+ if (NewName.Buffer != NULL) ExFreePoolWithTag(NewName.Buffer, TAG_VFAT);
+ if (RenameInfo->RootDirectory != NULL) ObDereferenceObject(RootFileObject);
+
+ return Status;
+#ifdef NASSERTS_RENAME
+#pragma pop_macro("ASSERT")
+#endif
}
-static NTSTATUS
-VfatGetNameInformation(PFILE_OBJECT FileObject,
- PVFATFCB FCB,
- PDEVICE_OBJECT DeviceObject,
- PFILE_NAME_INFORMATION NameInfo,
- PULONG BufferLength)
/*
* FUNCTION: Retrieve the file name information
*/
+static
+NTSTATUS
+VfatGetNameInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB FCB,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_NAME_INFORMATION NameInfo,
+ PULONG BufferLength)
{
- ULONG BytesToCopy;
+ ULONG BytesToCopy;
- UNREFERENCED_PARAMETER(FileObject);
- UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(FileObject);
+ UNREFERENCED_PARAMETER(DeviceExt);
- ASSERT(NameInfo != NULL);
- ASSERT(FCB != NULL);
+ ASSERT(NameInfo != NULL);
+ ASSERT(FCB != NULL);
- /* If buffer can't hold at least the file name length, bail out */
- if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
- return STATUS_BUFFER_OVERFLOW;
+ /* If buffer can't hold at least the file name length, bail out */
+ if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
+ return STATUS_BUFFER_OVERFLOW;
- /* Save file name length, and as much file len, as buffer length allows */
- NameInfo->FileNameLength = FCB->PathNameU.Length;
+ /* Save file name length, and as much file len, as buffer length allows */
+ NameInfo->FileNameLength = FCB->PathNameU.Length;
- /* Calculate amount of bytes to copy not to overflow the buffer */
- BytesToCopy = min(FCB->PathNameU.Length,
- *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
+ /* Calculate amount of bytes to copy not to overflow the buffer */
+ BytesToCopy = min(FCB->PathNameU.Length,
+ *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
- /* Fill in the bytes */
- RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
+ /* Fill in the bytes */
+ RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
- /* Check if we could write more but are not able to */
- if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
- {
- /* Return number of bytes written */
- *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
- return STATUS_BUFFER_OVERFLOW;
- }
+ /* Check if we could write more but are not able to */
+ if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
+ {
+ /* Return number of bytes written */
+ *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
+ return STATUS_BUFFER_OVERFLOW;
+ }
- /* We filled up as many bytes, as needed */
- *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
+ /* We filled up as many bytes, as needed */
+ *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
- return STATUS_SUCCESS;
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatGetInternalInformation(PVFATFCB Fcb,
- PFILE_INTERNAL_INFORMATION InternalInfo,
- PULONG BufferLength)
+static
+NTSTATUS
+VfatGetInternalInformation(
+ PVFATFCB Fcb,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_INTERNAL_INFORMATION InternalInfo,
+ PULONG BufferLength)
{
- ASSERT(InternalInfo);
- ASSERT(Fcb);
-
- if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
- return STATUS_BUFFER_OVERFLOW;
- // FIXME: get a real index, that can be used in a create operation
- InternalInfo->IndexNumber.QuadPart = 0;
- *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
- return STATUS_SUCCESS;
+ ASSERT(InternalInfo);
+ ASSERT(Fcb);
+
+ if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
+ return STATUS_BUFFER_OVERFLOW;
+
+ InternalInfo->IndexNumber.QuadPart = (LONGLONG)vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry) * DeviceExt->FatInfo.BytesPerCluster;
+
+ *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatGetNetworkOpenInformation(PVFATFCB Fcb,
- PDEVICE_EXTENSION DeviceExt,
- PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
- PULONG BufferLength)
/*
* FUNCTION: Retrieve the file network open information
*/
+static
+NTSTATUS
+VfatGetNetworkOpenInformation(
+ PVFATFCB Fcb,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
+ PULONG BufferLength)
{
- ASSERT(NetworkInfo);
- ASSERT(Fcb);
-
- if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
- return(STATUS_BUFFER_OVERFLOW);
-
- if (Fcb->Flags & FCB_IS_FATX_ENTRY)
- {
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.FatX.CreationDate,
- Fcb->entry.FatX.CreationTime,
- &NetworkInfo->CreationTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.FatX.AccessDate,
- Fcb->entry.FatX.AccessTime,
- &NetworkInfo->LastAccessTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.FatX.UpdateDate,
- Fcb->entry.FatX.UpdateTime,
- &NetworkInfo->LastWriteTime);
- NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
- }
- else
- {
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.Fat.CreationDate,
- Fcb->entry.Fat.CreationTime,
- &NetworkInfo->CreationTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.Fat.AccessDate,
- 0,
- &NetworkInfo->LastAccessTime);
- FsdDosDateTimeToSystemTime(DeviceExt,
- Fcb->entry.Fat.UpdateDate,
- Fcb->entry.Fat.UpdateTime,
- &NetworkInfo->LastWriteTime);
- NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
- }
- if (vfatFCBIsDirectory(Fcb))
- {
- NetworkInfo->EndOfFile.QuadPart = 0L;
- NetworkInfo->AllocationSize.QuadPart = 0L;
- }
- else
- {
- NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
- NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
- }
- NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
- /* Synthesize FILE_ATTRIBUTE_NORMAL */
- if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
- FILE_ATTRIBUTE_ARCHIVE |
- FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_HIDDEN |
- FILE_ATTRIBUTE_READONLY)))
- {
- DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
- NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
- }
+ ASSERT(NetworkInfo);
+ ASSERT(Fcb);
+
+ if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
+ return(STATUS_BUFFER_OVERFLOW);
+
+ if (vfatVolumeIsFatX(DeviceExt))
+ {
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.FatX.CreationDate,
+ Fcb->entry.FatX.CreationTime,
+ &NetworkInfo->CreationTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.FatX.AccessDate,
+ Fcb->entry.FatX.AccessTime,
+ &NetworkInfo->LastAccessTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.FatX.UpdateDate,
+ Fcb->entry.FatX.UpdateTime,
+ &NetworkInfo->LastWriteTime);
+ NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
+ }
+ else
+ {
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.Fat.CreationDate,
+ Fcb->entry.Fat.CreationTime,
+ &NetworkInfo->CreationTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.Fat.AccessDate,
+ 0,
+ &NetworkInfo->LastAccessTime);
+ FsdDosDateTimeToSystemTime(DeviceExt,
+ Fcb->entry.Fat.UpdateDate,
+ Fcb->entry.Fat.UpdateTime,
+ &NetworkInfo->LastWriteTime);
+ NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
+ }
+
+ if (vfatFCBIsDirectory(Fcb))
+ {
+ NetworkInfo->EndOfFile.QuadPart = 0L;
+ NetworkInfo->AllocationSize.QuadPart = 0L;
+ }
+ else
+ {
+ NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
+ NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
+ }
+
+ NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
+ /* Synthesize FILE_ATTRIBUTE_NORMAL */
+ if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_ARCHIVE |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_READONLY)))
+ {
+ DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
+ NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
+ }
- *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
- return STATUS_SUCCESS;
+ *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
+ return STATUS_SUCCESS;
}
-static NTSTATUS
-VfatGetEaInformation(PFILE_OBJECT FileObject,
- PVFATFCB Fcb,
- PDEVICE_OBJECT DeviceObject,
- PFILE_EA_INFORMATION Info,
- PULONG BufferLength)
+static
+NTSTATUS
+VfatGetEaInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB Fcb,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_EA_INFORMATION Info,
+ PULONG BufferLength)
{
- PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
-
UNREFERENCED_PARAMETER(FileObject);
UNREFERENCED_PARAMETER(Fcb);
}
-static NTSTATUS
-VfatGetAllInformation(PFILE_OBJECT FileObject,
- PVFATFCB Fcb,
- PDEVICE_OBJECT DeviceObject,
- PFILE_ALL_INFORMATION Info,
- PULONG BufferLength)
/*
* FUNCTION: Retrieve the all file information
*/
+static
+NTSTATUS
+VfatGetAllInformation(
+ PFILE_OBJECT FileObject,
+ PVFATFCB Fcb,
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_ALL_INFORMATION Info,
+ PULONG BufferLength)
{
- 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;
+ NTSTATUS Status;
+
+ ASSERT(Info);
+ ASSERT(Fcb);
+
+ if (*BufferLength < FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName))
+ return STATUS_BUFFER_OVERFLOW;
+
+ *BufferLength -= (sizeof(FILE_ACCESS_INFORMATION) + sizeof(FILE_MODE_INFORMATION) + sizeof(FILE_ALIGNMENT_INFORMATION));
+
+ /* Basic Information */
+ Status = VfatGetBasicInformation(FileObject, Fcb, DeviceExt, &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, DeviceExt, &Info->InternalInformation, BufferLength);
+ if (!NT_SUCCESS(Status)) return Status;
+ /* EA Information */
+ Status = VfatGetEaInformation(FileObject, Fcb, DeviceExt, &Info->EaInformation, BufferLength);
+ if (!NT_SUCCESS(Status)) return Status;
+ /* Position Information */
+ Status = VfatGetPositionInformation(FileObject, Fcb, DeviceExt, &Info->PositionInformation, BufferLength);
+ if (!NT_SUCCESS(Status)) return Status;
+ /* Name Information */
+ Status = VfatGetNameInformation(FileObject, Fcb, DeviceExt, &Info->NameInformation, BufferLength);
+
+ return Status;
}
-static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
+static
+VOID
+UpdateFileSize(
+ PFILE_OBJECT FileObject,
+ PVFATFCB Fcb,
+ ULONG Size,
+ ULONG ClusterSize,
+ BOOLEAN IsFatX)
{
- 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;
-
- CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
+ if (Size > 0)
+ {
+ Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, ClusterSize);
+ }
+ else
+ {
+ Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
+ }
+ if (!vfatFCBIsDirectory(Fcb))
+ {
+ if (IsFatX)
+ Fcb->entry.FatX.FileSize = Size;
+ else
+ Fcb->entry.Fat.FileSize = Size;
+ }
+ Fcb->RFCB.FileSize.QuadPart = Size;
+ Fcb->RFCB.ValidDataLength.QuadPart = Size;
+
+ CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
}
NTSTATUS
-VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
- PVFATFCB Fcb,
- PDEVICE_EXTENSION DeviceExt,
- PLARGE_INTEGER AllocationSize)
+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(File <%wZ>, AllocationSize %d %d)\n", &Fcb->PathNameU,
- AllocationSize->HighPart, AllocationSize->LowPart);
-
- 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)
+ ULONG OldSize;
+ ULONG Cluster, FirstCluster;
+ NTSTATUS Status;
+
+ ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
+ ULONG NewSize = AllocationSize->u.LowPart;
+ ULONG NCluster;
+ BOOLEAN AllocSizeChanged = FALSE, IsFatX = vfatVolumeIsFatX(DeviceExt);
+
+ DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
+ &Fcb->PathNameU, AllocationSize->HighPart, AllocationSize->LowPart);
+
+ if (IsFatX)
+ 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->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
- Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
+ 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 (IsFatX)
+ {
+ 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
{
- ASSERT((FirstCluster >> 16) == 0);
- Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
+ 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;
+ }
+
+ 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);
+ 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, vfatVolumeIsFatX(DeviceExt));
}
- else
+ else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
{
- 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;
- }
-
- 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);
- 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)
- {
-
- DPRINT("Check for the ability to set file size\n");
- if (!MmCanFileBeTruncated
- (FileObject->SectionObjectPointer,
- (PLARGE_INTEGER)AllocationSize))
- {
- DPRINT("Couldn't set file size!\n");
- return STATUS_USER_MAPPED_FILE;
- }
- DPRINT("Can set file size\n");
-
- 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)
+ DPRINT("Check for the ability to set file size\n");
+ if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
+ (PLARGE_INTEGER)AllocationSize))
{
- Fcb->entry.Fat.FirstCluster = 0;
- Fcb->entry.Fat.FirstClusterHigh = 0;
+ DPRINT("Couldn't set file size!\n");
+ return STATUS_USER_MAPPED_FILE;
+ }
+ DPRINT("Can set file size\n");
+
+ AllocSizeChanged = TRUE;
+ /* FIXME: Use the cached cluster/offset better way. */
+ Fcb->LastCluster = Fcb->LastOffset = 0;
+ UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize, vfatVolumeIsFatX(DeviceExt));
+ 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
{
- Fcb->entry.Fat.FirstCluster = 0;
+ if (IsFatX)
+ {
+ 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;
}
- }
- NCluster = Cluster = FirstCluster;
- Status = STATUS_SUCCESS;
+ if (DeviceExt->FatInfo.FatType == FAT32)
+ {
+ FAT32UpdateFreeClustersCount(DeviceExt);
+ }
}
- while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
+ else
{
- Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
- WriteCluster (DeviceExt, Cluster, 0);
- Cluster = NCluster;
+ UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize, vfatVolumeIsFatX(DeviceExt));
}
- }
- else
- {
- UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
- }
- /* Update the on-disk directory entry */
- Fcb->Flags |= FCB_IS_DIRTY;
- if (AllocSizeChanged)
+
+ /* Update the on-disk directory entry */
+ Fcb->Flags |= FCB_IS_DIRTY;
+ if (AllocSizeChanged)
{
- VfatUpdateEntry(Fcb);
+ VfatUpdateEntry(DeviceExt, Fcb);
+
+ vfatReportChange(DeviceExt, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
}
- return STATUS_SUCCESS;
+ return STATUS_SUCCESS;
}
-NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
/*
* FUNCTION: Retrieve the specified file information
*/
+NTSTATUS
+VfatQueryInformation(
+ PVFAT_IRP_CONTEXT IrpContext)
{
- FILE_INFORMATION_CLASS FileInformationClass;
- PVFATFCB FCB = NULL;
-
- NTSTATUS Status = 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:
- Status = VfatGetStandardInformation(FCB,
- SystemBuffer,
- &BufferLength);
- break;
- case FilePositionInformation:
- Status = VfatGetPositionInformation(IrpContext->FileObject,
- FCB,
- IrpContext->DeviceObject,
- SystemBuffer,
- &BufferLength);
- break;
- case FileBasicInformation:
- Status = VfatGetBasicInformation(IrpContext->FileObject,
- FCB,
- IrpContext->DeviceObject,
- SystemBuffer,
- &BufferLength);
- break;
- case FileNameInformation:
- Status = VfatGetNameInformation(IrpContext->FileObject,
- FCB,
- IrpContext->DeviceObject,
- SystemBuffer,
- &BufferLength);
- break;
- case FileInternalInformation:
- Status = VfatGetInternalInformation(FCB,
- SystemBuffer,
- &BufferLength);
- break;
- case FileNetworkOpenInformation:
- Status = VfatGetNetworkOpenInformation(FCB,
- IrpContext->DeviceExt,
- SystemBuffer,
- &BufferLength);
- break;
- case FileAllInformation:
- Status = VfatGetAllInformation(IrpContext->FileObject,
- FCB,
- IrpContext->DeviceObject,
- SystemBuffer,
- &BufferLength);
- break;
-
- case FileEaInformation:
- Status = VfatGetEaInformation(IrpContext->FileObject,
- FCB,
- IrpContext->DeviceObject,
- SystemBuffer,
- &BufferLength);
- break;
-
- case FileAlternateNameInformation:
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- }
-
- if (!(FCB->Flags & FCB_IS_PAGE_FILE))
- {
- ExReleaseResourceLite(&FCB->MainResource);
- }
- IrpContext->Irp->IoStatus.Status = Status;
- if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
- IrpContext->Irp->IoStatus.Information =
- IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
- else
- IrpContext->Irp->IoStatus.Information = 0;
- IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
- VfatFreeIrpContext(IrpContext);
+ FILE_INFORMATION_CLASS FileInformationClass;
+ PVFATFCB FCB;
+
+ NTSTATUS Status = 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]);
+
+ if (FCB == NULL)
+ {
+ DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
+ IrpContext->Irp->IoStatus.Information = 0;
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
+ BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
+
+ if (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
+ {
+ if (!ExAcquireResourceSharedLite(&FCB->MainResource,
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+ {
+ return VfatMarkIrpContextForQueue(IrpContext);
+ }
+ }
+
+ switch (FileInformationClass)
+ {
+ case FileStandardInformation:
+ Status = VfatGetStandardInformation(FCB,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FilePositionInformation:
+ Status = VfatGetPositionInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileBasicInformation:
+ Status = VfatGetBasicInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileNameInformation:
+ Status = VfatGetNameInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileInternalInformation:
+ Status = VfatGetInternalInformation(FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileNetworkOpenInformation:
+ Status = VfatGetNetworkOpenInformation(FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileAllInformation:
+ Status = VfatGetAllInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileEaInformation:
+ Status = VfatGetEaInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ &BufferLength);
+ break;
+
+ case FileAlternateNameInformation:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ if (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
+ {
+ ExReleaseResourceLite(&FCB->MainResource);
+ }
+
+ if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
+ IrpContext->Irp->IoStatus.Information =
+ IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
+ else
+ IrpContext->Irp->IoStatus.Information = 0;
- return Status;
+ return Status;
}
-NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
/*
* FUNCTION: Retrieve the specified file information
*/
+NTSTATUS
+VfatSetInformation(
+ PVFAT_IRP_CONTEXT IrpContext)
{
- 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 %p)\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 %p\n", SystemBuffer);
-
- /* Special: We should call MmCanFileBeTruncated here to determine if changing
- the file size would be allowed. If not, we bail with the right error.
- We must do this before acquiring the lock. */
- if (FileInformationClass == FileEndOfFileInformation)
- {
- DPRINT("Check for the ability to set file size\n");
- if (!MmCanFileBeTruncated
- (IrpContext->FileObject->SectionObjectPointer,
- (PLARGE_INTEGER)SystemBuffer))
- {
- DPRINT("Couldn't set file size!\n");
- IrpContext->Irp->IoStatus.Status = STATUS_USER_MAPPED_FILE;
- IrpContext->Irp->IoStatus.Information = 0;
- IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
- VfatFreeIrpContext(IrpContext);
- return STATUS_USER_MAPPED_FILE;
- }
- DPRINT("Can set file size\n");
- }
-
- 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;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ PVFATFCB FCB;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PVOID SystemBuffer;
+ BOOLEAN LockDir;
+
+ /* PRECONDITION */
+ ASSERT(IrpContext);
+
+ DPRINT("VfatSetInformation(IrpContext %p)\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 %p\n", SystemBuffer);
+
+ if (FCB == NULL)
+ {
+ DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
+ IrpContext->Irp->IoStatus.Information = 0;
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Special: We should call MmCanFileBeTruncated here to determine if changing
+ the file size would be allowed. If not, we bail with the right error.
+ We must do this before acquiring the lock. */
+ if (FileInformationClass == FileEndOfFileInformation)
+ {
+ DPRINT("Check for the ability to set file size\n");
+ if (!MmCanFileBeTruncated(IrpContext->FileObject->SectionObjectPointer,
+ (PLARGE_INTEGER)SystemBuffer))
+ {
+ DPRINT("Couldn't set file size!\n");
+ IrpContext->Irp->IoStatus.Information = 0;
+ return STATUS_USER_MAPPED_FILE;
+ }
+ DPRINT("Can set file size\n");
+ }
+
+ LockDir = FALSE;
+ if (FileInformationClass == FileRenameInformation || FileInformationClass == FileAllocationInformation ||
+ FileInformationClass == FileEndOfFileInformation || FileInformationClass == FileBasicInformation)
+ {
+ LockDir = TRUE;
+ }
+
+ if (LockDir)
+ {
+ if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+ {
+ return VfatMarkIrpContextForQueue(IrpContext);
+ }
+ }
+
+ if (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
+ {
+ if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+ {
+ if (LockDir)
+ {
+ ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
+ }
+
+ return VfatMarkIrpContextForQueue(IrpContext);
+ }
+ }
+
+ switch (FileInformationClass)
+ {
+ case FilePositionInformation:
+ Status = VfatSetPositionInformation(IrpContext->FileObject,
+ SystemBuffer);
+ break;
+
+ case FileDispositionInformation:
+ Status = VfatSetDispositionInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer);
+ break;
+
+ case FileAllocationInformation:
+ case FileEndOfFileInformation:
+ Status = VfatSetAllocationSizeInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ (PLARGE_INTEGER)SystemBuffer);
+ break;
+
+ case FileBasicInformation:
+ Status = VfatSetBasicInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer);
+ break;
+
+ case FileRenameInformation:
+ Status = VfatSetRenameInformation(IrpContext->FileObject,
+ FCB,
+ IrpContext->DeviceExt,
+ SystemBuffer,
+ IrpContext->Stack->Parameters.SetFile.FileObject);
+ break;
+
+ default:
+ Status = STATUS_NOT_SUPPORTED;
+ }
+
+ if (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
+ {
+ ExReleaseResourceLite(&FCB->MainResource);
+ }
+
+ if (LockDir)
+ {
+ ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
+ }
+
+ IrpContext->Irp->IoStatus.Information = 0;
+ return Status;
}
/* EOF */