[FASTFAT]

- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.

[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.

TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.

A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().

Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!

svn path=/trunk/; revision=64836
This commit is contained in:
Pierre Schweitzer 2014-10-19 21:38:32 +00:00
parent 39c0fb7d1f
commit b70df35327
7 changed files with 1676 additions and 959 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/close.c
* FILE: drivers/filesystems/fastfat/close.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
*/
@ -51,7 +51,7 @@ VfatCloseFile(
{
if (pFcb->Flags & FCB_DELETE_PENDING)
{
VfatDelEntry(DeviceExt, pFcb);
VfatDelEntry(DeviceExt, pFcb, NULL);
FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
&(DeviceExt->NotifyList),

View file

@ -18,9 +18,10 @@
*/
/*
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/create.c
* FILE: drivers/filesystems/fastfat/create.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
* Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -352,7 +353,6 @@ VfatOpenFile(
PUNICODE_STRING PathNameU,
PFILE_OBJECT FileObject,
ULONG RequestedDisposition,
BOOLEAN OpenTargetDir,
PVFATFCB *ParentFcb)
{
PVFATFCB Fcb;
@ -404,13 +404,6 @@ VfatOpenFile(
return Status;
}
/* In case we're to open target, just check whether file exist, but don't open it */
if (OpenTargetDir)
{
vfatReleaseFCB(DeviceExt, Fcb);
return STATUS_OBJECT_NAME_COLLISION;
}
if (Fcb->Flags & FCB_DELETE_PENDING)
{
vfatReleaseFCB(DeviceExt, Fcb);
@ -462,11 +455,8 @@ VfatCreateFile(
RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
#if 0
OpenTargetDir = (Stack->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE;
#else
OpenTargetDir = FALSE;
#endif
FileObject = Stack->FileObject;
DeviceExt = DeviceObject->DeviceExtension;
@ -558,14 +548,22 @@ VfatCreateFile(
}
/* Try opening the file. */
Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, OpenTargetDir, &ParentFcb);
if (OpenTargetDir)
if (!OpenTargetDir)
{
Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, &ParentFcb);
}
else
{
PVFATFCB TargetFcb;
LONG idx, FileNameLen;
if (Status == STATUS_OBJECT_NAME_COLLISION)
ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL;
Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU);
if (Status == STATUS_SUCCESS)
{
ParentFcb->RefCount++;
vfatReleaseFCB(DeviceExt, TargetFcb);
Irp->IoStatus.Information = FILE_EXISTS;
}
else
@ -593,10 +591,6 @@ VfatCreateFile(
/* We don't want to include / in the name */
FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR));
/* Try to open parent */
PathNameU.Length -= (PathNameU.Length - idx * sizeof(WCHAR));
Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, FALSE, &ParentFcb);
/* Update FO just to keep file name */
/* Skip first slash */
++idx;
@ -608,34 +602,49 @@ VfatCreateFile(
/* This is a relative open and we have only the filename, so open the parent directory
* It is in RelatedFileObject
*/
BOOLEAN Chomp = FALSE;
PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject;
DPRINT("%wZ\n", &PathNameU);
ASSERT(RelatedFileObject != NULL);
DPRINT("Relative opening\n");
DPRINT("FileObject->RelatedFileObject->FileName: %wZ\n", &RelatedFileObject->FileName);
/* VfatOpenFile() doesn't like our name ends with \, so chomp it if there's one */
if (RelatedFileObject->FileName.Buffer[RelatedFileObject->FileName.Length / sizeof(WCHAR) - 1] == L'\\')
{
Chomp = TRUE;
RelatedFileObject->FileName.Length -= sizeof(WCHAR);
}
/* Tricky part - fake our FO. It's NOT relative, we want to open the complete file path */
FileObject->RelatedFileObject = NULL;
Status = VfatOpenFile(DeviceExt, &RelatedFileObject->FileName, FileObject, RequestedDisposition, FALSE, &ParentFcb);
/* We're done opening, restore what we broke */
FileObject->RelatedFileObject = RelatedFileObject;
if (Chomp) RelatedFileObject->FileName.Length += sizeof(WCHAR);
ASSERT(FileObject->RelatedFileObject != NULL);
/* No need to modify the FO, it already has the name */
}
/* We're done with opening! */
if (ParentFcb != NULL)
{
Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject);
}
if (NT_SUCCESS(Status))
{
pFcb = FileObject->FsContext;
if (pFcb->OpenHandleCount == 0)
{
IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
Stack->Parameters.Create.ShareAccess,
FileObject,
&pFcb->FCBShareAccess);
}
else
{
Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
Stack->Parameters.Create.ShareAccess,
FileObject,
&pFcb->FCBShareAccess,
FALSE);
if (!NT_SUCCESS(Status))
{
VfatCloseFile(DeviceExt, FileObject);
return Status;
}
}
pFcb->OpenHandleCount++;
}
else if (ParentFcb != NULL)
{
vfatReleaseFCB(DeviceExt, ParentFcb);
}
return Status;
}
@ -673,7 +682,7 @@ VfatCreateFile(
Attributes |= FILE_ATTRIBUTE_ARCHIVE;
vfatSplitPathName(&PathNameU, NULL, &FileNameU);
Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
(UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
(UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS), NULL);
vfatReleaseFCB(DeviceExt, ParentFcb);
if (NT_SUCCESS(Status))
{

View file

@ -1,8 +1,11 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/dirwr.c
* FILE: drivers/filesystems/fastfat/dirwr.c
* PURPOSE: VFAT Filesystem : write in directory
* PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
* Herve Poussineau (reactos@poussine.freesurf.fr)
* Pierre Schweitzer (pierre@reactos.org)
*
*/
@ -66,6 +69,70 @@ VfatUpdateEntry(
}
}
/*
* rename an existing FAT entry
*/
NTSTATUS
vfatRenameEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb,
IN PUNICODE_STRING FileName,
IN BOOLEAN CaseChangeOnly)
{
OEM_STRING NameA;
ULONG StartIndex;
PVOID Context = NULL;
LARGE_INTEGER Offset;
PFATX_DIR_ENTRY pDirEntry;
UNICODE_STRING ShortName;
NTSTATUS Status;
DPRINT("vfatRenameEntry(%p, %p, %wZ, %d)\n", DeviceExt, pFcb, FileName, CaseChangeOnly);
if (pFcb->Flags & FCB_IS_FATX_ENTRY)
{
/* Open associated dir entry */
StartIndex = pFcb->startIndex;
Offset.u.HighPart = 0;
Offset.u.LowPart = (StartIndex * sizeof(FATX_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE;
if (!CcPinRead(pFcb->parentFcb->FileObject, &Offset, sizeof(FATX_DIR_ENTRY), TRUE,
&Context, (PVOID*)&pDirEntry))
{
DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset.u.HighPart, Offset.u.LowPart, PAGE_SIZE);
return STATUS_UNSUCCESSFUL;
}
pDirEntry = &pDirEntry[StartIndex % (PAGE_SIZE / sizeof(FATX_DIR_ENTRY))];
/* Set file name */
NameA.Buffer = (PCHAR)pDirEntry->Filename;
NameA.Length = 0;
NameA.MaximumLength = 42;
RtlUnicodeStringToOemString(&NameA, FileName, FALSE);
pDirEntry->FilenameLength = (unsigned char)NameA.Length;
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
/* Update FCB */
ShortName.Length = 0;
ShortName.MaximumLength = 0;
ShortName.Buffer = NULL;
Status = vfatUpdateFCB(DeviceExt, pFcb, FileName, &ShortName, pFcb->parentFcb);
if (NT_SUCCESS(Status))
{
CcPurgeCacheSection(&pFcb->parentFcb->SectionObjectPointers, NULL, 0, FALSE);
}
return Status;
}
else
{
/* This we cannot handle properly, move file - would likely need love */
return VfatMoveEntry(DeviceExt, pFcb, FileName, pFcb->parentFcb);
}
}
/*
* try to find contiguous entries frees in directory,
* extend a directory if is neccesary
@ -200,7 +267,8 @@ FATAddEntry(
IN PVFATFCB* Fcb,
IN PVFATFCB ParentFcb,
IN ULONG RequestedOptions,
IN UCHAR ReqAttr)
IN UCHAR ReqAttr,
IN PVFAT_MOVE_CONTEXT MoveContext)
{
PVOID Context = NULL;
PFAT_DIR_ENTRY pFatEntry;
@ -385,6 +453,13 @@ FATAddEntry(
DirContext.DirEntry.Fat.UpdateDate = DirContext.DirEntry.Fat.CreationDate;
DirContext.DirEntry.Fat.UpdateTime = DirContext.DirEntry.Fat.CreationTime;
DirContext.DirEntry.Fat.AccessDate = DirContext.DirEntry.Fat.CreationDate;
/* If it's moving, preserve creation time and file size */
if (MoveContext != NULL)
{
DirContext.DirEntry.Fat.CreationDate = MoveContext->CreationDate;
DirContext.DirEntry.Fat.CreationTime = MoveContext->CreationTime;
DirContext.DirEntry.Fat.FileSize = MoveContext->FileSize;
}
if (needLong)
{
@ -423,17 +498,36 @@ FATAddEntry(
DirContext.DirIndex = DirContext.StartIndex + nbSlots - 1;
if (RequestedOptions & FILE_DIRECTORY_FILE)
{
CurrentCluster = 0;
Status = NextCluster(DeviceExt, 0, &CurrentCluster, TRUE);
if (CurrentCluster == 0xffffffff || !NT_SUCCESS(Status))
/* If we aren't moving, use next */
if (MoveContext == NULL)
{
ExFreePoolWithTag(Buffer, TAG_VFAT);
if (!NT_SUCCESS(Status))
CurrentCluster = 0;
Status = NextCluster(DeviceExt, 0, &CurrentCluster, TRUE);
if (CurrentCluster == 0xffffffff || !NT_SUCCESS(Status))
{
return Status;
ExFreePoolWithTag(Buffer, TAG_VFAT);
if (!NT_SUCCESS(Status))
{
return Status;
}
return STATUS_DISK_FULL;
}
return STATUS_DISK_FULL;
}
else
{
CurrentCluster = MoveContext->FirstCluster;
}
if (DeviceExt->FatInfo.FatType == FAT32)
{
DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16);
}
DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster;
}
else if (MoveContext != NULL)
{
CurrentCluster = MoveContext->FirstCluster;
if (DeviceExt->FatInfo.FatType == FAT32)
{
DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16);
@ -491,7 +585,17 @@ FATAddEntry(
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
Status = vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);
if (MoveContext != NULL)
{
/* We're modifying an existing FCB - likely rename/move */
Status = vfatUpdateFCB(DeviceExt, *Fcb, &DirContext.LongNameU, &DirContext.ShortNameU, ParentFcb);
(*Fcb)->dirIndex = DirContext.DirIndex;
(*Fcb)->startIndex = DirContext.StartIndex;
}
else
{
Status = vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);
}
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Buffer, TAG_VFAT);
@ -510,13 +614,17 @@ FATAddEntry(
ExFreePoolWithTag(Buffer, TAG_VFAT);
return STATUS_UNSUCCESSFUL;
}
/* clear the new directory cluster */
RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
/* create '.' and '..' */
RtlCopyMemory(&pFatEntry[0].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
RtlCopyMemory(pFatEntry[0].ShortName, ". ", 11);
RtlCopyMemory(&pFatEntry[1].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
RtlCopyMemory(pFatEntry[1].ShortName, ".. ", 11);
/* clear the new directory cluster if not moving */
if (MoveContext == NULL)
{
RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
/* create '.' and '..' */
RtlCopyMemory(&pFatEntry[0].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
RtlCopyMemory(pFatEntry[0].ShortName, ". ", 11);
RtlCopyMemory(&pFatEntry[1].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);
RtlCopyMemory(pFatEntry[1].ShortName, ".. ", 11);
}
pFatEntry[1].FirstCluster = ParentFcb->entry.Fat.FirstCluster;
pFatEntry[1].FirstClusterHigh = ParentFcb->entry.Fat.FirstClusterHigh;
if (vfatFCBIsRoot(ParentFcb))
@ -542,7 +650,8 @@ FATXAddEntry(
IN PVFATFCB* Fcb,
IN PVFATFCB ParentFcb,
IN ULONG RequestedOptions,
IN UCHAR ReqAttr)
IN UCHAR ReqAttr,
IN PVFAT_MOVE_CONTEXT MoveContext)
{
PVOID Context = NULL;
LARGE_INTEGER SystemTime, FileOffset;
@ -578,7 +687,15 @@ FATXAddEntry(
DirContext.ShortNameU.MaximumLength = 0;
RtlZeroMemory(&DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY));
memset(DirContext.DirEntry.FatX.Filename, 0xff, 42);
DirContext.DirEntry.FatX.FirstCluster = 0;
/* Use cluster, if moving */
if (MoveContext != NULL)
{
DirContext.DirEntry.FatX.FirstCluster = MoveContext->FirstCluster;
}
else
{
DirContext.DirEntry.FatX.FirstCluster = 0;
}
DirContext.DirEntry.FatX.FileSize = 0;
/* set file name */
@ -603,6 +720,13 @@ FATXAddEntry(
DirContext.DirEntry.FatX.UpdateTime = DirContext.DirEntry.FatX.CreationTime;
DirContext.DirEntry.FatX.AccessDate = DirContext.DirEntry.FatX.CreationDate;
DirContext.DirEntry.FatX.AccessTime = DirContext.DirEntry.FatX.CreationTime;
/* If it's moving, preserve creation time and file size */
if (MoveContext != NULL)
{
DirContext.DirEntry.FatX.CreationDate = MoveContext->CreationDate;
DirContext.DirEntry.FatX.CreationTime = MoveContext->CreationTime;
DirContext.DirEntry.FatX.FileSize = MoveContext->FileSize;
}
/* add entry into parent directory */
FileOffset.u.HighPart = 0;
@ -616,8 +740,19 @@ FATXAddEntry(
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
/* FIXME: check status */
vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);
if (MoveContext != NULL)
{
/* We're modifying an existing FCB - likely rename/move */
/* FIXME: check status */
vfatUpdateFCB(DeviceExt, *Fcb, &DirContext.LongNameU, &DirContext.ShortNameU, ParentFcb);
(*Fcb)->dirIndex = DirContext.DirIndex;
(*Fcb)->startIndex = DirContext.StartIndex;
}
else
{
/* FIXME: check status */
vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);
}
DPRINT("addentry ok\n");
return STATUS_SUCCESS;
@ -630,12 +765,13 @@ VfatAddEntry(
IN PVFATFCB *Fcb,
IN PVFATFCB ParentFcb,
IN ULONG RequestedOptions,
IN UCHAR ReqAttr)
IN UCHAR ReqAttr,
IN PVFAT_MOVE_CONTEXT MoveContext)
{
if (DeviceExt->Flags & VCB_IS_FATX)
return FATXAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);
return FATXAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr, MoveContext);
else
return FATAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);
return FATAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr, MoveContext);
}
/*
@ -644,7 +780,8 @@ VfatAddEntry(
static NTSTATUS
FATDelEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb)
IN PVFATFCB pFcb,
OUT PVFAT_MOVE_CONTEXT MoveContext)
{
ULONG CurrentCluster = 0, NextCluster, i;
PVOID Context = NULL;
@ -687,13 +824,26 @@ FATDelEntry(
CcUnpinData(Context);
}
while (CurrentCluster && CurrentCluster != 0xffffffff)
/* In case of moving, don't delete data */
if (MoveContext != NULL)
{
GetNextCluster(DeviceExt, CurrentCluster, &NextCluster);
/* FIXME: check status */
WriteCluster(DeviceExt, CurrentCluster, 0);
CurrentCluster = NextCluster;
pDirEntry = &pDirEntry[pFcb->dirIndex % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))];
MoveContext->FirstCluster = CurrentCluster;
MoveContext->FileSize = pDirEntry->FileSize;
MoveContext->CreationTime = pDirEntry->CreationTime;
MoveContext->CreationDate = pDirEntry->CreationDate;
}
else
{
while (CurrentCluster && CurrentCluster != 0xffffffff)
{
GetNextCluster(DeviceExt, CurrentCluster, &NextCluster);
/* FIXME: check status */
WriteCluster(DeviceExt, CurrentCluster, 0);
CurrentCluster = NextCluster;
}
}
return STATUS_SUCCESS;
}
@ -703,7 +853,8 @@ FATDelEntry(
static NTSTATUS
FATXDelEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb)
IN PVFATFCB pFcb,
OUT PVFAT_MOVE_CONTEXT MoveContext)
{
ULONG CurrentCluster = 0, NextCluster;
PVOID Context = NULL;
@ -734,25 +885,78 @@ FATXDelEntry(
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
while (CurrentCluster && CurrentCluster != 0xffffffff)
/* In case of moving, don't delete data */
if (MoveContext != NULL)
{
GetNextCluster(DeviceExt, CurrentCluster, &NextCluster);
/* FIXME: check status */
WriteCluster(DeviceExt, CurrentCluster, 0);
CurrentCluster = NextCluster;
MoveContext->FirstCluster = CurrentCluster;
MoveContext->FileSize = pDirEntry->FileSize;
MoveContext->CreationTime = pDirEntry->CreationTime;
MoveContext->CreationDate = pDirEntry->CreationDate;
}
else
{
while (CurrentCluster && CurrentCluster != 0xffffffff)
{
GetNextCluster(DeviceExt, CurrentCluster, &NextCluster);
/* FIXME: check status */
WriteCluster(DeviceExt, CurrentCluster, 0);
CurrentCluster = NextCluster;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
VfatDelEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb)
IN PVFATFCB pFcb,
OUT PVFAT_MOVE_CONTEXT MoveContext)
{
if (DeviceExt->Flags & VCB_IS_FATX)
return FATXDelEntry(DeviceExt, pFcb);
return FATXDelEntry(DeviceExt, pFcb, MoveContext);
else
return FATDelEntry(DeviceExt, pFcb);
return FATDelEntry(DeviceExt, pFcb, MoveContext);
}
/*
* move an existing FAT entry
*/
NTSTATUS
VfatMoveEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb,
IN PUNICODE_STRING FileName,
IN PVFATFCB ParentFcb)
{
NTSTATUS Status;
PVFATFCB OldParent;
VFAT_MOVE_CONTEXT MoveContext;
DPRINT("VfatMoveEntry(%p, %p, %wZ, %p)\n", DeviceExt, pFcb, FileName, ParentFcb);
/* Delete old entry while keeping data */
Status = VfatDelEntry(DeviceExt, pFcb, &MoveContext);
if (!NT_SUCCESS(Status))
{
return Status;
}
OldParent = pFcb->parentFcb;
CcPurgeCacheSection(&OldParent->SectionObjectPointers, NULL, 0, FALSE);
/* Add our new entry with our cluster */
Status = VfatAddEntry(DeviceExt,
FileName,
&pFcb,
ParentFcb,
(vfatFCBIsDirectory(pFcb) ? FILE_DIRECTORY_FILE : 0),
*pFcb->Attributes,
&MoveContext);
CcPurgeCacheSection(&pFcb->parentFcb->SectionObjectPointers, NULL, 0, FALSE);
return Status;
}
/* EOF */

View file

@ -1,11 +1,12 @@
/*
* FILE: drivers/fs/vfat/fcb.c
* FILE: drivers/filesystems/fastfat/fcb.c
* PURPOSE: Routines to manipulate FCBs.
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
* Rex Jolliff (rex@lvcablemodem.com)
* Herve Poussineau (reactos@poussine.freesurf.fr)
* Pierre Schweitzer (pierre@reactos.org)
*/
/* ------------------------------------------------------- INCLUDES */
@ -156,6 +157,98 @@ vfatNewFCB(
return rcFCB;
}
static
VOID
vfatDelFCBFromTable(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB)
{
ULONG Index;
ULONG ShortIndex;
HASHENTRY* entry;
Index = pFCB->Hash.Hash % pVCB->HashTableSize;
ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
{
entry = pVCB->FcbHashTable[ShortIndex];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[ShortIndex] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->ShortHash.next;
}
}
entry = pVCB->FcbHashTable[Index];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[Index] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->Hash.next;
}
}
static
NTSTATUS
vfatMakeFullName(
PVFATFCB directoryFCB,
PUNICODE_STRING LongNameU,
PUNICODE_STRING ShortNameU,
PUNICODE_STRING NameU)
{
PWCHAR PathNameBuffer;
USHORT PathNameLength;
PathNameLength = directoryFCB->PathNameU.Length + max(LongNameU->Length, ShortNameU->Length);
if (!vfatFCBIsRoot(directoryFCB))
{
PathNameLength += sizeof(WCHAR);
}
if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR))
{
return STATUS_OBJECT_NAME_INVALID;
}
PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB);
if (!PathNameBuffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
NameU->Buffer = PathNameBuffer;
NameU->Length = 0;
NameU->MaximumLength = PathNameLength;
RtlCopyUnicodeString(NameU, &directoryFCB->PathNameU);
if (!vfatFCBIsRoot(directoryFCB))
{
RtlAppendUnicodeToString(NameU, L"\\");
}
if (LongNameU->Length > 0)
{
RtlAppendUnicodeStringToString(NameU, LongNameU);
}
else
{
RtlAppendUnicodeStringToString(NameU, ShortNameU);
}
NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
return STATUS_SUCCESS;
}
VOID
vfatDestroyCCB(
PVFATCCB pCcb)
@ -182,7 +275,7 @@ BOOLEAN
vfatFCBIsDirectory(
PVFATFCB FCB)
{
return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY;
return ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
}
BOOLEAN
@ -197,9 +290,6 @@ vfatReleaseFCB(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB)
{
HASHENTRY* entry;
ULONG Index;
ULONG ShortIndex;
PVFATFCB tmpFcb;
DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
@ -207,42 +297,13 @@ vfatReleaseFCB(
while (pFCB)
{
Index = pFCB->Hash.Hash % pVCB->HashTableSize;
ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
pFCB->RefCount--;
if (pFCB->RefCount == 0)
{
ASSERT(pFCB->OpenHandleCount == 0);
tmpFcb = pFCB->parentFcb;
RemoveEntryList (&pFCB->FcbListEntry);
if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
{
entry = pVCB->FcbHashTable[ShortIndex];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[ShortIndex] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->ShortHash.next;
}
}
entry = pVCB->FcbHashTable[Index];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[Index] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->Hash.next;
}
vfatDelFCBFromTable(pVCB, pFCB);
vfatDestroyFCB(pFCB);
}
else
@ -253,6 +314,7 @@ vfatReleaseFCB(
}
}
static
VOID
vfatAddFCBToTable(
PDEVICE_EXTENSION pVCB,
@ -279,6 +341,76 @@ vfatAddFCBToTable(
}
}
NTSTATUS
vfatUpdateFCB(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PUNICODE_STRING LongName,
PUNICODE_STRING ShortName,
PVFATFCB ParentFcb)
{
NTSTATUS Status;
PVFATFCB OldParent;
DPRINT("vfatUpdateFCB(%p, %p, %wZ, %wZ, %p)\n", pVCB, Fcb, LongName, ShortName, ParentFcb);
/* Delete old name */
if (Fcb->PathNameBuffer)
{
ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
}
/* Delete from table */
vfatDelFCBFromTable(pVCB, Fcb);
/* Get full path name */
Status = vfatMakeFullName(ParentFcb, LongName, ShortName, &Fcb->PathNameU);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Split it properly */
Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
/* Copy short name */
RtlCopyUnicodeString(&Fcb->ShortNameU, ShortName);
/* Recompute hashes */
Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
if (pVCB->Flags & VCB_IS_FATX)
{
Fcb->ShortHash.Hash = Fcb->Hash.Hash;
}
else
{
Fcb->ShortHash.Hash = vfatNameHash(0, &Fcb->DirNameU);
Fcb->ShortHash.Hash = vfatNameHash(Fcb->ShortHash.Hash, &Fcb->ShortNameU);
}
/* Set parent */
OldParent = Fcb->parentFcb;
Fcb->parentFcb = ParentFcb;
/* Add to the table */
vfatAddFCBToTable(pVCB, Fcb);
/* If we moved accross directories, dereferenced our old parent
* We also derefence in case we're just renaming since AddFCBToTable references it
*/
vfatReleaseFCB(pVCB, OldParent);
/* In case we were moving accross directories, reset caching on old parent */
//if (OldParent != ParentFcb)
//{
// CcUninitializeCacheMap(OldParent->FileObject, NULL, NULL);
//}
return STATUS_SUCCESS;
}
PVFATFCB
vfatGrabFCBFromTable(
PDEVICE_EXTENSION pVCB,
@ -460,48 +592,16 @@ vfatMakeFCBFromDirEntry(
PVFATFCB *fileFCB)
{
PVFATFCB rcFCB;
PWCHAR PathNameBuffer;
USHORT PathNameLength;
ULONG Size;
ULONG hash;
UNICODE_STRING NameU;
NTSTATUS Status;
PathNameLength = directoryFCB->PathNameU.Length + max(DirContext->LongNameU.Length, DirContext->ShortNameU.Length);
if (!vfatFCBIsRoot (directoryFCB))
Status = vfatMakeFullName(directoryFCB, &DirContext->LongNameU, &DirContext->ShortNameU, &NameU);
if (!NT_SUCCESS(Status))
{
PathNameLength += sizeof(WCHAR);
return Status;
}
if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR))
{
return STATUS_OBJECT_NAME_INVALID;
}
PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB);
if (!PathNameBuffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
NameU.Buffer = PathNameBuffer;
NameU.Length = 0;
NameU.MaximumLength = PathNameLength;
RtlCopyUnicodeString(&NameU, &directoryFCB->PathNameU);
if (!vfatFCBIsRoot(directoryFCB))
{
RtlAppendUnicodeToString(&NameU, L"\\");
}
hash = vfatNameHash(0, &NameU);
if (DirContext->LongNameU.Length > 0)
{
RtlAppendUnicodeStringToString(&NameU, &DirContext->LongNameU);
}
else
{
RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU);
}
NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0;
rcFCB = vfatNewFCB(vcb, &NameU);
RtlCopyMemory(&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU);
@ -511,7 +611,8 @@ vfatMakeFCBFromDirEntry(
}
else
{
rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU);
rcFCB->ShortHash.Hash = vfatNameHash(0, &rcFCB->DirNameU);
rcFCB->ShortHash.Hash = vfatNameHash(rcFCB->ShortHash.Hash, &rcFCB->ShortNameU);
}
if (vfatFCBIsDirectory(rcFCB))
@ -562,7 +663,7 @@ vfatMakeFCBFromDirEntry(
vfatAddFCBToTable(vcb, rcFCB);
*fileFCB = rcFCB;
ExFreePool(PathNameBuffer);
ExFreePool(NameU.Buffer);
return STATUS_SUCCESS;
}

