Merge trunk head (r43756)
[reactos.git] / reactos / drivers / filesystems / fastfat_new / fcb.c
1 /*
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>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 #define TAG_FILENAME 'fBnF'
15
16 /* FUNCTIONS ****************************************************************/
17
18 FSRTL_COMPARISON_RESULT
19 NTAPI
20 FatiCompareNames(PSTRING NameA,
21 PSTRING NameB)
22 {
23 ULONG MinimumLen, i;
24
25 /* Calc the minimum length */
26 MinimumLen = NameA->Length < NameB->Length ? NameA->Length :
27 NameB->Length;
28
29 /* Actually compare them */
30 i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinimumLen );
31
32 if (i < MinimumLen)
33 {
34 /* Compare prefixes */
35 if (NameA->Buffer[i] < NameB->Buffer[i])
36 return LessThan;
37 else
38 return GreaterThan;
39 }
40
41 /* Final comparison */
42 if (NameA->Length < NameB->Length)
43 return LessThan;
44 else if (NameA->Length > NameB->Length)
45 return GreaterThan;
46 else
47 return EqualTo;
48 }
49
50 PFCB
51 NTAPI
52 FatFindFcb(PFAT_IRP_CONTEXT IrpContext,
53 PRTL_SPLAY_LINKS *RootNode,
54 PSTRING AnsiName,
55 PBOOLEAN IsDosName)
56 {
57 PFCB_NAME_LINK Node;
58 FSRTL_COMPARISON_RESULT Comparison;
59 PRTL_SPLAY_LINKS Links;
60
61 Links = *RootNode;
62
63 while (Links)
64 {
65 Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
66
67 /* Compare the prefix */
68 if (*(PUCHAR)Node->Name.Ansi.Buffer != *(PUCHAR)AnsiName->Buffer)
69 {
70 if (*(PUCHAR)Node->Name.Ansi.Buffer < *(PUCHAR)AnsiName->Buffer)
71 Comparison = LessThan;
72 else
73 Comparison = GreaterThan;
74 }
75 else
76 {
77 /* Perform real comparison */
78 Comparison = FatiCompareNames(&Node->Name.Ansi, AnsiName);
79 }
80
81 /* Do they match? */
82 if (Comparison == GreaterThan)
83 {
84 /* No, it's greater, go to the left child */
85 Links = RtlLeftChild(Links);
86 }
87 else if (Comparison == LessThan)
88 {
89 /* No, it's lesser, go to the right child */
90 Links = RtlRightChild(Links);
91 }
92 else
93 {
94 /* Exact match, balance the tree */
95 *RootNode = RtlSplay(Links);
96
97 /* Save type of the name, if needed */
98 if (IsDosName)
99 *IsDosName = Node->IsDosName;
100
101 /* Return the found fcb */
102 return Node->Fcb;
103 }
104 }
105
106 /* Nothing found */
107 return NULL;
108 }
109
110 PFCB
111 NTAPI
112 FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext,
113 IN PVCB Vcb,
114 IN PFCB ParentDcb,
115 IN FF_FILE *FileHandle)
116 {
117 PFCB Fcb;
118
119 /* Allocate it and zero it */
120 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB);
121 RtlZeroMemory(Fcb, sizeof(FCB));
122
123 /* Set node types */
124 Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
125 Fcb->Header.NodeByteSize = sizeof(FCB);
126 Fcb->Condition = FcbGood;
127
128 /* Initialize resources */
129 Fcb->Header.Resource = &Fcb->Resource;
130 ExInitializeResourceLite(Fcb->Header.Resource);
131
132 Fcb->Header.PagingIoResource = &Fcb->PagingIoResource;
133 ExInitializeResourceLite(Fcb->Header.PagingIoResource);
134
135 /* Initialize mutexes */
136 Fcb->Header.FastMutex = &Fcb->HeaderMutex;
137 ExInitializeFastMutex(&Fcb->HeaderMutex);
138 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
139
140 /* Insert into parent's DCB list */
141 InsertTailList(&ParentDcb->Dcb.ParentDcbList, &Fcb->ParentDcbLinks);
142
143 /* Set backlinks */
144 Fcb->ParentFcb = ParentDcb;
145 Fcb->Vcb = Vcb;
146
147 /* Set file handle and sizes */
148 Fcb->Header.FileSize.LowPart = FileHandle->Filesize;
149 Fcb->Header.ValidDataLength.LowPart = FileHandle->Filesize;
150 Fcb->FatHandle = FileHandle;
151
152 /* Set names */
153 FatSetFcbNames(IrpContext, Fcb);
154
155 return Fcb;
156 }
157
158 PCCB
159 NTAPI
160 FatCreateCcb()
161 {
162 PCCB Ccb;
163
164 /* Allocate the CCB and zero it */
165 Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB);
166 RtlZeroMemory(Ccb, sizeof(CCB));
167
168 /* Set mandatory header */
169 Ccb->NodeTypeCode = FAT_NTC_FCB;
170 Ccb->NodeByteSize = sizeof(CCB);
171
172 return Ccb;
173 }
174
175 IO_STATUS_BLOCK
176 NTAPI
177 FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext,
178 IN PFILE_OBJECT FileObject,
179 IN PVCB Vcb,
180 IN PFCB Fcb,
181 IN PACCESS_MASK DesiredAccess,
182 IN USHORT ShareAccess,
183 IN ULONG AllocationSize,
184 IN PFILE_FULL_EA_INFORMATION EaBuffer,
185 IN ULONG EaLength,
186 IN UCHAR FileAttributes,
187 IN ULONG CreateDisposition,
188 IN BOOLEAN NoEaKnowledge,
189 IN BOOLEAN DeleteOnClose,
190 IN BOOLEAN OpenedAsDos,
191 OUT PBOOLEAN OplockPostIrp)
192 {
193 IO_STATUS_BLOCK Iosb = {{0}};
194 ACCESS_MASK AddedAccess = 0;
195 BOOLEAN Hidden;
196 BOOLEAN System;
197 PCCB Ccb = NULL;
198 NTSTATUS Status;
199
200 /* Acquire exclusive FCB lock */
201 (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
202
203 *OplockPostIrp = FALSE;
204
205 /* Check if there is a batch oplock */
206 if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock))
207 {
208 /* Return with a special information field */
209 Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
210
211 /* Check the oplock */
212 Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
213 IrpContext->Irp,
214 IrpContext,
215 FatOplockComplete,
216 FatPrePostIrp);
217
218 if (Iosb.Status != STATUS_SUCCESS &&
219 Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
220 {
221 /* The Irp needs to be queued */
222 *OplockPostIrp = TRUE;
223
224 /* Release the FCB and return */
225 FatReleaseFcb(IrpContext, Fcb);
226 return Iosb;
227 }
228 }
229
230 /* Validate parameters and modify access */
231 if (CreateDisposition == FILE_CREATE)
232 {
233 Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
234
235 /* Release the FCB and return */
236 FatReleaseFcb(IrpContext, Fcb);
237 return Iosb;
238 }
239 else if (CreateDisposition == FILE_SUPERSEDE)
240 {
241 SetFlag(AddedAccess, DELETE & ~(*DesiredAccess));
242 *DesiredAccess |= DELETE;
243 }
244 else if ((CreateDisposition == FILE_OVERWRITE) ||
245 (CreateDisposition == FILE_OVERWRITE_IF))
246 {
247 SetFlag(AddedAccess,
248 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
249 & ~(*DesiredAccess) );
250
251 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
252 }
253
254 // TODO: Check desired access
255
256 // TODO: Check if this file is readonly and DeleteOnClose is set
257
258 /* Validate disposition information */
259 if ((CreateDisposition == FILE_SUPERSEDE) ||
260 (CreateDisposition == FILE_OVERWRITE) ||
261 (CreateDisposition == FILE_OVERWRITE_IF))
262 {
263 // TODO: Get this attributes from the dirent
264 Hidden = FALSE;
265 System = FALSE;
266
267 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
268 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM)))
269 {
270 DPRINT1("Hidden/system attributes don't match\n");
271
272 Iosb.Status = STATUS_ACCESS_DENIED;
273
274 /* Release the FCB and return */
275 FatReleaseFcb(IrpContext, Fcb);
276 return Iosb;
277 }
278
279 // TODO: Check for write protected volume
280 }
281
282 /* Check share access */
283 Iosb.Status = IoCheckShareAccess(*DesiredAccess,
284 ShareAccess,
285 FileObject,
286 &Fcb->ShareAccess,
287 FALSE);
288 if (!NT_SUCCESS(Iosb.Status))
289 {
290 /* Release the FCB and return */
291 FatReleaseFcb(IrpContext, Fcb);
292 return Iosb;
293 }
294
295 /* Check the oplock status after checking for share access */
296 Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
297 IrpContext->Irp,
298 IrpContext,
299 FatOplockComplete,
300 FatPrePostIrp );
301
302 if (Iosb.Status != STATUS_SUCCESS &&
303 Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
304 {
305 /* The Irp needs to be queued */
306 *OplockPostIrp = TRUE;
307
308 /* Release the FCB and return */
309 FatReleaseFcb(IrpContext, Fcb);
310 return Iosb;
311 }
312
313 /* Set Fast I/O flag */
314 Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb);
315
316 /* Make sure image is not mapped */
317 if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA))
318 {
319 /* Try to flush the image section */
320 if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite))
321 {
322 /* Yes, image section exists, set correct status code */
323 if (DeleteOnClose)
324 Iosb.Status = STATUS_CANNOT_DELETE;
325 else
326 Iosb.Status = STATUS_SHARING_VIOLATION;
327
328 /* Release the FCB and return */
329 FatReleaseFcb(IrpContext, Fcb);
330 return Iosb;
331 }
332 }
333
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))
338 {
339 /* Set the flag that create is in progress */
340 SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);
341
342 /* Flush the cache */
343 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
344
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 );
349
350 /* Delete the cache section */
351 CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE);
352
353 /* Clear the flag */
354 ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);
355 }
356
357 /* Check create disposition flags and branch accordingly */
358 if (CreateDisposition == FILE_OPEN ||
359 CreateDisposition == FILE_OPEN_IF)
360 {
361 DPRINT("Opening a file\n");
362
363 /* Check if we need to bother with EA */
364 if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/)
365 {
366 UNIMPLEMENTED;
367 }
368
369 /* Set up file object */
370 Ccb = FatCreateCcb(IrpContext);
371 FatSetFileObject(FileObject,
372 UserFileOpen,
373 Fcb,
374 Ccb);
375
376 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
377
378 /* The file is opened */
379 Iosb.Information = FILE_OPENED;
380 goto SuccComplete;
381 }
382 else if ((CreateDisposition == FILE_SUPERSEDE) ||
383 (CreateDisposition == FILE_OVERWRITE) ||
384 (CreateDisposition == FILE_OVERWRITE_IF))
385 {
386 UNIMPLEMENTED;
387 ASSERT(FALSE);
388 }
389 else
390 {
391 /* We can't get here */
392 KeBugCheckEx(FAT_FILE_SYSTEM, CreateDisposition, 0, 0, 0);
393 }
394
395
396 SuccComplete:
397 /* If all is fine */
398 if (Iosb.Status != STATUS_PENDING &&
399 NT_SUCCESS(Iosb.Status))
400 {
401 /* Update access if needed */
402 if (AddedAccess)
403 {
404 /* Remove added access flags from desired access */
405 ClearFlag(*DesiredAccess, AddedAccess);
406
407 /* Check share access */
408 Status = IoCheckShareAccess(*DesiredAccess,
409 ShareAccess,
410 FileObject,
411 &Fcb->ShareAccess,
412 TRUE);
413
414 /* Make sure it's success */
415 ASSERT(Status == STATUS_SUCCESS);
416 }
417 else
418 {
419 /* Update the share access */
420 IoUpdateShareAccess(FileObject, &Fcb->ShareAccess);
421 }
422
423 /* Clear the delay close */
424 ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
425
426 /* Increase counters */
427 Fcb->OpenCount++;
428 Vcb->OpenFileCount++;
429
430 // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
431 }
432
433 return Iosb;
434 }
435
436 VOID
437 NTAPI
438 FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext,
439 IN PFCB Fcb,
440 OUT PUNICODE_STRING LongName)
441 {
442 FF_DIRENT DirEnt;
443 FF_ERROR Err;
444 OEM_STRING ShortName;
445 CHAR ShortNameBuf[13];
446 UCHAR EntryBuffer[32];
447 UCHAR NumLFNs;
448 OEM_STRING LongNameOem;
449 NTSTATUS Status;
450
451 /* Make sure this FCB has a FullFAT handle associated with it */
452 if (Fcb->FatHandle == NULL &&
453 FatNodeType(Fcb) == FAT_NTC_DCB)
454 {
455 /* Open the dir with FullFAT */
456 Fcb->FatHandle = FF_OpenW(Fcb->Vcb->Ioman, &Fcb->FullFileName, FF_MODE_DIR, NULL);
457 if (!Fcb->FatHandle)
458 {
459 ASSERT(FALSE);
460 }
461 }
462
463 /* Get the dir entry */
464 Err = FF_GetEntry(Fcb->Vcb->Ioman,
465 Fcb->FatHandle->DirEntry,
466 Fcb->FatHandle->DirCluster,
467 &DirEnt);
468
469 if (Err != FF_ERR_NONE)
470 {
471 DPRINT1("Error %d getting dirent of a file\n", Err);
472 return;
473 }
474
475 /* Read the dirent to fetch the raw short name */
476 FF_FetchEntry(Fcb->Vcb->Ioman,
477 Fcb->FatHandle->DirCluster,
478 Fcb->FatHandle->DirEntry,
479 EntryBuffer);
480 NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40);
481
482 /* Check if we only have a short name.
483 Convert it to unicode and return if that's the case */
484 if (NumLFNs == 0)
485 {
486 /* Initialize short name string */
487 ShortName.Buffer = ShortNameBuf;
488 ShortName.Length = 0;
489 ShortName.MaximumLength = 12;
490
491 /* Convert raw short name to a proper string */
492 Fati8dot3ToString((PCHAR)EntryBuffer, FALSE, &ShortName);
493
494 /* Convert it to unicode */
495 Status = RtlOemStringToCountedUnicodeString(LongName,
496 &ShortName,
497 FALSE);
498
499 /* Ensure conversion was successful */
500 ASSERT(Status == STATUS_SUCCESS);
501
502 /* Exit */
503 return;
504 }
505
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);
510
511 /* Convert it to unicode */
512 Status = RtlOemStringToUnicodeString(LongName, &LongNameOem, FALSE);
513
514 /* Ensure conversion was successful */
515 ASSERT(Status == STATUS_SUCCESS);
516 }
517
518
519 VOID
520 NTAPI
521 FatSetFullNameInFcb(PFCB Fcb,
522 PUNICODE_STRING Name)
523 {
524 PUNICODE_STRING ParentName;
525
526 /* Make sure this FCB's name wasn't already set */
527 ASSERT(Fcb->FullFileName.Buffer == NULL);
528
529 /* First of all, check exact case name */
530 if (Fcb->ExactCaseLongName.Buffer)
531 {
532 ASSERT(Fcb->ExactCaseLongName.Length != 0);
533
534 /* Use exact case name */
535 Name = &Fcb->ExactCaseLongName;
536 }
537
538 /* Treat root dir different */
539 if (FatNodeType(Fcb->ParentFcb) == FAT_NTC_ROOT_DCB)
540 {
541 /* Set lengths */
542 Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + Name->Length;
543 Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;
544
545 /* Allocate a buffer */
546 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
547 Fcb->FullFileName.Length,
548 TAG_FILENAME);
549
550 /* Prefix with a backslash */
551 Fcb->FullFileName.Buffer[0] = L'\\';
552
553 /* Copy the name here */
554 RtlCopyMemory(&Fcb->FullFileName.Buffer[1],
555 &Name->Buffer[0],
556 Name->Length );
557 }
558 else
559 {
560 ParentName = &Fcb->ParentFcb->FullFileName;
561
562 /* Check if parent's name is set */
563 if (!ParentName->Buffer)
564 return;
565
566 /* Set lengths */
567 Fcb->FullFileName.MaximumLength =
568 ParentName->Length + sizeof(WCHAR) + Name->Length;
569 Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;
570
571 /* Allocate a buffer */
572 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
573 Fcb->FullFileName.Length,
574 TAG_FILENAME );
575
576 /* Copy parent's name here */
577 RtlCopyMemory(&Fcb->FullFileName.Buffer[0],
578 &ParentName->Buffer[0],
579 ParentName->Length );
580
581 /* Add a backslash */
582 Fcb->FullFileName.Buffer[ParentName->Length / sizeof(WCHAR)] = L'\\';
583
584 /* Copy given name here */
585 RtlCopyMemory(&Fcb->FullFileName.Buffer[(ParentName->Length / sizeof(WCHAR)) + 1],
586 &Name->Buffer[0],
587 Name->Length );
588 }
589 }
590
591 VOID
592 NTAPI
593 FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext,
594 IN PFCB Fcb)
595 {
596 UNICODE_STRING LongName;
597 PFCB CurFcb = Fcb;
598 PFCB StopFcb;
599 PWCHAR TmpBuffer;
600 ULONG PathLength = 0;
601
602 /* Do nothing if it's already set */
603 if (Fcb->FullFileName.Buffer) return;
604
605 /* Allocate a temporary buffer */
606 LongName.Length = 0;
607 LongName.MaximumLength = FF_MAX_FILENAME * sizeof(WCHAR);
608 LongName.Buffer =
609 FsRtlAllocatePoolWithTag(PagedPool,
610 FF_MAX_FILENAME * sizeof(WCHAR),
611 TAG_FILENAME);
612
613 /* Go through all parents to calculate needed length */
614 while (CurFcb != Fcb->Vcb->RootDcb)
615 {
616 /* Does current FCB have FullFileName set? */
617 if (CurFcb != Fcb &&
618 CurFcb->FullFileName.Buffer)
619 {
620 /* Yes, just use it! */
621 PathLength += CurFcb->FullFileName.Length;
622
623 Fcb->FullFileName.Buffer =
624 FsRtlAllocatePoolWithTag(PagedPool,
625 PathLength,
626 TAG_FILENAME);
627
628 RtlCopyMemory(Fcb->FullFileName.Buffer,
629 CurFcb->FullFileName.Buffer,
630 CurFcb->FullFileName.Length);
631
632 break;
633 }
634
635 /* Sum up length of a current item */
636 PathLength += CurFcb->FileNameLength + sizeof(WCHAR);
637
638 /* Go to the parent */
639 CurFcb = CurFcb->ParentFcb;
640 }
641
642 /* Allocate FullFileName if it wasn't already allocated above */
643 if (!Fcb->FullFileName.Buffer)
644 {
645 Fcb->FullFileName.Buffer =
646 FsRtlAllocatePoolWithTag(PagedPool,
647 PathLength,
648 TAG_FILENAME);
649 }
650
651 StopFcb = CurFcb;
652
653 CurFcb = Fcb;
654 TmpBuffer = Fcb->FullFileName.Buffer + PathLength / sizeof(WCHAR);
655
656 /* Set lengths */
657 Fcb->FullFileName.Length = PathLength;
658 Fcb->FullFileName.MaximumLength = PathLength;
659
660 while (CurFcb != StopFcb)
661 {
662 /* Get its unicode name */
663 FatGetFcbUnicodeName(IrpContext,
664 CurFcb,
665 &LongName);
666
667 /* Copy it */
668 TmpBuffer -= LongName.Length / sizeof(WCHAR);
669 RtlCopyMemory(TmpBuffer, LongName.Buffer, LongName.Length);
670
671 /* Append with a backslash */
672 TmpBuffer -= 1;
673 *TmpBuffer = L'\\';
674
675 /* Go to the parent */
676 CurFcb = CurFcb->ParentFcb;
677 }
678
679 /* Free the temp buffer */
680 ExFreePool(LongName.Buffer);
681 }
682
683
684 VOID
685 NTAPI
686 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext,
687 IN PFCB Fcb)
688 {
689 FF_DIRENT DirEnt;
690 FF_ERROR Err;
691 POEM_STRING ShortName;
692 CHAR ShortNameRaw[13];
693 UCHAR EntryBuffer[32];
694 UCHAR NumLFNs;
695 PUNICODE_STRING UnicodeName;
696 OEM_STRING LongNameOem;
697 NTSTATUS Status;
698
699 /* Get the dir entry */
700 Err = FF_GetEntry(Fcb->Vcb->Ioman,
701 Fcb->FatHandle->DirEntry,
702 Fcb->FatHandle->DirCluster,
703 &DirEnt);
704
705 if (Err != FF_ERR_NONE)
706 {
707 DPRINT1("Error %d getting dirent of a file\n", Err);
708 return;
709 }
710
711 /* Read the dirent to fetch the raw short name */
712 FF_FetchEntry(Fcb->Vcb->Ioman,
713 Fcb->FatHandle->DirCluster,
714 Fcb->FatHandle->DirEntry,
715 EntryBuffer);
716 NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40);
717 RtlCopyMemory(ShortNameRaw, EntryBuffer, 11);
718
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);
724
725 /* Convert raw short name to a proper string */
726 Fati8dot3ToString(ShortNameRaw, FALSE, ShortName);
727
728 /* Add the short name link */
729 FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksAnsi, &Fcb->ShortName);
730 Fcb->ShortName.Fcb = Fcb;
731
732 /* Get the long file name (if any) */
733 if (NumLFNs > 0)
734 {
735 /* Prepare the oem string */
736 LongNameOem.Buffer = DirEnt.FileName;
737 LongNameOem.MaximumLength = FF_MAX_FILENAME;
738 LongNameOem.Length = strlen(DirEnt.FileName);
739
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);
745
746 /* Convert it to unicode */
747 Status = RtlOemStringToUnicodeString(UnicodeName, &LongNameOem, FALSE);
748 if (!NT_SUCCESS(Status))
749 {
750 ASSERT(FALSE);
751 }
752
753 /* Set its length */
754 Fcb->FileNameLength = UnicodeName->Length;
755
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);
761
762 RtlCopyMemory(Fcb->ExactCaseLongName.Buffer,
763 UnicodeName->Buffer,
764 UnicodeName->Length);
765
766 /* Perform a trick which is done by MS's FASTFAT driver to monocase
767 the filename */
768 RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE);
769 RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE);
770
771 DPRINT("Converted long name: %wZ\n", UnicodeName);
772
773 /* Add the long unicode name link */
774 FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksUnicode, &Fcb->LongName);
775 Fcb->LongName.Fcb = Fcb;
776
777 /* Indicate that this FCB has a unicode long name */
778 SetFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME);
779 }
780 else
781 {
782 /* No LFN, set exact case name to 0 length */
783 Fcb->ExactCaseLongName.Length = 0;
784 Fcb->ExactCaseLongName.MaximumLength = 0;
785
786 /* Set the length based on the short name */
787 Fcb->FileNameLength = RtlOemStringToCountedUnicodeSize(ShortName);
788 }
789
790 /* Mark the fact that names were added to splay trees*/
791 SetFlag(Fcb->State, FCB_STATE_HAS_NAMES);
792 }
793
794 VOID
795 NTAPI
796 Fati8dot3ToString(IN PCHAR FileName,
797 IN BOOLEAN DownCase,
798 OUT POEM_STRING OutString)
799 {
800 ULONG BaseLen, ExtLen;
801 CHAR *cString = OutString->Buffer;
802 ULONG i;
803
804 /* Calc base and ext lens */
805 for (BaseLen = 8; BaseLen > 0; BaseLen--)
806 {
807 if (FileName[BaseLen - 1] != ' ') break;
808 }
809
810 for (ExtLen = 3; ExtLen > 0; ExtLen--)
811 {
812 if (FileName[8 + ExtLen - 1] != ' ') break;
813 }
814
815 /* Process base name */
816 if (BaseLen)
817 {
818 RtlCopyMemory(cString, FileName, BaseLen);
819
820 /* Substitute the e5 thing */
821 if (cString[0] == 0x05) cString[0] = 0xe5;
822
823 /* Downcase if asked to */
824 if (DownCase)
825 {
826 /* Do it manually */
827 for (i = 0; i < BaseLen; i++)
828 {
829 if (cString[i] >= 'A' &&
830 cString[i] <= 'Z')
831 {
832 /* Lowercase it */
833 cString[i] += 'a' - 'A';
834 }
835
836 }
837 }
838 }
839
840 /* Process extension */
841 if (ExtLen)
842 {
843 /* Add the dot */
844 cString[BaseLen] = '.';
845 BaseLen++;
846
847 /* Copy the extension */
848 for (i = 0; i < ExtLen; i++)
849 {
850 cString[BaseLen + i] = FileName[8 + i];
851 }
852
853 /* Lowercase the extension if asked to */
854 if (DownCase)
855 {
856 /* Do it manually */
857 for (i = BaseLen; i < BaseLen + ExtLen; i++)
858 {
859 if (cString[i] >= 'A' &&
860 cString[i] <= 'Z')
861 {
862 /* Lowercase it */
863 cString[i] += 'a' - 'A';
864 }
865 }
866 }
867 }
868
869 /* Set the length */
870 OutString->Length = BaseLen + ExtLen;
871
872 DPRINT("'%s', len %d\n", OutString->Buffer, OutString->Length);
873 }
874
875 VOID
876 NTAPI
877 FatInsertName(IN PFAT_IRP_CONTEXT IrpContext,
878 IN PRTL_SPLAY_LINKS *RootNode,
879 IN PFCB_NAME_LINK Name)
880 {
881 PFCB_NAME_LINK NameLink;
882 FSRTL_COMPARISON_RESULT Comparison;
883
884 /* Initialize the splay links */
885 RtlInitializeSplayLinks(&Name->Links);
886
887 /* Is this the first entry? */
888 if (*RootNode == NULL)
889 {
890 /* Yes, become root and return */
891 *RootNode = &Name->Links;
892 return;
893 }
894
895 /* Get the name link */
896 NameLink = CONTAINING_RECORD(*RootNode, FCB_NAME_LINK, Links);
897 while (TRUE)
898 {
899 /* Compare the prefix */
900 if (*(PUCHAR)NameLink->Name.Ansi.Buffer != *(PUCHAR)&Name->Name.Ansi.Buffer)
901 {
902 if (*(PUCHAR)NameLink->Name.Ansi.Buffer < *(PUCHAR)&Name->Name.Ansi.Buffer)
903 Comparison = LessThan;
904 else
905 Comparison = GreaterThan;
906 }
907 else
908 {
909 /* Perform real comparison */
910 Comparison = FatiCompareNames(&NameLink->Name.Ansi, &Name->Name.Ansi);
911 }
912
913 /* Check the bad case first */
914 if (Comparison == EqualTo)
915 {
916 /* Must not happen */
917 ASSERT(FALSE);
918 }
919
920 /* Check comparison result */
921 if (Comparison == GreaterThan)
922 {
923 /* Go to the left child */
924 if (!RtlLeftChild(&NameLink->Links))
925 {
926 /* It's absent, insert here and break */
927 RtlInsertAsLeftChild(&NameLink->Links, &Name->Links);
928 break;
929 }
930 else
931 {
932 /* It's present, go inside it */
933 NameLink = CONTAINING_RECORD(RtlLeftChild(&NameLink->Links),
934 FCB_NAME_LINK,
935 Links);
936 }
937 }
938 else
939 {
940 /* Go to the right child */
941 if (!RtlRightChild(&NameLink->Links))
942 {
943 /* It's absent, insert here and break */
944 RtlInsertAsRightChild(&NameLink->Links, &Name->Links);
945 break;
946 }
947 else
948 {
949 /* It's present, go inside it */
950 NameLink = CONTAINING_RECORD(RtlRightChild(&NameLink->Links),
951 FCB_NAME_LINK,
952 Links);
953 }
954 }
955 }
956 }
957
958 VOID
959 NTAPI
960 FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext,
961 IN PFCB Fcb)
962 {
963 PRTL_SPLAY_LINKS RootNew;
964 PFCB Parent;
965
966 /* Reference the parent for simplicity */
967 Parent = Fcb->ParentFcb;
968
969 /* If this FCB hasn't been added to splay trees - just return */
970 if (!FlagOn( Fcb->State, FCB_STATE_HAS_NAMES ))
971 return;
972
973 /* Delete the short name link */
974 RootNew = RtlDelete(&Fcb->ShortName.Links);
975
976 /* Set the new root */
977 Parent->Dcb.SplayLinksAnsi = RootNew;
978
979 /* Deal with a unicode name if it exists */
980 if (FlagOn( Fcb->State, FCB_STATE_HAS_UNICODE_NAME ))
981 {
982 /* Delete the long unicode name link */
983 RootNew = RtlDelete(&Fcb->LongName.Links);
984
985 /* Set the new root */
986 Parent->Dcb.SplayLinksUnicode = RootNew;
987
988 /* Free the long name string's buffer*/
989 RtlFreeUnicodeString(&Fcb->LongName.Name.String);
990
991 /* Clear the "has unicode name" flag */
992 ClearFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME);
993 }
994
995 /* This FCB has no names added to splay trees now */
996 ClearFlag(Fcb->State, FCB_STATE_HAS_NAMES);
997 }
998
999
1000 /* EOF */