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 <wctype.h> /* towlower prototype */
21 /* -------------------------------------------------------- DEFINES */
23 #define TAG_FCB TAG('V', 'F', 'C', 'B')
25 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
27 /* -------------------------------------------------------- PUBLICS */
29 ULONG
vfatNameHash(ULONG hash
, PUNICODE_STRING NameU
)
35 ASSERT(NameU
->Buffer
[0] != L
'.');
37 last
= NameU
->Buffer
+ NameU
->Length
/ sizeof(WCHAR
);
41 c
= towlower(*curr
++);
42 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
48 vfatSplitPathName(PUNICODE_STRING PathNameU
, PUNICODE_STRING DirNameU
, PUNICODE_STRING FileNameU
)
52 pName
= PathNameU
->Buffer
+ PathNameU
->Length
/ sizeof(WCHAR
) - 1;
53 while (*pName
!= L
'\\' && pName
>= PathNameU
->Buffer
)
58 ASSERT(*pName
== L
'\\' || pName
< PathNameU
->Buffer
);
61 FileNameU
->Buffer
= pName
+ 1;
62 FileNameU
->Length
= FileNameU
->MaximumLength
= Length
* sizeof(WCHAR
);
66 DirNameU
->Buffer
= PathNameU
->Buffer
;
67 DirNameU
->Length
= (pName
+ 1 - PathNameU
->Buffer
) * sizeof(WCHAR
);
68 DirNameU
->MaximumLength
= DirNameU
->Length
;
73 vfatInitFcb(PVFATFCB Fcb
, PUNICODE_STRING NameU
)
75 USHORT PathNameBufferLength
;
78 PathNameBufferLength
= NameU
->Length
+ sizeof(WCHAR
);
80 PathNameBufferLength
= 0;
82 Fcb
->PathNameBuffer
= ExAllocatePool(NonPagedPool
, PathNameBufferLength
);
83 if (!Fcb
->PathNameBuffer
)
85 /* FIXME: what to do if no more memory? */
86 DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU
);
87 KEBUGCHECKEX(0, (ULONG_PTR
)Fcb
, (ULONG_PTR
)NameU
, 0, 0);
90 Fcb
->PathNameU
.Length
= 0;
91 Fcb
->PathNameU
.Buffer
= Fcb
->PathNameBuffer
;
92 Fcb
->PathNameU
.MaximumLength
= PathNameBufferLength
;
93 Fcb
->ShortNameU
.Length
= 0;
94 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
95 Fcb
->ShortNameU
.MaximumLength
= sizeof(Fcb
->ShortNameBuffer
);
96 Fcb
->DirNameU
.Buffer
= Fcb
->PathNameU
.Buffer
;
97 if (NameU
&& NameU
->Length
)
99 RtlCopyUnicodeString(&Fcb
->PathNameU
, NameU
);
100 vfatSplitPathName(&Fcb
->PathNameU
, &Fcb
->DirNameU
, &Fcb
->LongNameU
);
104 Fcb
->DirNameU
.Buffer
= Fcb
->LongNameU
.Buffer
= NULL
;
105 Fcb
->DirNameU
.MaximumLength
= Fcb
->DirNameU
.Length
= 0;
106 Fcb
->LongNameU
.MaximumLength
= Fcb
->LongNameU
.Length
= 0;
108 RtlZeroMemory(&Fcb
->FCBShareAccess
, sizeof(SHARE_ACCESS
));
109 Fcb
->OpenHandleCount
= 0;
113 vfatNewFCB(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING pFileNameU
)
117 DPRINT("'%wZ'\n", pFileNameU
);
119 rcFCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
);
124 RtlZeroMemory(rcFCB
, sizeof(VFATFCB
));
125 vfatInitFcb(rcFCB
, pFileNameU
);
126 if (pVCB
->Flags
& VCB_IS_FATX
)
128 rcFCB
->Flags
|= FCB_IS_FATX_ENTRY
;
129 rcFCB
->Attributes
= &rcFCB
->entry
.FatX
.Attrib
;
132 rcFCB
->Attributes
= &rcFCB
->entry
.Fat
.Attrib
;
133 rcFCB
->Hash
.Hash
= vfatNameHash(0, &rcFCB
->PathNameU
);
134 rcFCB
->Hash
.self
= rcFCB
;
135 rcFCB
->ShortHash
.self
= rcFCB
;
136 ExInitializeResourceLite(&rcFCB
->PagingIoResource
);
137 ExInitializeResourceLite(&rcFCB
->MainResource
);
138 FsRtlInitializeFileLock(&rcFCB
->FileLock
, NULL
, NULL
);
139 ExInitializeFastMutex(&rcFCB
->LastMutex
);
140 rcFCB
->RFCB
.PagingIoResource
= &rcFCB
->PagingIoResource
;
141 rcFCB
->RFCB
.Resource
= &rcFCB
->MainResource
;
142 rcFCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
148 vfatDestroyCCB(PVFATCCB pCcb
)
150 if (pCcb
->SearchPattern
.Buffer
)
152 ExFreePool(pCcb
->SearchPattern
.Buffer
);
154 ExFreeToNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
, pCcb
);
158 vfatDestroyFCB(PVFATFCB pFCB
)
160 FsRtlUninitializeFileLock(&pFCB
->FileLock
);
161 ExFreePool(pFCB
->PathNameBuffer
);
162 ExDeleteResourceLite(&pFCB
->PagingIoResource
);
163 ExDeleteResourceLite(&pFCB
->MainResource
);
164 ExFreeToNPagedLookasideList(&VfatGlobalData
->FcbLookasideList
, pFCB
);
168 vfatFCBIsDirectory(PVFATFCB FCB
)
170 return *FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
;
174 vfatFCBIsRoot(PVFATFCB FCB
)
176 return FCB
->PathNameU
.Length
== sizeof(WCHAR
) && FCB
->PathNameU
.Buffer
[0] == L
'\\' ? TRUE
: FALSE
;
180 vfatReleaseFCB(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
187 DPRINT ("releasing FCB at %x: %wZ, refCount:%d\n",
194 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
195 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
197 if (pFCB
->RefCount
== 0)
199 tmpFcb
= pFCB
->parentFcb
;
200 RemoveEntryList (&pFCB
->FcbListEntry
);
201 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
203 entry
= pVCB
->FcbHashTable
[ShortIndex
];
204 if (entry
->self
== pFCB
)
206 pVCB
->FcbHashTable
[ShortIndex
] = entry
->next
;
210 while (entry
->next
->self
!= pFCB
)
214 entry
->next
= pFCB
->ShortHash
.next
;
217 entry
= pVCB
->FcbHashTable
[Index
];
218 if (entry
->self
== pFCB
)
220 pVCB
->FcbHashTable
[Index
] = entry
->next
;
224 while (entry
->next
->self
!= pFCB
)
228 entry
->next
= pFCB
->Hash
.next
;
230 vfatDestroyFCB (pFCB
);
241 vfatAddFCBToTable(PDEVICE_EXTENSION pVCB
, PVFATFCB pFCB
)
246 Index
= pFCB
->Hash
.Hash
% pVCB
->HashTableSize
;
247 ShortIndex
= pFCB
->ShortHash
.Hash
% pVCB
->HashTableSize
;
249 InsertTailList (&pVCB
->FcbListHead
, &pFCB
->FcbListEntry
);
251 pFCB
->Hash
.next
= pVCB
->FcbHashTable
[Index
];
252 pVCB
->FcbHashTable
[Index
] = &pFCB
->Hash
;
253 if (pFCB
->Hash
.Hash
!= pFCB
->ShortHash
.Hash
)
255 pFCB
->ShortHash
.next
= pVCB
->FcbHashTable
[ShortIndex
];
256 pVCB
->FcbHashTable
[ShortIndex
] = &pFCB
->ShortHash
;
260 pFCB
->parentFcb
->RefCount
++;
265 vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB
, PUNICODE_STRING PathNameU
)
269 UNICODE_STRING DirNameU
;
270 UNICODE_STRING FileNameU
;
271 PUNICODE_STRING FcbNameU
;
275 DPRINT("'%wZ'\n", PathNameU
);
277 Hash
= vfatNameHash(0, PathNameU
);
279 entry
= pVCB
->FcbHashTable
[Hash
% pVCB
->HashTableSize
];
282 vfatSplitPathName(PathNameU
, &DirNameU
, &FileNameU
);
287 if (entry
->Hash
== Hash
)
290 DPRINT("'%wZ' '%wZ'\n", &DirNameU
, &rcFCB
->DirNameU
);
291 if (RtlEqualUnicodeString(&DirNameU
, &rcFCB
->DirNameU
, TRUE
))
293 if (rcFCB
->Hash
.Hash
== Hash
)
295 FcbNameU
= &rcFCB
->LongNameU
;
299 FcbNameU
= &rcFCB
->ShortNameU
;
301 /* compare the file name */
302 DPRINT("'%wZ' '%wZ'\n", &FileNameU
, FcbNameU
);
303 if (RtlEqualUnicodeString(&FileNameU
, FcbNameU
, TRUE
))
318 vfatFCBInitializeCacheFromVolume (PVCB vcb
, PVFATFCB fcb
)
320 #ifdef USE_ROS_CC_AND_FS
322 ULONG fileCacheQuantum
;
324 PFILE_OBJECT fileObject
;
327 fileObject
= IoCreateStreamFileObject (NULL
, vcb
->StorageDevice
);
329 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
332 return STATUS_INSUFFICIENT_RESOURCES
;
334 RtlZeroMemory(newCCB
, sizeof (VFATCCB
));
336 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
337 fileObject
->FsContext
= fcb
;
338 fileObject
->FsContext2
= newCCB
;
339 fcb
->FileObject
= fileObject
;
342 #ifdef USE_ROS_CC_AND_FS
343 fileCacheQuantum
= (vcb
->FatInfo
.BytesPerCluster
>= PAGE_SIZE
) ?
344 vcb
->FatInfo
.BytesPerCluster
: PAGE_SIZE
;
346 status
= CcRosInitializeFileCache (fileObject
,
348 if (!NT_SUCCESS (status
))
350 DbgPrint ("CcRosInitializeFileCache failed\n");
354 /* FIXME: Guard by SEH. */
355 CcInitializeCacheMap(fileObject
,
356 (PCC_FILE_SIZES
)(&fcb
->RFCB
.AllocationSize
),
358 &VfatGlobalData
->CacheMgrCallbacks
,
362 fcb
->Flags
|= FCB_CACHE_INITIALIZED
;
363 return STATUS_SUCCESS
;
367 vfatMakeRootFCB(PDEVICE_EXTENSION pVCB
)
370 ULONG FirstCluster
, CurrentCluster
, Size
= 0;
371 NTSTATUS Status
= STATUS_SUCCESS
;
372 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
374 FCB
= vfatNewFCB(pVCB
, &NameU
);
375 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
377 memset(FCB
->entry
.FatX
.Filename
, ' ', 42);
378 FCB
->entry
.FatX
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
379 FCB
->entry
.FatX
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
380 FCB
->entry
.FatX
.FirstCluster
= 1;
381 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
385 memset(FCB
->entry
.Fat
.Filename
, ' ', 11);
386 FCB
->entry
.Fat
.FileSize
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
387 FCB
->entry
.Fat
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
388 if (pVCB
->FatInfo
.FatType
== FAT32
)
390 CurrentCluster
= FirstCluster
= pVCB
->FatInfo
.RootCluster
;
391 FCB
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0xffff);
392 FCB
->entry
.Fat
.FirstClusterHigh
= (unsigned short)(FirstCluster
>> 16);
394 while (CurrentCluster
!= 0xffffffff && NT_SUCCESS(Status
))
396 Size
+= pVCB
->FatInfo
.BytesPerCluster
;
397 Status
= NextCluster (pVCB
, FirstCluster
, &CurrentCluster
, FALSE
);
402 FCB
->entry
.Fat
.FirstCluster
= 1;
403 Size
= pVCB
->FatInfo
.rootDirectorySectors
* pVCB
->FatInfo
.BytesPerSector
;
406 FCB
->ShortHash
.Hash
= FCB
->Hash
.Hash
;
409 FCB
->RFCB
.FileSize
.QuadPart
= Size
;
410 FCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
411 FCB
->RFCB
.AllocationSize
.QuadPart
= Size
;
412 FCB
->RFCB
.IsFastIoPossible
= FastIoIsNotPossible
;
414 vfatFCBInitializeCacheFromVolume(pVCB
, FCB
);
415 vfatAddFCBToTable(pVCB
, FCB
);
421 vfatOpenRootFCB(PDEVICE_EXTENSION pVCB
)
424 UNICODE_STRING NameU
= RTL_CONSTANT_STRING(L
"\\");
426 FCB
= vfatGrabFCBFromTable (pVCB
, &NameU
);
429 FCB
= vfatMakeRootFCB (pVCB
);
436 vfatMakeFCBFromDirEntry(PVCB vcb
,
437 PVFATFCB directoryFCB
,
438 PVFAT_DIRENTRY_CONTEXT DirContext
,
442 PWCHAR PathNameBuffer
;
443 USHORT PathNameLength
;
447 UNICODE_STRING NameU
;
449 PathNameLength
= directoryFCB
->PathNameU
.Length
+ max(DirContext
->LongNameU
.Length
, DirContext
->ShortNameU
.Length
);
450 if (!vfatFCBIsRoot (directoryFCB
))
452 PathNameLength
+= sizeof(WCHAR
);
455 if (PathNameLength
> LONGNAME_MAX_LENGTH
* sizeof(WCHAR
))
457 return STATUS_OBJECT_NAME_INVALID
;
459 PathNameBuffer
= ExAllocatePool(NonPagedPool
, PathNameLength
+ sizeof(WCHAR
));
462 return STATUS_INSUFFICIENT_RESOURCES
;
464 NameU
.Buffer
= PathNameBuffer
;
466 NameU
.MaximumLength
= PathNameLength
;
468 RtlCopyUnicodeString(&NameU
, &directoryFCB
->PathNameU
);
469 if (!vfatFCBIsRoot (directoryFCB
))
471 RtlAppendUnicodeToString(&NameU
, L
"\\");
473 hash
= vfatNameHash(0, &NameU
);
474 if (DirContext
->LongNameU
.Length
> 0)
476 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->LongNameU
);
480 RtlAppendUnicodeStringToString(&NameU
, &DirContext
->ShortNameU
);
482 NameU
.Buffer
[NameU
.Length
/ sizeof(WCHAR
)] = 0;
484 rcFCB
= vfatNewFCB (vcb
, &NameU
);
485 RtlCopyMemory (&rcFCB
->entry
, &DirContext
->DirEntry
, sizeof (DIR_ENTRY
));
486 RtlCopyUnicodeString(&rcFCB
->ShortNameU
, &DirContext
->ShortNameU
);
487 if (vcb
->Flags
& VCB_IS_FATX
)
489 rcFCB
->ShortHash
.Hash
= rcFCB
->Hash
.Hash
;
493 rcFCB
->ShortHash
.Hash
= vfatNameHash(hash
, &rcFCB
->ShortNameU
);
496 if (vfatFCBIsDirectory(rcFCB
))
498 ULONG FirstCluster
, CurrentCluster
;
501 FirstCluster
= vfatDirEntryGetFirstCluster (vcb
, &rcFCB
->entry
);
502 if (FirstCluster
== 1)
504 Size
= vcb
->FatInfo
.rootDirectorySectors
* vcb
->FatInfo
.BytesPerSector
;
506 else if (FirstCluster
!= 0)
508 CurrentCluster
= FirstCluster
;
509 while (CurrentCluster
!= 0xffffffff)
511 Size
+= vcb
->FatInfo
.BytesPerCluster
;
512 Status
= NextCluster (vcb
, FirstCluster
, &CurrentCluster
, FALSE
);
516 else if (rcFCB
->Flags
& FCB_IS_FATX_ENTRY
)
518 Size
= rcFCB
->entry
.FatX
.FileSize
;
522 Size
= rcFCB
->entry
.Fat
.FileSize
;
524 rcFCB
->dirIndex
= DirContext
->DirIndex
;
525 rcFCB
->startIndex
= DirContext
->StartIndex
;
526 if ((rcFCB
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot (directoryFCB
))
528 ASSERT(DirContext
->DirIndex
>= 2 && DirContext
->StartIndex
>= 2);
529 rcFCB
->dirIndex
= DirContext
->DirIndex
-2;
530 rcFCB
->startIndex
= DirContext
->StartIndex
-2;
532 rcFCB
->RFCB
.FileSize
.QuadPart
= Size
;
533 rcFCB
->RFCB
.ValidDataLength
.QuadPart
= Size
;
534 rcFCB
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, vcb
->FatInfo
.BytesPerCluster
);
536 if (vfatFCBIsDirectory(rcFCB
))
538 vfatFCBInitializeCacheFromVolume(vcb
, rcFCB
);
540 rcFCB
->parentFcb
= directoryFCB
;
541 vfatAddFCBToTable (vcb
, rcFCB
);
544 ExFreePool(PathNameBuffer
);
545 return STATUS_SUCCESS
;
549 vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb
,
551 PFILE_OBJECT fileObject
)
555 newCCB
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
559 return STATUS_INSUFFICIENT_RESOURCES
;
561 RtlZeroMemory (newCCB
, sizeof (VFATCCB
));
563 fileObject
->SectionObjectPointer
= &fcb
->SectionObjectPointers
;
564 fileObject
->FsContext
= fcb
;
565 fileObject
->FsContext2
= newCCB
;
566 DPRINT ("file open: fcb:%x PathName:%wZ\n", fcb
, &fcb
->PathNameU
);
568 return STATUS_SUCCESS
;
572 vfatDirFindFile (PDEVICE_EXTENSION pDeviceExt
,
573 PVFATFCB pDirectoryFCB
,
574 PUNICODE_STRING FileToFindU
,
575 PVFATFCB
* pFoundFCB
)
578 PVOID Context
= NULL
;
580 BOOLEAN First
= TRUE
;
581 VFAT_DIRENTRY_CONTEXT DirContext
;
582 /* This buffer must have a size of 260 characters, because
583 vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
584 WCHAR LongNameBuffer
[260];
585 WCHAR ShortNameBuffer
[13];
586 BOOLEAN FoundLong
= FALSE
;
587 BOOLEAN FoundShort
= FALSE
;
590 ASSERT(pDirectoryFCB
);
593 DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%wZ)\n",
597 DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB
->PathNameU
);
599 DirContext
.DirIndex
= 0;
600 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
601 DirContext
.LongNameU
.Length
= 0;
602 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
603 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
604 DirContext
.ShortNameU
.Length
= 0;
605 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
609 status
= pDeviceExt
->GetNextDirEntry(&Context
,
615 if (status
== STATUS_NO_MORE_ENTRIES
)
617 return STATUS_OBJECT_NAME_NOT_FOUND
;
619 if (!NT_SUCCESS(status
))
624 DPRINT (" Index:%d longName:%wZ\n",
626 &DirContext
.LongNameU
);
627 DirContext
.LongNameU
.Buffer
[DirContext
.LongNameU
.Length
/ sizeof(WCHAR
)] = 0;
628 DirContext
.ShortNameU
.Buffer
[DirContext
.ShortNameU
.Length
/ sizeof(WCHAR
)] = 0;
629 if (!ENTRY_VOLUME(pDeviceExt
, &DirContext
.DirEntry
))
631 FoundLong
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.LongNameU
, TRUE
);
632 if (FoundLong
== FALSE
)
634 FoundShort
= RtlEqualUnicodeString(FileToFindU
, &DirContext
.ShortNameU
, TRUE
);
636 if (FoundLong
|| FoundShort
)
638 status
= vfatMakeFCBFromDirEntry (pDeviceExt
,
642 CcUnpinData(Context
);
646 DirContext
.DirIndex
++;
649 return STATUS_OBJECT_NAME_NOT_FOUND
;
653 vfatGetFCBForFile (PDEVICE_EXTENSION pVCB
,
654 PVFATFCB
*pParentFCB
,
656 PUNICODE_STRING pFileNameU
)
661 UNICODE_STRING NameU
;
662 UNICODE_STRING RootNameU
= RTL_CONSTANT_STRING(L
"\\");
663 PWCHAR curr
, prev
, last
;
666 DPRINT ("vfatGetFCBForFile (%x,%x,%x,%wZ)\n",
672 parentFCB
= *pParentFCB
;
674 if (parentFCB
== NULL
)
676 // Trivial case, open of the root directory on volume
677 if (RtlEqualUnicodeString(pFileNameU
, &RootNameU
, FALSE
))
679 DPRINT ("returning root FCB\n");
681 FCB
= vfatOpenRootFCB (pVCB
);
685 return (FCB
!= NULL
) ? STATUS_SUCCESS
: STATUS_OBJECT_PATH_NOT_FOUND
;
688 /* Check for an existing FCB */
689 FCB
= vfatGrabFCBFromTable (pVCB
, pFileNameU
);
693 *pParentFCB
= FCB
->parentFcb
;
694 (*pParentFCB
)->RefCount
++;
695 return STATUS_SUCCESS
;
698 last
= curr
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
699 while (*curr
!= L
'\\' && curr
> pFileNameU
->Buffer
)
704 if (curr
> pFileNameU
->Buffer
)
706 NameU
.Buffer
= pFileNameU
->Buffer
;
707 NameU
.MaximumLength
= NameU
.Length
= (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
);
708 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
711 Length
= (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
);
712 if (Length
!= FCB
->PathNameU
.Length
)
714 if (pFileNameU
->Length
+ FCB
->PathNameU
.Length
- Length
> pFileNameU
->MaximumLength
)
716 vfatReleaseFCB (pVCB
, FCB
);
717 return STATUS_OBJECT_NAME_INVALID
;
719 RtlMoveMemory(pFileNameU
->Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
),
720 curr
, pFileNameU
->Length
- Length
);
721 pFileNameU
->Length
+= (USHORT
)(FCB
->PathNameU
.Length
- Length
);
722 curr
= pFileNameU
->Buffer
+ FCB
->PathNameU
.Length
/ sizeof(WCHAR
);
723 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
725 RtlCopyMemory(pFileNameU
->Buffer
, FCB
->PathNameU
.Buffer
, FCB
->PathNameU
.Length
);
735 FCB
= vfatOpenRootFCB(pVCB
);
736 curr
= pFileNameU
->Buffer
;
746 prev
= curr
= pFileNameU
->Buffer
- 1;
747 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
754 vfatReleaseFCB (pVCB
, parentFCB
);
757 // fail if element in FCB is not a directory
758 if (!vfatFCBIsDirectory (FCB
))
760 DPRINT ("Element in requested path is not a directory\n");
762 vfatReleaseFCB (pVCB
, FCB
);
767 return STATUS_OBJECT_PATH_NOT_FOUND
;
772 Length
= (curr
- prev
) * sizeof(WCHAR
);
773 if (Length
!= parentFCB
->LongNameU
.Length
)
775 if (pFileNameU
->Length
+ parentFCB
->LongNameU
.Length
- Length
> pFileNameU
->MaximumLength
)
777 vfatReleaseFCB (pVCB
, parentFCB
);
778 return STATUS_OBJECT_NAME_INVALID
;
780 RtlMoveMemory(prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
), curr
,
781 pFileNameU
->Length
- (curr
- pFileNameU
->Buffer
) * sizeof(WCHAR
));
782 pFileNameU
->Length
+= (USHORT
)(parentFCB
->LongNameU
.Length
- Length
);
783 curr
= prev
+ parentFCB
->LongNameU
.Length
/ sizeof(WCHAR
);
784 last
= pFileNameU
->Buffer
+ pFileNameU
->Length
/ sizeof(WCHAR
) - 1;
786 RtlCopyMemory(prev
, parentFCB
->LongNameU
.Buffer
, parentFCB
->LongNameU
.Length
);
790 while (*curr
!= L
'\\' && curr
<= last
)
794 NameU
.Buffer
= pFileNameU
->Buffer
;
795 NameU
.Length
= (curr
- NameU
.Buffer
) * sizeof(WCHAR
);
796 NameU
.MaximumLength
= pFileNameU
->MaximumLength
;
797 DPRINT("%wZ\n", &NameU
);
798 FCB
= vfatGrabFCBFromTable(pVCB
, &NameU
);
802 NameU
.MaximumLength
= NameU
.Length
= (curr
- prev
) * sizeof(WCHAR
);
803 status
= vfatDirFindFile(pVCB
, parentFCB
, &NameU
, &FCB
);
804 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
809 *pParentFCB
= parentFCB
;
810 return STATUS_OBJECT_NAME_NOT_FOUND
;
814 vfatReleaseFCB (pVCB
, parentFCB
);
816 return STATUS_OBJECT_PATH_NOT_FOUND
;
819 else if (!NT_SUCCESS (status
))
821 vfatReleaseFCB (pVCB
, parentFCB
);
830 *pParentFCB
= parentFCB
;
833 return STATUS_SUCCESS
;