mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 12:04:51 +00:00
Add a per-directory cache of short filenames allowing us to generate them
uniquely. dir /x now shows properly unambiguous short filenames. Also, we weren't FsRtlEnterFilesystem ing in directory operations. Fix that too. svn path=/trunk/; revision=39374
This commit is contained in:
parent
b6eeb280a5
commit
37d6382770
4 changed files with 164 additions and 53 deletions
|
@ -162,8 +162,6 @@ typedef struct
|
|||
PFILE_OBJECT StreamFileObject;
|
||||
|
||||
CDINFO CdInfo;
|
||||
|
||||
|
||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION, VCB, *PVCB;
|
||||
|
||||
|
||||
|
@ -173,6 +171,14 @@ typedef struct
|
|||
|
||||
#define MAX_PATH 260
|
||||
|
||||
typedef struct _CDFS_SHORT_NAME
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
LARGE_INTEGER StreamOffset;
|
||||
UNICODE_STRING Name;
|
||||
WCHAR NameBuffer[13];
|
||||
} CDFS_SHORT_NAME, *PCDFS_SHORT_NAME;
|
||||
|
||||
typedef struct _FCB
|
||||
{
|
||||
FSRTL_COMMON_FCB_HEADER RFCB;
|
||||
|
@ -201,6 +207,9 @@ typedef struct _FCB
|
|||
ULONG Flags;
|
||||
|
||||
DIR_RECORD Entry;
|
||||
|
||||
ERESOURCE NameListResource;
|
||||
LIST_ENTRY ShortNameList;
|
||||
} FCB, *PFCB;
|
||||
|
||||
|
||||
|
@ -224,8 +233,6 @@ typedef struct _CCB
|
|||
|
||||
#define TAG_CCB TAG('I', 'C', 'C', 'B')
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PDRIVER_OBJECT DriverObject;
|
||||
|
@ -389,6 +396,12 @@ VOID
|
|||
CdfsFileFlagsToAttributes(PFCB Fcb,
|
||||
PULONG FileAttributes);
|
||||
|
||||
VOID
|
||||
CdfsShortNameCacheGet
|
||||
(PFCB DirectoryFcb,
|
||||
PLARGE_INTEGER StreamOffset,
|
||||
PUNICODE_STRING LongName,
|
||||
PUNICODE_STRING ShortName);
|
||||
|
||||
/* rw.c */
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "cdfs.h"
|
||||
|
||||
#define NDEBUG
|
||||
//#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
@ -176,9 +176,7 @@ CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
|
|||
PVOID Context = NULL;
|
||||
ULONG DirSize;
|
||||
PDIR_RECORD Record;
|
||||
LARGE_INTEGER StreamOffset;
|
||||
BOOLEAN HasSpaces;
|
||||
GENERATE_NAME_CONTEXT NameContext;
|
||||
LARGE_INTEGER StreamOffset, OffsetOfEntry;
|
||||
|
||||
DPRINT("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
|
||||
Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
|
||||
|
@ -276,8 +274,9 @@ CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
|
|||
DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
|
||||
Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
|
||||
|
||||
Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
|
||||
DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
|
||||
Status = CdfsGetEntryName
|
||||
(DeviceExt, &Context, &Block, &StreamOffset,
|
||||
DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
|
||||
|
||||
if (Status == STATUS_NO_MORE_ENTRIES)
|
||||
{
|
||||
|
@ -296,27 +295,8 @@ CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
|
|||
ShortName.MaximumLength = 26;
|
||||
ShortName.Buffer = ShortNameBuffer;
|
||||
|
||||
if ((RtlIsNameLegalDOS8Dot3(&LongName, NULL, &HasSpaces) == FALSE) ||
|
||||
(HasSpaces == TRUE))
|
||||
{
|
||||
RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));
|
||||
|
||||
/* FIXME: check if the generated filename already exists
|
||||
* and generate a new one if this is the case */
|
||||
|
||||
/* Build short name */
|
||||
RtlGenerate8dot3Name(&LongName,
|
||||
FALSE,
|
||||
&NameContext,
|
||||
&ShortName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy short name */
|
||||
RtlUpcaseUnicodeString(&ShortName,
|
||||
&LongName,
|
||||
FALSE);
|
||||
}
|
||||
OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
|
||||
CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);
|
||||
|
||||
DPRINT("ShortName '%wZ'\n", &ShortName);
|
||||
|
||||
|
@ -773,6 +753,7 @@ CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
|
|||
NTSTATUS Status;
|
||||
|
||||
DPRINT("CdfsDirectoryControl() called\n");
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
|
@ -798,6 +779,7 @@ CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
|
|||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "cdfs.h"
|
||||
|
||||
#define NDEBUG
|
||||
//#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
@ -92,9 +92,11 @@ CdfsCreateFCB(PCWSTR FileName)
|
|||
|
||||
ExInitializeResourceLite(&Fcb->PagingIoResource);
|
||||
ExInitializeResourceLite(&Fcb->MainResource);
|
||||
ExInitializeResourceLite(&Fcb->NameListResource);
|
||||
Fcb->RFCB.PagingIoResource = &Fcb->PagingIoResource;
|
||||
Fcb->RFCB.Resource = &Fcb->MainResource;
|
||||
Fcb->RFCB.IsFastIoPossible = FastIoIsNotPossible;
|
||||
InitializeListHead(&Fcb->ShortNameList);
|
||||
|
||||
return(Fcb);
|
||||
}
|
||||
|
@ -103,9 +105,18 @@ CdfsCreateFCB(PCWSTR FileName)
|
|||
VOID
|
||||
CdfsDestroyFCB(PFCB Fcb)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
ExDeleteResourceLite(&Fcb->PagingIoResource);
|
||||
ExDeleteResourceLite(&Fcb->MainResource);
|
||||
|
||||
while (!IsListEmpty(&Fcb->ShortNameList))
|
||||
{
|
||||
Entry = Fcb->ShortNameList.Flink;
|
||||
RemoveEntryList(Entry);
|
||||
ExFreePool(Entry);
|
||||
}
|
||||
|
||||
ExFreePool(Fcb);
|
||||
}
|
||||
|
||||
|
@ -458,16 +469,13 @@ CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt,
|
|||
ULONG BlockOffset;
|
||||
NTSTATUS Status;
|
||||
|
||||
LARGE_INTEGER StreamOffset;
|
||||
LARGE_INTEGER StreamOffset, OffsetOfEntry;
|
||||
PVOID Context;
|
||||
|
||||
WCHAR ShortNameBuffer[13];
|
||||
UNICODE_STRING ShortName;
|
||||
UNICODE_STRING LongName;
|
||||
UNICODE_STRING FileToFindUpcase;
|
||||
BOOLEAN HasSpaces;
|
||||
GENERATE_NAME_CONTEXT NameContext;
|
||||
|
||||
|
||||
ASSERT(DeviceExt);
|
||||
ASSERT(DirectoryFcb);
|
||||
|
@ -533,22 +541,8 @@ CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt,
|
|||
ShortName.Buffer = ShortNameBuffer;
|
||||
memset(ShortNameBuffer, 0, 26);
|
||||
|
||||
if ((RtlIsNameLegalDOS8Dot3(&LongName, NULL, &HasSpaces) == FALSE) ||
|
||||
(HasSpaces == TRUE))
|
||||
{
|
||||
/* Build short name */
|
||||
RtlGenerate8dot3Name(&LongName,
|
||||
FALSE,
|
||||
&NameContext,
|
||||
&ShortName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy short name */
|
||||
RtlUpcaseUnicodeString(&ShortName,
|
||||
&LongName,
|
||||
FALSE);
|
||||
}
|
||||
OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
|
||||
CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName);
|
||||
|
||||
DPRINT("ShortName '%wZ'\n", &ShortName);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "cdfs.h"
|
||||
|
||||
#define NDEBUG
|
||||
//#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
@ -95,4 +95,126 @@ CdfsFileFlagsToAttributes(PFCB Fcb,
|
|||
((Fcb->Entry.FileFlags & FILE_FLAG_READONLY) ? FILE_ATTRIBUTE_READONLY : 0);
|
||||
}
|
||||
|
||||
/* Writes a number into a string, ending at the target position. */
|
||||
static PWCHAR
|
||||
CdfsWriteNumberInShortName
|
||||
(PWCHAR EndOfNumberTarget,
|
||||
ULONG Number)
|
||||
{
|
||||
while (Number)
|
||||
{
|
||||
*EndOfNumberTarget = '0' + (Number % 10);
|
||||
EndOfNumberTarget--;
|
||||
Number /= 10;
|
||||
}
|
||||
return EndOfNumberTarget;
|
||||
}
|
||||
|
||||
VOID
|
||||
CdfsShortNameCacheGet
|
||||
(PFCB DirectoryFcb,
|
||||
PLARGE_INTEGER StreamOffset,
|
||||
PUNICODE_STRING LongName,
|
||||
PUNICODE_STRING ShortName)
|
||||
{
|
||||
BOOLEAN HasSpaces;
|
||||
PWCHAR LastDot, Scan;
|
||||
ULONG Number = 1;
|
||||
PLIST_ENTRY Entry;
|
||||
PCDFS_SHORT_NAME ShortNameEntry;
|
||||
GENERATE_NAME_CONTEXT Context = { };
|
||||
|
||||
DPRINT("CdfsShortNameCacheGet(%I64u,%wZ)\n", StreamOffset->QuadPart, LongName);
|
||||
|
||||
/* Get the name list resource */
|
||||
ExAcquireResourceExclusiveLite(&DirectoryFcb->NameListResource, TRUE);
|
||||
|
||||
/* Try to find the name in our cache */
|
||||
for (Entry = DirectoryFcb->ShortNameList.Flink;
|
||||
Entry != &DirectoryFcb->ShortNameList;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
|
||||
if (ShortNameEntry->StreamOffset.QuadPart == StreamOffset->QuadPart)
|
||||
{
|
||||
/* Cache hit */
|
||||
RtlCopyMemory
|
||||
(ShortName->Buffer, ShortNameEntry->Name.Buffer,
|
||||
ShortNameEntry->Name.Length);
|
||||
ShortName->Length = ShortNameEntry->Name.Length;
|
||||
ExReleaseResourceLite(&DirectoryFcb->NameListResource);
|
||||
DPRINT("Yield short name %wZ from cache\n", ShortName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache miss */
|
||||
if ((RtlIsNameLegalDOS8Dot3(LongName, NULL, &HasSpaces) == FALSE) ||
|
||||
(HasSpaces == TRUE))
|
||||
{
|
||||
RtlGenerate8dot3Name(LongName, FALSE, &Context, ShortName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy short name */
|
||||
RtlUpcaseUnicodeString
|
||||
(ShortName,
|
||||
LongName,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
DPRINT("Initial Guess %wZ\n", ShortName);
|
||||
|
||||
/* Find the part that'll be numberified */
|
||||
LastDot = &ShortName->Buffer[(ShortName->Length / sizeof(WCHAR)) - 1];
|
||||
for (Scan = ShortName->Buffer;
|
||||
Scan - ShortName->Buffer < ShortName->Length;
|
||||
Scan++)
|
||||
if (*Scan == '.') LastDot = Scan - 1;
|
||||
|
||||
/* Make it unique by scanning the cache and bumping */
|
||||
/* Note that incrementing the ambiguous name is enough, since we add new
|
||||
* entries at the tail. We'll scan over all collisions. */
|
||||
/* XXX could perform better. */
|
||||
for (Entry = DirectoryFcb->ShortNameList.Flink;
|
||||
Entry != &DirectoryFcb->ShortNameList;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
ShortNameEntry = CONTAINING_RECORD(Entry, CDFS_SHORT_NAME, Entry);
|
||||
if (RtlCompareUnicodeString
|
||||
(ShortName,
|
||||
&ShortNameEntry->Name,
|
||||
TRUE) == 0) /* Match */
|
||||
{
|
||||
Scan = CdfsWriteNumberInShortName(LastDot, ++Number);
|
||||
*Scan = '~';
|
||||
DPRINT("Collide; try %wZ\n", ShortName);
|
||||
}
|
||||
}
|
||||
|
||||
/* We've scanned over all entries and now have a unique one. Cache it. */
|
||||
ShortNameEntry = ExAllocatePool(PagedPool, sizeof(CDFS_SHORT_NAME));
|
||||
if (!ShortNameEntry)
|
||||
{
|
||||
/* We couldn't cache it, but we can return it. We run the risk of
|
||||
* generating a non-unique name later. */
|
||||
ExReleaseResourceLite(&DirectoryFcb->NameListResource);
|
||||
DPRINT1("Couldn't cache potentially clashing 8.3 name %wZ\n", ShortName);
|
||||
return;
|
||||
}
|
||||
|
||||
ShortNameEntry->StreamOffset = *StreamOffset;
|
||||
ShortNameEntry->Name.Buffer = ShortNameEntry->NameBuffer;
|
||||
ShortNameEntry->Name.Length = ShortName->Length;
|
||||
ShortNameEntry->Name.MaximumLength = sizeof(ShortNameEntry->NameBuffer);
|
||||
RtlCopyMemory
|
||||
(ShortNameEntry->NameBuffer,
|
||||
ShortName->Buffer,
|
||||
ShortName->Length);
|
||||
InsertTailList(&DirectoryFcb->ShortNameList, &ShortNameEntry->Entry);
|
||||
ExReleaseResourceLite(&DirectoryFcb->NameListResource);
|
||||
|
||||
DPRINT("Returning short name %wZ for long name %wZ\n", ShortName, LongName);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue