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
->RFCB
.NodeTypeCode
= NODE_TYPE_FCB
;
102 Fcb
->RFCB
.NodeByteSize
= sizeof(VFATFCB
);
104 Fcb
->PathNameU
.Length
= 0;
105 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
106 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
107 Fcb
->ShortNameU
.Length
= 0;
108 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
109 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
110 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
111 if (NameU
&& NameU
->Length
)
113 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
114 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
118 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
119 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
120 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
122 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
123 Fcb
->OpenHandleCount
= 0;
128 PDEVICE_EXTENSION pVCB
,
129 PUNICODE_STRING pFileNameU
)
133 DPRINT("'%wZ'\n", pFileNameU
);
135 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
140 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
141 vfatInitFcb(rcFCB
, pFileNameU
);
142 if (vfatVolumeIsFatX(pVCB
))
143 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
;
156 InitializeListHead(&rcFCB
->ParentListHead
);
164 PDEVICE_EXTENSION pVCB
,
171 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
172 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
174 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
176 entry
= pVCB
->FcbHashTable
[ShortIndex
];
177 if (entry
->self
== pFCB
)
179 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
183 while (entry
->next
->self
!= pFCB
)
187 entry
->next
= pFCB
->ShortHash
.next
;
190 entry
= pVCB
->FcbHashTable
[Index
];
191 if (entry
->self
== pFCB
)
193 pVCB
->FcbHashTable
[Index
] = entry
->next
;
197 while (entry
->next
->self
!= pFCB
)
201 entry
->next
= pFCB
->Hash
.next
;
204 RemoveEntryList(&pFCB
->FcbListEntry
);
210 PVFATFCB directoryFCB
,
211 PUNICODE_STRING LongNameU
,
212 PUNICODE_STRING ShortNameU
,
213 PUNICODE_STRING NameU
)
215 PWCHAR PathNameBuffer
;
216 USHORT PathNameLength
;
218 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(LongNameU
->Length
, ShortNameU
->Length
);
219 if (!vfatFCBIsRoot(directoryFCB
))
221 PathNameLength
+= sizeof(WCHAR
);
224 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
226 return STATUS_OBJECT_NAME_INVALID
;
228 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
231 return STATUS_INSUFFICIENT_RESOURCES
;
233 NameU
->Buffer
= PathNameBuffer
;
235 NameU
->MaximumLength
= PathNameLength
;
237 RtlCopyUnicodeString(NameU
, &directoryFCB
->PathNameU
);
238 if (!vfatFCBIsRoot(directoryFCB
))
240 RtlAppendUnicodeToString(NameU
, L
"\\");
242 if (LongNameU
->Length
> 0)
244 RtlAppendUnicodeStringToString(NameU
, LongNameU
);
248 RtlAppendUnicodeStringToString(NameU
, ShortNameU
);
250 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
252 return STATUS_SUCCESS
;
259 if (pCcb
->SearchPattern
.Buffer
)
261 ExFreePoolWithTag(pCcb
->SearchPattern
.Buffer
, TAG_VFAT
);
263 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
270 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
271 if (!vfatFCBIsRoot(pFCB
) &&
272 !BooleanFlagOn(pFCB
->Flags
, FCB_IS_FAT
) && !BooleanFlagOn(pFCB
->Flags
, FCB_IS_VOLUME
))
274 RemoveEntryList(&pFCB
->ParentListEntry
);
276 ExFreePool(pFCB
->PathNameBuffer
);
277 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
278 ExDeleteResourceLite(&pFCB
->MainResource
);
279 ASSERT(IsListEmpty(&pFCB
->ParentListHead
));
280 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
287 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
292 PDEVICE_EXTENSION pVCB
,
295 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
297 ASSERT(pFCB
!= pVCB
->VolumeFcb
);
298 ASSERT(pFCB
->RefCount
> 0);
304 PDEVICE_EXTENSION pVCB
,
309 DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
310 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
312 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
318 ASSERT(pFCB
!= pVCB
->VolumeFcb
);
319 ASSERT(pFCB
->RefCount
> 0);
320 RefCount
= --pFCB
->RefCount
;
322 if (RefCount
== 1 && BooleanFlagOn(pFCB
->Flags
, FCB_CACHE_INITIALIZED
))
324 PFILE_OBJECT tmpFileObject
;
325 tmpFileObject
= pFCB
->FileObject
;
327 pFCB
->FileObject
= NULL
;
328 CcUninitializeCacheMap(tmpFileObject
, NULL
, NULL
);
329 ClearFlag(pFCB
->Flags
, FCB_CACHE_INITIALIZED
);
330 ObDereferenceObject(tmpFileObject
);
335 ASSERT(pFCB
->OpenHandleCount
== 0);
336 tmpFcb
= pFCB
->parentFcb
;
337 vfatDelFCBFromTable(pVCB
, pFCB
);
338 vfatDestroyFCB(pFCB
);
351 PDEVICE_EXTENSION pVCB
,
357 ASSERT(pFCB
->Hash
.Hash
== vfatNameHash(0, &pFCB
->PathNameU
));
358 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
359 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
361 InsertTailList(&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
363 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
364 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
365 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
367 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
368 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
372 vfatGrabFCB(pVCB
, pFCB
->parentFcb
);
378 vfatInitFCBFromDirEntry(
379 PDEVICE_EXTENSION Vcb
,
381 PVFAT_DIRENTRY_CONTEXT DirContext
)
385 RtlCopyMemory(&Fcb
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
386 RtlCopyUnicodeString(&Fcb
->ShortNameU
, &DirContext
->ShortNameU
);
387 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
388 if (vfatVolumeIsFatX(Vcb
))
390 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
394 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
395 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
398 if (vfatFCBIsDirectory(Fcb
))
400 ULONG FirstCluster
, CurrentCluster
;
401 NTSTATUS Status
= STATUS_SUCCESS
;
403 FirstCluster
= vfatDirEntryGetFirstCluster(Vcb
, &Fcb
->entry
);
404 if (FirstCluster
== 1)
406 Size
= Vcb
->FatInfo
.rootDirectorySectors
* Vcb
->FatInfo
.BytesPerSector
;
408 else if (FirstCluster
!= 0)
410 CurrentCluster
= FirstCluster
;
411 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
413 Size
+= Vcb
->FatInfo
.BytesPerCluster
;
414 Status
= NextCluster(Vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
418 else if (vfatVolumeIsFatX(Vcb
))
420 Size
= Fcb
->entry
.FatX
.FileSize
;
424 Size
= Fcb
->entry
.Fat
.FileSize
;
426 Fcb
->dirIndex
= DirContext
->DirIndex
;
427 Fcb
->startIndex
= DirContext
->StartIndex
;
428 if (vfatVolumeIsFatX(Vcb
) && !vfatFCBIsRoot(Fcb
))
430 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
431 Fcb
->dirIndex
= DirContext
->DirIndex
-2;
432 Fcb
->startIndex
= DirContext
->StartIndex
-2;
434 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
435 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
436 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, Vcb
->FatInfo
.BytesPerCluster
);
440 vfatSetFCBNewDirName(
441 PDEVICE_EXTENSION pVCB
,
446 UNICODE_STRING NewNameU
;
448 /* Get full path name */
449 Status
= vfatMakeFullName(ParentFcb
, &Fcb
->LongNameU
, &Fcb
->ShortNameU
, &NewNameU
);
450 if (!NT_SUCCESS(Status
))
455 /* Delete old name */
456 if (Fcb
->PathNameBuffer
)
458 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
460 Fcb
->PathNameU
= NewNameU
;
462 /* Delete from table */
463 vfatDelFCBFromTable(pVCB
, Fcb
);
465 /* Split it properly */
466 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
467 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
468 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
469 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
470 if (vfatVolumeIsFatX(pVCB
))
472 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
476 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
477 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
480 vfatAddFCBToTable(pVCB
, Fcb
);
481 vfatReleaseFCB(pVCB
, ParentFcb
);
483 return STATUS_SUCCESS
;
488 PDEVICE_EXTENSION pVCB
,
490 PVFAT_DIRENTRY_CONTEXT DirContext
,
496 DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB
, Fcb
, DirContext
, ParentFcb
);
498 /* Get full path name */
499 Status
= vfatMakeFullName(ParentFcb
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &Fcb
->PathNameU
);
500 if (!NT_SUCCESS(Status
))
505 /* Delete old name */
506 if (Fcb
->PathNameBuffer
)
508 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
511 /* Delete from table */
512 vfatDelFCBFromTable(pVCB
, Fcb
);
514 /* Split it properly */
515 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
516 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
517 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
519 /* Save old parent */
520 OldParent
= Fcb
->parentFcb
;
521 RemoveEntryList(&Fcb
->ParentListEntry
);
524 vfatInitFCBFromDirEntry(pVCB
, Fcb
, DirContext
);
526 if (vfatFCBIsDirectory(Fcb
))
528 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
530 Fcb
->parentFcb
= ParentFcb
;
531 InsertTailList(&ParentFcb
->ParentListHead
, &Fcb
->ParentListEntry
);
532 vfatAddFCBToTable(pVCB
, Fcb
);
534 /* If we moved across directories, dereference our old parent
535 * We also dereference in case we're just renaming since AddFCBToTable references it
537 vfatReleaseFCB(pVCB
, OldParent
);
539 return STATUS_SUCCESS
;
543 vfatGrabFCBFromTable(
544 PDEVICE_EXTENSION pVCB
,
545 PUNICODE_STRING PathNameU
)
549 UNICODE_STRING DirNameU
;
550 UNICODE_STRING FileNameU
;
551 PUNICODE_STRING FcbNameU
;
555 DPRINT("'%wZ'\n", PathNameU
);
557 ASSERT(PathNameU
->Length
>= sizeof(WCHAR
) && PathNameU
->Buffer
[0] == L
'\\');
558 Hash
= vfatNameHash(0, PathNameU
);
560 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
563 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
568 if (entry
->Hash
== Hash
)
571 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
572 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
574 if (rcFCB
->Hash
.Hash
== Hash
)
576 FcbNameU
= &rcFCB
->LongNameU
;
580 FcbNameU
= &rcFCB
->ShortNameU
;
582 /* compare the file name */
583 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
584 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
586 vfatGrabFCB(pVCB
, rcFCB
);
598 vfatFCBInitializeCacheFromVolume(
602 PFILE_OBJECT fileObject
;
606 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
608 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
611 ObDereferenceObject(fileObject
);
612 return STATUS_INSUFFICIENT_RESOURCES
;
614 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
616 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
617 fileObject
->FsContext
= fcb
;
618 fileObject
->FsContext2
= newCCB
;
619 fcb
->FileObject
= fileObject
;
623 CcInitializeCacheMap(fileObject
,
624 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
626 &VfatGlobalData
->CacheMgrCallbacks
,
629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
631 status
= _SEH2_GetExceptionCode();
632 fcb
->FileObject
= NULL
;
633 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, newCCB
);
634 ObDereferenceObject(fileObject
);
639 vfatGrabFCB(vcb
, fcb
);
640 SetFlag(fcb
->Flags
, FCB_CACHE_INITIALIZED
);
641 return STATUS_SUCCESS
;
646 PDEVICE_EXTENSION pVCB
)
649 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
650 NTSTATUS Status
= STATUS_SUCCESS
;
651 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
653 FCB
= vfatNewFCB(pVCB
, &NameU
);
654 if (vfatVolumeIsFatX(pVCB
))
656 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
657 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
658 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
659 FCB
->entry
.FatX
.FirstCluster
= 1;
660 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
664 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
665 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
666 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
667 if (pVCB
->FatInfo
.FatType
== FAT32
)
669 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
670 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
671 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
673 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
675 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
676 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
681 FCB
->entry
.Fat
.FirstCluster
= 1;
682 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
685 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
688 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
689 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
690 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
691 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
693 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
694 vfatAddFCBToTable(pVCB
, FCB
);
701 PDEVICE_EXTENSION pVCB
)
704 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
706 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
709 FCB
= vfatMakeRootFCB(pVCB
);
716 vfatMakeFCBFromDirEntry(
718 PVFATFCB directoryFCB
,
719 PVFAT_DIRENTRY_CONTEXT DirContext
,
723 UNICODE_STRING NameU
;
726 Status
= vfatMakeFullName(directoryFCB
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &NameU
);
727 if (!NT_SUCCESS(Status
))
732 rcFCB
= vfatNewFCB(vcb
, &NameU
);
733 vfatInitFCBFromDirEntry(vcb
, rcFCB
, DirContext
);
736 if (vfatFCBIsDirectory(rcFCB
))
738 Status
= vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
739 if (!NT_SUCCESS(Status
))
741 vfatReleaseFCB(vcb
, rcFCB
);
742 ExFreePoolWithTag(NameU
.Buffer
, TAG_FCB
);
746 rcFCB
->parentFcb
= directoryFCB
;
747 InsertTailList(&directoryFCB
->ParentListHead
, &rcFCB
->ParentListEntry
);
748 vfatAddFCBToTable(vcb
, rcFCB
);
751 ExFreePoolWithTag(NameU
.Buffer
, TAG_FCB
);
752 return STATUS_SUCCESS
;
756 vfatAttachFCBToFileObject(
757 PDEVICE_EXTENSION vcb
,
759 PFILE_OBJECT fileObject
)
763 UNREFERENCED_PARAMETER(vcb
);
765 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
768 return STATUS_INSUFFICIENT_RESOURCES
;
770 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
772 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
773 fileObject
->FsContext
= fcb
;
774 fileObject
->FsContext2
= newCCB
;
775 DPRINT("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
777 return STATUS_SUCCESS
;
782 PDEVICE_EXTENSION pDeviceExt
,
783 PVFATFCB pDirectoryFCB
,
784 PUNICODE_STRING FileToFindU
,
788 PVOID Context
= NULL
;
790 BOOLEAN First
= TRUE
;
791 VFAT_DIRENTRY_CONTEXT DirContext
;
792 /* This buffer must have a size of 260 characters, because
793 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
794 WCHAR LongNameBuffer
[260];
795 WCHAR ShortNameBuffer
[13];
796 BOOLEAN FoundLong
= FALSE
;
797 BOOLEAN FoundShort
= FALSE
;
798 BOOLEAN IsFatX
= vfatVolumeIsFatX(pDeviceExt
);
801 ASSERT(pDirectoryFCB
);
804 DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
805 pDeviceExt
, pDirectoryFCB
, FileToFindU
);
806 DPRINT("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
808 DirContext
.DirIndex
= 0;
809 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
810 DirContext
.LongNameU
.Length
= 0;
811 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
812 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
813 DirContext
.ShortNameU
.Length
= 0;
814 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
818 status
= VfatGetNextDirEntry(pDeviceExt
,
825 if (status
== STATUS_NO_MORE_ENTRIES
)
827 return STATUS_OBJECT_NAME_NOT_FOUND
;
829 if (!NT_SUCCESS(status
))
834 DPRINT(" Index:%u longName:%wZ\n",
835 DirContext
.DirIndex
, &DirContext
.LongNameU
);
837 if (!ENTRY_VOLUME(IsFatX
, &DirContext
.DirEntry
))
839 if (DirContext
.LongNameU
.Length
== 0 ||
840 DirContext
.ShortNameU
.Length
== 0)
842 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
843 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
845 ASSERT(DirContext
.LongNameU
.Length
!= 0 &&
846 DirContext
.ShortNameU
.Length
!= 0);
848 DirContext
.DirIndex
++;
851 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
852 if (FoundLong
== FALSE
)
854 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
856 if (FoundLong
|| FoundShort
)
858 status
= vfatMakeFCBFromDirEntry(pDeviceExt
,
862 CcUnpinData(Context
);
866 DirContext
.DirIndex
++;
869 return STATUS_OBJECT_NAME_NOT_FOUND
;
874 PDEVICE_EXTENSION pVCB
,
875 PVFATFCB
*pParentFCB
,
877 PUNICODE_STRING pFileNameU
)
882 UNICODE_STRING NameU
;
883 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
884 UNICODE_STRING FileNameU
;
885 WCHAR NameBuffer
[260];
886 PWCHAR curr
, prev
, last
;
889 DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
890 pVCB
, pParentFCB
, pFCB
, pFileNameU
);
892 RtlInitEmptyUnicodeString(&FileNameU
, NameBuffer
, sizeof(NameBuffer
));
894 parentFCB
= *pParentFCB
;
896 if (parentFCB
== NULL
)
898 /* Passed-in name is the full name */
899 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
901 // Trivial case, open of the root directory on volume
902 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
904 DPRINT("returning root FCB\n");
906 FCB
= vfatOpenRootFCB(pVCB
);
910 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
913 /* Check for an existing FCB */
914 FCB
= vfatGrabFCBFromTable(pVCB
, &FileNameU
);
918 *pParentFCB
= FCB
->parentFcb
;
919 vfatGrabFCB(pVCB
, *pParentFCB
);
920 return STATUS_SUCCESS
;
923 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
924 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
929 if (curr
> FileNameU
.Buffer
)
931 NameU
.Buffer
= FileNameU
.Buffer
;
932 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
933 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
936 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
937 if (Length
!= FCB
->PathNameU
.Length
)
939 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
941 vfatReleaseFCB(pVCB
, FCB
);
942 return STATUS_OBJECT_NAME_INVALID
;
944 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
945 curr
, FileNameU
.Length
- Length
);
946 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
947 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
948 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
950 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
960 FCB
= vfatOpenRootFCB(pVCB
);
961 curr
= FileNameU
.Buffer
;
969 /* Make absolute path */
970 RtlCopyUnicodeString(&FileNameU
, &parentFCB
->PathNameU
);
971 curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
974 RtlAppendUnicodeToString(&FileNameU
, L
"\\");
977 ASSERT(*curr
== L
'\\');
978 RtlAppendUnicodeStringToString(&FileNameU
, pFileNameU
);
983 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
990 vfatReleaseFCB(pVCB
, parentFCB
);
993 // fail if element in FCB is not a directory
994 if (!vfatFCBIsDirectory(FCB
))
996 DPRINT ("Element in requested path is not a directory\n");
998 vfatReleaseFCB(pVCB
, FCB
);
1003 return STATUS_OBJECT_PATH_NOT_FOUND
;
1008 Length
= (curr
- prev
) * sizeof(WCHAR
);
1009 if (Length
!= parentFCB
->LongNameU
.Length
)
1011 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
1013 vfatReleaseFCB(pVCB
, parentFCB
);
1016 return STATUS_OBJECT_NAME_INVALID
;
1018 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
1019 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
1020 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
1021 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
1022 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1024 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
1028 while (*curr
!= L
'\\' && curr
<= last
)
1032 NameU
.Buffer
= FileNameU
.Buffer
;
1033 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
1034 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
1035 DPRINT("%wZ\n", &NameU
);
1036 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
1039 NameU
.Buffer
= prev
;
1040 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
1041 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
1042 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1047 *pParentFCB
= parentFCB
;
1048 return STATUS_OBJECT_NAME_NOT_FOUND
;
1052 vfatReleaseFCB(pVCB
, parentFCB
);
1054 return STATUS_OBJECT_PATH_NOT_FOUND
;
1057 else if (!NT_SUCCESS(status
))
1059 vfatReleaseFCB(pVCB
, parentFCB
);
1068 *pParentFCB
= parentFCB
;
1071 return STATUS_SUCCESS
;