2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/fcb.c
5 * PURPOSE: FCB manipulation routines.
6 * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
9 /* INCLUDES *****************************************************************/
14 #define TAG_FILENAME 'fBnF'
16 /* FUNCTIONS ****************************************************************/
18 FSRTL_COMPARISON_RESULT
20 FatiCompareNames(PSTRING NameA
,
25 /* Calc the minimum length */
26 MinimumLen
= NameA
->Length
< NameB
->Length
? NameA
->Length
:
29 /* Actually compare them */
30 i
= (ULONG
)RtlCompareMemory( NameA
->Buffer
, NameB
->Buffer
, MinimumLen
);
34 /* Compare prefixes */
35 if (NameA
->Buffer
[i
] < NameB
->Buffer
[i
])
41 /* Final comparison */
42 if (NameA
->Length
< NameB
->Length
)
44 else if (NameA
->Length
> NameB
->Length
)
52 FatFindFcb(PFAT_IRP_CONTEXT IrpContext
,
53 PRTL_SPLAY_LINKS
*RootNode
,
58 FSRTL_COMPARISON_RESULT Comparison
;
59 PRTL_SPLAY_LINKS Links
;
65 Node
= CONTAINING_RECORD(Links
, FCB_NAME_LINK
, Links
);
67 /* Compare the prefix */
68 if (*(PUCHAR
)Node
->Name
.Ansi
.Buffer
!= *(PUCHAR
)AnsiName
->Buffer
)
70 if (*(PUCHAR
)Node
->Name
.Ansi
.Buffer
< *(PUCHAR
)AnsiName
->Buffer
)
71 Comparison
= LessThan
;
73 Comparison
= GreaterThan
;
77 /* Perform real comparison */
78 Comparison
= FatiCompareNames(&Node
->Name
.Ansi
, AnsiName
);
82 if (Comparison
== GreaterThan
)
84 /* No, it's greater, go to the left child */
85 Links
= RtlLeftChild(Links
);
87 else if (Comparison
== LessThan
)
89 /* No, it's lesser, go to the right child */
90 Links
= RtlRightChild(Links
);
94 /* Exact match, balance the tree */
95 *RootNode
= RtlSplay(Links
);
97 /* Save type of the name, if needed */
99 *IsDosName
= Node
->IsDosName
;
101 /* Return the found fcb */
112 FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext
,
115 IN FF_FILE
*FileHandle
)
119 /* Allocate it and zero it */
120 Fcb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FCB
), TAG_FCB
);
121 RtlZeroMemory(Fcb
, sizeof(FCB
));
124 Fcb
->Header
.NodeTypeCode
= FAT_NTC_FCB
;
125 Fcb
->Header
.NodeByteSize
= sizeof(FCB
);
126 Fcb
->Condition
= FcbGood
;
128 /* Initialize resources */
129 Fcb
->Header
.Resource
= &Fcb
->Resource
;
130 ExInitializeResourceLite(Fcb
->Header
.Resource
);
132 Fcb
->Header
.PagingIoResource
= &Fcb
->PagingIoResource
;
133 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
135 /* Initialize mutexes */
136 Fcb
->Header
.FastMutex
= &Fcb
->HeaderMutex
;
137 ExInitializeFastMutex(&Fcb
->HeaderMutex
);
138 FsRtlSetupAdvancedHeader(&Fcb
->Header
, &Fcb
->HeaderMutex
);
140 /* Insert into parent's DCB list */
141 InsertTailList(&ParentDcb
->Dcb
.ParentDcbList
, &Fcb
->ParentDcbLinks
);
144 Fcb
->ParentFcb
= ParentDcb
;
147 /* Set file handle and sizes */
148 Fcb
->Header
.FileSize
.LowPart
= FileHandle
->Filesize
;
149 Fcb
->Header
.ValidDataLength
.LowPart
= FileHandle
->Filesize
;
150 Fcb
->FatHandle
= FileHandle
;
152 /* Initialize locks */
153 FsRtlInitializeFileLock(&Fcb
->Fcb
.Lock
, NULL
, NULL
);
154 FsRtlInitializeOplock(&Fcb
->Fcb
.Oplock
);
157 FatSetFcbNames(IrpContext
, Fcb
);
164 FatDeleteFcb(IN PFAT_IRP_CONTEXT IrpContext
,
167 DPRINT("FatDeleteFcb %p\n", Fcb
);
169 if (Fcb
->OpenCount
!= 0)
171 DPRINT1("Trying to delete FCB with OpenCount %d\n", Fcb
->OpenCount
);
175 if ((Fcb
->Header
.NodeTypeCode
== FAT_NTC_DCB
) ||
176 (Fcb
->Header
.NodeTypeCode
== FAT_NTC_ROOT_DCB
))
178 /* Make sure it's a valid deletion */
179 ASSERT(Fcb
->Dcb
.DirectoryFileOpenCount
== 0);
180 ASSERT(IsListEmpty(&Fcb
->Dcb
.ParentDcbList
));
181 ASSERT(Fcb
->Dcb
.DirectoryFile
== NULL
);
186 FsRtlUninitializeFileLock(&Fcb
->Fcb
.Lock
);
187 FsRtlUninitializeOplock(&Fcb
->Fcb
.Oplock
);
190 /* Release any possible filter contexts */
191 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
193 /* Remove from parents queue */
194 if (Fcb
->Header
.NodeTypeCode
!= FAT_NTC_ROOT_DCB
)
196 RemoveEntryList(&(Fcb
->ParentDcbLinks
));
199 /* Free FullFAT handle */
200 if (Fcb
->FatHandle
) FF_Close(Fcb
->FatHandle
);
202 /* Remove from the splay table */
203 if (FlagOn(Fcb
->State
, FCB_STATE_HAS_NAMES
))
204 FatRemoveNames(IrpContext
, Fcb
);
206 /* Free file name buffers */
207 if (Fcb
->Header
.NodeTypeCode
!= FAT_NTC_ROOT_DCB
)
209 if (Fcb
->FullFileName
.Buffer
)
210 ExFreePool(Fcb
->FullFileName
.Buffer
);
213 if (Fcb
->ExactCaseLongName
.Buffer
)
214 ExFreePool(Fcb
->ExactCaseLongName
.Buffer
);
216 /* Free this FCB, finally */
226 /* Allocate the CCB and zero it */
227 Ccb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CCB
), TAG_CCB
);
228 RtlZeroMemory(Ccb
, sizeof(CCB
));
230 /* Set mandatory header */
231 Ccb
->NodeTypeCode
= FAT_NTC_FCB
;
232 Ccb
->NodeByteSize
= sizeof(CCB
);
239 FatDeleteCcb(IN PFAT_IRP_CONTEXT IrpContext
,
242 // TODO: Deallocate CCB strings, if any
250 FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext
,
251 IN PFILE_OBJECT FileObject
,
254 IN PACCESS_MASK DesiredAccess
,
255 IN USHORT ShareAccess
,
256 IN ULONG AllocationSize
,
257 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
259 IN UCHAR FileAttributes
,
260 IN ULONG CreateDisposition
,
261 IN BOOLEAN NoEaKnowledge
,
262 IN BOOLEAN DeleteOnClose
,
263 IN BOOLEAN OpenedAsDos
,
264 OUT PBOOLEAN OplockPostIrp
)
266 IO_STATUS_BLOCK Iosb
= {{0}};
267 ACCESS_MASK AddedAccess
= 0;
271 NTSTATUS Status
, StatusPrev
;
273 /* Acquire exclusive FCB lock */
274 (VOID
)FatAcquireExclusiveFcb(IrpContext
, Fcb
);
276 *OplockPostIrp
= FALSE
;
278 /* Check if there is a batch oplock */
279 if (FsRtlCurrentBatchOplock(&Fcb
->Fcb
.Oplock
))
281 /* Return with a special information field */
282 Iosb
.Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
284 /* Check the oplock */
285 Iosb
.Status
= FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
291 if (Iosb
.Status
!= STATUS_SUCCESS
&&
292 Iosb
.Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
)
294 /* The Irp needs to be queued */
295 *OplockPostIrp
= TRUE
;
297 /* Release the FCB and return */
298 FatReleaseFcb(IrpContext
, Fcb
);
303 /* Validate parameters and modify access */
304 if (CreateDisposition
== FILE_CREATE
)
306 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
308 /* Release the FCB and return */
309 FatReleaseFcb(IrpContext
, Fcb
);
312 else if (CreateDisposition
== FILE_SUPERSEDE
)
314 SetFlag(AddedAccess
, DELETE
& ~(*DesiredAccess
));
315 *DesiredAccess
|= DELETE
;
317 else if ((CreateDisposition
== FILE_OVERWRITE
) ||
318 (CreateDisposition
== FILE_OVERWRITE_IF
))
321 (FILE_WRITE_DATA
| FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
)
322 & ~(*DesiredAccess
) );
324 *DesiredAccess
|= FILE_WRITE_DATA
| FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
;
327 // TODO: Check desired access
329 // TODO: Check if this file is readonly and DeleteOnClose is set
331 /* Validate disposition information */
332 if ((CreateDisposition
== FILE_SUPERSEDE
) ||
333 (CreateDisposition
== FILE_OVERWRITE
) ||
334 (CreateDisposition
== FILE_OVERWRITE_IF
))
336 // TODO: Get this attributes from the dirent
340 if ((Hidden
&& !FlagOn(FileAttributes
, FILE_ATTRIBUTE_HIDDEN
)) ||
341 (System
&& !FlagOn(FileAttributes
, FILE_ATTRIBUTE_SYSTEM
)))
343 DPRINT1("Hidden/system attributes don't match\n");
345 Iosb
.Status
= STATUS_ACCESS_DENIED
;
347 /* Release the FCB and return */
348 FatReleaseFcb(IrpContext
, Fcb
);
352 // TODO: Check for write protected volume
355 /* Check share access */
356 Iosb
.Status
= IoCheckShareAccess(*DesiredAccess
,
361 if (!NT_SUCCESS(Iosb
.Status
))
363 /* Release the FCB and return */
364 FatReleaseFcb(IrpContext
, Fcb
);
368 /* Check the oplock status after checking for share access */
369 Iosb
.Status
= FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
375 if (Iosb
.Status
!= STATUS_SUCCESS
&&
376 Iosb
.Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
)
378 /* The Irp needs to be queued */
379 *OplockPostIrp
= TRUE
;
381 /* Release the FCB and return */
382 FatReleaseFcb(IrpContext
, Fcb
);
386 /* Set Fast I/O flag */
387 Fcb
->Header
.IsFastIoPossible
= FALSE
; //FatiIsFastIoPossible(Fcb);
389 /* Make sure image is not mapped */
390 if (DeleteOnClose
|| FlagOn(*DesiredAccess
, FILE_WRITE_DATA
))
392 /* Try to flush the image section */
393 if (!MmFlushImageSection(&Fcb
->SectionObjectPointers
, MmFlushForWrite
))
395 /* Yes, image section exists, set correct status code */
397 Iosb
.Status
= STATUS_CANNOT_DELETE
;
399 Iosb
.Status
= STATUS_SHARING_VIOLATION
;
401 /* Release the FCB and return */
402 FatReleaseFcb(IrpContext
, Fcb
);
407 /* Flush the cache if it's non-cached non-pagefile access */
408 if (FlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
) &&
409 Fcb
->SectionObjectPointers
.DataSectionObject
&&
410 !FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
))
412 /* Set the flag that create is in progress */
413 SetFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
415 /* Flush the cache */
416 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
418 /* Acquire and release Paging I/O resource before purging the cache section
419 to let lazy writer finish */
420 ExAcquireResourceExclusiveLite( Fcb
->Header
.PagingIoResource
, TRUE
);
421 ExReleaseResourceLite( Fcb
->Header
.PagingIoResource
);
423 /* Delete the cache section */
424 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
, NULL
, 0, FALSE
);
427 ClearFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
430 /* Check create disposition flags and branch accordingly */
431 if (CreateDisposition
== FILE_OPEN
||
432 CreateDisposition
== FILE_OPEN_IF
)
434 DPRINT("Opening a file\n");
436 /* Check if we need to bother with EA */
437 if (NoEaKnowledge
&& FALSE
/* FatIsFat32(Vcb)*/)
442 /* Set up file object */
443 Ccb
= FatCreateCcb();
444 FatSetFileObject(FileObject
,
449 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
451 /* The file is opened */
452 Iosb
.Information
= FILE_OPENED
;
455 else if ((CreateDisposition
== FILE_SUPERSEDE
) ||
456 (CreateDisposition
== FILE_OVERWRITE
) ||
457 (CreateDisposition
== FILE_OVERWRITE_IF
))
459 /* Remember previous status */
460 StatusPrev
= Iosb
.Status
;
462 // TODO: Check system security access
464 /* Perform overwrite operation */
465 Iosb
= FatiOverwriteFile(IrpContext
,
475 /* Restore previous status in case of success */
476 if (Iosb
.Status
== STATUS_SUCCESS
)
477 Iosb
.Status
= StatusPrev
;
479 /* Fall down to completion */
483 /* We can't get here */
484 KeBugCheckEx(FAT_FILE_SYSTEM
, CreateDisposition
, 0, 0, 0);
490 if (Iosb
.Status
!= STATUS_PENDING
&&
491 NT_SUCCESS(Iosb
.Status
))
493 /* Update access if needed */
496 /* Remove added access flags from desired access */
497 ClearFlag(*DesiredAccess
, AddedAccess
);
499 /* Check share access */
500 Status
= IoCheckShareAccess(*DesiredAccess
,
506 /* Make sure it's success */
507 ASSERT(Status
== STATUS_SUCCESS
);
511 /* Update the share access */
512 IoUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
);
515 /* Clear the delay close */
516 ClearFlag(Fcb
->State
, FCB_STATE_DELAY_CLOSE
);
518 /* Increase counters */
521 Vcb
->OpenFileCount
++;
522 if (IsFileObjectReadOnly(FileObject
)) Vcb
->ReadOnlyCount
++;
523 if (FlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
)) Fcb
->NonCachedUncleanCount
++;
525 // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
533 FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext
,
535 OUT PUNICODE_STRING LongName
)
539 OEM_STRING ShortName
;
540 CHAR ShortNameBuf
[13];
541 UCHAR EntryBuffer
[32];
543 OEM_STRING LongNameOem
;
546 /* Make sure this FCB has a FullFAT handle associated with it */
547 if (Fcb
->FatHandle
== NULL
&&
548 FatNodeType(Fcb
) == FAT_NTC_DCB
)
550 /* Open the dir with FullFAT */
551 Fcb
->FatHandle
= FF_OpenW(Fcb
->Vcb
->Ioman
, &Fcb
->FullFileName
, FF_MODE_DIR
, NULL
);
558 /* Get the dir entry */
559 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
560 Fcb
->FatHandle
->DirEntry
,
561 Fcb
->FatHandle
->DirCluster
,
564 if (Err
!= FF_ERR_NONE
)
566 DPRINT1("Error %d getting dirent of a file\n", Err
);
570 /* Read the dirent to fetch the raw short name */
571 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
572 Fcb
->FatHandle
->DirCluster
,
573 Fcb
->FatHandle
->DirEntry
,
575 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
577 /* Check if we only have a short name.
578 Convert it to unicode and return if that's the case */
581 /* Initialize short name string */
582 ShortName
.Buffer
= ShortNameBuf
;
583 ShortName
.Length
= 0;
584 ShortName
.MaximumLength
= 12;
586 /* Convert raw short name to a proper string */
587 Fati8dot3ToString((PCHAR
)EntryBuffer
, FALSE
, &ShortName
);
589 /* Convert it to unicode */
590 Status
= RtlOemStringToCountedUnicodeString(LongName
,
594 /* Ensure conversion was successful */
595 ASSERT(Status
== STATUS_SUCCESS
);
601 /* Convert LFN from OEM to unicode and return */
602 LongNameOem
.Buffer
= DirEnt
.FileName
;
603 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
604 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
606 /* Convert it to unicode */
607 Status
= RtlOemStringToUnicodeString(LongName
, &LongNameOem
, FALSE
);
609 /* Ensure conversion was successful */
610 ASSERT(Status
== STATUS_SUCCESS
);
616 FatSetFullNameInFcb(PFCB Fcb
,
617 PUNICODE_STRING Name
)
619 PUNICODE_STRING ParentName
;
621 /* Make sure this FCB's name wasn't already set */
622 ASSERT(Fcb
->FullFileName
.Buffer
== NULL
);
624 /* First of all, check exact case name */
625 if (Fcb
->ExactCaseLongName
.Buffer
)
627 ASSERT(Fcb
->ExactCaseLongName
.Length
!= 0);
629 /* Use exact case name */
630 Name
= &Fcb
->ExactCaseLongName
;
633 /* Treat root dir different */
634 if (FatNodeType(Fcb
->ParentFcb
) == FAT_NTC_ROOT_DCB
)
637 Fcb
->FullFileName
.MaximumLength
= sizeof(WCHAR
) + Name
->Length
;
638 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
640 /* Allocate a buffer */
641 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
642 Fcb
->FullFileName
.Length
,
645 /* Prefix with a backslash */
646 Fcb
->FullFileName
.Buffer
[0] = L
'\\';
648 /* Copy the name here */
649 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[1],
655 ParentName
= &Fcb
->ParentFcb
->FullFileName
;
657 /* Check if parent's name is set */
658 if (!ParentName
->Buffer
)
662 Fcb
->FullFileName
.MaximumLength
=
663 ParentName
->Length
+ sizeof(WCHAR
) + Name
->Length
;
664 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
666 /* Allocate a buffer */
667 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
668 Fcb
->FullFileName
.Length
,
671 /* Copy parent's name here */
672 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[0],
673 &ParentName
->Buffer
[0],
674 ParentName
->Length
);
676 /* Add a backslash */
677 Fcb
->FullFileName
.Buffer
[ParentName
->Length
/ sizeof(WCHAR
)] = L
'\\';
679 /* Copy given name here */
680 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[(ParentName
->Length
/ sizeof(WCHAR
)) + 1],
688 FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext
,
691 UNICODE_STRING LongName
;
695 ULONG PathLength
= 0;
697 /* Do nothing if it's already set */
698 if (Fcb
->FullFileName
.Buffer
) return;
700 /* Allocate a temporary buffer */
702 LongName
.MaximumLength
= FF_MAX_FILENAME
* sizeof(WCHAR
);
704 FsRtlAllocatePoolWithTag(PagedPool
,
705 FF_MAX_FILENAME
* sizeof(WCHAR
),
708 /* Go through all parents to calculate needed length */
709 while (CurFcb
!= Fcb
->Vcb
->RootDcb
)
711 /* Does current FCB have FullFileName set? */
713 CurFcb
->FullFileName
.Buffer
)
715 /* Yes, just use it! */
716 PathLength
+= CurFcb
->FullFileName
.Length
;
718 Fcb
->FullFileName
.Buffer
=
719 FsRtlAllocatePoolWithTag(PagedPool
,
723 RtlCopyMemory(Fcb
->FullFileName
.Buffer
,
724 CurFcb
->FullFileName
.Buffer
,
725 CurFcb
->FullFileName
.Length
);
730 /* Sum up length of a current item */
731 PathLength
+= CurFcb
->FileNameLength
+ sizeof(WCHAR
);
733 /* Go to the parent */
734 CurFcb
= CurFcb
->ParentFcb
;
737 /* Allocate FullFileName if it wasn't already allocated above */
738 if (!Fcb
->FullFileName
.Buffer
)
740 Fcb
->FullFileName
.Buffer
=
741 FsRtlAllocatePoolWithTag(PagedPool
,
749 TmpBuffer
= Fcb
->FullFileName
.Buffer
+ PathLength
/ sizeof(WCHAR
);
752 Fcb
->FullFileName
.Length
= PathLength
;
753 Fcb
->FullFileName
.MaximumLength
= PathLength
;
755 while (CurFcb
!= StopFcb
)
757 /* Get its unicode name */
758 FatGetFcbUnicodeName(IrpContext
,
763 TmpBuffer
-= LongName
.Length
/ sizeof(WCHAR
);
764 RtlCopyMemory(TmpBuffer
, LongName
.Buffer
, LongName
.Length
);
766 /* Append with a backslash */
770 /* Go to the parent */
771 CurFcb
= CurFcb
->ParentFcb
;
774 /* Free the temp buffer */
775 ExFreePool(LongName
.Buffer
);
781 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext
,
786 POEM_STRING ShortName
;
787 CHAR ShortNameRaw
[13];
788 UCHAR EntryBuffer
[32];
790 PUNICODE_STRING UnicodeName
;
791 OEM_STRING LongNameOem
;
794 /* Get the dir entry */
795 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
796 Fcb
->FatHandle
->DirEntry
,
797 Fcb
->FatHandle
->DirCluster
,
800 if (Err
!= FF_ERR_NONE
)
802 DPRINT1("Error %d getting dirent of a file\n", Err
);
806 /* Read the dirent to fetch the raw short name */
807 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
808 Fcb
->FatHandle
->DirCluster
,
809 Fcb
->FatHandle
->DirEntry
,
811 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
812 RtlCopyMemory(ShortNameRaw
, EntryBuffer
, 11);
814 /* Initialize short name string */
815 ShortName
= &Fcb
->ShortName
.Name
.Ansi
;
816 ShortName
->Buffer
= Fcb
->ShortNameBuffer
;
817 ShortName
->Length
= 0;
818 ShortName
->MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
820 /* Convert raw short name to a proper string */
821 Fati8dot3ToString(ShortNameRaw
, FALSE
, ShortName
);
823 /* Add the short name link */
824 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksAnsi
, &Fcb
->ShortName
);
825 Fcb
->ShortName
.Fcb
= Fcb
;
827 /* Get the long file name (if any) */
830 /* Prepare the oem string */
831 LongNameOem
.Buffer
= DirEnt
.FileName
;
832 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
833 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
835 /* Prepare the unicode string */
836 UnicodeName
= &Fcb
->LongName
.Name
.String
;
837 UnicodeName
->Length
= (LongNameOem
.Length
+ 1) * sizeof(WCHAR
);
838 UnicodeName
->MaximumLength
= UnicodeName
->Length
;
839 UnicodeName
->Buffer
= FsRtlAllocatePool(PagedPool
, UnicodeName
->Length
);
841 /* Convert it to unicode */
842 Status
= RtlOemStringToUnicodeString(UnicodeName
, &LongNameOem
, FALSE
);
843 if (!NT_SUCCESS(Status
))
849 Fcb
->FileNameLength
= UnicodeName
->Length
;
851 /* Save case-preserved copy */
852 Fcb
->ExactCaseLongName
.Length
= UnicodeName
->Length
;
853 Fcb
->ExactCaseLongName
.MaximumLength
= UnicodeName
->Length
;
854 Fcb
->ExactCaseLongName
.Buffer
=
855 FsRtlAllocatePoolWithTag(PagedPool
, UnicodeName
->Length
, TAG_FILENAME
);
857 RtlCopyMemory(Fcb
->ExactCaseLongName
.Buffer
,
859 UnicodeName
->Length
);
861 /* Perform a trick which is done by MS's FASTFAT driver to monocase
863 RtlDowncaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
864 RtlUpcaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
866 DPRINT("Converted long name: %wZ\n", UnicodeName
);
868 /* Add the long unicode name link */
869 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksUnicode
, &Fcb
->LongName
);
870 Fcb
->LongName
.Fcb
= Fcb
;
872 /* Indicate that this FCB has a unicode long name */
873 SetFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
877 /* No LFN, set exact case name to 0 length */
878 Fcb
->ExactCaseLongName
.Length
= 0;
879 Fcb
->ExactCaseLongName
.MaximumLength
= 0;
881 /* Set the length based on the short name */
882 Fcb
->FileNameLength
= RtlOemStringToCountedUnicodeSize(ShortName
);
885 /* Mark the fact that names were added to splay trees*/
886 SetFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);
891 Fati8dot3ToString(IN PCHAR FileName
,
893 OUT POEM_STRING OutString
)
895 ULONG BaseLen
, ExtLen
;
896 CHAR
*cString
= OutString
->Buffer
;
899 /* Calc base and ext lens */
900 for (BaseLen
= 8; BaseLen
> 0; BaseLen
--)
902 if (FileName
[BaseLen
- 1] != ' ') break;
905 for (ExtLen
= 3; ExtLen
> 0; ExtLen
--)
907 if (FileName
[8 + ExtLen
- 1] != ' ') break;
910 /* Process base name */
913 RtlCopyMemory(cString
, FileName
, BaseLen
);
915 /* Substitute the e5 thing */
916 if (cString
[0] == 0x05) cString
[0] = 0xe5;
918 /* Downcase if asked to */
922 for (i
= 0; i
< BaseLen
; i
++)
924 if (cString
[i
] >= 'A' &&
928 cString
[i
] += 'a' - 'A';
935 /* Process extension */
939 cString
[BaseLen
] = '.';
942 /* Copy the extension */
943 for (i
= 0; i
< ExtLen
; i
++)
945 cString
[BaseLen
+ i
] = FileName
[8 + i
];
948 /* Lowercase the extension if asked to */
952 for (i
= BaseLen
; i
< BaseLen
+ ExtLen
; i
++)
954 if (cString
[i
] >= 'A' &&
958 cString
[i
] += 'a' - 'A';
965 OutString
->Length
= BaseLen
+ ExtLen
;
967 DPRINT("'%s', len %d\n", OutString
->Buffer
, OutString
->Length
);
972 FatInsertName(IN PFAT_IRP_CONTEXT IrpContext
,
973 IN PRTL_SPLAY_LINKS
*RootNode
,
974 IN PFCB_NAME_LINK Name
)
976 PFCB_NAME_LINK NameLink
;
977 FSRTL_COMPARISON_RESULT Comparison
;
979 /* Initialize the splay links */
980 RtlInitializeSplayLinks(&Name
->Links
);
982 /* Is this the first entry? */
983 if (*RootNode
== NULL
)
985 /* Yes, become root and return */
986 *RootNode
= &Name
->Links
;
990 /* Get the name link */
991 NameLink
= CONTAINING_RECORD(*RootNode
, FCB_NAME_LINK
, Links
);
994 /* Compare the prefix */
995 if (*(PUCHAR
)NameLink
->Name
.Ansi
.Buffer
!= *(PUCHAR
)&Name
->Name
.Ansi
.Buffer
)
997 if (*(PUCHAR
)NameLink
->Name
.Ansi
.Buffer
< *(PUCHAR
)&Name
->Name
.Ansi
.Buffer
)
998 Comparison
= LessThan
;
1000 Comparison
= GreaterThan
;
1004 /* Perform real comparison */
1005 Comparison
= FatiCompareNames(&NameLink
->Name
.Ansi
, &Name
->Name
.Ansi
);
1008 /* Check the bad case first */
1009 if (Comparison
== EqualTo
)
1011 /* Must not happen */
1015 /* Check comparison result */
1016 if (Comparison
== GreaterThan
)
1018 /* Go to the left child */
1019 if (!RtlLeftChild(&NameLink
->Links
))
1021 /* It's absent, insert here and break */
1022 RtlInsertAsLeftChild(&NameLink
->Links
, &Name
->Links
);
1027 /* It's present, go inside it */
1028 NameLink
= CONTAINING_RECORD(RtlLeftChild(&NameLink
->Links
),
1035 /* Go to the right child */
1036 if (!RtlRightChild(&NameLink
->Links
))
1038 /* It's absent, insert here and break */
1039 RtlInsertAsRightChild(&NameLink
->Links
, &Name
->Links
);
1044 /* It's present, go inside it */
1045 NameLink
= CONTAINING_RECORD(RtlRightChild(&NameLink
->Links
),
1055 FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext
,
1058 PRTL_SPLAY_LINKS RootNew
;
1061 /* Reference the parent for simplicity */
1062 Parent
= Fcb
->ParentFcb
;
1064 /* If this FCB hasn't been added to splay trees - just return */
1065 if (!FlagOn( Fcb
->State
, FCB_STATE_HAS_NAMES
))
1068 /* Delete the short name link */
1069 RootNew
= RtlDelete(&Fcb
->ShortName
.Links
);
1071 /* Set the new root */
1072 Parent
->Dcb
.SplayLinksAnsi
= RootNew
;
1074 /* Deal with a unicode name if it exists */
1075 if (FlagOn( Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
))
1077 /* Delete the long unicode name link */
1078 RootNew
= RtlDelete(&Fcb
->LongName
.Links
);
1080 /* Set the new root */
1081 Parent
->Dcb
.SplayLinksUnicode
= RootNew
;
1083 /* Free the long name string's buffer*/
1084 RtlFreeUnicodeString(&Fcb
->LongName
.Name
.String
);
1086 /* Clear the "has unicode name" flag */
1087 ClearFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
1090 /* This FCB has no names added to splay trees now */
1091 ClearFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);