Author: arty
Date: Tue Feb 3 21:39:23 2009
New Revision: 39374
URL:
http://svn.reactos.org/svn/reactos?rev=39374&view=rev
Log:
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.
Modified:
trunk/reactos/drivers/filesystems/cdfs/cdfs.h
trunk/reactos/drivers/filesystems/cdfs/dirctl.c
trunk/reactos/drivers/filesystems/cdfs/fcb.c
trunk/reactos/drivers/filesystems/cdfs/misc.c
Modified: trunk/reactos/drivers/filesystems/cdfs/cdfs.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/cdfs/c…
==============================================================================
--- trunk/reactos/drivers/filesystems/cdfs/cdfs.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/cdfs/cdfs.h [iso-8859-1] Tue Feb 3 21:39:23 2009
@@ -162,8 +162,6 @@
PFILE_OBJECT StreamFileObject;
CDINFO CdInfo;
-
-
} DEVICE_EXTENSION, *PDEVICE_EXTENSION, VCB, *PVCB;
@@ -172,6 +170,14 @@
#define FCB_IS_VOLUME 0x0004
#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
{
@@ -201,6 +207,9 @@
ULONG Flags;
DIR_RECORD Entry;
+
+ ERESOURCE NameListResource;
+ LIST_ENTRY ShortNameList;
} FCB, *PFCB;
@@ -224,8 +233,6 @@
#define TAG_CCB TAG('I', 'C', 'C', 'B')
-
-
typedef struct
{
PDRIVER_OBJECT DriverObject;
@@ -389,6 +396,12 @@
CdfsFileFlagsToAttributes(PFCB Fcb,
PULONG FileAttributes);
+VOID
+CdfsShortNameCacheGet
+(PFCB DirectoryFcb,
+ PLARGE_INTEGER StreamOffset,
+ PUNICODE_STRING LongName,
+ PUNICODE_STRING ShortName);
/* rw.c */
Modified: trunk/reactos/drivers/filesystems/cdfs/dirctl.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/cdfs/d…
==============================================================================
--- trunk/reactos/drivers/filesystems/cdfs/dirctl.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/cdfs/dirctl.c [iso-8859-1] Tue Feb 3 21:39:23 2009
@@ -31,7 +31,7 @@
#include "cdfs.h"
-#define NDEBUG
+//#define NDEBUG
#include <debug.h>
/* FUNCTIONS ****************************************************************/
@@ -176,9 +176,7 @@
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 @@
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 @@
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 @@
NTSTATUS Status;
DPRINT("CdfsDirectoryControl() called\n");
+ FsRtlEnterFileSystem();
Stack = IoGetCurrentIrpStackLocation(Irp);
@@ -798,6 +779,7 @@
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ FsRtlExitFileSystem();
return(Status);
}
Modified: trunk/reactos/drivers/filesystems/cdfs/fcb.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/cdfs/f…
==============================================================================
--- trunk/reactos/drivers/filesystems/cdfs/fcb.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/cdfs/fcb.c [iso-8859-1] Tue Feb 3 21:39:23 2009
@@ -30,7 +30,7 @@
#include "cdfs.h"
-#define NDEBUG
+//#define NDEBUG
#include <debug.h>
/* FUNCTIONS ****************************************************************/
@@ -92,9 +92,11 @@
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,8 +105,17 @@
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 @@
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 @@
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);
Modified: trunk/reactos/drivers/filesystems/cdfs/misc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/cdfs/m…
==============================================================================
--- trunk/reactos/drivers/filesystems/cdfs/misc.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/cdfs/misc.c [iso-8859-1] Tue Feb 3 21:39:23 2009
@@ -30,7 +30,7 @@
#include "cdfs.h"
-#define NDEBUG
+//#define NDEBUG
#include <debug.h>
/* FUNCTIONS ****************************************************************/
@@ -95,4 +95,126 @@
((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 */