4 * FILE: drivers/fs/vfat/fcb.c
5 * PURPOSE: Routines to manipulate FCBs.
6 * COPYRIGHT: See COPYING in the top level directory
7 * PROJECT: ReactOS kernel
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 * Rex Jolliff (rex@lvcablemodem.com)
11 * Herve Poussineau (reactos@poussine.freesurf.fr)
14 /* ------------------------------------------------------- INCLUDES */
16 #include <ddk/ntddk.h>
17 #include <ntos/kefuncs.h>
20 #include <rosrtl/string.h>
27 /* -------------------------------------------------------- DEFINES */
29 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
30 #define TAG_FCB TAG('V', 'F', 'C', 'B')
32 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
34 /* -------------------------------------------------------- PUBLICS */
36 ULONG
vfatNameHash(ULONG hash
, PUNICODE_STRING NameU
)
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;
55 vfatSplitPathName(PUNICODE_STRING PathNameU
, PUNICODE_STRING DirNameU
, 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
;
80 vfatInitFcb(PVFATFCB Fcb
, PUNICODE_STRING NameU
)
82 Fcb
->PathNameU
.Length
= 0;
83 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
84 Fcb
->PathNameU
.MaximumLength
= sizeof(Fcb
->PathNameBuffer
);
85 Fcb
->ShortNameU
.Length
= 0;
86 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
87 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
88 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
89 if (NameU
&& NameU
->Length
)
91 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
92 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
96 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
97 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
98 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
100 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
101 Fcb
->OpenHandleCount
= 0;
105 vfatNewFCB(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING pFileNameU
)
109 DPRINT("'%wZ'\n", pFileNameU
);
111 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
116 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
117 vfatInitFcb(rcFCB
, pFileNameU
);
118 if (pVCB
->Flags
& VCB_IS_FATX
)
120 rcFCB
->Flags
|= FCB_IS_FATX_ENTRY
;
121 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
124 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
125 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
126 rcFCB
->Hash
.self
= rcFCB
;
127 rcFCB
->ShortHash
.self
= rcFCB
;
128 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
129 ExInitializeResourceLite(&rcFCB
->MainResource
);
130 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
131 ExInitializeFastMutex(&rcFCB
->LastMutex
);
136 vfatDestroyCCB(PVFATCCB pCcb
)
138 if (pCcb
->SearchPattern
.Buffer
)
140 ExFreePool(pCcb
->SearchPattern
.Buffer
);
142 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
146 vfatDestroyFCB(PVFATFCB pFCB
)
148 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
149 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
150 ExDeleteResourceLite(&pFCB
->MainResource
);
151 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
155 vfatFCBIsDirectory(PVFATFCB FCB
)
157 return *FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
;
161 vfatFCBIsRoot(PVFATFCB FCB
)
163 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
167 vfatReleaseFCB(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
174 DPRINT ("releasing FCB at %x: %wZ, refCount:%d\n",
181 Index
= pFCB
->Hash
.Hash
% FCB_HASH_TABLE_SIZE
;
182 ShortIndex
= pFCB
->ShortHash
.Hash
% FCB_HASH_TABLE_SIZE
;
184 if (pFCB
->RefCount
<= 0 && (!vfatFCBIsDirectory (pFCB
) || pFCB
->Flags
& FCB_DELETE_PENDING
))
186 tmpFcb
= pFCB
->parentFcb
;
187 RemoveEntryList (&pFCB
->FcbListEntry
);
188 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
190 entry
= pVCB
->FcbHashTable
[ShortIndex
];
191 if (entry
->self
== pFCB
)
193 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
197 while (entry
->next
->self
!= pFCB
)
201 entry
->next
= pFCB
->ShortHash
.next
;
204 entry
= pVCB
->FcbHashTable
[Index
];
205 if (entry
->self
== pFCB
)
207 pVCB
->FcbHashTable
[Index
] = entry
->next
;
211 while (entry
->next
->self
!= pFCB
)
215 entry
->next
= pFCB
->Hash
.next
;
217 if (vfatFCBIsDirectory(pFCB
))
219 /* Uninitialize file cache if initialized for this file object. */
220 if (pFCB
->FileObject
->SectionObjectPointer
->SharedCacheMap
)
222 CcRosReleaseFileCache(pFCB
->FileObject
);
224 vfatDestroyCCB(pFCB
->FileObject
->FsContext2
);
225 pFCB
->FileObject
->FsContext2
= NULL
;
226 pFCB
->FileObject
->FsContext
= NULL
;
227 ObDereferenceObject(pFCB
->FileObject
);
229 vfatDestroyFCB (pFCB
);
240 vfatAddFCBToTable(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
245 Index
= pFCB
->Hash
.Hash
% FCB_HASH_TABLE_SIZE
;
246 ShortIndex
= pFCB
->ShortHash
.Hash
% FCB_HASH_TABLE_SIZE
;
248 InsertTailList (&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
250 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
251 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
252 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
254 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
255 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
259 pFCB
->parentFcb
->RefCount
++;
264 vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING PathNameU
)
268 UNICODE_STRING DirNameU
;
269 UNICODE_STRING FileNameU
;
270 PUNICODE_STRING FcbNameU
;
274 DPRINT("'%wZ'\n", PathNameU
);
276 Hash
= vfatNameHash(0, PathNameU
);
278 entry
= pVCB
->FcbHashTable
[Hash
% FCB_HASH_TABLE_SIZE
];
281 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
286 if (entry
->Hash
== Hash
)
289 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
290 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
292 if (rcFCB
->Hash
.Hash
== Hash
)
294 FcbNameU
= &rcFCB
->LongNameU
;
298 FcbNameU
= &rcFCB
->ShortNameU
;
300 /* compare the file name */
301 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
302 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
317 vfatFCBInitializeCacheFromVolume (PVCB vcb
, PVFATFCB fcb
)
320 PFILE_OBJECT fileObject
;
321 ULONG fileCacheQuantum
;
324 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
326 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
329 return STATUS_INSUFFICIENT_RESOURCES
;
331 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
333 fileObject
->Flags
|= FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
334 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
335 fileObject
->FsContext
= fcb
;
336 fileObject
->FsContext2
= newCCB
;
337 fcb
->FileObject
= fileObject
;
340 fileCacheQuantum
= (vcb
->FatInfo
.BytesPerCluster
>= PAGE_SIZE
) ?
341 vcb
->FatInfo
.BytesPerCluster
: PAGE_SIZE
;
343 status
= CcRosInitializeFileCache (fileObject
,
345 if (!NT_SUCCESS (status
))
347 DbgPrint ("CcRosInitializeFileCache failed\n");
351 fcb
->Flags
|= FCB_CACHE_INITIALIZED
;
357 vfatMakeRootFCB(PDEVICE_EXTENSION pVCB
)
360 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
361 NTSTATUS Status
= STATUS_SUCCESS
;
362 UNICODE_STRING NameU
;
364 RtlRosInitUnicodeStringFromLiteral(&NameU
, L
"\\");
366 FCB
= vfatNewFCB(pVCB
, &NameU
);
367 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
369 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
370 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
371 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
372 FCB
->entry
.FatX
.FirstCluster
= 1;
373 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
377 memset(FCB
->entry
.Fat
.Filename
, ' ', 11);
378 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
379 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
380 if (pVCB
->FatInfo
.FatType
== FAT32
)
382 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
383 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
384 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
386 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
388 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
389 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
394 FCB
->entry
.Fat
.FirstCluster
= 1;
395 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
398 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
401 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
402 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
403 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
405 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
406 vfatAddFCBToTable(pVCB
, FCB
);
412 vfatOpenRootFCB(PDEVICE_EXTENSION pVCB
)
415 UNICODE_STRING NameU
;
417 RtlRosInitUnicodeStringFromLiteral(&NameU
, L
"\\");
419 FCB
= vfatGrabFCBFromTable (pVCB
, &NameU
);
422 FCB
= vfatMakeRootFCB (pVCB
);
429 vfatMakeFCBFromDirEntry(PVCB vcb
,
430 PVFATFCB directoryFCB
,
431 PVFAT_DIRENTRY_CONTEXT DirContext
,
435 WCHAR pathName
[MAX_PATH
];
439 UNICODE_STRING NameU
;
441 if (directoryFCB
->PathNameU
.Length
+ 2 * sizeof(WCHAR
) +
442 + DirContext
->LongNameU
.Length
> MAX_PATH
* sizeof(WCHAR
))
444 return STATUS_OBJECT_NAME_INVALID
;
446 NameU
.Buffer
= pathName
;
448 NameU
.MaximumLength
= sizeof(pathName
);
450 RtlCopyUnicodeString(&NameU
, &directoryFCB
->PathNameU
);
451 if (!vfatFCBIsRoot (directoryFCB
))
453 RtlAppendUnicodeToString(&NameU
, L
"\\");
455 hash
= vfatNameHash(0, &NameU
);
456 if (DirContext
->LongNameU
.Length
> 0)
458 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->LongNameU
);
462 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->ShortNameU
);
464 NameU
.Buffer
[NameU
.Length
/ sizeof(WCHAR
)] = 0;
466 rcFCB
= vfatNewFCB (vcb
, &NameU
);
467 RtlCopyMemory (&rcFCB
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
468 RtlCopyUnicodeString(&rcFCB
->ShortNameU
, &DirContext
->ShortNameU
);
469 if (vcb
->Flags
& VCB_IS_FATX
)
471 rcFCB
->ShortHash
.Hash
= rcFCB
->Hash
.Hash
;
475 rcFCB
->ShortHash
.Hash
= vfatNameHash(hash
, &rcFCB
->ShortNameU
);
478 if (vfatFCBIsDirectory(rcFCB
))
480 ULONG FirstCluster
, CurrentCluster
;
483 FirstCluster
= vfatDirEntryGetFirstCluster (vcb
, &rcFCB
->entry
);
484 if (FirstCluster
== 1)
486 Size
= vcb
->FatInfo
.rootDirectorySectors
* vcb
->FatInfo
.BytesPerSector
;
488 else if (FirstCluster
!= 0)
490 CurrentCluster
= FirstCluster
;
491 while (CurrentCluster
!= 0xffffffff)
493 Size
+= vcb
->FatInfo
.BytesPerCluster
;
494 Status
= NextCluster (vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
498 else if (rcFCB
->Flags
& FCB_IS_FATX_ENTRY
)
500 Size
= rcFCB
->entry
.FatX
.FileSize
;
504 Size
= rcFCB
->entry
.Fat
.FileSize
;
506 rcFCB
->dirIndex
= DirContext
->DirIndex
;
507 rcFCB
->startIndex
= DirContext
->StartIndex
;
508 rcFCB
->RFCB
.FileSize
.QuadPart
= Size
;
509 rcFCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
510 rcFCB
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, vcb
->FatInfo
.BytesPerCluster
);
512 if (vfatFCBIsDirectory(rcFCB
))
514 vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
516 rcFCB
->parentFcb
= directoryFCB
;
517 vfatAddFCBToTable (vcb
, rcFCB
);
520 return STATUS_SUCCESS
;
524 vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb
,
526 PFILE_OBJECT fileObject
)
530 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
534 return STATUS_INSUFFICIENT_RESOURCES
;
536 RtlZeroMemory (newCCB
, sizeof (VFATCCB
));
538 fileObject
->Flags
= fileObject
->Flags
| FO_FCB_IS_VALID
|
539 FO_DIRECT_CACHE_PAGING_READ
;
540 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
541 fileObject
->FsContext
= fcb
;
542 fileObject
->FsContext2
= newCCB
;
543 DPRINT ("file open: fcb:%x PathName:%wZ file size: %d\n", fcb
, &fcb
->PathNameU
, fcb
->entry
.FileSize
);
545 return STATUS_SUCCESS
;
549 vfatDirFindFile (PDEVICE_EXTENSION pDeviceExt
,
550 PVFATFCB pDirectoryFCB
,
551 PUNICODE_STRING FileToFindU
,
552 PVFATFCB
* pFoundFCB
)
555 PVOID Context
= NULL
;
557 BOOLEAN First
= TRUE
;
558 VFAT_DIRENTRY_CONTEXT DirContext
;
559 WCHAR LongNameBuffer
[MAX_PATH
];
560 WCHAR ShortNameBuffer
[13];
561 BOOLEAN FoundLong
= FALSE
;
562 BOOLEAN FoundShort
= FALSE
;
565 ASSERT(pDirectoryFCB
);
568 DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%wZ)\n",
572 DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
574 DirContext
.DirIndex
= 0;
575 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
576 DirContext
.LongNameU
.Length
= 0;
577 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
578 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
579 DirContext
.ShortNameU
.Length
= 0;
580 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
584 status
= pDeviceExt
->GetNextDirEntry(&Context
,
590 if (status
== STATUS_NO_MORE_ENTRIES
)
592 return STATUS_OBJECT_NAME_NOT_FOUND
;
594 if (!NT_SUCCESS(status
))
599 DPRINT (" Index:%d longName:%wZ\n",
601 &DirContext
.LongNameU
);
602 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
603 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
604 if (!ENTRY_VOLUME(pDeviceExt
, &DirContext
.DirEntry
))
606 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
607 if (FoundLong
== FALSE
)
609 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
611 if (FoundLong
|| FoundShort
)
613 status
= vfatMakeFCBFromDirEntry (pDeviceExt
,
617 CcUnpinData(Context
);
621 DirContext
.DirIndex
++;
624 return STATUS_OBJECT_NAME_NOT_FOUND
;
628 vfatGetFCBForFile (PDEVICE_EXTENSION pVCB
,
629 PVFATFCB
*pParentFCB
,
631 PUNICODE_STRING pFileNameU
)
636 UNICODE_STRING NameU
;
637 UNICODE_STRING RootNameU
;
638 PWCHAR curr
, prev
, last
;
641 DPRINT ("vfatGetFCBForFile (%x,%x,%x,%wZ)\n",
647 parentFCB
= *pParentFCB
;
649 if (parentFCB
== NULL
)
651 RtlRosInitUnicodeStringFromLiteral(&RootNameU
, L
"\\");
653 // Trivial case, open of the root directory on volume
654 if (RtlEqualUnicodeString(pFileNameU
, &RootNameU
, FALSE
))
656 DPRINT ("returning root FCB\n");
658 FCB
= vfatOpenRootFCB (pVCB
);
662 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
665 /* Check for an existing FCB */
666 FCB
= vfatGrabFCBFromTable (pVCB
, pFileNameU
);
670 *pParentFCB
= FCB
->parentFcb
;
671 (*pParentFCB
)->RefCount
++;
672 return STATUS_SUCCESS
;
675 last
= curr
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
676 while (*curr
!= L
'\\' && curr
> pFileNameU
->Buffer
)
681 if (curr
> pFileNameU
->Buffer
)
683 NameU
.Buffer
= pFileNameU
->Buffer
;
684 NameU
.MaximumLength
= NameU
.Length
= (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
);
685 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
688 Length
= (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
);
689 if (Length
!= FCB
->PathNameU
.Length
)
691 if (pFileNameU
->Length
+ FCB
->PathNameU
.Length
- Length
> pFileNameU
->MaximumLength
)
693 vfatReleaseFCB (pVCB
, FCB
);
694 return STATUS_OBJECT_NAME_INVALID
;
696 memmove(pFileNameU
->Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
697 curr
, pFileNameU
->Length
- Length
);
698 pFileNameU
->Length
+= FCB
->PathNameU
.Length
- Length
;
699 curr
= pFileNameU
->Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
700 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
702 RtlCopyMemory(pFileNameU
->Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
712 FCB
= vfatOpenRootFCB(pVCB
);
713 curr
= pFileNameU
->Buffer
;
723 prev
= curr
= pFileNameU
->Buffer
- 1;
724 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
731 vfatReleaseFCB (pVCB
, parentFCB
);
734 // fail if element in FCB is not a directory
735 if (!vfatFCBIsDirectory (FCB
))
737 DPRINT ("Element in requested path is not a directory\n");
739 vfatReleaseFCB (pVCB
, FCB
);
744 return STATUS_OBJECT_PATH_NOT_FOUND
;
749 Length
= (curr
- prev
) * sizeof(WCHAR
);
750 if (Length
!= parentFCB
->LongNameU
.Length
)
752 if (pFileNameU
->Length
+ parentFCB
->LongNameU
.Length
- Length
> pFileNameU
->MaximumLength
)
754 vfatReleaseFCB (pVCB
, parentFCB
);
755 return STATUS_OBJECT_NAME_INVALID
;
757 memmove(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
758 pFileNameU
->Length
- (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
));
759 pFileNameU
->Length
+= parentFCB
->LongNameU
.Length
- Length
;
760 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
761 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
763 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
767 while (*curr
!= L
'\\' && curr
<= last
)
771 NameU
.Buffer
= pFileNameU
->Buffer
;
772 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
773 NameU
.MaximumLength
= pFileNameU
->MaximumLength
;
774 DPRINT("%wZ\n", &NameU
);
775 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
779 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
780 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
781 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
786 *pParentFCB
= parentFCB
;
787 return STATUS_OBJECT_NAME_NOT_FOUND
;
791 vfatReleaseFCB (pVCB
, parentFCB
);
793 return STATUS_OBJECT_PATH_NOT_FOUND
;
796 else if (!NT_SUCCESS (status
))
798 vfatReleaseFCB (pVCB
, parentFCB
);
807 *pParentFCB
= parentFCB
;
810 return STATUS_SUCCESS
;