2 * FILE: drivers/fs/vfat/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)
11 /* ------------------------------------------------------- INCLUDES */
19 #include <wctype.h> /* towlower prototype */
22 /* -------------------------------------------------------- DEFINES */
24 #define TAG_FCB 'BCFV'
26 /* -------------------------------------------------------- PUBLICS */
32 PUNICODE_STRING NameU
)
38 // LFN could start from "."
39 //ASSERT(NameU->Buffer[0] != L'.');
41 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
45 c
= towlower(*curr
++);
46 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
53 PUNICODE_STRING PathNameU
,
54 PUNICODE_STRING DirNameU
,
55 PUNICODE_STRING FileNameU
)
59 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
60 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
65 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
68 FileNameU
->Buffer
= pName
+ 1;
69 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
73 DirNameU
->Buffer
= PathNameU
->Buffer
;
74 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
75 DirNameU
->MaximumLength
= DirNameU
->Length
;
83 PUNICODE_STRING NameU
)
85 USHORT PathNameBufferLength
;
88 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
90 PathNameBufferLength
= 0;
92 Fcb
->PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
, TAG_FCB
);
93 if (!Fcb
->PathNameBuffer
)
95 /* FIXME: what to do if no more memory? */
96 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
97 KeBugCheckEx(FAT_FILE_SYSTEM
, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
100 Fcb
->PathNameU
.Length
= 0;
101 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
102 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
103 Fcb
->ShortNameU
.Length
= 0;
104 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
105 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
106 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
107 if (NameU
&& NameU
->Length
)
109 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
110 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
114 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
115 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
116 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
118 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
119 Fcb
->OpenHandleCount
= 0;
124 PDEVICE_EXTENSION pVCB
,
125 PUNICODE_STRING pFileNameU
)
129 DPRINT("'%wZ'\n", pFileNameU
);
131 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
136 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
137 vfatInitFcb(rcFCB
, pFileNameU
);
138 if (pVCB
->Flags
& VCB_IS_FATX
)
140 rcFCB
->Flags
|= FCB_IS_FATX_ENTRY
;
141 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
144 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
145 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
146 rcFCB
->Hash
.self
= rcFCB
;
147 rcFCB
->ShortHash
.self
= rcFCB
;
148 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
149 ExInitializeResourceLite(&rcFCB
->MainResource
);
150 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
151 ExInitializeFastMutex(&rcFCB
->LastMutex
);
152 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
153 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
154 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
163 if (pCcb
->SearchPattern
.Buffer
)
165 ExFreePoolWithTag(pCcb
->SearchPattern
.Buffer
, TAG_VFAT
);
167 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
174 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
175 ExFreePool(pFCB
->PathNameBuffer
);
176 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
177 ExDeleteResourceLite(&pFCB
->MainResource
);
178 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
185 return *FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
;
192 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
197 PDEVICE_EXTENSION pVCB
,
205 DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
206 pFCB
, &pFCB
->PathNameU
, pFCB
->RefCount
);
210 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
211 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
213 if (pFCB
->RefCount
== 0)
215 tmpFcb
= pFCB
->parentFcb
;
216 RemoveEntryList (&pFCB
->FcbListEntry
);
217 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
219 entry
= pVCB
->FcbHashTable
[ShortIndex
];
220 if (entry
->self
== pFCB
)
222 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
226 while (entry
->next
->self
!= pFCB
)
230 entry
->next
= pFCB
->ShortHash
.next
;
233 entry
= pVCB
->FcbHashTable
[Index
];
234 if (entry
->self
== pFCB
)
236 pVCB
->FcbHashTable
[Index
] = entry
->next
;
240 while (entry
->next
->self
!= pFCB
)
244 entry
->next
= pFCB
->Hash
.next
;
246 vfatDestroyFCB(pFCB
);
258 PDEVICE_EXTENSION pVCB
,
264 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
265 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
267 InsertTailList(&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
269 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
270 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
271 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
273 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
274 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
278 pFCB
->parentFcb
->RefCount
++;
283 vfatGrabFCBFromTable(
284 PDEVICE_EXTENSION pVCB
,
285 PUNICODE_STRING PathNameU
)
289 UNICODE_STRING DirNameU
;
290 UNICODE_STRING FileNameU
;
291 PUNICODE_STRING FcbNameU
;
295 DPRINT("'%wZ'\n", PathNameU
);
297 Hash
= vfatNameHash(0, PathNameU
);
299 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
302 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
307 if (entry
->Hash
== Hash
)
310 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
311 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
313 if (rcFCB
->Hash
.Hash
== Hash
)
315 FcbNameU
= &rcFCB
->LongNameU
;
319 FcbNameU
= &rcFCB
->ShortNameU
;
321 /* compare the file name */
322 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
323 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
337 vfatFCBInitializeCacheFromVolume(
341 PFILE_OBJECT fileObject
;
345 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
347 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
350 ObDereferenceObject(fileObject
);
351 return STATUS_INSUFFICIENT_RESOURCES
;
353 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
355 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
356 fileObject
->FsContext
= fcb
;
357 fileObject
->FsContext2
= newCCB
;
358 fcb
->FileObject
= fileObject
;
363 CcInitializeCacheMap(fileObject
,
364 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
366 &VfatGlobalData
->CacheMgrCallbacks
,
369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
371 status
= _SEH2_GetExceptionCode();
373 fcb
->FileObject
= NULL
;
374 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, newCCB
);
375 ObDereferenceObject(fileObject
);
380 fcb
->Flags
|= FCB_CACHE_INITIALIZED
;
381 return STATUS_SUCCESS
;
386 PDEVICE_EXTENSION pVCB
)
389 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
390 NTSTATUS Status
= STATUS_SUCCESS
;
391 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
393 FCB
= vfatNewFCB(pVCB
, &NameU
);
394 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
396 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
397 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
398 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
399 FCB
->entry
.FatX
.FirstCluster
= 1;
400 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
404 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
405 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
406 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
407 if (pVCB
->FatInfo
.FatType
== FAT32
)
409 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
410 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
411 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
413 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
415 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
416 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
421 FCB
->entry
.Fat
.FirstCluster
= 1;
422 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
425 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
428 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
429 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
430 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
431 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
433 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
434 vfatAddFCBToTable(pVCB
, FCB
);
441 PDEVICE_EXTENSION pVCB
)
444 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
446 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
449 FCB
= vfatMakeRootFCB(pVCB
);
456 vfatMakeFCBFromDirEntry(
458 PVFATFCB directoryFCB
,
459 PVFAT_DIRENTRY_CONTEXT DirContext
,
463 PWCHAR PathNameBuffer
;
464 USHORT PathNameLength
;
468 UNICODE_STRING NameU
;
470 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(DirContext
->LongNameU
.Length
, DirContext
->ShortNameU
.Length
);
471 if (!vfatFCBIsRoot (directoryFCB
))
473 PathNameLength
+= sizeof(WCHAR
);
476 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
478 return STATUS_OBJECT_NAME_INVALID
;
480 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
483 return STATUS_INSUFFICIENT_RESOURCES
;
485 NameU
.Buffer
= PathNameBuffer
;
487 NameU
.MaximumLength
= PathNameLength
;
489 RtlCopyUnicodeString(&NameU
, &directoryFCB
->PathNameU
);
490 if (!vfatFCBIsRoot(directoryFCB
))
492 RtlAppendUnicodeToString(&NameU
, L
"\\");
494 hash
= vfatNameHash(0, &NameU
);
495 if (DirContext
->LongNameU
.Length
> 0)
497 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->LongNameU
);
501 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->ShortNameU
);
503 NameU
.Buffer
[NameU
.Length
/ sizeof(WCHAR
)] = 0;
505 rcFCB
= vfatNewFCB(vcb
, &NameU
);
506 RtlCopyMemory(&rcFCB
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
507 RtlCopyUnicodeString(&rcFCB
->ShortNameU
, &DirContext
->ShortNameU
);
508 if (vcb
->Flags
& VCB_IS_FATX
)
510 rcFCB
->ShortHash
.Hash
= rcFCB
->Hash
.Hash
;
514 rcFCB
->ShortHash
.Hash
= vfatNameHash(hash
, &rcFCB
->ShortNameU
);
517 if (vfatFCBIsDirectory(rcFCB
))
519 ULONG FirstCluster
, CurrentCluster
;
520 NTSTATUS Status
= STATUS_SUCCESS
;
522 FirstCluster
= vfatDirEntryGetFirstCluster(vcb
, &rcFCB
->entry
);
523 if (FirstCluster
== 1)
525 Size
= vcb
->FatInfo
.rootDirectorySectors
* vcb
->FatInfo
.BytesPerSector
;
527 else if (FirstCluster
!= 0)
529 CurrentCluster
= FirstCluster
;
530 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
532 Size
+= vcb
->FatInfo
.BytesPerCluster
;
533 Status
= NextCluster(vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
537 else if (rcFCB
->Flags
& FCB_IS_FATX_ENTRY
)
539 Size
= rcFCB
->entry
.FatX
.FileSize
;
543 Size
= rcFCB
->entry
.Fat
.FileSize
;
545 rcFCB
->dirIndex
= DirContext
->DirIndex
;
546 rcFCB
->startIndex
= DirContext
->StartIndex
;
547 if ((rcFCB
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot(directoryFCB
))
549 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
550 rcFCB
->dirIndex
= DirContext
->DirIndex
-2;
551 rcFCB
->startIndex
= DirContext
->StartIndex
-2;
553 rcFCB
->RFCB
.FileSize
.QuadPart
= Size
;
554 rcFCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
555 rcFCB
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, vcb
->FatInfo
.BytesPerCluster
);
557 if (vfatFCBIsDirectory(rcFCB
))
559 vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
561 rcFCB
->parentFcb
= directoryFCB
;
562 vfatAddFCBToTable(vcb
, rcFCB
);
565 ExFreePool(PathNameBuffer
);
566 return STATUS_SUCCESS
;
570 vfatAttachFCBToFileObject(
571 PDEVICE_EXTENSION vcb
,
573 PFILE_OBJECT fileObject
)
577 UNREFERENCED_PARAMETER(vcb
);
579 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
582 return STATUS_INSUFFICIENT_RESOURCES
;
584 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
586 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
587 fileObject
->FsContext
= fcb
;
588 fileObject
->FsContext2
= newCCB
;
589 DPRINT("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
591 return STATUS_SUCCESS
;
596 PDEVICE_EXTENSION pDeviceExt
,
597 PVFATFCB pDirectoryFCB
,
598 PUNICODE_STRING FileToFindU
,
602 PVOID Context
= NULL
;
604 BOOLEAN First
= TRUE
;
605 VFAT_DIRENTRY_CONTEXT DirContext
;
606 /* This buffer must have a size of 260 characters, because
607 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
608 WCHAR LongNameBuffer
[260];
609 WCHAR ShortNameBuffer
[13];
610 BOOLEAN FoundLong
= FALSE
;
611 BOOLEAN FoundShort
= FALSE
;
614 ASSERT(pDirectoryFCB
);
617 DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
618 pDeviceExt
, pDirectoryFCB
, FileToFindU
);
619 DPRINT("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
621 DirContext
.DirIndex
= 0;
622 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
623 DirContext
.LongNameU
.Length
= 0;
624 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
625 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
626 DirContext
.ShortNameU
.Length
= 0;
627 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
631 status
= pDeviceExt
->GetNextDirEntry(&Context
,
637 if (status
== STATUS_NO_MORE_ENTRIES
)
639 return STATUS_OBJECT_NAME_NOT_FOUND
;
641 if (!NT_SUCCESS(status
))
646 DPRINT(" Index:%u longName:%wZ\n",
647 DirContext
.DirIndex
, &DirContext
.LongNameU
);
649 if (!ENTRY_VOLUME(pDeviceExt
, &DirContext
.DirEntry
))
651 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
652 if (FoundLong
== FALSE
)
654 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
656 if (FoundLong
|| FoundShort
)
658 status
= vfatMakeFCBFromDirEntry(pDeviceExt
,
662 CcUnpinData(Context
);
666 DirContext
.DirIndex
++;
669 return STATUS_OBJECT_NAME_NOT_FOUND
;
674 PDEVICE_EXTENSION pVCB
,
675 PVFATFCB
*pParentFCB
,
677 PUNICODE_STRING pFileNameU
)
682 UNICODE_STRING NameU
;
683 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
684 UNICODE_STRING FileNameU
;
685 WCHAR NameBuffer
[260];
686 PWCHAR curr
, prev
, last
;
689 DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
690 pVCB
, pParentFCB
, pFCB
, pFileNameU
);
692 FileNameU
.Buffer
= NameBuffer
;
693 FileNameU
.MaximumLength
= sizeof(NameBuffer
);
694 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
696 parentFCB
= *pParentFCB
;
698 if (parentFCB
== NULL
)
700 // Trivial case, open of the root directory on volume
701 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
703 DPRINT("returning root FCB\n");
705 FCB
= vfatOpenRootFCB(pVCB
);
709 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
712 /* Check for an existing FCB */
713 FCB
= vfatGrabFCBFromTable(pVCB
, &FileNameU
);
717 *pParentFCB
= FCB
->parentFcb
;
718 (*pParentFCB
)->RefCount
++;
719 return STATUS_SUCCESS
;
722 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
723 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
728 if (curr
> FileNameU
.Buffer
)
730 NameU
.Buffer
= FileNameU
.Buffer
;
731 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
732 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
735 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
736 if (Length
!= FCB
->PathNameU
.Length
)
738 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
740 vfatReleaseFCB(pVCB
, FCB
);
741 return STATUS_OBJECT_NAME_INVALID
;
743 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
744 curr
, FileNameU
.Length
- Length
);
745 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
746 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
747 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
749 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
759 FCB
= vfatOpenRootFCB(pVCB
);
760 curr
= FileNameU
.Buffer
;
770 prev
= curr
= FileNameU
.Buffer
- 1;
771 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
778 vfatReleaseFCB(pVCB
, parentFCB
);
781 // fail if element in FCB is not a directory
782 if (!vfatFCBIsDirectory(FCB
))
784 DPRINT ("Element in requested path is not a directory\n");
786 vfatReleaseFCB(pVCB
, FCB
);
791 return STATUS_OBJECT_PATH_NOT_FOUND
;
796 Length
= (curr
- prev
) * sizeof(WCHAR
);
797 if (Length
!= parentFCB
->LongNameU
.Length
)
799 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
801 vfatReleaseFCB(pVCB
, parentFCB
);
802 return STATUS_OBJECT_NAME_INVALID
;
804 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
805 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
806 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
807 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
808 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
810 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
814 while (*curr
!= L
'\\' && curr
<= last
)
818 NameU
.Buffer
= FileNameU
.Buffer
;
819 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
820 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
821 DPRINT("%wZ\n", &NameU
);
822 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
826 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
827 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
828 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
833 *pParentFCB
= parentFCB
;
834 return STATUS_OBJECT_NAME_NOT_FOUND
;
838 vfatReleaseFCB(pVCB
, parentFCB
);
840 return STATUS_OBJECT_PATH_NOT_FOUND
;
843 else if (!NT_SUCCESS(status
))
845 vfatReleaseFCB(pVCB
, parentFCB
);
854 *pParentFCB
= parentFCB
;
857 return STATUS_SUCCESS
;