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'
28 extern UNICODE_STRING DebugFile
;
31 /* -------------------------------------------------------- PUBLICS */
37 PUNICODE_STRING NameU
)
43 // LFN could start from "."
44 //ASSERT(NameU->Buffer[0] != L'.');
46 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
50 c
= towlower(*curr
++);
51 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
58 PUNICODE_STRING PathNameU
,
59 PUNICODE_STRING DirNameU
,
60 PUNICODE_STRING FileNameU
)
64 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
65 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
70 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
73 FileNameU
->Buffer
= pName
+ 1;
74 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
78 DirNameU
->Buffer
= PathNameU
->Buffer
;
79 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
80 DirNameU
->MaximumLength
= DirNameU
->Length
;
88 PUNICODE_STRING NameU
)
90 USHORT PathNameBufferLength
;
93 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
95 PathNameBufferLength
= 0;
97 Fcb
->PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
, TAG_FCB
);
98 if (!Fcb
->PathNameBuffer
)
100 /* FIXME: what to do if no more memory? */
101 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
102 KeBugCheckEx(FAT_FILE_SYSTEM
, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
105 Fcb
->RFCB
.NodeTypeCode
= NODE_TYPE_FCB
;
106 Fcb
->RFCB
.NodeByteSize
= sizeof(VFATFCB
);
108 Fcb
->PathNameU
.Length
= 0;
109 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
110 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
111 Fcb
->ShortNameU
.Length
= 0;
112 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
113 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
114 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
115 if (NameU
&& NameU
->Length
)
117 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
118 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
122 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
123 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
124 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
126 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
127 Fcb
->OpenHandleCount
= 0;
132 PDEVICE_EXTENSION pVCB
,
133 PUNICODE_STRING pFileNameU
)
137 DPRINT("'%wZ'\n", pFileNameU
);
139 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
144 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
145 vfatInitFcb(rcFCB
, pFileNameU
);
146 if (vfatVolumeIsFatX(pVCB
))
147 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
149 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
150 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
151 rcFCB
->Hash
.self
= rcFCB
;
152 rcFCB
->ShortHash
.self
= rcFCB
;
153 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
154 ExInitializeResourceLite(&rcFCB
->MainResource
);
155 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
156 ExInitializeFastMutex(&rcFCB
->LastMutex
);
157 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
158 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
159 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
160 InitializeListHead(&rcFCB
->ParentListHead
);
168 PDEVICE_EXTENSION pVCB
,
175 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
176 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
178 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
180 entry
= pVCB
->FcbHashTable
[ShortIndex
];
181 if (entry
->self
== pFCB
)
183 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
187 while (entry
->next
->self
!= pFCB
)
191 entry
->next
= pFCB
->ShortHash
.next
;
194 entry
= pVCB
->FcbHashTable
[Index
];
195 if (entry
->self
== pFCB
)
197 pVCB
->FcbHashTable
[Index
] = entry
->next
;
201 while (entry
->next
->self
!= pFCB
)
205 entry
->next
= pFCB
->Hash
.next
;
208 RemoveEntryList(&pFCB
->FcbListEntry
);
214 PVFATFCB directoryFCB
,
215 PUNICODE_STRING LongNameU
,
216 PUNICODE_STRING ShortNameU
,
217 PUNICODE_STRING NameU
)
219 PWCHAR PathNameBuffer
;
220 USHORT PathNameLength
;
222 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(LongNameU
->Length
, ShortNameU
->Length
);
223 if (!vfatFCBIsRoot(directoryFCB
))
225 PathNameLength
+= sizeof(WCHAR
);
228 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
230 return STATUS_OBJECT_NAME_INVALID
;
232 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
235 return STATUS_INSUFFICIENT_RESOURCES
;
237 NameU
->Buffer
= PathNameBuffer
;
239 NameU
->MaximumLength
= PathNameLength
;
241 RtlCopyUnicodeString(NameU
, &directoryFCB
->PathNameU
);
242 if (!vfatFCBIsRoot(directoryFCB
))
244 RtlAppendUnicodeToString(NameU
, L
"\\");
246 if (LongNameU
->Length
> 0)
248 RtlAppendUnicodeStringToString(NameU
, LongNameU
);
252 RtlAppendUnicodeStringToString(NameU
, ShortNameU
);
254 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
256 return STATUS_SUCCESS
;
263 if (pCcb
->SearchPattern
.Buffer
)
265 ExFreePoolWithTag(pCcb
->SearchPattern
.Buffer
, TAG_VFAT
);
267 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
275 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
277 DPRINT1("Destroying: %p (%wZ) %d\n", pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
281 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
282 if (!vfatFCBIsRoot(pFCB
) &&
283 !BooleanFlagOn(pFCB
->Flags
, FCB_IS_FAT
) && !BooleanFlagOn(pFCB
->Flags
, FCB_IS_VOLUME
))
285 RemoveEntryList(&pFCB
->ParentListEntry
);
287 ExFreePool(pFCB
->PathNameBuffer
);
288 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
289 ExDeleteResourceLite(&pFCB
->MainResource
);
290 ASSERT(IsListEmpty(&pFCB
->ParentListHead
));
291 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
298 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
307 PDEVICE_EXTENSION pVCB
,
318 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
320 DPRINT1("Inc ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB
->RefCount
, pFCB
->OpenHandleCount
, pFCB
, &pFCB
->PathNameU
, File
, Line
, Func
);
324 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
326 ASSERT(pFCB
!= pVCB
->VolumeFcb
);
327 ASSERT(pFCB
->RefCount
> 0);
337 PDEVICE_EXTENSION pVCB
,
350 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
352 DPRINT1("Dec ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB
->RefCount
, pFCB
->OpenHandleCount
, pFCB
, &pFCB
->PathNameU
, File
, Line
, Func
);
355 DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
356 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
359 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
365 ASSERT(pFCB
!= pVCB
->VolumeFcb
);
366 ASSERT(pFCB
->RefCount
> 0);
367 RefCount
= --pFCB
->RefCount
;
369 if (RefCount
== 1 && BooleanFlagOn(pFCB
->Flags
, FCB_CACHE_INITIALIZED
))
371 PFILE_OBJECT tmpFileObject
;
372 tmpFileObject
= pFCB
->FileObject
;
374 pFCB
->FileObject
= NULL
;
375 CcUninitializeCacheMap(tmpFileObject
, NULL
, NULL
);
376 ClearFlag(pFCB
->Flags
, FCB_CACHE_INITIALIZED
);
377 ObDereferenceObject(tmpFileObject
);
382 ASSERT(pFCB
->OpenHandleCount
== 0);
383 tmpFcb
= pFCB
->parentFcb
;
384 vfatDelFCBFromTable(pVCB
, pFCB
);
385 vfatDestroyFCB(pFCB
);
398 PDEVICE_EXTENSION pVCB
,
404 ASSERT(pFCB
->Hash
.Hash
== vfatNameHash(0, &pFCB
->PathNameU
));
405 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
406 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
408 InsertTailList(&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
410 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
411 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
412 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
414 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
415 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
419 vfatGrabFCB(pVCB
, pFCB
->parentFcb
);
425 vfatInitFCBFromDirEntry(
426 PDEVICE_EXTENSION Vcb
,
428 PVFAT_DIRENTRY_CONTEXT DirContext
)
432 RtlCopyMemory(&Fcb
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
433 RtlCopyUnicodeString(&Fcb
->ShortNameU
, &DirContext
->ShortNameU
);
434 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
435 if (vfatVolumeIsFatX(Vcb
))
437 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
441 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
442 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
445 if (vfatFCBIsDirectory(Fcb
))
447 ULONG FirstCluster
, CurrentCluster
;
448 NTSTATUS Status
= STATUS_SUCCESS
;
450 FirstCluster
= vfatDirEntryGetFirstCluster(Vcb
, &Fcb
->entry
);
451 if (FirstCluster
== 1)
453 Size
= Vcb
->FatInfo
.rootDirectorySectors
* Vcb
->FatInfo
.BytesPerSector
;
455 else if (FirstCluster
!= 0)
457 CurrentCluster
= FirstCluster
;
458 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
460 Size
+= Vcb
->FatInfo
.BytesPerCluster
;
461 Status
= NextCluster(Vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
465 else if (vfatVolumeIsFatX(Vcb
))
467 Size
= Fcb
->entry
.FatX
.FileSize
;
471 Size
= Fcb
->entry
.Fat
.FileSize
;
473 Fcb
->dirIndex
= DirContext
->DirIndex
;
474 Fcb
->startIndex
= DirContext
->StartIndex
;
475 if (vfatVolumeIsFatX(Vcb
) && !vfatFCBIsRoot(Fcb
))
477 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
478 Fcb
->dirIndex
= DirContext
->DirIndex
-2;
479 Fcb
->startIndex
= DirContext
->StartIndex
-2;
481 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
482 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
483 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, Vcb
->FatInfo
.BytesPerCluster
);
487 vfatSetFCBNewDirName(
488 PDEVICE_EXTENSION pVCB
,
493 UNICODE_STRING NewNameU
;
495 /* Get full path name */
496 Status
= vfatMakeFullName(ParentFcb
, &Fcb
->LongNameU
, &Fcb
->ShortNameU
, &NewNameU
);
497 if (!NT_SUCCESS(Status
))
502 /* Delete old name */
503 if (Fcb
->PathNameBuffer
)
505 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
507 Fcb
->PathNameU
= NewNameU
;
509 /* Delete from table */
510 vfatDelFCBFromTable(pVCB
, Fcb
);
512 /* Split it properly */
513 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
514 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
515 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
516 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
517 if (vfatVolumeIsFatX(pVCB
))
519 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
523 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
524 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
527 vfatAddFCBToTable(pVCB
, Fcb
);
528 vfatReleaseFCB(pVCB
, ParentFcb
);
530 return STATUS_SUCCESS
;
535 PDEVICE_EXTENSION pVCB
,
537 PVFAT_DIRENTRY_CONTEXT DirContext
,
543 DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB
, Fcb
, DirContext
, ParentFcb
);
545 /* Get full path name */
546 Status
= vfatMakeFullName(ParentFcb
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &Fcb
->PathNameU
);
547 if (!NT_SUCCESS(Status
))
552 /* Delete old name */
553 if (Fcb
->PathNameBuffer
)
555 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
558 /* Delete from table */
559 vfatDelFCBFromTable(pVCB
, Fcb
);
561 /* Split it properly */
562 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
563 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
564 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
566 /* Save old parent */
567 OldParent
= Fcb
->parentFcb
;
568 RemoveEntryList(&Fcb
->ParentListEntry
);
571 vfatInitFCBFromDirEntry(pVCB
, Fcb
, DirContext
);
573 if (vfatFCBIsDirectory(Fcb
))
575 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
577 Fcb
->parentFcb
= ParentFcb
;
578 InsertTailList(&ParentFcb
->ParentListHead
, &Fcb
->ParentListEntry
);
579 vfatAddFCBToTable(pVCB
, Fcb
);
581 /* If we moved across directories, dereference our old parent
582 * We also dereference in case we're just renaming since AddFCBToTable references it
584 vfatReleaseFCB(pVCB
, OldParent
);
586 return STATUS_SUCCESS
;
590 vfatGrabFCBFromTable(
591 PDEVICE_EXTENSION pVCB
,
592 PUNICODE_STRING PathNameU
)
596 UNICODE_STRING DirNameU
;
597 UNICODE_STRING FileNameU
;
598 PUNICODE_STRING FcbNameU
;
602 DPRINT("'%wZ'\n", PathNameU
);
604 ASSERT(PathNameU
->Length
>= sizeof(WCHAR
) && PathNameU
->Buffer
[0] == L
'\\');
605 Hash
= vfatNameHash(0, PathNameU
);
607 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
610 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
615 if (entry
->Hash
== Hash
)
618 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
619 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
621 if (rcFCB
->Hash
.Hash
== Hash
)
623 FcbNameU
= &rcFCB
->LongNameU
;
627 FcbNameU
= &rcFCB
->ShortNameU
;
629 /* compare the file name */
630 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
631 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
633 vfatGrabFCB(pVCB
, rcFCB
);
645 vfatFCBInitializeCacheFromVolume(
649 PFILE_OBJECT fileObject
;
653 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
656 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &fcb
->LongNameU
, FALSE
, NULL
))
658 DPRINT1("Attaching %p to %p (%d)\n", fcb
, fileObject
, fcb
->RefCount
);
662 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
665 ObDereferenceObject(fileObject
);
666 return STATUS_INSUFFICIENT_RESOURCES
;
668 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
670 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
671 fileObject
->FsContext
= fcb
;
672 fileObject
->FsContext2
= newCCB
;
673 fileObject
->Vpb
= vcb
->IoVPB
;
674 fcb
->FileObject
= fileObject
;
678 CcInitializeCacheMap(fileObject
,
679 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
681 &VfatGlobalData
->CacheMgrCallbacks
,
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
686 status
= _SEH2_GetExceptionCode();
687 fcb
->FileObject
= NULL
;
688 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, newCCB
);
689 ObDereferenceObject(fileObject
);
694 vfatGrabFCB(vcb
, fcb
);
695 SetFlag(fcb
->Flags
, FCB_CACHE_INITIALIZED
);
696 return STATUS_SUCCESS
;
701 PDEVICE_EXTENSION pVCB
)
704 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
705 NTSTATUS Status
= STATUS_SUCCESS
;
706 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
708 FCB
= vfatNewFCB(pVCB
, &NameU
);
709 if (vfatVolumeIsFatX(pVCB
))
711 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
712 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
713 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
714 FCB
->entry
.FatX
.FirstCluster
= 1;
715 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
719 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
720 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
721 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
722 if (pVCB
->FatInfo
.FatType
== FAT32
)
724 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
725 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
726 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
728 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
730 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
731 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
736 FCB
->entry
.Fat
.FirstCluster
= 1;
737 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
740 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
743 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
744 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
745 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
746 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
748 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
749 vfatAddFCBToTable(pVCB
, FCB
);
756 PDEVICE_EXTENSION pVCB
)
759 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
761 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
764 FCB
= vfatMakeRootFCB(pVCB
);
771 vfatMakeFCBFromDirEntry(
773 PVFATFCB directoryFCB
,
774 PVFAT_DIRENTRY_CONTEXT DirContext
,
778 UNICODE_STRING NameU
;
781 Status
= vfatMakeFullName(directoryFCB
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &NameU
);
782 if (!NT_SUCCESS(Status
))
787 rcFCB
= vfatNewFCB(vcb
, &NameU
);
788 vfatInitFCBFromDirEntry(vcb
, rcFCB
, DirContext
);
791 if (vfatFCBIsDirectory(rcFCB
))
793 Status
= vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
794 if (!NT_SUCCESS(Status
))
796 vfatReleaseFCB(vcb
, rcFCB
);
797 ExFreePoolWithTag(NameU
.Buffer
, TAG_FCB
);
801 rcFCB
->parentFcb
= directoryFCB
;
802 InsertTailList(&directoryFCB
->ParentListHead
, &rcFCB
->ParentListEntry
);
803 vfatAddFCBToTable(vcb
, rcFCB
);
806 ExFreePoolWithTag(NameU
.Buffer
, TAG_FCB
);
807 return STATUS_SUCCESS
;
811 vfatAttachFCBToFileObject(
812 PDEVICE_EXTENSION vcb
,
814 PFILE_OBJECT fileObject
)
818 UNREFERENCED_PARAMETER(vcb
);
821 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &fcb
->LongNameU
, FALSE
, NULL
))
823 DPRINT1("Attaching %p to %p (%d)\n", fcb
, fileObject
, fcb
->RefCount
);
827 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
830 return STATUS_INSUFFICIENT_RESOURCES
;
832 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
834 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
835 fileObject
->FsContext
= fcb
;
836 fileObject
->FsContext2
= newCCB
;
837 fileObject
->Vpb
= vcb
->IoVPB
;
838 DPRINT("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
841 fcb
->Flags
&= ~FCB_CLEANED_UP
;
842 fcb
->Flags
&= ~FCB_CLOSED
;
845 return STATUS_SUCCESS
;
850 PDEVICE_EXTENSION pDeviceExt
,
851 PVFATFCB pDirectoryFCB
,
852 PUNICODE_STRING FileToFindU
,
856 PVOID Context
= NULL
;
858 BOOLEAN First
= TRUE
;
859 VFAT_DIRENTRY_CONTEXT DirContext
;
860 /* This buffer must have a size of 260 characters, because
861 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
862 WCHAR LongNameBuffer
[260];
863 WCHAR ShortNameBuffer
[13];
864 BOOLEAN FoundLong
= FALSE
;
865 BOOLEAN FoundShort
= FALSE
;
866 BOOLEAN IsFatX
= vfatVolumeIsFatX(pDeviceExt
);
869 ASSERT(pDirectoryFCB
);
872 DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
873 pDeviceExt
, pDirectoryFCB
, FileToFindU
);
874 DPRINT("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
876 DirContext
.DirIndex
= 0;
877 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
878 DirContext
.LongNameU
.Length
= 0;
879 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
880 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
881 DirContext
.ShortNameU
.Length
= 0;
882 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
886 status
= VfatGetNextDirEntry(pDeviceExt
,
893 if (status
== STATUS_NO_MORE_ENTRIES
)
895 return STATUS_OBJECT_NAME_NOT_FOUND
;
897 if (!NT_SUCCESS(status
))
902 DPRINT(" Index:%u longName:%wZ\n",
903 DirContext
.DirIndex
, &DirContext
.LongNameU
);
905 if (!ENTRY_VOLUME(IsFatX
, &DirContext
.DirEntry
))
907 if (DirContext
.LongNameU
.Length
== 0 ||
908 DirContext
.ShortNameU
.Length
== 0)
910 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
911 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
913 ASSERT(DirContext
.LongNameU
.Length
!= 0 &&
914 DirContext
.ShortNameU
.Length
!= 0);
916 DirContext
.DirIndex
++;
919 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
920 if (FoundLong
== FALSE
)
922 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
924 if (FoundLong
|| FoundShort
)
926 status
= vfatMakeFCBFromDirEntry(pDeviceExt
,
930 CcUnpinData(Context
);
934 DirContext
.DirIndex
++;
937 return STATUS_OBJECT_NAME_NOT_FOUND
;
942 PDEVICE_EXTENSION pVCB
,
943 PVFATFCB
*pParentFCB
,
945 PUNICODE_STRING pFileNameU
)
950 UNICODE_STRING NameU
;
951 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
952 UNICODE_STRING FileNameU
;
953 WCHAR NameBuffer
[260];
954 PWCHAR curr
, prev
, last
;
957 DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
958 pVCB
, pParentFCB
, pFCB
, pFileNameU
);
960 RtlInitEmptyUnicodeString(&FileNameU
, NameBuffer
, sizeof(NameBuffer
));
962 parentFCB
= *pParentFCB
;
964 if (parentFCB
== NULL
)
966 /* Passed-in name is the full name */
967 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
969 // Trivial case, open of the root directory on volume
970 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
972 DPRINT("returning root FCB\n");
974 FCB
= vfatOpenRootFCB(pVCB
);
978 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
981 /* Check for an existing FCB */
982 FCB
= vfatGrabFCBFromTable(pVCB
, &FileNameU
);
986 *pParentFCB
= FCB
->parentFcb
;
987 vfatGrabFCB(pVCB
, *pParentFCB
);
988 return STATUS_SUCCESS
;
991 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
992 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
997 if (curr
> FileNameU
.Buffer
)
999 NameU
.Buffer
= FileNameU
.Buffer
;
1000 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
1001 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
1004 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
1005 if (Length
!= FCB
->PathNameU
.Length
)
1007 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
1009 vfatReleaseFCB(pVCB
, FCB
);
1010 return STATUS_OBJECT_NAME_INVALID
;
1012 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
1013 curr
, FileNameU
.Length
- Length
);
1014 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
1015 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
1016 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1018 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
1028 FCB
= vfatOpenRootFCB(pVCB
);
1029 curr
= FileNameU
.Buffer
;
1037 /* Make absolute path */
1038 RtlCopyUnicodeString(&FileNameU
, &parentFCB
->PathNameU
);
1039 curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1042 RtlAppendUnicodeToString(&FileNameU
, L
"\\");
1045 ASSERT(*curr
== L
'\\');
1046 RtlAppendUnicodeStringToString(&FileNameU
, pFileNameU
);
1051 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1054 while (curr
<= last
)
1058 vfatReleaseFCB(pVCB
, parentFCB
);
1061 // fail if element in FCB is not a directory
1062 if (!vfatFCBIsDirectory(FCB
))
1064 DPRINT ("Element in requested path is not a directory\n");
1066 vfatReleaseFCB(pVCB
, FCB
);
1071 return STATUS_OBJECT_PATH_NOT_FOUND
;
1076 Length
= (curr
- prev
) * sizeof(WCHAR
);
1077 if (Length
!= parentFCB
->LongNameU
.Length
)
1079 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
1081 vfatReleaseFCB(pVCB
, parentFCB
);
1084 return STATUS_OBJECT_NAME_INVALID
;
1086 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
1087 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
1088 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
1089 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
1090 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1092 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
1096 while (*curr
!= L
'\\' && curr
<= last
)
1100 NameU
.Buffer
= FileNameU
.Buffer
;
1101 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
1102 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
1103 DPRINT("%wZ\n", &NameU
);
1104 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
1107 NameU
.Buffer
= prev
;
1108 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
1109 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
1110 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1115 *pParentFCB
= parentFCB
;
1116 return STATUS_OBJECT_NAME_NOT_FOUND
;
1120 vfatReleaseFCB(pVCB
, parentFCB
);
1122 return STATUS_OBJECT_PATH_NOT_FOUND
;
1125 else if (!NT_SUCCESS(status
))
1127 vfatReleaseFCB(pVCB
, parentFCB
);
1136 *pParentFCB
= parentFCB
;
1139 return STATUS_SUCCESS
;