diff --git a/reactos/drivers/filesystems/cdfs/cdfs.h b/reactos/drivers/filesystems/cdfs/cdfs.h index e8b164ff7b1..744fa73607d 100644 --- a/reactos/drivers/filesystems/cdfs/cdfs.h +++ b/reactos/drivers/filesystems/cdfs/cdfs.h @@ -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 */ diff --git a/reactos/drivers/filesystems/cdfs/dirctl.c b/reactos/drivers/filesystems/cdfs/dirctl.c index a54eb529141..bf43c518f35 100644 --- a/reactos/drivers/filesystems/cdfs/dirctl.c +++ b/reactos/drivers/filesystems/cdfs/dirctl.c @@ -31,7 +31,7 @@ #include "cdfs.h" -#define NDEBUG +//#define NDEBUG #include /* 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); } diff --git a/reactos/drivers/filesystems/cdfs/fcb.c b/reactos/drivers/filesystems/cdfs/fcb.c index 76ee526f824..39102b4455d 100644 --- a/reactos/drivers/filesystems/cdfs/fcb.c +++ b/reactos/drivers/filesystems/cdfs/fcb.c @@ -30,7 +30,7 @@ #include "cdfs.h" -#define NDEBUG +//#define NDEBUG #include /* 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); diff --git a/reactos/drivers/filesystems/cdfs/misc.c b/reactos/drivers/filesystems/cdfs/misc.c index 9aca5fcafb1..1aa700fcf8e 100644 --- a/reactos/drivers/filesystems/cdfs/misc.c +++ b/reactos/drivers/filesystems/cdfs/misc.c @@ -30,7 +30,7 @@ #include "cdfs.h" -#define NDEBUG +//#define NDEBUG #include /* 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 */