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 */
14 #include <wctype.h> /* towlower prototype */
20 /* -------------------------------------------------------- DEFINES */
22 #define TAG_FCB 'BCFV'
24 /* -------------------------------------------------------- PUBLICS */
26 static ULONG
vfatNameHash(ULONG hash
, PUNICODE_STRING NameU
)
32 ASSERT(NameU
->Buffer
[0] != L
'.');
34 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
38 c
= towlower(*curr
++);
39 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
45 vfatSplitPathName(PUNICODE_STRING PathNameU
, PUNICODE_STRING DirNameU
, PUNICODE_STRING FileNameU
)
49 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
50 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
55 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
58 FileNameU
->Buffer
= pName
+ 1;
59 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
63 DirNameU
->Buffer
= PathNameU
->Buffer
;
64 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
65 DirNameU
->MaximumLength
= DirNameU
->Length
;
70 vfatInitFcb(PVFATFCB Fcb
, PUNICODE_STRING NameU
)
72 USHORT PathNameBufferLength
;
75 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
77 PathNameBufferLength
= 0;
79 Fcb
->PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
, TAG_FCB
);
80 if (!Fcb
->PathNameBuffer
)
82 /* FIXME: what to do if no more memory? */
83 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
84 KeBugCheckEx(FAT_FILE_SYSTEM
, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
87 Fcb
->PathNameU
.Length
= 0;
88 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
89 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
90 Fcb
->ShortNameU
.Length
= 0;
91 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
92 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
93 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
94 if (NameU
&& NameU
->Length
)
96 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
97 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
101 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
102 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
103 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
105 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
106 Fcb
->OpenHandleCount
= 0;
110 vfatNewFCB(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING pFileNameU
)
114 DPRINT("'%wZ'\n", pFileNameU
);
116 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
121 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
122 vfatInitFcb(rcFCB
, pFileNameU
);
123 if (pVCB
->Flags
& VCB_IS_FATX
)
125 rcFCB
->Flags
|= FCB_IS_FATX_ENTRY
;
126 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
129 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
130 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
131 rcFCB
->Hash
.self
= rcFCB
;
132 rcFCB
->ShortHash
.self
= rcFCB
;
133 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
134 ExInitializeResourceLite(&rcFCB
->MainResource
);
135 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
136 ExInitializeFastMutex(&rcFCB
->LastMutex
);
137 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
138 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
139 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
145 vfatDestroyCCB(PVFATCCB pCcb
)
147 if (pCcb
->SearchPattern
.Buffer
)
149 ExFreePool(pCcb
->SearchPattern
.Buffer
);
151 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
155 vfatDestroyFCB(PVFATFCB pFCB
)
157 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
158 ExFreePool(pFCB
->PathNameBuffer
);
159 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
160 ExDeleteResourceLite(&pFCB
->MainResource
);
161 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
165 vfatFCBIsDirectory(PVFATFCB FCB
)
167 return *FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
;
171 vfatFCBIsRoot(PVFATFCB FCB
)
173 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
177 vfatReleaseFCB(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
184 DPRINT ("releasing FCB at %p: %wZ, refCount:%d\n",
191 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
192 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
194 if (pFCB
->RefCount
== 0)
196 tmpFcb
= pFCB
->parentFcb
;
197 RemoveEntryList (&pFCB
->FcbListEntry
);
198 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
200 entry
= pVCB
->FcbHashTable
[ShortIndex
];
201 if (entry
->self
== pFCB
)
203 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
207 while (entry
->next
->self
!= pFCB
)
211 entry
->next
= pFCB
->ShortHash
.next
;
214 entry
= pVCB
->FcbHashTable
[Index
];
215 if (entry
->self
== pFCB
)
217 pVCB
->FcbHashTable
[Index
] = entry
->next
;
221 while (entry
->next
->self
!= pFCB
)
225 entry
->next
= pFCB
->Hash
.next
;
227 vfatDestroyFCB (pFCB
);
238 vfatAddFCBToTable(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
243 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
244 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
246 InsertTailList (&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
248 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
249 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
250 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
252 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
253 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
257 pFCB
->parentFcb
->RefCount
++;
262 vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING PathNameU
)
266 UNICODE_STRING DirNameU
;
267 UNICODE_STRING FileNameU
;
268 PUNICODE_STRING FcbNameU
;
272 DPRINT("'%wZ'\n", PathNameU
);
274 Hash
= vfatNameHash(0, PathNameU
);
276 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
279 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
284 if (entry
->Hash
== Hash
)
287 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
288 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
290 if (rcFCB
->Hash
.Hash
== Hash
)
292 FcbNameU
= &rcFCB
->LongNameU
;
296 FcbNameU
= &rcFCB
->ShortNameU
;
298 /* compare the file name */
299 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
300 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
313 vfatFCBInitializeCacheFromVolume (PVCB vcb
, PVFATFCB fcb
)
315 PFILE_OBJECT fileObject
;
318 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
320 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
323 return STATUS_INSUFFICIENT_RESOURCES
;
325 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
327 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
328 fileObject
->FsContext
= fcb
;
329 fileObject
->FsContext2
= newCCB
;
330 fcb
->FileObject
= fileObject
;
333 CcInitializeCacheMap(fileObject
,
334 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
336 &VfatGlobalData
->CacheMgrCallbacks
,
339 fcb
->Flags
|= FCB_CACHE_INITIALIZED
;
340 return STATUS_SUCCESS
;
344 vfatMakeRootFCB(PDEVICE_EXTENSION pVCB
)
347 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
348 NTSTATUS Status
= STATUS_SUCCESS
;
349 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
351 FCB
= vfatNewFCB(pVCB
, &NameU
);
352 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
354 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
355 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
356 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
357 FCB
->entry
.FatX
.FirstCluster
= 1;
358 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
362 memset(FCB
->entry
.Fat
.ShortName
, ' ', 11);
363 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
364 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
365 if (pVCB
->FatInfo
.FatType
== FAT32
)
367 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
368 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
369 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
371 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
373 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
374 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
379 FCB
->entry
.Fat
.FirstCluster
= 1;
380 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
383 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
386 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
387 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
388 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
389 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
391 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
392 vfatAddFCBToTable(pVCB
, FCB
);
398 vfatOpenRootFCB(PDEVICE_EXTENSION pVCB
)
401 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
403 FCB
= vfatGrabFCBFromTable (pVCB
, &NameU
);
406 FCB
= vfatMakeRootFCB (pVCB
);
413 vfatMakeFCBFromDirEntry(
415 PVFATFCB directoryFCB
,
416 PVFAT_DIRENTRY_CONTEXT DirContext
,
420 PWCHAR PathNameBuffer
;
421 USHORT PathNameLength
;
425 UNICODE_STRING NameU
;
427 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(DirContext
->LongNameU
.Length
, DirContext
->ShortNameU
.Length
);
428 if (!vfatFCBIsRoot (directoryFCB
))
430 PathNameLength
+= sizeof(WCHAR
);
433 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
435 return STATUS_OBJECT_NAME_INVALID
;
437 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
), TAG_FCB
);
440 return STATUS_INSUFFICIENT_RESOURCES
;
442 NameU
.Buffer
= PathNameBuffer
;
444 NameU
.MaximumLength
= PathNameLength
;
446 RtlCopyUnicodeString(&NameU
, &directoryFCB
->PathNameU
);
447 if (!vfatFCBIsRoot (directoryFCB
))
449 RtlAppendUnicodeToString(&NameU
, L
"\\");
451 hash
= vfatNameHash(0, &NameU
);
452 if (DirContext
->LongNameU
.Length
> 0)
454 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->LongNameU
);
458 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->ShortNameU
);
460 NameU
.Buffer
[NameU
.Length
/ sizeof(WCHAR
)] = 0;
462 rcFCB
= vfatNewFCB (vcb
, &NameU
);
463 RtlCopyMemory (&rcFCB
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
464 RtlCopyUnicodeString(&rcFCB
->ShortNameU
, &DirContext
->ShortNameU
);
465 if (vcb
->Flags
& VCB_IS_FATX
)
467 rcFCB
->ShortHash
.Hash
= rcFCB
->Hash
.Hash
;
471 rcFCB
->ShortHash
.Hash
= vfatNameHash(hash
, &rcFCB
->ShortNameU
);
474 if (vfatFCBIsDirectory(rcFCB
))
476 ULONG FirstCluster
, CurrentCluster
;
479 FirstCluster
= vfatDirEntryGetFirstCluster (vcb
, &rcFCB
->entry
);
480 if (FirstCluster
== 1)
482 Size
= vcb
->FatInfo
.rootDirectorySectors
* vcb
->FatInfo
.BytesPerSector
;
484 else if (FirstCluster
!= 0)
486 CurrentCluster
= FirstCluster
;
487 while (CurrentCluster
!= 0xffffffff)
489 Size
+= vcb
->FatInfo
.BytesPerCluster
;
490 Status
= NextCluster (vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
494 else if (rcFCB
->Flags
& FCB_IS_FATX_ENTRY
)
496 Size
= rcFCB
->entry
.FatX
.FileSize
;
500 Size
= rcFCB
->entry
.Fat
.FileSize
;
502 rcFCB
->dirIndex
= DirContext
->DirIndex
;
503 rcFCB
->startIndex
= DirContext
->StartIndex
;
504 if ((rcFCB
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot (directoryFCB
))
506 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
507 rcFCB
->dirIndex
= DirContext
->DirIndex
-2;
508 rcFCB
->startIndex
= DirContext
->StartIndex
-2;
510 rcFCB
->RFCB
.FileSize
.QuadPart
= Size
;
511 rcFCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
512 rcFCB
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, vcb
->FatInfo
.BytesPerCluster
);
514 if (vfatFCBIsDirectory(rcFCB
))
516 vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
518 rcFCB
->parentFcb
= directoryFCB
;
519 vfatAddFCBToTable (vcb
, rcFCB
);
522 ExFreePool(PathNameBuffer
);
523 return STATUS_SUCCESS
;
527 vfatAttachFCBToFileObject (
528 PDEVICE_EXTENSION vcb
,
530 PFILE_OBJECT fileObject
)
534 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
537 return STATUS_INSUFFICIENT_RESOURCES
;
539 RtlZeroMemory (newCCB
, sizeof (VFATCCB
));
541 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
542 fileObject
->FsContext
= fcb
;
543 fileObject
->FsContext2
= newCCB
;
544 DPRINT ("file open: fcb:%p PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
546 return STATUS_SUCCESS
;
551 PDEVICE_EXTENSION pDeviceExt
,
552 PVFATFCB pDirectoryFCB
,
553 PUNICODE_STRING FileToFindU
,
554 PVFATFCB
* pFoundFCB
)
557 PVOID Context
= NULL
;
559 BOOLEAN First
= TRUE
;
560 VFAT_DIRENTRY_CONTEXT DirContext
;
561 /* This buffer must have a size of 260 characters, because
562 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
563 WCHAR LongNameBuffer
[260];
564 WCHAR ShortNameBuffer
[13];
565 BOOLEAN FoundLong
= FALSE
;
566 BOOLEAN FoundShort
= FALSE
;
569 ASSERT(pDirectoryFCB
);
572 DPRINT ("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
576 DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
578 DirContext
.DirIndex
= 0;
579 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
580 DirContext
.LongNameU
.Length
= 0;
581 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
582 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
583 DirContext
.ShortNameU
.Length
= 0;
584 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
588 status
= pDeviceExt
->GetNextDirEntry(&Context
,
594 if (status
== STATUS_NO_MORE_ENTRIES
)
596 return STATUS_OBJECT_NAME_NOT_FOUND
;
598 if (!NT_SUCCESS(status
))
603 DPRINT (" Index:%d longName:%wZ\n",
605 &DirContext
.LongNameU
);
606 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
607 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
608 if (!ENTRY_VOLUME(pDeviceExt
, &DirContext
.DirEntry
))
610 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
611 if (FoundLong
== FALSE
)
613 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
615 if (FoundLong
|| FoundShort
)
617 status
= vfatMakeFCBFromDirEntry (pDeviceExt
,
621 CcUnpinData(Context
);
625 DirContext
.DirIndex
++;
628 return STATUS_OBJECT_NAME_NOT_FOUND
;
633 PDEVICE_EXTENSION pVCB
,
634 PVFATFCB
*pParentFCB
,
636 PUNICODE_STRING pFileNameU
)
641 UNICODE_STRING NameU
;
642 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
643 UNICODE_STRING FileNameU
;
644 WCHAR NameBuffer
[260];
645 PWCHAR curr
, prev
, last
;
648 DPRINT ("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
654 FileNameU
.Buffer
= NameBuffer
;
655 FileNameU
.MaximumLength
= sizeof(NameBuffer
);
656 RtlCopyUnicodeString(&FileNameU
, pFileNameU
);
658 parentFCB
= *pParentFCB
;
660 if (parentFCB
== NULL
)
662 // Trivial case, open of the root directory on volume
663 if (RtlEqualUnicodeString(&FileNameU
, &RootNameU
, FALSE
))
665 DPRINT ("returning root FCB\n");
667 FCB
= vfatOpenRootFCB (pVCB
);
671 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
674 /* Check for an existing FCB */
675 FCB
= vfatGrabFCBFromTable (pVCB
, &FileNameU
);
679 *pParentFCB
= FCB
->parentFcb
;
680 (*pParentFCB
)->RefCount
++;
681 return STATUS_SUCCESS
;
684 last
= curr
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
685 while (*curr
!= L
'\\' && curr
> FileNameU
.Buffer
)
690 if (curr
> FileNameU
.Buffer
)
692 NameU
.Buffer
= FileNameU
.Buffer
;
693 NameU
.MaximumLength
= NameU
.Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
694 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
697 Length
= (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
);
698 if (Length
!= FCB
->PathNameU
.Length
)
700 if (FileNameU
.Length
+ FCB
->PathNameU
.Length
- Length
> FileNameU
.MaximumLength
)
702 vfatReleaseFCB (pVCB
, FCB
);
703 return STATUS_OBJECT_NAME_INVALID
;
705 RtlMoveMemory(FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
706 curr
, FileNameU
.Length
- Length
);
707 FileNameU
.Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
708 curr
= FileNameU
.Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
709 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
711 RtlCopyMemory(FileNameU
.Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
721 FCB
= vfatOpenRootFCB(pVCB
);
722 curr
= FileNameU
.Buffer
;
732 prev
= curr
= FileNameU
.Buffer
- 1;
733 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
740 vfatReleaseFCB (pVCB
, parentFCB
);
743 // fail if element in FCB is not a directory
744 if (!vfatFCBIsDirectory (FCB
))
746 DPRINT ("Element in requested path is not a directory\n");
748 vfatReleaseFCB (pVCB
, FCB
);
753 return STATUS_OBJECT_PATH_NOT_FOUND
;
758 Length
= (curr
- prev
) * sizeof(WCHAR
);
759 if (Length
!= parentFCB
->LongNameU
.Length
)
761 if (FileNameU
.Length
+ parentFCB
->LongNameU
.Length
- Length
> FileNameU
.MaximumLength
)
763 vfatReleaseFCB (pVCB
, parentFCB
);
764 return STATUS_OBJECT_NAME_INVALID
;
766 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
767 FileNameU
.Length
- (curr
- FileNameU
.Buffer
) * sizeof(WCHAR
));
768 FileNameU
.Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
769 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
770 last
= FileNameU
.Buffer
+ FileNameU
.Length
/ sizeof(WCHAR
) - 1;
772 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
776 while (*curr
!= L
'\\' && curr
<= last
)
780 NameU
.Buffer
= FileNameU
.Buffer
;
781 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
782 NameU
.MaximumLength
= FileNameU
.MaximumLength
;
783 DPRINT("%wZ\n", &NameU
);
784 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
788 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
789 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
790 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
795 *pParentFCB
= parentFCB
;
796 return STATUS_OBJECT_NAME_NOT_FOUND
;
800 vfatReleaseFCB (pVCB
, parentFCB
);
802 return STATUS_OBJECT_PATH_NOT_FOUND
;
805 else if (!NT_SUCCESS (status
))
807 vfatReleaseFCB (pVCB
, parentFCB
);
816 *pParentFCB
= parentFCB
;
819 return STATUS_SUCCESS
;