View file

@ -1,10 +1,11 @@
/*
* 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)
*
*/
@ -373,6 +374,467 @@ VfatSetDispositionInformation(
return STATUS_SUCCESS;
}
static NTSTATUS
vfatPrepareTargetForRename(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB * ParentFCB,
IN PUNICODE_STRING NewName,
IN BOOLEAN ReplaceIfExists,
IN PUNICODE_STRING ParentName,
OUT PBOOLEAN Deleted)
{
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))
{
/* 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) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY));
{
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
return STATUS_OBJECT_NAME_COLLISION;
}
/* Attempt to flush (might close the file) */
if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
{
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
return STATUS_ACCESS_DENIED;
}
/* If we are, ensure the file isn't open by anyone! */
if (TargetFcb->OpenHandleCount != 0)
{
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
return STATUS_ACCESS_DENIED;
}
/* Effectively delete old file to allow renaming */
VfatDelEntry(DeviceExt, TargetFcb, NULL);
(*ParentFCB)->RefCount++;
vfatReleaseFCB(DeviceExt, TargetFcb);
*Deleted = TRUE;
}
else
{
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
return STATUS_OBJECT_NAME_COLLISION;
}
}
else if (*ParentFCB != NULL)
{
return STATUS_SUCCESS;
}
/* Failure */
return Status;
}
/*
* FUNCTION: Set the file name information
*/
static
NTSTATUS
VfatSetRenameInformation(
PFILE_OBJECT FileObject,
PVFATFCB FCB,
PDEVICE_EXTENSION DeviceObject,
PFILE_RENAME_INFORMATION RenameInfo,
PFILE_OBJECT TargetFileObject)
{
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;
DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject, FCB, DeviceObject, RenameInfo, TargetFileObject);
/* Disallow renaming root */
if (vfatFCBIsRoot(FCB))
{
return STATUS_INVALID_PARAMETER;
}
/* 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;
}
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);
/* Are we working in place? */
if (FsRtlAreNamesEqual(&SourcePath, &NewPath, TRUE, NULL))
{
if (FsRtlAreNamesEqual(&SourceFile, &NewFile, FALSE, NULL))
{
Status = STATUS_SUCCESS;
goto Cleanup;
}
if (FsRtlAreNamesEqual(&SourceFile, &NewFile, TRUE, NULL))
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_RENAMED_OLD_NAME,
NULL);
Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, TRUE);
if (NT_SUCCESS(Status))
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_RENAMED_NEW_NAME,
NULL);
}
}
else
{
/* Try to find target */
ParentFCB = FCB->parentFcb;
ParentFCB->RefCount++;
Status = vfatPrepareTargetForRename(DeviceObject,
&ParentFCB,
&NewFile,
RenameInfo->ReplaceIfExists,
&NewPath,
&DeletedTarget);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
(DeletedTarget ? FILE_ACTION_REMOVED : FILE_ACTION_RENAMED_OLD_NAME),
NULL);
Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, FALSE);
if (NT_SUCCESS(Status))
{
if (DeletedTarget)
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
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,
NULL);
}
else
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_RENAMED_NEW_NAME,
NULL);
}
}
}
}
else
{
/* Try to find target */
ParentFCB = NULL;
Status = vfatPrepareTargetForRename(DeviceObject,
&ParentFCB,
&NewName,
RenameInfo->ReplaceIfExists,
&NewPath,
&DeletedTarget);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_REMOVED,
NULL);
Status = VfatMoveEntry(DeviceObject, FCB, &NewFile, ParentFCB);
if (NT_SUCCESS(Status))
{
if (DeletedTarget)
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
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,
NULL);
}
else
{
FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
&(DeviceObject->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
NULL,
((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_ADDED,
NULL);
}
}
}
Cleanup:
if (ParentFCB != NULL) vfatReleaseFCB(DeviceObject, ParentFCB);
if (NewName.Buffer != NULL) ExFreePoolWithTag(NewName.Buffer, TAG_VFAT);
if (RenameInfo->RootDirectory != NULL) ObDereferenceObject(RootFileObject);
return Status;
}
/*
* FUNCTION: Retrieve the file name information
*/
@ -1005,11 +1467,24 @@ VfatSetInformation(
DPRINT("Can set file size\n");
}
if (FileInformationClass == FileRenameInformation)
{
if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
(BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
{
return VfatQueueRequest(IrpContext);
}
}
if (!(FCB->Flags & FCB_IS_PAGE_FILE))
{
if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
(BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
{
if (FileInformationClass == FileRenameInformation)
{
ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
}
return VfatQueueRequest(IrpContext);
}
}
@ -1044,7 +1519,11 @@ VfatSetInformation(
break;
case FileRenameInformation:
Status = STATUS_NOT_IMPLEMENTED;
Status = VfatSetRenameInformation(IrpContext->FileObject,
FCB,
IrpContext->DeviceExt,
SystemBuffer,
IrpContext->Stack->Parameters.SetFile.FileObject);
break;
default:
@ -1056,6 +1535,11 @@ VfatSetInformation(
ExReleaseResourceLite(&FCB->MainResource);
}
if (FileInformationClass == FileRenameInformation)
{
ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
}
IrpContext->Irp->IoStatus.Status = Status;
IrpContext->Irp->IoStatus.Information = 0;
IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);

View file

@ -460,6 +460,13 @@ typedef struct _VFAT_DIRENTRY_CONTEXT
UNICODE_STRING ShortNameU;
} VFAT_DIRENTRY_CONTEXT, *PVFAT_DIRENTRY_CONTEXT;
typedef struct _VFAT_MOVE_CONTEXT
{
ULONG FirstCluster;
ULONG FileSize;
USHORT CreationDate;
USHORT CreationTime;
} VFAT_MOVE_CONTEXT, *PVFAT_MOVE_CONTEXT;
/* blockdev.c */
@ -594,7 +601,8 @@ VfatAddEntry(
PVFATFCB* Fcb,
PVFATFCB ParentFcb,
ULONG RequestedOptions,
UCHAR ReqAttr);
UCHAR ReqAttr,
PVFAT_MOVE_CONTEXT MoveContext);
NTSTATUS
VfatUpdateEntry(
@ -603,7 +611,8 @@ VfatUpdateEntry(
NTSTATUS
VfatDelEntry(
PDEVICE_EXTENSION,
PVFATFCB);
PVFATFCB,
PVFAT_MOVE_CONTEXT);
BOOLEAN
vfatFindDirSpace(
@ -612,6 +621,20 @@ vfatFindDirSpace(
ULONG nbSlots,
PULONG start);
NTSTATUS
vfatRenameEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb,
IN PUNICODE_STRING FileName,
IN BOOLEAN CaseChangeOnly);
NTSTATUS
VfatMoveEntry(
IN PDEVICE_EXTENSION DeviceExt,
IN PVFATFCB pFcb,
IN PUNICODE_STRING FileName,
IN PVFATFCB ParentFcb);
/* ea.h */
NTSTATUS
@ -747,6 +770,14 @@ vfatNewFCB(
PDEVICE_EXTENSION pVCB,
PUNICODE_STRING pFileNameU);
NTSTATUS
vfatUpdateFCB(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PUNICODE_STRING LongName,
PUNICODE_STRING ShortName,
PVFATFCB ParentFcb);
VOID
vfatDestroyFCB(
PVFATFCB pFCB);
@ -765,11 +796,6 @@ vfatReleaseFCB(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB);
VOID
vfatAddFCBToTable(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB);
PVFATFCB
vfatGrabFCBFromTable(
PDEVICE_EXTENSION pDeviceExt,