2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
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 global volume counter */
427 Vcb
->OpenFileCount
++;
429 // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
437 FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext
,
439 OUT PUNICODE_STRING LongName
)
443 OEM_STRING ShortName
;
444 CHAR ShortNameBuf
[13];
445 UCHAR EntryBuffer
[32];
447 OEM_STRING LongNameOem
;
450 /* Make sure this FCB has a FullFAT handle associated with it */
451 if (Fcb
->FatHandle
== NULL
&&
452 FatNodeType(Fcb
) == FAT_NTC_DCB
)
454 /* Open the dir with FullFAT */
455 Fcb
->FatHandle
= FF_OpenW(Fcb
->Vcb
->Ioman
, &Fcb
->FullFileName
, FF_MODE_DIR
, NULL
);
462 /* Get the dir entry */
463 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
464 Fcb
->FatHandle
->DirEntry
,
465 Fcb
->FatHandle
->DirCluster
,
468 if (Err
!= FF_ERR_NONE
)
470 DPRINT1("Error %d getting dirent of a file\n", Err
);
474 /* Read the dirent to fetch the raw short name */
475 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
476 Fcb
->FatHandle
->DirCluster
,
477 Fcb
->FatHandle
->DirEntry
,
479 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
481 /* Check if we only have a short name.
482 Convert it to unicode and return if that's the case */
485 /* Initialize short name string */
486 ShortName
.Buffer
= ShortNameBuf
;
487 ShortName
.Length
= 0;
488 ShortName
.MaximumLength
= 12;
490 /* Convert raw short name to a proper string */
491 Fati8dot3ToString((PCHAR
)EntryBuffer
, FALSE
, &ShortName
);
493 /* Convert it to unicode */
494 Status
= RtlOemStringToCountedUnicodeString(LongName
,
498 /* Ensure conversion was successful */
499 ASSERT(Status
== STATUS_SUCCESS
);
505 /* Convert LFN from OEM to unicode and return */
506 LongNameOem
.Buffer
= DirEnt
.FileName
;
507 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
508 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
510 /* Convert it to unicode */
511 Status
= RtlOemStringToUnicodeString(LongName
, &LongNameOem
, FALSE
);
513 /* Ensure conversion was successful */
514 ASSERT(Status
== STATUS_SUCCESS
);
520 FatSetFullNameInFcb(PFCB Fcb
,
521 PUNICODE_STRING Name
)
523 PUNICODE_STRING ParentName
;
525 /* Make sure this FCB's name wasn't already set */
526 ASSERT(Fcb
->FullFileName
.Buffer
== NULL
);
528 /* First of all, check exact case name */
529 if (Fcb
->ExactCaseLongName
.Buffer
)
531 ASSERT(Fcb
->ExactCaseLongName
.Length
!= 0);
533 /* Use exact case name */
534 Name
= &Fcb
->ExactCaseLongName
;
537 /* Treat root dir different */
538 if (FatNodeType(Fcb
->ParentFcb
) == FAT_NTC_ROOT_DCB
)
541 Fcb
->FullFileName
.MaximumLength
= sizeof(WCHAR
) + Name
->Length
;
542 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
544 /* Allocate a buffer */
545 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
546 Fcb
->FullFileName
.Length
,
549 /* Prefix with a backslash */
550 Fcb
->FullFileName
.Buffer
[0] = L
'\\';
552 /* Copy the name here */
553 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[1],
559 ParentName
= &Fcb
->ParentFcb
->FullFileName
;
561 /* Check if parent's name is set */
562 if (!ParentName
->Buffer
)
566 Fcb
->FullFileName
.MaximumLength
=
567 ParentName
->Length
+ sizeof(WCHAR
) + Name
->Length
;
568 Fcb
->FullFileName
.Length
= Fcb
->FullFileName
.MaximumLength
;
570 /* Allocate a buffer */
571 Fcb
->FullFileName
.Buffer
= FsRtlAllocatePoolWithTag(PagedPool
,
572 Fcb
->FullFileName
.Length
,
575 /* Copy parent's name here */
576 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[0],
577 &ParentName
->Buffer
[0],
578 ParentName
->Length
);
580 /* Add a backslash */
581 Fcb
->FullFileName
.Buffer
[ParentName
->Length
/ sizeof(WCHAR
)] = L
'\\';
583 /* Copy given name here */
584 RtlCopyMemory(&Fcb
->FullFileName
.Buffer
[(ParentName
->Length
/ sizeof(WCHAR
)) + 1],
592 FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext
,
595 UNICODE_STRING LongName
;
599 ULONG PathLength
= 0;
601 /* Do nothing if it's already set */
602 if (Fcb
->FullFileName
.Buffer
) return;
604 /* Allocate a temporary buffer */
606 LongName
.MaximumLength
= FF_MAX_FILENAME
* sizeof(WCHAR
);
608 FsRtlAllocatePoolWithTag(PagedPool
,
609 FF_MAX_FILENAME
* sizeof(WCHAR
),
612 /* Go through all parents to calculate needed length */
613 while (CurFcb
!= Fcb
->Vcb
->RootDcb
)
615 /* Does current FCB have FullFileName set? */
617 CurFcb
->FullFileName
.Buffer
)
619 /* Yes, just use it! */
620 PathLength
+= CurFcb
->FullFileName
.Length
;
622 Fcb
->FullFileName
.Buffer
=
623 FsRtlAllocatePoolWithTag(PagedPool
,
627 RtlCopyMemory(Fcb
->FullFileName
.Buffer
,
628 CurFcb
->FullFileName
.Buffer
,
629 CurFcb
->FullFileName
.Length
);
634 /* Sum up length of a current item */
635 PathLength
+= CurFcb
->FileNameLength
+ sizeof(WCHAR
);
637 /* Go to the parent */
638 CurFcb
= CurFcb
->ParentFcb
;
641 /* Allocate FullFileName if it wasn't already allocated above */
642 if (!Fcb
->FullFileName
.Buffer
)
644 Fcb
->FullFileName
.Buffer
=
645 FsRtlAllocatePoolWithTag(PagedPool
,
653 TmpBuffer
= Fcb
->FullFileName
.Buffer
+ PathLength
/ sizeof(WCHAR
);
656 Fcb
->FullFileName
.Length
= PathLength
;
657 Fcb
->FullFileName
.MaximumLength
= PathLength
;
659 while (CurFcb
!= StopFcb
)
661 /* Get its unicode name */
662 FatGetFcbUnicodeName(IrpContext
,
667 TmpBuffer
-= LongName
.Length
/ sizeof(WCHAR
);
668 RtlCopyMemory(TmpBuffer
, LongName
.Buffer
, LongName
.Length
);
670 /* Append with a backslash */
674 /* Go to the parent */
675 CurFcb
= CurFcb
->ParentFcb
;
678 /* Free the temp buffer */
679 ExFreePool(LongName
.Buffer
);
685 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext
,
690 POEM_STRING ShortName
;
691 CHAR ShortNameRaw
[13];
692 UCHAR EntryBuffer
[32];
694 PUNICODE_STRING UnicodeName
;
695 OEM_STRING LongNameOem
;
698 /* Get the dir entry */
699 Err
= FF_GetEntry(Fcb
->Vcb
->Ioman
,
700 Fcb
->FatHandle
->DirEntry
,
701 Fcb
->FatHandle
->DirCluster
,
704 if (Err
!= FF_ERR_NONE
)
706 DPRINT1("Error %d getting dirent of a file\n", Err
);
710 /* Read the dirent to fetch the raw short name */
711 FF_FetchEntry(Fcb
->Vcb
->Ioman
,
712 Fcb
->FatHandle
->DirCluster
,
713 Fcb
->FatHandle
->DirEntry
,
715 NumLFNs
= (UCHAR
)(EntryBuffer
[0] & ~0x40);
716 RtlCopyMemory(ShortNameRaw
, EntryBuffer
, 11);
718 /* Initialize short name string */
719 ShortName
= &Fcb
->ShortName
.Name
.Ansi
;
720 ShortName
->Buffer
= Fcb
->ShortNameBuffer
;
721 ShortName
->Length
= 0;
722 ShortName
->MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
724 /* Convert raw short name to a proper string */
725 Fati8dot3ToString(ShortNameRaw
, FALSE
, ShortName
);
727 /* Add the short name link */
728 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksAnsi
, &Fcb
->ShortName
);
729 Fcb
->ShortName
.Fcb
= Fcb
;
731 /* Get the long file name (if any) */
734 /* Prepare the oem string */
735 LongNameOem
.Buffer
= DirEnt
.FileName
;
736 LongNameOem
.MaximumLength
= FF_MAX_FILENAME
;
737 LongNameOem
.Length
= strlen(DirEnt
.FileName
);
739 /* Prepare the unicode string */
740 UnicodeName
= &Fcb
->LongName
.Name
.String
;
741 UnicodeName
->Length
= (LongNameOem
.Length
+ 1) * sizeof(WCHAR
);
742 UnicodeName
->MaximumLength
= UnicodeName
->Length
;
743 UnicodeName
->Buffer
= FsRtlAllocatePool(PagedPool
, UnicodeName
->Length
);
745 /* Convert it to unicode */
746 Status
= RtlOemStringToUnicodeString(UnicodeName
, &LongNameOem
, FALSE
);
747 if (!NT_SUCCESS(Status
))
753 Fcb
->FileNameLength
= UnicodeName
->Length
;
755 /* Save case-preserved copy */
756 Fcb
->ExactCaseLongName
.Length
= UnicodeName
->Length
;
757 Fcb
->ExactCaseLongName
.MaximumLength
= UnicodeName
->Length
;
758 Fcb
->ExactCaseLongName
.Buffer
=
759 FsRtlAllocatePoolWithTag(PagedPool
, UnicodeName
->Length
, TAG_FILENAME
);
761 RtlCopyMemory(Fcb
->ExactCaseLongName
.Buffer
,
763 UnicodeName
->Length
);
765 /* Perform a trick which is done by MS's FASTFAT driver to monocase
767 RtlDowncaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
768 RtlUpcaseUnicodeString(UnicodeName
, UnicodeName
, FALSE
);
770 DPRINT("Converted long name: %wZ\n", UnicodeName
);
772 /* Add the long unicode name link */
773 FatInsertName(IrpContext
, &Fcb
->ParentFcb
->Dcb
.SplayLinksUnicode
, &Fcb
->LongName
);
774 Fcb
->LongName
.Fcb
= Fcb
;
776 /* Indicate that this FCB has a unicode long name */
777 SetFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
781 /* No LFN, set exact case name to 0 length */
782 Fcb
->ExactCaseLongName
.Length
= 0;
783 Fcb
->ExactCaseLongName
.MaximumLength
= 0;
785 /* Set the length based on the short name */
786 Fcb
->FileNameLength
= RtlOemStringToCountedUnicodeSize(ShortName
);
789 /* Mark the fact that names were added to splay trees*/
790 SetFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);
795 Fati8dot3ToString(IN PCHAR FileName
,
797 OUT POEM_STRING OutString
)
799 ULONG BaseLen
, ExtLen
;
800 CHAR
*cString
= OutString
->Buffer
;
803 /* Calc base and ext lens */
804 for (BaseLen
= 8; BaseLen
> 0; BaseLen
--)
806 if (FileName
[BaseLen
- 1] != ' ') break;
809 for (ExtLen
= 3; ExtLen
> 0; ExtLen
--)
811 if (FileName
[8 + ExtLen
- 1] != ' ') break;
814 /* Process base name */
817 RtlCopyMemory(cString
, FileName
, BaseLen
);
819 /* Substitute the e5 thing */
820 if (cString
[0] == 0x05) cString
[0] = 0xe5;
822 /* Downcase if asked to */
826 for (i
= 0; i
< BaseLen
; i
++)
828 if (cString
[i
] >= 'A' &&
832 cString
[i
] += 'a' - 'A';
839 /* Process extension */
843 cString
[BaseLen
] = '.';
846 /* Copy the extension */
847 for (i
= 0; i
< ExtLen
; i
++)
849 cString
[BaseLen
+ i
] = FileName
[8 + i
];
852 /* Lowercase the extension if asked to */
856 for (i
= BaseLen
; i
< BaseLen
+ ExtLen
; i
++)
858 if (cString
[i
] >= 'A' &&
862 cString
[i
] += 'a' - 'A';
869 OutString
->Length
= BaseLen
+ ExtLen
;
871 DPRINT("'%s', len %d\n", OutString
->Buffer
, OutString
->Length
);
876 FatInsertName(IN PFAT_IRP_CONTEXT IrpContext
,
877 IN PRTL_SPLAY_LINKS
*RootNode
,
878 IN PFCB_NAME_LINK Name
)
880 PFCB_NAME_LINK NameLink
;
881 FSRTL_COMPARISON_RESULT Comparison
;
883 /* Initialize the splay links */
884 RtlInitializeSplayLinks(&Name
->Links
);
886 /* Is this the first entry? */
887 if (*RootNode
== NULL
)
889 /* Yes, become root and return */
890 *RootNode
= &Name
->Links
;
894 /* Get the name link */
895 NameLink
= CONTAINING_RECORD(*RootNode
, FCB_NAME_LINK
, Links
);
898 /* Compare prefixes */
899 Comparison
= FatiCompareNames(&NameLink
->Name
.Ansi
, &Name
->Name
.Ansi
);
901 /* Check the bad case first */
902 if (Comparison
== EqualTo
)
904 /* Must not happen */
908 /* Check comparison result */
909 if (Comparison
== GreaterThan
)
911 /* Go to the left child */
912 if (!RtlLeftChild(&NameLink
->Links
))
914 /* It's absent, insert here and break */
915 RtlInsertAsLeftChild(&NameLink
->Links
, &NameLink
->Links
);
920 /* It's present, go inside it */
921 NameLink
= CONTAINING_RECORD(RtlLeftChild(&NameLink
->Links
),
928 /* Go to the right child */
929 if (!RtlRightChild(&NameLink
->Links
))
931 /* It's absent, insert here and break */
932 RtlInsertAsRightChild(&NameLink
->Links
, &Name
->Links
);
937 /* It's present, go inside it */
938 NameLink
= CONTAINING_RECORD(RtlRightChild(&NameLink
->Links
),
948 FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext
,
951 PRTL_SPLAY_LINKS RootNew
;
954 /* Reference the parent for simplicity */
955 Parent
= Fcb
->ParentFcb
;
957 /* If this FCB hasn't been added to splay trees - just return */
958 if (!FlagOn( Fcb
->State
, FCB_STATE_HAS_NAMES
))
961 /* Delete the short name link */
962 RootNew
= RtlDelete(&Fcb
->ShortName
.Links
);
964 /* Set the new root */
965 Parent
->Dcb
.SplayLinksAnsi
= RootNew
;
967 /* Deal with a unicode name if it exists */
968 if (FlagOn( Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
))
970 /* Delete the long unicode name link */
971 RootNew
= RtlDelete(&Fcb
->LongName
.Links
);
973 /* Set the new root */
974 Parent
->Dcb
.SplayLinksUnicode
= RootNew
;
976 /* Free the long name string's buffer*/
977 RtlFreeUnicodeString(&Fcb
->LongName
.Name
.String
);
979 /* Clear the "has unicode name" flag */
980 ClearFlag(Fcb
->State
, FCB_STATE_HAS_UNICODE_NAME
);
983 /* This FCB has no names added to splay trees now */
984 ClearFlag(Fcb
->State
, FCB_STATE_HAS_NAMES
);