2 * FILE: drivers/filesystems/fastfat/fcb.c
3 * PURPOSE: Routines to manipulate FCBs.
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Rex Jolliff (rex@lvcablemodem.com)
8 * Herve Poussineau (reactos@poussine.freesurf.fr)
9 * Pierre Schweitzer (pierre@reactos.org)
12 /* ------------------------------------------------------- INCLUDES */
20 #include <wctype.h> /* towlower prototype */
23 /* -------------------------------------------------------- DEFINES */
25 #define TAG_FCB 'BCFV'
27 /* -------------------------------------------------------- PUBLICS */
33 PUNICODE_STRING NameU
)
39 // LFN could start from "."
40 //ASSERT(NameU->Buffer[0] != L'.');
42 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
46 c
= towlower(*curr
++);
47 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
54 PUNICODE_STRING PathNameU
,
55 PUNICODE_STRING DirNameU
,
56 PUNICODE_STRING FileNameU
)
60 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
61 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
66 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
69 FileNameU
->Buffer
= pName
+ 1;
70 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
74 DirNameU
->Buffer
= PathNameU
->Buffer
;
75 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
76 DirNameU
->MaximumLength
= DirNameU
->Length
;
84 PUNICODE_STRING NameU
)
86 USHORT PathNameBufferLength
;
89 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
91 PathNameBufferLength
= 0;
93 Fcb
->PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
, TAG_FCB
);
94 if (!Fcb
->PathNameBuffer
)
96 /* FIXME: what to do if no more memory? */
97 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
98 KeBugCheckEx(FAT_FILE_SYSTEM
, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
101 Fcb
->PathNameU
.Length
= 0;
102 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
103 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
104 Fcb
->ShortNameU
.Length
= 0;
105 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
106 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
107 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
108 if (NameU
&& NameU
->Length
)
110 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
111 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
115 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
116 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
117 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
119 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
120 Fcb
->OpenHandleCount
= 0;
125 PDEVICE_EXTENSION pVCB
,
126 PUNICODE_STRING pFileNameU
)
130 DPRINT("'%wZ'\n", pFileNameU
);
132 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
137 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
138 vfatInitFcb(rcFCB
, pFileNameU
);
139 if (pVCB
->Flags
& VCB_IS_FATX
)
141 rcFCB
->Flags
|= FCB_IS_FATX_ENTRY
;
142 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
145 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
146 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
147 rcFCB
->Hash
.self
= rcFCB
;
148 rcFCB
->ShortHash
.self
= rcFCB
;
149 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
150 ExInitializeResourceLite(&rcFCB
->MainResource
);
151 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
152 ExInitializeFastMutex(&rcFCB
->LastMutex
);
153 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
154 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
155 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
163 PDEVICE_EXTENSION pVCB
,
170 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
171 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
173 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
175 entry
= pVCB
->FcbHashTable
[ShortIndex
];
176 if (entry
->self
== pFCB
)
178 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
182 while (entry
->next
->self
!= pFCB
)
186 entry
->next
= pFCB
->ShortHash
.next
;
189 entry
= pVCB
->FcbHashTable
[Index
];
190 if (entry
->self
== pFCB
)
192 pVCB
->FcbHashTable
[Index
] = entry
->next
;
196 while (entry
->next
->self
!= pFCB
)
200 entry
->next
= pFCB
->Hash
.next
;
203 RemoveEntryList(&pFCB
->FcbListEntry
);
209 PVFATFCB directoryFCB
,
210 PUNICODE_STRING LongNameU
,
211 PUNICODE_STRING ShortNameU
,
212 PUNICODE_STRING NameU
)
214 PWCHAR PathNameBuffer
;
215 USHORT PathNameLength
;
217 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(LongNameU
->Length
, ShortNameU
->Length
);
218 if (!vfatFCBIsRoot(directoryFCB
))
220 PathNameLength
+= sizeof(WCHAR
);
223 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
225 return STATUS_OBJECT_NAME_INVALID
;
227 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
230 return STATUS_INSUFFICIENT_RESOURCES
;
232 NameU
->Buffer
= PathNameBuffer
;
234 NameU
->MaximumLength
= PathNameLength
;
236 RtlCopyUnicodeString(NameU
, &directoryFCB
->PathNameU
);
237 if (!vfatFCBIsRoot(directoryFCB
))
239 RtlAppendUnicodeToString(NameU
, L
"\\");
241 if (LongNameU
->Length
> 0)
243 RtlAppendUnicodeStringToString(NameU
, LongNameU
);
247 RtlAppendUnicodeStringToString(NameU
, ShortNameU
);
249 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
251 return STATUS_SUCCESS
;
258 if (pCcb
->SearchPattern
.Buffer
)
260 ExFreePoolWithTag(pCcb
->SearchPattern
.Buffer
, TAG_VFAT
);
262 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
269 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
270 ExFreePool(pFCB
->PathNameBuffer
);
271 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
272 ExDeleteResourceLite(&pFCB
->MainResource
);
273 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
280 return ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) == FILE_ATTRIBUTE_DIRECTORY
);
287 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
292 PDEVICE_EXTENSION pVCB
,
297 DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
298 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
303 if (pFCB
->RefCount
== 0)
305 ASSERT(pFCB
->OpenHandleCount
== 0);
306 tmpFcb
= pFCB
->parentFcb
;
307 vfatDelFCBFromTable(pVCB
, pFCB
);
308 vfatDestroyFCB(pFCB
);
321 PDEVICE_EXTENSION pVCB
,
327 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
328 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
330 InsertTailList(&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
332 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
333 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
334 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
336 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
337 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
341 pFCB
->parentFcb
->RefCount
++;
347 PDEVICE_EXTENSION pVCB
,
349 PUNICODE_STRING LongName
,
350 PUNICODE_STRING ShortName
,
356 DPRINT("vfatUpdateFCB(%p, %p, %wZ, %wZ, %p)\n", pVCB
, Fcb
, LongName
, ShortName
, ParentFcb
);
358 /* Delete old name */
359 if (Fcb
->PathNameBuffer
)
361 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
364 /* Delete from table */
365 vfatDelFCBFromTable(pVCB
, Fcb
);
367 /* Get full path name */
368 Status
= vfatMakeFullName(ParentFcb
, LongName
, ShortName
, &Fcb
->PathNameU
);
369 if (!NT_SUCCESS(Status
))
374 /* Split it properly */
375 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
376 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
377 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
379 /* Copy short name */
380 RtlCopyUnicodeString(&Fcb
->ShortNameU
, ShortName
);
382 /* Recompute hashes */
383 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
384 if (pVCB
->Flags
& VCB_IS_FATX
)
386 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
390 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
391 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
395 OldParent
= Fcb
->parentFcb
;
396 Fcb
->parentFcb
= ParentFcb
;
398 /* Add to the table */
399 vfatAddFCBToTable(pVCB
, Fcb
);
401 /* If we moved accross directories, dereferenced our old parent
402 * We also derefence in case we're just renaming since AddFCBToTable references it
404 vfatReleaseFCB(pVCB
, OldParent
);
406 /* In case we were moving accross directories, reset caching on old parent */
407 //if (OldParent != ParentFcb)
409 // CcUninitializeCacheMap(OldParent->FileObject, NULL, NULL);
412 return STATUS_SUCCESS
;
416 vfatGrabFCBFromTable(
417 PDEVICE_EXTENSION pVCB
,
418 PUNICODE_STRING PathNameU
)
422 UNICODE_STRING DirNameU
;
423 UNICODE_STRING FileNameU
;
424 PUNICODE_STRING FcbNameU
;
428 DPRINT("'%wZ'\n", PathNameU
);
430 Hash
= vfatNameHash(0, PathNameU
);
432 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
435 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
440 if (entry
->Hash
== Hash
)
443 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
444 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
446 if (rcFCB
->Hash
.Hash
== Hash
)
448 FcbNameU
= &rcFCB
->LongNameU
;
452 FcbNameU
= &rcFCB
->ShortNameU
;
454 /* compare the file name */
455 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
456 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
470 vfatFCBInitializeCacheFromVolume(
474 PFILE_OBJECT fileObject
;
478 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
480 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
483 ObDereferenceObject(fileObject
);
484 return STATUS_INSUFFICIENT_RESOURCES
;
486 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
488 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
489 fileObject
->FsContext
= fcb
;
490 fileObject
->FsContext2
= newCCB
;
491 fcb
->FileObject
= fileObject
;
496 CcInitializeCacheMap(fileObject
,
497 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
499 &VfatGlobalData
->CacheMgrCallbacks
,
502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
504 status
= _SEH2_GetExceptionCode();
506 fcb
->FileObject
= NULL
;
507 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, newCCB
);
508 ObDereferenceObject(fileObject
);
513 fcb
->Flags
|= FCB_CACHE_INITIALIZED
;
514 return STATUS_SUCCESS
;
519 PDEVICE_EXTENSION pVCB
)
522 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
523 NTSTATUS Status
= STATUS_SUCCESS
;
524 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
526 FCB
= vfatNewFCB(pVCB
, &NameU
);
527 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
529 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
530 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
531 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
532 FCB
->entry
.FatX
.FirstCluster
= 1;
533 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
537 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
538 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
539 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
540 if (pVCB
->FatInfo
.FatType
== FAT32
)
542 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
543 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
544 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
546 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
548 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
549 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
554 FCB
->entry
.Fat
.FirstCluster
= 1;
555 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
558 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
561 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
562 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
563 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
564 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
566 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
567 vfatAddFCBToTable(pVCB
, FCB
);
574 PDEVICE_EXTENSION pVCB
)
577 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
579 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
582 FCB
= vfatMakeRootFCB(pVCB
);
589 vfatMakeFCBFromDirEntry(
591 PVFATFCB directoryFCB
,
592 PVFAT_DIRENTRY_CONTEXT DirContext
,
597 UNICODE_STRING NameU
;
600 Status
= vfatMakeFullName(directoryFCB
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &NameU
);
601 if (!NT_SUCCESS(Status
))
606 rcFCB
= vfatNewFCB(vcb
, &NameU
);
607 RtlCopyMemory(&rcFCB
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
608 RtlCopyUnicodeString(&rcFCB
->ShortNameU
, &DirContext
->ShortNameU
);
609 if (vcb
->Flags
& VCB_IS_FATX
)
611 rcFCB
->ShortHash
.Hash
= rcFCB
->Hash
.Hash
;
615 rcFCB
->ShortHash
.Hash
= vfatNameHash(0, &rcFCB
->DirNameU
);
616 rcFCB
->ShortHash
.Hash
= vfatNameHash(rcFCB
->ShortHash
.Hash
, &rcFCB
->ShortNameU
);
619 if (vfatFCBIsDirectory(rcFCB
))
621 ULONG FirstCluster
, CurrentCluster
;
622 NTSTATUS Status
= STATUS_SUCCESS
;
624 FirstCluster
= vfatDirEntryGetFirstCluster(vcb
, &rcFCB
->entry
);
625 if (FirstCluster
== 1)
627 Size
= vcb
->FatInfo
.rootDirectorySectors
* vcb
->FatInfo
.BytesPerSector
;
629 else if (FirstCluster
!= 0)
631 CurrentCluster
= FirstCluster
;
632 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
634 Size
+= vcb
->FatInfo
.BytesPerCluster
;
635 Status
= NextCluster(vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
639 else if (rcFCB
->Flags
& FCB_IS_FATX_ENTRY
)
641 Size
= rcFCB
->entry
.FatX
.FileSize
;
645 Size
= rcFCB
->entry
.Fat
.FileSize
;
647 rcFCB
->dirIndex
= DirContext
->DirIndex
;
648 rcFCB
->startIndex
= DirContext
->StartIndex
;
649 if ((rcFCB
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot(directoryFCB
))
651 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
652 rcFCB
->dirIndex
= DirContext
->DirIndex
-2;
653 rcFCB
->startIndex
= DirContext
->StartIndex
-2;
655 rcFCB
->RFCB
.FileSize
.QuadPart
= Size
;
656 rcFCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
657 rcFCB
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, vcb
->FatInfo
.BytesPerCluster
);
659 if (vfatFCBIsDirectory(rcFCB
))
661 vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
663 rcFCB
->parentFcb
= directoryFCB
;
664 vfatAddFCBToTable(vcb
, rcFCB
);
667 ExFreePool(NameU
.Buffer
);
668 return STATUS_SUCCESS
;
672 vfatAttachFCBToFileObject(
673 PDEVICE_EXTENSION vcb
,
675 PFILE_OBJECT fileObject
)
679 UNREFERENCED_PARAMETER(vcb
);
681 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
684 return STATUS_INSUFFICIENT_RESOURCES
;
686 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
688 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
689 fileObject
->FsContext
= fcb
;
690 fileObject
->FsContext2
= newCCB
;
691 DPRINT("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
693 return STATUS_SUCCESS
;
698 PDEVICE_EXTENSION pDeviceExt
,
699 PVFATFCB pDirectoryFCB
,
700 PUNICODE_STRING FileToFindU
,
704 PVOID Context
= NULL
;
706 BOOLEAN First
= TRUE
;
707 VFAT_DIRENTRY_CONTEXT DirContext
;
708 /* This buffer must have a size of 260 characters, because
709 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
710 WCHAR LongNameBuffer
[260];
711 WCHAR ShortNameBuffer
[13];
712 BOOLEAN FoundLong
= FALSE
;
713 BOOLEAN FoundShort
= FALSE
;
716 ASSERT(pDirectoryFCB
);
719 DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
720 pDeviceExt
, pDirectoryFCB
, FileToFindU
);
721 DPRINT("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
723 DirContext
.DirIndex
= 0;
724 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
725 DirContext
.LongNameU
.Length
= 0;
726 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
727 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
728 DirContext
.ShortNameU
.Length
= 0;
729 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
733 status
= pDeviceExt
->GetNextDirEntry(&Context
,
739 if (status
== STATUS_NO_MORE_ENTRIES
)
741 return STATUS_OBJECT_NAME_NOT_FOUND
;
743 if (!NT_SUCCESS(status
))
748 DPRINT(" Index:%u longName:%wZ\n",
749 DirContext
.DirIndex
, &DirContext
.LongNameU
);
751 if (!ENTRY_VOLUME(pDeviceExt
, &DirContext
.DirEntry
))
753 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
754 if (FoundLong
== FALSE
)
756 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
758 if (FoundLong
|| FoundShort
)
760 status
= vfatMakeFCBFromDirEntry(pDeviceExt
,
764 CcUnpinData(Context
);
768 DirContext
.DirIndex
++;
771 return STATUS_OBJECT_NAME_NOT_FOUND
;
776 PDEVICE_EXTENSION pVCB
,
777 PVFATFCB
*pParentFCB
,
779 PUNICODE_STRING pFileNameU
)
784 UNICODE_STRING NameU
;
785 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
786 UNICODE_STRING FileNameU
;
787 WCHAR NameBuffer
[260];
788 PWCHAR curr
, prev
, last
;
791 DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
792 pVCB
, pParentFCB
, pFCB
, pFileNameU
);
794 FileNameU
.Buffer
= NameBuffer
;
795 FileNameU
.MaximumLength
= sizeof(NameBuffer
);
796 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
798 parentFCB
= *pParentFCB
;
800 if (parentFCB
== NULL
)
802 // Trivial case, open of the root directory on volume
803 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
805 DPRINT("returning root FCB\n");
807 FCB
= vfatOpenRootFCB(pVCB
);
811 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
814 /* Check for an existing FCB */
815 FCB
= vfatGrabFCBFromTable(pVCB
, &FileNameU
);
819 *pParentFCB
= FCB
->parentFcb
;
820 (*pParentFCB
)->RefCount
++;
821 return STATUS_SUCCESS
;
824 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
825 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
830 if (curr
> FileNameU
.Buffer
)
832 NameU
.Buffer
= FileNameU
.Buffer
;
833 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
834 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
837 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
838 if (Length
!= FCB
->PathNameU
.Length
)
840 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
842 vfatReleaseFCB(pVCB
, FCB
);
843 return STATUS_OBJECT_NAME_INVALID
;
845 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
846 curr
, FileNameU
.Length
- Length
);
847 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
848 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
849 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
851 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
861 FCB
= vfatOpenRootFCB(pVCB
);
862 curr
= FileNameU
.Buffer
;
872 prev
= curr
= FileNameU
.Buffer
- 1;
873 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
880 vfatReleaseFCB(pVCB
, parentFCB
);
883 // fail if element in FCB is not a directory
884 if (!vfatFCBIsDirectory(FCB
))
886 DPRINT ("Element in requested path is not a directory\n");
888 vfatReleaseFCB(pVCB
, FCB
);
893 return STATUS_OBJECT_PATH_NOT_FOUND
;
898 Length
= (curr
- prev
) * sizeof(WCHAR
);
899 if (Length
!= parentFCB
->LongNameU
.Length
)
901 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
903 vfatReleaseFCB(pVCB
, parentFCB
);
904 return STATUS_OBJECT_NAME_INVALID
;
906 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
907 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
908 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
909 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
910 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
912 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
916 while (*curr
!= L
'\\' && curr
<= last
)
920 NameU
.Buffer
= FileNameU
.Buffer
;
921 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
922 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
923 DPRINT("%wZ\n", &NameU
);
924 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
928 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
929 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
930 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
935 *pParentFCB
= parentFCB
;
936 return STATUS_OBJECT_NAME_NOT_FOUND
;
940 vfatReleaseFCB(pVCB
, parentFCB
);
942 return STATUS_OBJECT_PATH_NOT_FOUND
;
945 else if (!NT_SUCCESS(status
))
947 vfatReleaseFCB(pVCB
, parentFCB
);
956 *pParentFCB
= parentFCB
;
959 return STATUS_SUCCESS
;