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 */
26 extern UNICODE_STRING DebugFile
;
29 /* -------------------------------------------------------- PUBLICS */
35 PUNICODE_STRING NameU
)
41 // LFN could start from "."
42 //ASSERT(NameU->Buffer[0] != L'.');
44 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
48 c
= towlower(*curr
++);
49 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
56 PUNICODE_STRING PathNameU
,
57 PUNICODE_STRING DirNameU
,
58 PUNICODE_STRING FileNameU
)
62 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
63 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
68 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
71 FileNameU
->Buffer
= pName
+ 1;
72 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
76 DirNameU
->Buffer
= PathNameU
->Buffer
;
77 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
78 DirNameU
->MaximumLength
= DirNameU
->Length
;
86 PUNICODE_STRING NameU
)
88 USHORT PathNameBufferLength
;
91 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
93 PathNameBufferLength
= 0;
95 Fcb
->PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
, TAG_FCB
);
96 if (!Fcb
->PathNameBuffer
)
98 /* FIXME: what to do if no more memory? */
99 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
100 KeBugCheckEx(FAT_FILE_SYSTEM
, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
103 Fcb
->RFCB
.NodeTypeCode
= NODE_TYPE_FCB
;
104 Fcb
->RFCB
.NodeByteSize
= sizeof(VFATFCB
);
106 Fcb
->PathNameU
.Length
= 0;
107 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
108 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
109 Fcb
->ShortNameU
.Length
= 0;
110 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
111 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
112 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
113 if (NameU
&& NameU
->Length
)
115 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
116 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
120 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
121 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
122 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
124 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
125 Fcb
->OpenHandleCount
= 0;
130 PDEVICE_EXTENSION pVCB
,
131 PUNICODE_STRING pFileNameU
)
135 DPRINT("'%wZ'\n", pFileNameU
);
137 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
142 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
143 vfatInitFcb(rcFCB
, pFileNameU
);
144 if (vfatVolumeIsFatX(pVCB
))
145 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
147 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
148 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
149 rcFCB
->Hash
.self
= rcFCB
;
150 rcFCB
->ShortHash
.self
= rcFCB
;
151 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
152 ExInitializeResourceLite(&rcFCB
->MainResource
);
153 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
154 ExInitializeFastMutex(&rcFCB
->LastMutex
);
155 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
156 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
157 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
158 InitializeListHead(&rcFCB
->ParentListHead
);
166 PDEVICE_EXTENSION pVCB
,
173 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
174 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
176 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
178 entry
= pVCB
->FcbHashTable
[ShortIndex
];
179 if (entry
->self
== pFCB
)
181 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
185 while (entry
->next
->self
!= pFCB
)
189 entry
->next
= pFCB
->ShortHash
.next
;
192 entry
= pVCB
->FcbHashTable
[Index
];
193 if (entry
->self
== pFCB
)
195 pVCB
->FcbHashTable
[Index
] = entry
->next
;
199 while (entry
->next
->self
!= pFCB
)
203 entry
->next
= pFCB
->Hash
.next
;
206 RemoveEntryList(&pFCB
->FcbListEntry
);
212 PVFATFCB directoryFCB
,
213 PUNICODE_STRING LongNameU
,
214 PUNICODE_STRING ShortNameU
,
215 PUNICODE_STRING NameU
)
217 PWCHAR PathNameBuffer
;
218 USHORT PathNameLength
;
220 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(LongNameU
->Length
, ShortNameU
->Length
);
221 if (!vfatFCBIsRoot(directoryFCB
))
223 PathNameLength
+= sizeof(WCHAR
);
226 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
228 return STATUS_OBJECT_NAME_INVALID
;
230 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
233 return STATUS_INSUFFICIENT_RESOURCES
;
235 NameU
->Buffer
= PathNameBuffer
;
237 NameU
->MaximumLength
= PathNameLength
;
239 RtlCopyUnicodeString(NameU
, &directoryFCB
->PathNameU
);
240 if (!vfatFCBIsRoot(directoryFCB
))
242 RtlAppendUnicodeToString(NameU
, L
"\\");
244 if (LongNameU
->Length
> 0)
246 RtlAppendUnicodeStringToString(NameU
, LongNameU
);
250 RtlAppendUnicodeStringToString(NameU
, ShortNameU
);
252 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
254 return STATUS_SUCCESS
;
261 if (pCcb
->SearchPattern
.Buffer
)
263 ExFreePoolWithTag(pCcb
->SearchPattern
.Buffer
, TAG_SEARCH
);
265 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
273 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
275 DPRINT1("Destroying: %p (%wZ) %d\n", pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
279 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
281 if (!vfatFCBIsRoot(pFCB
) &&
282 !BooleanFlagOn(pFCB
->Flags
, FCB_IS_FAT
) && !BooleanFlagOn(pFCB
->Flags
, FCB_IS_VOLUME
))
284 RemoveEntryList(&pFCB
->ParentListEntry
);
286 ExFreePool(pFCB
->PathNameBuffer
);
287 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
288 ExDeleteResourceLite(&pFCB
->MainResource
);
289 ASSERT(IsListEmpty(&pFCB
->ParentListHead
));
290 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
297 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
306 PDEVICE_EXTENSION pVCB
,
317 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
319 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
);
322 DPRINT("Grabbing FCB at %p: %wZ, refCount:%d\n",
323 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
326 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
328 ASSERT(!BooleanFlagOn(pFCB
->Flags
, FCB_IS_FAT
));
329 ASSERT(pFCB
!= pVCB
->VolumeFcb
&& !BooleanFlagOn(pFCB
->Flags
, FCB_IS_VOLUME
));
330 ASSERT(pFCB
->RefCount
> 0);
340 PDEVICE_EXTENSION pVCB
,
353 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &pFCB
->LongNameU
, FALSE
, NULL
))
355 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
);
358 DPRINT("Releasing FCB at %p: %wZ, refCount:%d\n",
359 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
362 ASSERT(ExIsResourceAcquiredExclusive(&pVCB
->DirResource
));
368 ASSERT(!BooleanFlagOn(pFCB
->Flags
, FCB_IS_FAT
));
369 ASSERT(pFCB
!= pVCB
->VolumeFcb
&& !BooleanFlagOn(pFCB
->Flags
, FCB_IS_VOLUME
));
370 ASSERT(pFCB
->RefCount
> 0);
371 RefCount
= --pFCB
->RefCount
;
373 if (RefCount
== 1 && BooleanFlagOn(pFCB
->Flags
, FCB_CACHE_INITIALIZED
))
375 PFILE_OBJECT tmpFileObject
;
376 tmpFileObject
= pFCB
->FileObject
;
378 pFCB
->FileObject
= NULL
;
379 CcUninitializeCacheMap(tmpFileObject
, NULL
, NULL
);
380 ClearFlag(pFCB
->Flags
, FCB_CACHE_INITIALIZED
);
381 ObDereferenceObject(tmpFileObject
);
386 ASSERT(pFCB
->OpenHandleCount
== 0);
387 tmpFcb
= pFCB
->parentFcb
;
388 vfatDelFCBFromTable(pVCB
, pFCB
);
389 vfatDestroyFCB(pFCB
);
402 PDEVICE_EXTENSION pVCB
,
408 ASSERT(pFCB
->Hash
.Hash
== vfatNameHash(0, &pFCB
->PathNameU
));
409 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
410 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
412 InsertTailList(&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
414 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
415 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
416 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
418 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
419 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
423 vfatGrabFCB(pVCB
, pFCB
->parentFcb
);
429 vfatInitFCBFromDirEntry(
430 PDEVICE_EXTENSION Vcb
,
432 PVFAT_DIRENTRY_CONTEXT DirContext
)
436 RtlCopyMemory(&Fcb
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
437 RtlCopyUnicodeString(&Fcb
->ShortNameU
, &DirContext
->ShortNameU
);
438 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
439 if (vfatVolumeIsFatX(Vcb
))
441 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
445 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
446 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
449 if (vfatFCBIsDirectory(Fcb
))
451 ULONG FirstCluster
, CurrentCluster
;
452 NTSTATUS Status
= STATUS_SUCCESS
;
454 FirstCluster
= vfatDirEntryGetFirstCluster(Vcb
, &Fcb
->entry
);
455 if (FirstCluster
== 1)
457 Size
= Vcb
->FatInfo
.rootDirectorySectors
* Vcb
->FatInfo
.BytesPerSector
;
459 else if (FirstCluster
!= 0)
461 CurrentCluster
= FirstCluster
;
462 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
464 Size
+= Vcb
->FatInfo
.BytesPerCluster
;
465 Status
= NextCluster(Vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
469 else if (vfatVolumeIsFatX(Vcb
))
471 Size
= Fcb
->entry
.FatX
.FileSize
;
475 Size
= Fcb
->entry
.Fat
.FileSize
;
477 Fcb
->dirIndex
= DirContext
->DirIndex
;
478 Fcb
->startIndex
= DirContext
->StartIndex
;
479 if (vfatVolumeIsFatX(Vcb
) && !vfatFCBIsRoot(Fcb
))
481 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
482 Fcb
->dirIndex
= DirContext
->DirIndex
-2;
483 Fcb
->startIndex
= DirContext
->StartIndex
-2;
485 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
486 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
487 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, Vcb
->FatInfo
.BytesPerCluster
);
491 vfatSetFCBNewDirName(
492 PDEVICE_EXTENSION pVCB
,
497 UNICODE_STRING NewNameU
;
499 /* Get full path name */
500 Status
= vfatMakeFullName(ParentFcb
, &Fcb
->LongNameU
, &Fcb
->ShortNameU
, &NewNameU
);
501 if (!NT_SUCCESS(Status
))
506 /* Delete old name */
507 if (Fcb
->PathNameBuffer
)
509 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
511 Fcb
->PathNameU
= NewNameU
;
513 /* Delete from table */
514 vfatDelFCBFromTable(pVCB
, Fcb
);
516 /* Split it properly */
517 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
518 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
519 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
520 Fcb
->Hash
.Hash
= vfatNameHash(0, &Fcb
->PathNameU
);
521 if (vfatVolumeIsFatX(pVCB
))
523 Fcb
->ShortHash
.Hash
= Fcb
->Hash
.Hash
;
527 Fcb
->ShortHash
.Hash
= vfatNameHash(0, &Fcb
->DirNameU
);
528 Fcb
->ShortHash
.Hash
= vfatNameHash(Fcb
->ShortHash
.Hash
, &Fcb
->ShortNameU
);
531 vfatAddFCBToTable(pVCB
, Fcb
);
532 vfatReleaseFCB(pVCB
, ParentFcb
);
534 return STATUS_SUCCESS
;
539 PDEVICE_EXTENSION pVCB
,
541 PVFAT_DIRENTRY_CONTEXT DirContext
,
547 DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB
, Fcb
, DirContext
, ParentFcb
);
549 /* Get full path name */
550 Status
= vfatMakeFullName(ParentFcb
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &Fcb
->PathNameU
);
551 if (!NT_SUCCESS(Status
))
556 /* Delete old name */
557 if (Fcb
->PathNameBuffer
)
559 ExFreePoolWithTag(Fcb
->PathNameBuffer
, TAG_FCB
);
562 /* Delete from table */
563 vfatDelFCBFromTable(pVCB
, Fcb
);
565 /* Split it properly */
566 Fcb
->PathNameBuffer
= Fcb
->PathNameU
.Buffer
;
567 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
568 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
570 /* Save old parent */
571 OldParent
= Fcb
->parentFcb
;
572 RemoveEntryList(&Fcb
->ParentListEntry
);
575 vfatInitFCBFromDirEntry(pVCB
, Fcb
, DirContext
);
577 if (vfatFCBIsDirectory(Fcb
))
579 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
581 Fcb
->parentFcb
= ParentFcb
;
582 InsertTailList(&ParentFcb
->ParentListHead
, &Fcb
->ParentListEntry
);
583 vfatAddFCBToTable(pVCB
, Fcb
);
585 /* If we moved across directories, dereference our old parent
586 * We also dereference in case we're just renaming since AddFCBToTable references it
588 vfatReleaseFCB(pVCB
, OldParent
);
590 return STATUS_SUCCESS
;
594 vfatGrabFCBFromTable(
595 PDEVICE_EXTENSION pVCB
,
596 PUNICODE_STRING PathNameU
)
600 UNICODE_STRING DirNameU
;
601 UNICODE_STRING FileNameU
;
602 PUNICODE_STRING FcbNameU
;
606 DPRINT("'%wZ'\n", PathNameU
);
608 ASSERT(PathNameU
->Length
>= sizeof(WCHAR
) && PathNameU
->Buffer
[0] == L
'\\');
609 Hash
= vfatNameHash(0, PathNameU
);
611 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
614 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
619 if (entry
->Hash
== Hash
)
622 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
623 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
625 if (rcFCB
->Hash
.Hash
== Hash
)
627 FcbNameU
= &rcFCB
->LongNameU
;
631 FcbNameU
= &rcFCB
->ShortNameU
;
633 /* compare the file name */
634 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
635 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
637 vfatGrabFCB(pVCB
, rcFCB
);
649 PDEVICE_EXTENSION pVCB
)
652 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
653 NTSTATUS Status
= STATUS_SUCCESS
;
654 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
656 ASSERT(pVCB
->RootFcb
== NULL
);
658 FCB
= vfatNewFCB(pVCB
, &NameU
);
659 if (vfatVolumeIsFatX(pVCB
))
661 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
662 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
663 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
664 FCB
->entry
.FatX
.FirstCluster
= 1;
665 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
669 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
670 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
671 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
672 if (pVCB
->FatInfo
.FatType
== FAT32
)
674 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
675 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
676 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
678 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
680 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
681 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
686 FCB
->entry
.Fat
.FirstCluster
= 1;
687 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
690 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
693 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
694 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
695 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
696 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
698 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
699 vfatAddFCBToTable(pVCB
, FCB
);
709 PDEVICE_EXTENSION pVCB
)
712 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
714 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
717 FCB
= vfatMakeRootFCB(pVCB
);
719 ASSERT(FCB
== pVCB
->RootFcb
);
725 vfatMakeFCBFromDirEntry(
727 PVFATFCB directoryFCB
,
728 PVFAT_DIRENTRY_CONTEXT DirContext
,
732 UNICODE_STRING NameU
;
735 Status
= vfatMakeFullName(directoryFCB
, &DirContext
->LongNameU
, &DirContext
->ShortNameU
, &NameU
);
736 if (!NT_SUCCESS(Status
))
741 rcFCB
= vfatNewFCB(vcb
, &NameU
);
742 vfatInitFCBFromDirEntry(vcb
, rcFCB
, DirContext
);
745 rcFCB
->parentFcb
= directoryFCB
;
746 InsertTailList(&directoryFCB
->ParentListHead
, &rcFCB
->ParentListEntry
);
747 vfatAddFCBToTable(vcb
, rcFCB
);
750 ExFreePoolWithTag(NameU
.Buffer
, TAG_FCB
);
751 return STATUS_SUCCESS
;
755 vfatAttachFCBToFileObject(
756 PDEVICE_EXTENSION vcb
,
758 PFILE_OBJECT fileObject
)
763 if (DebugFile
.Buffer
!= NULL
&& FsRtlIsNameInExpression(&DebugFile
, &fcb
->LongNameU
, FALSE
, NULL
))
765 DPRINT1("Attaching %p to %p (%d)\n", fcb
, fileObject
, fcb
->RefCount
);
769 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
772 return STATUS_INSUFFICIENT_RESOURCES
;
774 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
776 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
777 fileObject
->FsContext
= fcb
;
778 fileObject
->FsContext2
= newCCB
;
779 fileObject
->Vpb
= vcb
->IoVPB
;
780 DPRINT("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
783 fcb
->Flags
&= ~FCB_CLEANED_UP
;
784 fcb
->Flags
&= ~FCB_CLOSED
;
787 return STATUS_SUCCESS
;
792 PDEVICE_EXTENSION pDeviceExt
,
793 PVFATFCB pDirectoryFCB
,
794 PUNICODE_STRING FileToFindU
,
798 PVOID Context
= NULL
;
800 BOOLEAN First
= TRUE
;
801 VFAT_DIRENTRY_CONTEXT DirContext
;
802 /* This buffer must have a size of 260 characters, because
803 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
804 WCHAR LongNameBuffer
[260];
805 WCHAR ShortNameBuffer
[13];
806 BOOLEAN FoundLong
= FALSE
;
807 BOOLEAN FoundShort
= FALSE
;
808 BOOLEAN IsFatX
= vfatVolumeIsFatX(pDeviceExt
);
811 ASSERT(pDirectoryFCB
);
814 DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
815 pDeviceExt
, pDirectoryFCB
, FileToFindU
);
816 DPRINT("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
818 DirContext
.DirIndex
= 0;
819 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
820 DirContext
.LongNameU
.Length
= 0;
821 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
822 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
823 DirContext
.ShortNameU
.Length
= 0;
824 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
825 DirContext
.DeviceExt
= pDeviceExt
;
829 status
= VfatGetNextDirEntry(pDeviceExt
,
836 if (status
== STATUS_NO_MORE_ENTRIES
)
838 return STATUS_OBJECT_NAME_NOT_FOUND
;
840 if (!NT_SUCCESS(status
))
845 DPRINT(" Index:%u longName:%wZ\n",
846 DirContext
.DirIndex
, &DirContext
.LongNameU
);
848 if (!ENTRY_VOLUME(IsFatX
, &DirContext
.DirEntry
))
850 if (DirContext
.LongNameU
.Length
== 0 ||
851 DirContext
.ShortNameU
.Length
== 0)
853 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
854 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
856 ASSERT(DirContext
.LongNameU
.Length
!= 0 &&
857 DirContext
.ShortNameU
.Length
!= 0);
859 DirContext
.DirIndex
++;
862 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
863 if (FoundLong
== FALSE
)
865 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
867 if (FoundLong
|| FoundShort
)
869 status
= vfatMakeFCBFromDirEntry(pDeviceExt
,
873 CcUnpinData(Context
);
877 DirContext
.DirIndex
++;
880 return STATUS_OBJECT_NAME_NOT_FOUND
;
885 PDEVICE_EXTENSION pVCB
,
886 PVFATFCB
*pParentFCB
,
888 PUNICODE_STRING pFileNameU
)
893 UNICODE_STRING NameU
;
894 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
895 UNICODE_STRING FileNameU
;
896 WCHAR NameBuffer
[260];
897 PWCHAR curr
, prev
, last
;
900 DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
901 pVCB
, pParentFCB
, pFCB
, pFileNameU
);
903 RtlInitEmptyUnicodeString(&FileNameU
, NameBuffer
, sizeof(NameBuffer
));
905 parentFCB
= *pParentFCB
;
907 if (parentFCB
== NULL
)
909 /* Passed-in name is the full name */
910 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
912 // Trivial case, open of the root directory on volume
913 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
915 DPRINT("returning root FCB\n");
917 FCB
= vfatOpenRootFCB(pVCB
);
921 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
924 /* Check for an existing FCB */
925 FCB
= vfatGrabFCBFromTable(pVCB
, &FileNameU
);
929 *pParentFCB
= FCB
->parentFcb
;
930 vfatGrabFCB(pVCB
, *pParentFCB
);
931 return STATUS_SUCCESS
;
934 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
935 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
940 if (curr
> FileNameU
.Buffer
)
942 NameU
.Buffer
= FileNameU
.Buffer
;
943 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
944 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
947 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
948 if (Length
!= FCB
->PathNameU
.Length
)
950 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
952 vfatReleaseFCB(pVCB
, FCB
);
953 return STATUS_OBJECT_NAME_INVALID
;
955 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
956 curr
, FileNameU
.Length
- Length
);
957 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
958 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
959 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
961 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
971 FCB
= vfatOpenRootFCB(pVCB
);
972 curr
= FileNameU
.Buffer
;
980 /* Make absolute path */
981 RtlCopyUnicodeString(&FileNameU
, &parentFCB
->PathNameU
);
982 curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
985 RtlAppendUnicodeToString(&FileNameU
, L
"\\");
988 ASSERT(*curr
== L
'\\');
989 RtlAppendUnicodeStringToString(&FileNameU
, pFileNameU
);
994 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1001 vfatReleaseFCB(pVCB
, parentFCB
);
1004 // fail if element in FCB is not a directory
1005 if (!vfatFCBIsDirectory(FCB
))
1007 DPRINT ("Element in requested path is not a directory\n");
1009 vfatReleaseFCB(pVCB
, FCB
);
1014 return STATUS_OBJECT_PATH_NOT_FOUND
;
1019 Length
= (curr
- prev
) * sizeof(WCHAR
);
1020 if (Length
!= parentFCB
->LongNameU
.Length
)
1022 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
1024 vfatReleaseFCB(pVCB
, parentFCB
);
1027 return STATUS_OBJECT_NAME_INVALID
;
1029 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
1030 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
1031 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
1032 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
1033 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
1035 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
1039 while (*curr
!= L
'\\' && curr
<= last
)
1043 NameU
.Buffer
= FileNameU
.Buffer
;
1044 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
1045 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
1046 DPRINT("%wZ\n", &NameU
);
1047 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
1050 NameU
.Buffer
= prev
;
1051 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
1052 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
1053 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1058 *pParentFCB
= parentFCB
;
1059 return STATUS_OBJECT_NAME_NOT_FOUND
;
1063 vfatReleaseFCB(pVCB
, parentFCB
);
1065 return STATUS_OBJECT_PATH_NOT_FOUND
;
1068 else if (!NT_SUCCESS(status
))
1070 vfatReleaseFCB(pVCB
, parentFCB
);
1079 *pParentFCB
= parentFCB
;
1082 return STATUS_SUCCESS
;