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
;
153 FatSetFcbNames(IrpContext
, Fcb
);
164 /* Allocate the CCB and zero it */
165 Ccb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CCB
), TAG_CCB
);
166 RtlZeroMemory(Ccb
, sizeof(CCB
));
168 /* Set mandatory header */
169 Ccb
->NodeTypeCode
= FAT_NTC_FCB
;
170 Ccb
->NodeByteSize
= sizeof(CCB
);
177 FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext
,
178 IN PFILE_OBJECT FileObject
,
181 IN PACCESS_MASK DesiredAccess
,
182 IN USHORT ShareAccess
,
183 IN ULONG AllocationSize
,
184 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
186 IN UCHAR FileAttributes
,
187 IN ULONG CreateDisposition
,
188 IN BOOLEAN NoEaKnowledge
,
189 IN BOOLEAN DeleteOnClose
,
190 IN BOOLEAN OpenedAsDos
,
191 OUT PBOOLEAN OplockPostIrp
)
193 IO_STATUS_BLOCK Iosb
= {{0}};
194 ACCESS_MASK AddedAccess
= 0;
200 /* Acquire exclusive FCB lock */
201 (VOID
)FatAcquireExclusiveFcb(IrpContext
, Fcb
);
203 *OplockPostIrp
= FALSE
;
205 /* Check if there is a batch oplock */
206 if (FsRtlCurrentBatchOplock(&Fcb
->Fcb
.Oplock
))
208 /* Return with a special information field */
209 Iosb
.Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
211 /* Check the oplock */
212 Iosb
.Status
= FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
218 if (Iosb
.Status
!= STATUS_SUCCESS
&&
219 Iosb
.Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
)
221 /* The Irp needs to be queued */
222 *OplockPostIrp
= TRUE
;
224 /* Release the FCB and return */
225 FatReleaseFcb(IrpContext
, Fcb
);
230 /* Validate parameters and modify access */
231 if (CreateDisposition
== FILE_CREATE
)
233 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
235 /* Release the FCB and return */
236 FatReleaseFcb(IrpContext
, Fcb
);
239 else if (CreateDisposition
== FILE_SUPERSEDE
)
241 SetFlag(AddedAccess
, DELETE
& ~(*DesiredAccess
));
242 *DesiredAccess
|= DELETE
;
244 else if ((CreateDisposition
== FILE_OVERWRITE
) ||
245 (CreateDisposition
== FILE_OVERWRITE_IF
))
248 (FILE_WRITE_DATA
| FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
)
249 & ~(*DesiredAccess
) );
251 *DesiredAccess
|= FILE_WRITE_DATA
| FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
;
254 // TODO: Check desired access
256 // TODO: Check if this file is readonly and DeleteOnClose is set
258 /* Validate disposition information */
259 if ((CreateDisposition
== FILE_SUPERSEDE
) ||
260 (CreateDisposition
== FILE_OVERWRITE
) ||
261 (CreateDisposition
== FILE_OVERWRITE_IF
))
263 // TODO: Get this attributes from the dirent
267 if ((Hidden
&& !FlagOn(FileAttributes
, FILE_ATTRIBUTE_HIDDEN
)) ||
268 (System
&& !FlagOn(FileAttributes
, FILE_ATTRIBUTE_SYSTEM
)))
270 DPRINT1("Hidden/system attributes don't match\n");
272 Iosb
.Status
= STATUS_ACCESS_DENIED
;
274 /* Release the FCB and return */
275 FatReleaseFcb(IrpContext
, Fcb
);
279 // TODO: Check for write protected volume
282 /* Check share access */
283 Iosb
.Status
= IoCheckShareAccess(*DesiredAccess
,
288 if (!NT_SUCCESS(Iosb
.Status
))
290 /* Release the FCB and return */
291 FatReleaseFcb(IrpContext
, Fcb
);
295 /* Check the oplock status after checking for share access */
296 Iosb
.Status
= FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
302 if (Iosb
.Status
!= STATUS_SUCCESS
&&
303 Iosb
.Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
)
305 /* The Irp needs to be queued */
306 *OplockPostIrp
= TRUE
;
308 /* Release the FCB and return */
309 FatReleaseFcb(IrpContext
, Fcb
);
313 /* Set Fast I/O flag */
314 Fcb
->Header
.IsFastIoPossible
= FALSE
; //FatiIsFastIoPossible(Fcb);
316 /* Make sure image is not mapped */
317 if (DeleteOnClose
|| FlagOn(*DesiredAccess
, FILE_WRITE_DATA
))
319 /* Try to flush the image section */
320 if (!MmFlushImageSection(&Fcb
->SectionObjectPointers
, MmFlushForWrite
))
322 /* Yes, image section exists, set correct status code */
324 Iosb
.Status
= STATUS_CANNOT_DELETE
;
326 Iosb
.Status
= STATUS_SHARING_VIOLATION
;
328 /* Release the FCB and return */
329 FatReleaseFcb(IrpContext
, Fcb
);
334 /* Flush the cache if it's non-cached non-pagefile access */
335 if (FlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
) &&
336 Fcb
->SectionObjectPointers
.DataSectionObject
&&
337 !FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
))
339 /* Set the flag that create is in progress */
340 SetFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
342 /* Flush the cache */
343 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
345 /* Acquire and release Paging I/O resource before purging the cache section
346 to let lazy writer finish */
347 ExAcquireResourceExclusiveLite( Fcb
->Header
.PagingIoResource
, TRUE
);
348 ExReleaseResourceLite( Fcb
->Header
.PagingIoResource
);
350 /* Delete the cache section */
351 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
, NULL
, 0, FALSE
);
354 ClearFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
357 /* Check create disposition flags and branch accordingly */
358 if (CreateDisposition
== FILE_OPEN
||
359 CreateDisposition
== FILE_OPEN_IF
)
361 DPRINT("Opening a file\n");
363 /* Check if we need to bother with EA */
364 if (NoEaKnowledge
&& FALSE
/* FatIsFat32(Vcb)*/)
369 /* Set up file object */
370 Ccb
= FatCreateCcb(IrpContext
);
371 FatSetFileObject(FileObject
,
376 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
378 /* The file is opened */
379 Iosb
.Information
= FILE_OPENED
;
382 else if ((CreateDisposition
== FILE_SUPERSEDE
) ||
383 (CreateDisposition
== FILE_OVERWRITE
) ||
384 (CreateDisposition
== FILE_OVERWRITE_IF
))
391 /* We can't get here */
392 KeBugCheckEx(0x23, CreateDisposition
, 0, 0, 0);
398 if (Iosb
.Status
!= STATUS_PENDING
&&
399 NT_SUCCESS(Iosb
.Status
))
401 /* Update access if needed */
404 /* Remove added access flags from desired access */
405 ClearFlag(*DesiredAccess
, AddedAccess
);
407 /* Check share access */
408 Status
= IoCheckShareAccess(*DesiredAccess
,
414 /* Make sure it's success */
415 ASSERT(Status
== STATUS_SUCCESS
);
419 /* Update the share access */
420 IoUpdateShareAccess(FileObject
, &Fcb
->ShareAccess
);
423 /* Clear the delay close */
424 ClearFlag(Fcb
->State
, FCB_STATE_DELAY_CLOSE
);
426 /* Increase counters */
428 Vcb
->OpenFileCount
++;
430 // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
438 FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext
,
440 OUT PUNICODE_STRING LongName
)
444 OEM_STRING ShortName
;
445 CHAR ShortNameBuf
[13];
446 UCHAR EntryBuffer
[32];
448 OEM_STRING LongNameOem
;
451 /* Make sure this FCB has a FullFAT handle associated with it */
452 if (Fcb
->FatHandle
== NULL
&&
453 FatNodeType(Fcb
) == FAT_NTC_DCB
)
455 /* Open the dir with FullFAT */
456 Fcb
->FatHandle
= FF_OpenW(Fcb
->Vcb
->Ioman
, &Fcb
->FullFileName
, FF_MODE_DIR
, NULL
);
463 /* Get the dir entry */
464 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
465 Fcb
->FatHandle
->DirEntry
,
466 Fcb
->FatHandle
->DirCluster
,
469 if (Err
!= FF_ERR_NONE
)
471 DPRINT1("Error %d getting dirent of a file\n", Err
);
475 /* Read the dirent to fetch the raw short name */
476 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
477 Fcb
->FatHandle
->DirCluster
,
478 Fcb
->FatHandle
->DirEntry
,
480 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
482 /* Check if we only have a short name.
483 Convert it to unicode and return if that's the case */
486 /* Initialize short name string */
487 ShortName
.Buffer
= ShortNameBuf
;
488 ShortName
.Length
= 0;
489 ShortName
.MaximumLength
= 12;
491 /* Convert raw short name to a proper string */
492 Fati8dot3ToString((PCHAR
)EntryBuffer
, FALSE
, &ShortName
);
494 /* Convert it to unicode */
495 Status
= RtlOemStringToCountedUnicodeString(LongName
,
499 /* Ensure conversion was successful */
500 ASSERT(Status
== STATUS_SUCCESS
);
506 /* Convert LFN from OEM to unicode and return */
507 LongNameOem
.Buffer
= DirEnt
.FileName
;
508 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
509 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
511 /* Convert it to unicode */
512 Status
= RtlOemStringToUnicodeString(LongName
, &LongNameOem
, FALSE
);
514 /* Ensure conversion was successful */
515 ASSERT(Status
== STATUS_SUCCESS
);
521 FatSetFullNameInFcb(PFCB Fcb
,
522 PUNICODE_STRING Name
)
524 PUNICODE_STRING ParentName
;
526 /* Make sure this FCB's name wasn't already set */
527 ASSERT(Fcb
->FullFileName
.Buffer
== NULL
);
529 /* First of all, check exact case name */
530 if (Fcb
->ExactCaseLongName
.Buffer
)
532 ASSERT(Fcb
->ExactCaseLongName
.Length
!= 0);
534 /* Use exact case name */
535 Name
= &Fcb
->ExactCaseLongName
;
538 /* Treat root dir different */
539 if (FatNodeType(Fcb
->ParentFcb
) == FAT_NTC_ROOT_DCB
)
542 Fcb
->FullFileName
.MaximumLength
= sizeof(WCHAR
) + Name
->Length
;
543 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
545 /* Allocate a buffer */
546 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
547 Fcb
->FullFileName
.Length
,
550 /* Prefix with a backslash */
551 Fcb
->FullFileName
.Buffer
[0] = L
'\\';
553 /* Copy the name here */
554 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[1],
560 ParentName
= &Fcb
->ParentFcb
->FullFileName
;
562 /* Check if parent's name is set */
563 if (!ParentName
->Buffer
)
567 Fcb
->FullFileName
.MaximumLength
=
568 ParentName
->Length
+ sizeof(WCHAR
) + Name
->Length
;
569 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
571 /* Allocate a buffer */
572 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
573 Fcb
->FullFileName
.Length
,
576 /* Copy parent's name here */
577 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[0],
578 &ParentName
->Buffer
[0],
579 ParentName
->Length
);
581 /* Add a backslash */
582 Fcb
->FullFileName
.Buffer
[ParentName
->Length
/ sizeof(WCHAR
)] = L
'\\';
584 /* Copy given name here */
585 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[(ParentName
->Length
/ sizeof(WCHAR
)) + 1],
593 FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext
,
596 UNICODE_STRING LongName
;
600 ULONG PathLength
= 0;
602 /* Do nothing if it's already set */
603 if (Fcb
->FullFileName
.Buffer
) return;
605 /* Allocate a temporary buffer */
607 LongName
.MaximumLength
= FF_MAX_FILENAME
* sizeof(WCHAR
);
609 FsRtlAllocatePoolWithTag(PagedPool
,
610 FF_MAX_FILENAME
* sizeof(WCHAR
),
613 /* Go through all parents to calculate needed length */
614 while (CurFcb
!= Fcb
->Vcb
->RootDcb
)
616 /* Does current FCB have FullFileName set? */
618 CurFcb
->FullFileName
.Buffer
)
620 /* Yes, just use it! */
621 PathLength
+= CurFcb
->FullFileName
.Length
;
623 Fcb
->FullFileName
.Buffer
=
624 FsRtlAllocatePoolWithTag(PagedPool
,
628 RtlCopyMemory(Fcb
->FullFileName
.Buffer
,
629 CurFcb
->FullFileName
.Buffer
,
630 CurFcb
->FullFileName
.Length
);
635 /* Sum up length of a current item */
636 PathLength
+= CurFcb
->FileNameLength
+ sizeof(WCHAR
);
638 /* Go to the parent */
639 CurFcb
= CurFcb
->ParentFcb
;
642 /* Allocate FullFileName if it wasn't already allocated above */
643 if (!Fcb
->FullFileName
.Buffer
)
645 Fcb
->FullFileName
.Buffer
=
646 FsRtlAllocatePoolWithTag(PagedPool
,
654 TmpBuffer
= Fcb
->FullFileName
.Buffer
+ PathLength
/ sizeof(WCHAR
);
657 Fcb
->FullFileName
.Length
= PathLength
;
658 Fcb
->FullFileName
.MaximumLength
= PathLength
;
660 while (CurFcb
!= StopFcb
)
662 /* Get its unicode name */
663 FatGetFcbUnicodeName(IrpContext
,
668 TmpBuffer
-= LongName
.Length
/ sizeof(WCHAR
);
669 RtlCopyMemory(TmpBuffer
, LongName
.Buffer
, LongName
.Length
);
671 /* Append with a backslash */
675 /* Go to the parent */
676 CurFcb
= CurFcb
->ParentFcb
;
679 /* Free the temp buffer */
680 ExFreePool(LongName
.Buffer
);
686 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext
,
691 POEM_STRING ShortName
;
692 CHAR ShortNameRaw
[13];
693 UCHAR EntryBuffer
[32];
695 PUNICODE_STRING UnicodeName
;
696 OEM_STRING LongNameOem
;
699 /* Get the dir entry */
700 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
701 Fcb
->FatHandle
->DirEntry
,
702 Fcb
->FatHandle
->DirCluster
,
705 if (Err
!= FF_ERR_NONE
)
707 DPRINT1("Error %d getting dirent of a file\n", Err
);
711 /* Read the dirent to fetch the raw short name */
712 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
713 Fcb
->FatHandle
->DirCluster
,
714 Fcb
->FatHandle
->DirEntry
,
716 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
717 RtlCopyMemory(ShortNameRaw
, EntryBuffer
, 11);
719 /* Initialize short name string */
720 ShortName
= &Fcb
->ShortName
.Name
.Ansi
;
721 ShortName
->Buffer
= Fcb
->ShortNameBuffer
;
722 ShortName
->Length
= 0;
723 ShortName
->MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
725 /* Convert raw short name to a proper string */
726 Fati8dot3ToString(ShortNameRaw
, FALSE
, ShortName
);
728 /* Add the short name link */
729 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksAnsi
, &Fcb
->ShortName
);
730 Fcb
->ShortName
.Fcb
= Fcb
;
732 /* Get the long file name (if any) */
735 /* Prepare the oem string */
736 LongNameOem
.Buffer
= DirEnt
.FileName
;
737 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
738 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
740 /* Prepare the unicode string */
741 UnicodeName
= &Fcb
->LongName
.Name
.String
;
742 UnicodeName
->Length
= (LongNameOem
.Length
+ 1) * sizeof(WCHAR
);
743 UnicodeName
->MaximumLength
= UnicodeName
->Length
;
744 UnicodeName
->Buffer
= FsRtlAllocatePool(PagedPool
, UnicodeName
->Length
);
746 /* Convert it to unicode */
747 Status
= RtlOemStringToUnicodeString(UnicodeName
, &LongNameOem
, FALSE
);
748 if (!NT_SUCCESS(Status
))
754 Fcb
->FileNameLength
= UnicodeName
->Length
;
756 /* Save case-preserved copy */
757 Fcb
->ExactCaseLongName
.Length
= UnicodeName
->Length
;
758 Fcb
->ExactCaseLongName
.MaximumLength
= UnicodeName
->Length
;
759 Fcb
->ExactCaseLongName
.Buffer
=
760 FsRtlAllocatePoolWithTag(PagedPool
, UnicodeName
->Length
, TAG_FILENAME
);
762 RtlCopyMemory(Fcb
->ExactCaseLongName
.Buffer
,
764 UnicodeName
->Length
);
766 /* Perform a trick which is done by MS's FASTFAT driver to monocase
768 RtlDowncaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
769 RtlUpcaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
771 DPRINT("Converted long name: %wZ\n", UnicodeName
);
773 /* Add the long unicode name link */
774 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksUnicode
, &Fcb
->LongName
);
775 Fcb
->LongName
.Fcb
= Fcb
;
777 /* Indicate that this FCB has a unicode long name */
778 SetFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
782 /* No LFN, set exact case name to 0 length */
783 Fcb
->ExactCaseLongName
.Length
= 0;
784 Fcb
->ExactCaseLongName
.MaximumLength
= 0;
786 /* Set the length based on the short name */
787 Fcb
->FileNameLength
= RtlOemStringToCountedUnicodeSize(ShortName
);
790 /* Mark the fact that names were added to splay trees*/
791 SetFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);
796 Fati8dot3ToString(IN PCHAR FileName
,
798 OUT POEM_STRING OutString
)
800 ULONG BaseLen
, ExtLen
;
801 CHAR
*cString
= OutString
->Buffer
;
804 /* Calc base and ext lens */
805 for (BaseLen
= 8; BaseLen
> 0; BaseLen
--)
807 if (FileName
[BaseLen
- 1] != ' ') break;
810 for (ExtLen
= 3; ExtLen
> 0; ExtLen
--)
812 if (FileName
[8 + ExtLen
- 1] != ' ') break;
815 /* Process base name */
818 RtlCopyMemory(cString
, FileName
, BaseLen
);
820 /* Substitute the e5 thing */
821 if (cString
[0] == 0x05) cString
[0] = 0xe5;
823 /* Downcase if asked to */
827 for (i
= 0; i
< BaseLen
; i
++)
829 if (cString
[i
] >= 'A' &&
833 cString
[i
] += 'a' - 'A';
840 /* Process extension */
844 cString
[BaseLen
] = '.';
847 /* Copy the extension */
848 for (i
= 0; i
< ExtLen
; i
++)
850 cString
[BaseLen
+ i
] = FileName
[8 + i
];
853 /* Lowercase the extension if asked to */
857 for (i
= BaseLen
; i
< BaseLen
+ ExtLen
; i
++)
859 if (cString
[i
] >= 'A' &&
863 cString
[i
] += 'a' - 'A';
870 OutString
->Length
= BaseLen
+ ExtLen
;
872 DPRINT("'%s', len %d\n", OutString
->Buffer
, OutString
->Length
);
877 FatInsertName(IN PFAT_IRP_CONTEXT IrpContext
,
878 IN PRTL_SPLAY_LINKS
*RootNode
,
879 IN PFCB_NAME_LINK Name
)
881 PFCB_NAME_LINK NameLink
;
882 FSRTL_COMPARISON_RESULT Comparison
;
884 /* Initialize the splay links */
885 RtlInitializeSplayLinks(&Name
->Links
);
887 /* Is this the first entry? */
888 if (*RootNode
== NULL
)
890 /* Yes, become root and return */
891 *RootNode
= &Name
->Links
;
895 /* Get the name link */
896 NameLink
= CONTAINING_RECORD(*RootNode
, FCB_NAME_LINK
, Links
);
899 /* Compare the prefix */
900 if (*(PUCHAR
)NameLink
->Name
.Ansi
.Buffer
!= *(PUCHAR
)&Name
->Name
.Ansi
.Buffer
)
902 if (*(PUCHAR
)NameLink
->Name
.Ansi
.Buffer
< *(PUCHAR
)&Name
->Name
.Ansi
.Buffer
)
903 Comparison
= LessThan
;
905 Comparison
= GreaterThan
;
909 /* Perform real comparison */
910 Comparison
= FatiCompareNames(&NameLink
->Name
.Ansi
, &Name
->Name
.Ansi
);
913 /* Check the bad case first */
914 if (Comparison
== EqualTo
)
916 /* Must not happen */
920 /* Check comparison result */
921 if (Comparison
== GreaterThan
)
923 /* Go to the left child */
924 if (!RtlLeftChild(&NameLink
->Links
))
926 /* It's absent, insert here and break */
927 RtlInsertAsLeftChild(&NameLink
->Links
, &Name
->Links
);
932 /* It's present, go inside it */
933 NameLink
= CONTAINING_RECORD(RtlLeftChild(&NameLink
->Links
),
940 /* Go to the right child */
941 if (!RtlRightChild(&NameLink
->Links
))
943 /* It's absent, insert here and break */
944 RtlInsertAsRightChild(&NameLink
->Links
, &Name
->Links
);
949 /* It's present, go inside it */
950 NameLink
= CONTAINING_RECORD(RtlRightChild(&NameLink
->Links
),
960 FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext
,
963 PRTL_SPLAY_LINKS RootNew
;
966 /* Reference the parent for simplicity */
967 Parent
= Fcb
->ParentFcb
;
969 /* If this FCB hasn't been added to splay trees - just return */
970 if (!FlagOn( Fcb
->State
, FCB_STATE_HAS_NAMES
))
973 /* Delete the short name link */
974 RootNew
= RtlDelete(&Fcb
->ShortName
.Links
);
976 /* Set the new root */
977 Parent
->Dcb
.SplayLinksAnsi
= RootNew
;
979 /* Deal with a unicode name if it exists */
980 if (FlagOn( Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
))
982 /* Delete the long unicode name link */
983 RootNew
= RtlDelete(&Fcb
->LongName
.Links
);
985 /* Set the new root */
986 Parent
->Dcb
.SplayLinksUnicode
= RootNew
;
988 /* Free the long name string's buffer*/
989 RtlFreeUnicodeString(&Fcb
->LongName
.Name
.String
);
991 /* Clear the "has unicode name" flag */
992 ClearFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
995 /* This FCB has no names added to splay trees now */
996 ClearFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);