xref: /reactos/drivers/filesystems/vfatfs/fcb.c (revision 542e9f2b)
114c39362SHervé Poussineau /*
2*542e9f2bSStanislav Motylkov  * PROJECT:     VFAT Filesystem
3*542e9f2bSStanislav Motylkov  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4*542e9f2bSStanislav Motylkov  * PURPOSE:     Routines to manipulate FCBs
5*542e9f2bSStanislav Motylkov  * COPYRIGHT:   Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
6*542e9f2bSStanislav Motylkov  *              Copyright 2001 Rex Jolliff <rex@lvcablemodem.com>
7*542e9f2bSStanislav Motylkov  *              Copyright 2005-2022 Hervé Poussineau <hpoussin@reactos.org>
8*542e9f2bSStanislav Motylkov  *              Copyright 2008-2018 Pierre Schweitzer <pierre@reactos.org>
914c39362SHervé Poussineau  */
1014c39362SHervé Poussineau 
1114c39362SHervé Poussineau /*  -------------------------------------------------------  INCLUDES  */
1214c39362SHervé Poussineau 
1314c39362SHervé Poussineau #include "vfat.h"
1414c39362SHervé Poussineau 
1514c39362SHervé Poussineau #define NDEBUG
1614c39362SHervé Poussineau #include <debug.h>
1714c39362SHervé Poussineau 
1814c39362SHervé Poussineau #ifdef __GNUC__
1914c39362SHervé Poussineau #include <wctype.h> /* towlower prototype */
2014c39362SHervé Poussineau #endif
2114c39362SHervé Poussineau 
2214c39362SHervé Poussineau /*  --------------------------------------------------------  DEFINES  */
2314c39362SHervé Poussineau 
2414c39362SHervé Poussineau #ifdef KDBG
2514c39362SHervé Poussineau extern UNICODE_STRING DebugFile;
2614c39362SHervé Poussineau #endif
2714c39362SHervé Poussineau 
2814c39362SHervé Poussineau /*  --------------------------------------------------------  PUBLICS  */
2914c39362SHervé Poussineau 
3014c39362SHervé Poussineau static
3114c39362SHervé Poussineau ULONG
vfatNameHash(ULONG hash,PUNICODE_STRING NameU)3214c39362SHervé Poussineau vfatNameHash(
3314c39362SHervé Poussineau     ULONG hash,
3414c39362SHervé Poussineau     PUNICODE_STRING NameU)
3514c39362SHervé Poussineau {
3614c39362SHervé Poussineau     PWCHAR last;
3714c39362SHervé Poussineau     PWCHAR curr;
3814c39362SHervé Poussineau     register WCHAR c;
3914c39362SHervé Poussineau 
4014c39362SHervé Poussineau     // LFN could start from "."
4114c39362SHervé Poussineau     //ASSERT(NameU->Buffer[0] != L'.');
4214c39362SHervé Poussineau     curr = NameU->Buffer;
4314c39362SHervé Poussineau     last = NameU->Buffer + NameU->Length / sizeof(WCHAR);
4414c39362SHervé Poussineau 
4514c39362SHervé Poussineau     while(curr < last)
4614c39362SHervé Poussineau     {
4714c39362SHervé Poussineau         c = towlower(*curr++);
4814c39362SHervé Poussineau         hash = (hash + (c << 4) + (c >> 4)) * 11;
4914c39362SHervé Poussineau     }
5014c39362SHervé Poussineau     return hash;
5114c39362SHervé Poussineau }
5214c39362SHervé Poussineau 
5314c39362SHervé Poussineau VOID
vfatSplitPathName(PUNICODE_STRING PathNameU,PUNICODE_STRING DirNameU,PUNICODE_STRING FileNameU)5414c39362SHervé Poussineau vfatSplitPathName(
5514c39362SHervé Poussineau     PUNICODE_STRING PathNameU,
5614c39362SHervé Poussineau     PUNICODE_STRING DirNameU,
5714c39362SHervé Poussineau     PUNICODE_STRING FileNameU)
5814c39362SHervé Poussineau {
5914c39362SHervé Poussineau     PWCHAR pName;
6014c39362SHervé Poussineau     USHORT Length = 0;
6114c39362SHervé Poussineau     pName = PathNameU->Buffer + PathNameU->Length / sizeof(WCHAR) - 1;
6214c39362SHervé Poussineau     while (*pName != L'\\' && pName >= PathNameU->Buffer)
6314c39362SHervé Poussineau     {
6414c39362SHervé Poussineau         pName--;
6514c39362SHervé Poussineau         Length++;
6614c39362SHervé Poussineau     }
6714c39362SHervé Poussineau     ASSERT(*pName == L'\\' || pName < PathNameU->Buffer);
6814c39362SHervé Poussineau     if (FileNameU)
6914c39362SHervé Poussineau     {
7014c39362SHervé Poussineau         FileNameU->Buffer = pName + 1;
7114c39362SHervé Poussineau         FileNameU->Length = FileNameU->MaximumLength = Length * sizeof(WCHAR);
7214c39362SHervé Poussineau     }
7314c39362SHervé Poussineau     if (DirNameU)
7414c39362SHervé Poussineau     {
7514c39362SHervé Poussineau         DirNameU->Buffer = PathNameU->Buffer;
7614c39362SHervé Poussineau         DirNameU->Length = (pName + 1 - PathNameU->Buffer) * sizeof(WCHAR);
7714c39362SHervé Poussineau         DirNameU->MaximumLength = DirNameU->Length;
7814c39362SHervé Poussineau     }
7914c39362SHervé Poussineau }
8014c39362SHervé Poussineau 
8114c39362SHervé Poussineau static
8214c39362SHervé Poussineau VOID
vfatInitFcb(PVFATFCB Fcb,PUNICODE_STRING NameU)8314c39362SHervé Poussineau vfatInitFcb(
8414c39362SHervé Poussineau     PVFATFCB Fcb,
8514c39362SHervé Poussineau     PUNICODE_STRING NameU)
8614c39362SHervé Poussineau {
8714c39362SHervé Poussineau     USHORT PathNameBufferLength;
8814c39362SHervé Poussineau 
8914c39362SHervé Poussineau     if (NameU)
9014c39362SHervé Poussineau         PathNameBufferLength = NameU->Length + sizeof(WCHAR);
9114c39362SHervé Poussineau     else
9214c39362SHervé Poussineau         PathNameBufferLength = 0;
9314c39362SHervé Poussineau 
9414c39362SHervé Poussineau     Fcb->PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength, TAG_FCB);
9514c39362SHervé Poussineau     if (!Fcb->PathNameBuffer)
9614c39362SHervé Poussineau     {
9714c39362SHervé Poussineau         /* FIXME: what to do if no more memory? */
9814c39362SHervé Poussineau         DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU);
9914c39362SHervé Poussineau         KeBugCheckEx(FAT_FILE_SYSTEM, (ULONG_PTR)Fcb, (ULONG_PTR)NameU, 0, 0);
10014c39362SHervé Poussineau     }
10114c39362SHervé Poussineau 
10214c39362SHervé Poussineau     Fcb->RFCB.NodeTypeCode = NODE_TYPE_FCB;
10314c39362SHervé Poussineau     Fcb->RFCB.NodeByteSize = sizeof(VFATFCB);
10414c39362SHervé Poussineau 
10514c39362SHervé Poussineau     Fcb->PathNameU.Length = 0;
10614c39362SHervé Poussineau     Fcb->PathNameU.Buffer = Fcb->PathNameBuffer;
10714c39362SHervé Poussineau     Fcb->PathNameU.MaximumLength = PathNameBufferLength;
10814c39362SHervé Poussineau     Fcb->ShortNameU.Length = 0;
10914c39362SHervé Poussineau     Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
11014c39362SHervé Poussineau     Fcb->ShortNameU.MaximumLength = sizeof(Fcb->ShortNameBuffer);
11114c39362SHervé Poussineau     Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
11214c39362SHervé Poussineau     if (NameU && NameU->Length)
11314c39362SHervé Poussineau     {
11414c39362SHervé Poussineau         RtlCopyUnicodeString(&Fcb->PathNameU, NameU);
11514c39362SHervé Poussineau         vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
11614c39362SHervé Poussineau     }
11714c39362SHervé Poussineau     else
11814c39362SHervé Poussineau     {
11914c39362SHervé Poussineau         Fcb->DirNameU.Buffer = Fcb->LongNameU.Buffer = NULL;
12014c39362SHervé Poussineau         Fcb->DirNameU.MaximumLength = Fcb->DirNameU.Length = 0;
12114c39362SHervé Poussineau         Fcb->LongNameU.MaximumLength = Fcb->LongNameU.Length = 0;
12214c39362SHervé Poussineau     }
12314c39362SHervé Poussineau     RtlZeroMemory(&Fcb->FCBShareAccess, sizeof(SHARE_ACCESS));
12414c39362SHervé Poussineau     Fcb->OpenHandleCount = 0;
12514c39362SHervé Poussineau }
12614c39362SHervé Poussineau 
12714c39362SHervé Poussineau PVFATFCB
vfatNewFCB(PDEVICE_EXTENSION pVCB,PUNICODE_STRING pFileNameU)12814c39362SHervé Poussineau vfatNewFCB(
12914c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
13014c39362SHervé Poussineau     PUNICODE_STRING pFileNameU)
13114c39362SHervé Poussineau {
13214c39362SHervé Poussineau     PVFATFCB  rcFCB;
13314c39362SHervé Poussineau 
13414c39362SHervé Poussineau     DPRINT("'%wZ'\n", pFileNameU);
13514c39362SHervé Poussineau 
13614c39362SHervé Poussineau     rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
13714c39362SHervé Poussineau     if (rcFCB == NULL)
13814c39362SHervé Poussineau     {
13914c39362SHervé Poussineau         return NULL;
14014c39362SHervé Poussineau     }
14114c39362SHervé Poussineau     RtlZeroMemory(rcFCB, sizeof(VFATFCB));
14214c39362SHervé Poussineau     vfatInitFcb(rcFCB, pFileNameU);
14314c39362SHervé Poussineau     if (vfatVolumeIsFatX(pVCB))
14414c39362SHervé Poussineau         rcFCB->Attributes = &rcFCB->entry.FatX.Attrib;
14514c39362SHervé Poussineau     else
14614c39362SHervé Poussineau         rcFCB->Attributes = &rcFCB->entry.Fat.Attrib;
14714c39362SHervé Poussineau     rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU);
14814c39362SHervé Poussineau     rcFCB->Hash.self = rcFCB;
14914c39362SHervé Poussineau     rcFCB->ShortHash.self = rcFCB;
15014c39362SHervé Poussineau     ExInitializeResourceLite(&rcFCB->PagingIoResource);
15114c39362SHervé Poussineau     ExInitializeResourceLite(&rcFCB->MainResource);
15214c39362SHervé Poussineau     FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL);
15314c39362SHervé Poussineau     ExInitializeFastMutex(&rcFCB->LastMutex);
15414c39362SHervé Poussineau     rcFCB->RFCB.PagingIoResource = &rcFCB->PagingIoResource;
15514c39362SHervé Poussineau     rcFCB->RFCB.Resource = &rcFCB->MainResource;
15614c39362SHervé Poussineau     rcFCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
15714c39362SHervé Poussineau     InitializeListHead(&rcFCB->ParentListHead);
15814c39362SHervé Poussineau 
15914c39362SHervé Poussineau     return  rcFCB;
16014c39362SHervé Poussineau }
16114c39362SHervé Poussineau 
16214c39362SHervé Poussineau static
16314c39362SHervé Poussineau VOID
vfatDelFCBFromTable(PDEVICE_EXTENSION pVCB,PVFATFCB pFCB)16414c39362SHervé Poussineau vfatDelFCBFromTable(
16514c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
16614c39362SHervé Poussineau     PVFATFCB pFCB)
16714c39362SHervé Poussineau {
16814c39362SHervé Poussineau     ULONG Index;
16914c39362SHervé Poussineau     ULONG ShortIndex;
17014c39362SHervé Poussineau     HASHENTRY* entry;
17114c39362SHervé Poussineau 
17214c39362SHervé Poussineau     Index = pFCB->Hash.Hash % pVCB->HashTableSize;
17314c39362SHervé Poussineau     ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
17414c39362SHervé Poussineau 
17514c39362SHervé Poussineau     if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
17614c39362SHervé Poussineau     {
17714c39362SHervé Poussineau         entry = pVCB->FcbHashTable[ShortIndex];
17814c39362SHervé Poussineau         if (entry->self == pFCB)
17914c39362SHervé Poussineau         {
18014c39362SHervé Poussineau             pVCB->FcbHashTable[ShortIndex] = entry->next;
18114c39362SHervé Poussineau         }
18214c39362SHervé Poussineau         else
18314c39362SHervé Poussineau         {
18414c39362SHervé Poussineau             while (entry->next->self != pFCB)
18514c39362SHervé Poussineau             {
18614c39362SHervé Poussineau                 entry = entry->next;
18714c39362SHervé Poussineau             }
18814c39362SHervé Poussineau             entry->next = pFCB->ShortHash.next;
18914c39362SHervé Poussineau         }
19014c39362SHervé Poussineau     }
19114c39362SHervé Poussineau     entry = pVCB->FcbHashTable[Index];
19214c39362SHervé Poussineau     if (entry->self == pFCB)
19314c39362SHervé Poussineau     {
19414c39362SHervé Poussineau         pVCB->FcbHashTable[Index] = entry->next;
19514c39362SHervé Poussineau     }
19614c39362SHervé Poussineau     else
19714c39362SHervé Poussineau     {
19814c39362SHervé Poussineau         while (entry->next->self != pFCB)
19914c39362SHervé Poussineau         {
20014c39362SHervé Poussineau             entry = entry->next;
20114c39362SHervé Poussineau         }
20214c39362SHervé Poussineau         entry->next = pFCB->Hash.next;
20314c39362SHervé Poussineau     }
20414c39362SHervé Poussineau 
20514c39362SHervé Poussineau     RemoveEntryList(&pFCB->FcbListEntry);
20614c39362SHervé Poussineau }
20714c39362SHervé Poussineau 
20814c39362SHervé Poussineau static
20914c39362SHervé Poussineau NTSTATUS
vfatMakeFullName(PVFATFCB directoryFCB,PUNICODE_STRING LongNameU,PUNICODE_STRING ShortNameU,PUNICODE_STRING NameU)21014c39362SHervé Poussineau vfatMakeFullName(
21114c39362SHervé Poussineau     PVFATFCB directoryFCB,
21214c39362SHervé Poussineau     PUNICODE_STRING LongNameU,
21314c39362SHervé Poussineau     PUNICODE_STRING ShortNameU,
21414c39362SHervé Poussineau     PUNICODE_STRING NameU)
21514c39362SHervé Poussineau {
21614c39362SHervé Poussineau     PWCHAR PathNameBuffer;
21714c39362SHervé Poussineau     USHORT PathNameLength;
21814c39362SHervé Poussineau 
21914c39362SHervé Poussineau     PathNameLength = directoryFCB->PathNameU.Length + max(LongNameU->Length, ShortNameU->Length);
22014c39362SHervé Poussineau     if (!vfatFCBIsRoot(directoryFCB))
22114c39362SHervé Poussineau     {
22214c39362SHervé Poussineau         PathNameLength += sizeof(WCHAR);
22314c39362SHervé Poussineau     }
22414c39362SHervé Poussineau 
22514c39362SHervé Poussineau     if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR))
22614c39362SHervé Poussineau     {
22714c39362SHervé Poussineau         return  STATUS_OBJECT_NAME_INVALID;
22814c39362SHervé Poussineau     }
22914c39362SHervé Poussineau     PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB);
23014c39362SHervé Poussineau     if (!PathNameBuffer)
23114c39362SHervé Poussineau     {
23214c39362SHervé Poussineau         return STATUS_INSUFFICIENT_RESOURCES;
23314c39362SHervé Poussineau     }
23414c39362SHervé Poussineau     NameU->Buffer = PathNameBuffer;
23514c39362SHervé Poussineau     NameU->Length = 0;
23614c39362SHervé Poussineau     NameU->MaximumLength = PathNameLength;
23714c39362SHervé Poussineau 
23814c39362SHervé Poussineau     RtlCopyUnicodeString(NameU, &directoryFCB->PathNameU);
23914c39362SHervé Poussineau     if (!vfatFCBIsRoot(directoryFCB))
24014c39362SHervé Poussineau     {
24114c39362SHervé Poussineau         RtlAppendUnicodeToString(NameU, L"\\");
24214c39362SHervé Poussineau     }
24314c39362SHervé Poussineau     if (LongNameU->Length > 0)
24414c39362SHervé Poussineau     {
24514c39362SHervé Poussineau         RtlAppendUnicodeStringToString(NameU, LongNameU);
24614c39362SHervé Poussineau     }
24714c39362SHervé Poussineau     else
24814c39362SHervé Poussineau     {
24914c39362SHervé Poussineau         RtlAppendUnicodeStringToString(NameU, ShortNameU);
25014c39362SHervé Poussineau     }
25114c39362SHervé Poussineau     NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
25214c39362SHervé Poussineau 
25314c39362SHervé Poussineau     return STATUS_SUCCESS;
25414c39362SHervé Poussineau }
25514c39362SHervé Poussineau 
25614c39362SHervé Poussineau VOID
vfatDestroyCCB(PVFATCCB pCcb)25714c39362SHervé Poussineau vfatDestroyCCB(
25814c39362SHervé Poussineau     PVFATCCB pCcb)
25914c39362SHervé Poussineau {
26014c39362SHervé Poussineau     if (pCcb->SearchPattern.Buffer)
26114c39362SHervé Poussineau     {
26214c39362SHervé Poussineau         ExFreePoolWithTag(pCcb->SearchPattern.Buffer, TAG_SEARCH);
26314c39362SHervé Poussineau     }
26414c39362SHervé Poussineau     ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
26514c39362SHervé Poussineau }
26614c39362SHervé Poussineau 
26714c39362SHervé Poussineau VOID
vfatDestroyFCB(PVFATFCB pFCB)26814c39362SHervé Poussineau vfatDestroyFCB(
26914c39362SHervé Poussineau     PVFATFCB pFCB)
27014c39362SHervé Poussineau {
27114c39362SHervé Poussineau #ifdef KDBG
27214c39362SHervé Poussineau     if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
27314c39362SHervé Poussineau     {
27414c39362SHervé Poussineau         DPRINT1("Destroying: %p (%wZ) %d\n", pFCB, &pFCB->PathNameU, pFCB->RefCount);
27514c39362SHervé Poussineau     }
27614c39362SHervé Poussineau #endif
27714c39362SHervé Poussineau 
27814c39362SHervé Poussineau     FsRtlUninitializeFileLock(&pFCB->FileLock);
27914c39362SHervé Poussineau 
28014c39362SHervé Poussineau     if (!vfatFCBIsRoot(pFCB) &&
28114c39362SHervé Poussineau         !BooleanFlagOn(pFCB->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME))
28214c39362SHervé Poussineau     {
28314c39362SHervé Poussineau         RemoveEntryList(&pFCB->ParentListEntry);
28414c39362SHervé Poussineau     }
28514c39362SHervé Poussineau     ExFreePool(pFCB->PathNameBuffer);
28614c39362SHervé Poussineau     ExDeleteResourceLite(&pFCB->PagingIoResource);
28714c39362SHervé Poussineau     ExDeleteResourceLite(&pFCB->MainResource);
28814c39362SHervé Poussineau     ASSERT(IsListEmpty(&pFCB->ParentListHead));
28914c39362SHervé Poussineau     ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
29014c39362SHervé Poussineau }
29114c39362SHervé Poussineau 
29214c39362SHervé Poussineau BOOLEAN
vfatFCBIsRoot(PVFATFCB FCB)29314c39362SHervé Poussineau vfatFCBIsRoot(
29414c39362SHervé Poussineau     PVFATFCB FCB)
29514c39362SHervé Poussineau {
29614c39362SHervé Poussineau     return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE;
29714c39362SHervé Poussineau }
29814c39362SHervé Poussineau 
29914c39362SHervé Poussineau VOID
30014c39362SHervé Poussineau #ifndef KDBG
vfatGrabFCB(PDEVICE_EXTENSION pVCB,PVFATFCB pFCB,PCSTR File,ULONG Line,PCSTR Func)30114c39362SHervé Poussineau vfatGrabFCB(
30214c39362SHervé Poussineau #else
30314c39362SHervé Poussineau _vfatGrabFCB(
30414c39362SHervé Poussineau #endif
30514c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
30614c39362SHervé Poussineau     PVFATFCB pFCB
30714c39362SHervé Poussineau #ifdef KDBG
30814c39362SHervé Poussineau     ,
30914c39362SHervé Poussineau     PCSTR File,
31014c39362SHervé Poussineau     ULONG Line,
31114c39362SHervé Poussineau     PCSTR Func
31214c39362SHervé Poussineau #endif
31314c39362SHervé Poussineau )
31414c39362SHervé Poussineau {
31514c39362SHervé Poussineau #ifdef KDBG
31614c39362SHervé Poussineau     if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
31714c39362SHervé Poussineau     {
31814c39362SHervé Poussineau         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);
31914c39362SHervé Poussineau     }
32014c39362SHervé Poussineau #else
32114c39362SHervé Poussineau     DPRINT("Grabbing FCB at %p: %wZ, refCount:%d\n",
32214c39362SHervé Poussineau            pFCB, &pFCB->PathNameU, pFCB->RefCount);
32314c39362SHervé Poussineau #endif
32414c39362SHervé Poussineau 
32514c39362SHervé Poussineau     ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
32614c39362SHervé Poussineau 
32714c39362SHervé Poussineau     ASSERT(!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT));
32814c39362SHervé Poussineau     ASSERT(pFCB != pVCB->VolumeFcb && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME));
32914c39362SHervé Poussineau     ASSERT(pFCB->RefCount > 0);
33014c39362SHervé Poussineau     ++pFCB->RefCount;
33114c39362SHervé Poussineau }
33214c39362SHervé Poussineau 
33314c39362SHervé Poussineau VOID
33414c39362SHervé Poussineau #ifndef KDBG
vfatReleaseFCB(PDEVICE_EXTENSION pVCB,PVFATFCB pFCB,PCSTR File,ULONG Line,PCSTR Func)33514c39362SHervé Poussineau vfatReleaseFCB(
33614c39362SHervé Poussineau #else
33714c39362SHervé Poussineau _vfatReleaseFCB(
33814c39362SHervé Poussineau #endif
33914c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
34014c39362SHervé Poussineau     PVFATFCB pFCB
34114c39362SHervé Poussineau #ifdef KDBG
34214c39362SHervé Poussineau     ,
34314c39362SHervé Poussineau     PCSTR File,
34414c39362SHervé Poussineau     ULONG Line,
34514c39362SHervé Poussineau     PCSTR Func
34614c39362SHervé Poussineau #endif
34714c39362SHervé Poussineau )
34814c39362SHervé Poussineau {
34914c39362SHervé Poussineau     PVFATFCB tmpFcb;
35014c39362SHervé Poussineau 
35114c39362SHervé Poussineau #ifdef KDBG
35214c39362SHervé Poussineau     if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
35314c39362SHervé Poussineau     {
35414c39362SHervé Poussineau         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);
35514c39362SHervé Poussineau     }
35614c39362SHervé Poussineau #else
35714c39362SHervé Poussineau     DPRINT("Releasing FCB at %p: %wZ, refCount:%d\n",
35814c39362SHervé Poussineau            pFCB, &pFCB->PathNameU, pFCB->RefCount);
35914c39362SHervé Poussineau #endif
36014c39362SHervé Poussineau 
36114c39362SHervé Poussineau     ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
36214c39362SHervé Poussineau 
36314c39362SHervé Poussineau     while (pFCB)
36414c39362SHervé Poussineau     {
36514c39362SHervé Poussineau         ULONG RefCount;
36614c39362SHervé Poussineau 
36714c39362SHervé Poussineau         ASSERT(!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT));
36814c39362SHervé Poussineau         ASSERT(pFCB != pVCB->VolumeFcb && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME));
36914c39362SHervé Poussineau         ASSERT(pFCB->RefCount > 0);
37014c39362SHervé Poussineau         RefCount = --pFCB->RefCount;
37114c39362SHervé Poussineau 
37214c39362SHervé Poussineau         if (RefCount == 1 && BooleanFlagOn(pFCB->Flags, FCB_CACHE_INITIALIZED))
37314c39362SHervé Poussineau         {
37414c39362SHervé Poussineau             PFILE_OBJECT tmpFileObject;
37514c39362SHervé Poussineau             tmpFileObject = pFCB->FileObject;
37614c39362SHervé Poussineau 
37714c39362SHervé Poussineau             pFCB->FileObject = NULL;
37814c39362SHervé Poussineau             CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
37914c39362SHervé Poussineau             ClearFlag(pFCB->Flags, FCB_CACHE_INITIALIZED);
38014c39362SHervé Poussineau             ObDereferenceObject(tmpFileObject);
38114c39362SHervé Poussineau         }
38214c39362SHervé Poussineau 
38314c39362SHervé Poussineau         if (RefCount == 0)
38414c39362SHervé Poussineau         {
38514c39362SHervé Poussineau             ASSERT(pFCB->OpenHandleCount == 0);
38614c39362SHervé Poussineau             tmpFcb = pFCB->parentFcb;
38714c39362SHervé Poussineau             vfatDelFCBFromTable(pVCB, pFCB);
38814c39362SHervé Poussineau             vfatDestroyFCB(pFCB);
38914c39362SHervé Poussineau         }
39014c39362SHervé Poussineau         else
39114c39362SHervé Poussineau         {
39214c39362SHervé Poussineau             tmpFcb = NULL;
39314c39362SHervé Poussineau         }
39414c39362SHervé Poussineau         pFCB = tmpFcb;
39514c39362SHervé Poussineau     }
39614c39362SHervé Poussineau }
39714c39362SHervé Poussineau 
39814c39362SHervé Poussineau static
39914c39362SHervé Poussineau VOID
vfatAddFCBToTable(PDEVICE_EXTENSION pVCB,PVFATFCB pFCB)40014c39362SHervé Poussineau vfatAddFCBToTable(
40114c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
40214c39362SHervé Poussineau     PVFATFCB pFCB)
40314c39362SHervé Poussineau {
40414c39362SHervé Poussineau     ULONG Index;
40514c39362SHervé Poussineau     ULONG ShortIndex;
40614c39362SHervé Poussineau 
40714c39362SHervé Poussineau     ASSERT(pFCB->Hash.Hash == vfatNameHash(0, &pFCB->PathNameU));
40814c39362SHervé Poussineau     Index = pFCB->Hash.Hash % pVCB->HashTableSize;
40914c39362SHervé Poussineau     ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
41014c39362SHervé Poussineau 
41114c39362SHervé Poussineau     InsertTailList(&pVCB->FcbListHead, &pFCB->FcbListEntry);
41214c39362SHervé Poussineau 
41314c39362SHervé Poussineau     pFCB->Hash.next = pVCB->FcbHashTable[Index];
41414c39362SHervé Poussineau     pVCB->FcbHashTable[Index] = &pFCB->Hash;
41514c39362SHervé Poussineau     if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
41614c39362SHervé Poussineau     {
41714c39362SHervé Poussineau         pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex];
41814c39362SHervé Poussineau         pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash;
41914c39362SHervé Poussineau     }
42014c39362SHervé Poussineau     if (pFCB->parentFcb)
42114c39362SHervé Poussineau     {
42214c39362SHervé Poussineau         vfatGrabFCB(pVCB, pFCB->parentFcb);
42314c39362SHervé Poussineau     }
42414c39362SHervé Poussineau }
42514c39362SHervé Poussineau 
42614c39362SHervé Poussineau static
42714c39362SHervé Poussineau VOID
vfatInitFCBFromDirEntry(PDEVICE_EXTENSION Vcb,PVFATFCB ParentFcb,PVFATFCB Fcb,PVFAT_DIRENTRY_CONTEXT DirContext)42814c39362SHervé Poussineau vfatInitFCBFromDirEntry(
42914c39362SHervé Poussineau     PDEVICE_EXTENSION Vcb,
430fa809fd2SHervé Poussineau     PVFATFCB ParentFcb,
43114c39362SHervé Poussineau     PVFATFCB Fcb,
43214c39362SHervé Poussineau     PVFAT_DIRENTRY_CONTEXT DirContext)
43314c39362SHervé Poussineau {
43414c39362SHervé Poussineau     ULONG Size;
43514c39362SHervé Poussineau 
43614c39362SHervé Poussineau     RtlCopyMemory(&Fcb->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
43714c39362SHervé Poussineau     RtlCopyUnicodeString(&Fcb->ShortNameU, &DirContext->ShortNameU);
43814c39362SHervé Poussineau     Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
43914c39362SHervé Poussineau     if (vfatVolumeIsFatX(Vcb))
44014c39362SHervé Poussineau     {
44114c39362SHervé Poussineau         Fcb->ShortHash.Hash = Fcb->Hash.Hash;
44214c39362SHervé Poussineau     }
44314c39362SHervé Poussineau     else
44414c39362SHervé Poussineau     {
44514c39362SHervé Poussineau         Fcb->ShortHash.Hash = vfatNameHash(0, &Fcb->DirNameU);
44614c39362SHervé Poussineau         Fcb->ShortHash.Hash = vfatNameHash(Fcb->ShortHash.Hash, &Fcb->ShortNameU);
44714c39362SHervé Poussineau     }
44814c39362SHervé Poussineau 
44914c39362SHervé Poussineau     if (vfatFCBIsDirectory(Fcb))
45014c39362SHervé Poussineau     {
45114c39362SHervé Poussineau         ULONG FirstCluster, CurrentCluster;
45214c39362SHervé Poussineau         NTSTATUS Status = STATUS_SUCCESS;
45314c39362SHervé Poussineau         Size = 0;
45414c39362SHervé Poussineau         FirstCluster = vfatDirEntryGetFirstCluster(Vcb, &Fcb->entry);
45514c39362SHervé Poussineau         if (FirstCluster == 1)
45614c39362SHervé Poussineau         {
45714c39362SHervé Poussineau             Size = Vcb->FatInfo.rootDirectorySectors * Vcb->FatInfo.BytesPerSector;
45814c39362SHervé Poussineau         }
45914c39362SHervé Poussineau         else if (FirstCluster != 0)
46014c39362SHervé Poussineau         {
46114c39362SHervé Poussineau             CurrentCluster = FirstCluster;
46214c39362SHervé Poussineau             while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
46314c39362SHervé Poussineau             {
46414c39362SHervé Poussineau                 Size += Vcb->FatInfo.BytesPerCluster;
46514c39362SHervé Poussineau                 Status = NextCluster(Vcb, FirstCluster, &CurrentCluster, FALSE);
46614c39362SHervé Poussineau             }
46714c39362SHervé Poussineau         }
46814c39362SHervé Poussineau     }
46914c39362SHervé Poussineau     else if (vfatVolumeIsFatX(Vcb))
47014c39362SHervé Poussineau     {
47114c39362SHervé Poussineau         Size = Fcb->entry.FatX.FileSize;
47214c39362SHervé Poussineau     }
47314c39362SHervé Poussineau     else
47414c39362SHervé Poussineau     {
47514c39362SHervé Poussineau         Size = Fcb->entry.Fat.FileSize;
47614c39362SHervé Poussineau     }
47714c39362SHervé Poussineau     Fcb->dirIndex = DirContext->DirIndex;
47814c39362SHervé Poussineau     Fcb->startIndex = DirContext->StartIndex;
479fa809fd2SHervé Poussineau     Fcb->parentFcb = ParentFcb;
480fa809fd2SHervé Poussineau     if (vfatVolumeIsFatX(Vcb) && !vfatFCBIsRoot(ParentFcb))
48114c39362SHervé Poussineau     {
48214c39362SHervé Poussineau         ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2);
48314c39362SHervé Poussineau         Fcb->dirIndex = DirContext->DirIndex-2;
48414c39362SHervé Poussineau         Fcb->startIndex = DirContext->StartIndex-2;
48514c39362SHervé Poussineau     }
48614c39362SHervé Poussineau     Fcb->RFCB.FileSize.QuadPart = Size;
48714c39362SHervé Poussineau     Fcb->RFCB.ValidDataLength.QuadPart = Size;
48814c39362SHervé Poussineau     Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, Vcb->FatInfo.BytesPerCluster);
48914c39362SHervé Poussineau }
49014c39362SHervé Poussineau 
49114c39362SHervé Poussineau NTSTATUS
vfatSetFCBNewDirName(PDEVICE_EXTENSION pVCB,PVFATFCB Fcb,PVFATFCB ParentFcb)49214c39362SHervé Poussineau vfatSetFCBNewDirName(
49314c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
49414c39362SHervé Poussineau     PVFATFCB Fcb,
49514c39362SHervé Poussineau     PVFATFCB ParentFcb)
49614c39362SHervé Poussineau {
49714c39362SHervé Poussineau     NTSTATUS Status;
49814c39362SHervé Poussineau     UNICODE_STRING NewNameU;
49914c39362SHervé Poussineau 
50014c39362SHervé Poussineau     /* Get full path name */
50114c39362SHervé Poussineau     Status = vfatMakeFullName(ParentFcb, &Fcb->LongNameU, &Fcb->ShortNameU, &NewNameU);
50214c39362SHervé Poussineau     if (!NT_SUCCESS(Status))
50314c39362SHervé Poussineau     {
50414c39362SHervé Poussineau         return Status;
50514c39362SHervé Poussineau     }
50614c39362SHervé Poussineau 
50714c39362SHervé Poussineau     /* Delete old name */
50814c39362SHervé Poussineau     if (Fcb->PathNameBuffer)
50914c39362SHervé Poussineau     {
51014c39362SHervé Poussineau         ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
51114c39362SHervé Poussineau     }
51214c39362SHervé Poussineau     Fcb->PathNameU = NewNameU;
51314c39362SHervé Poussineau 
51414c39362SHervé Poussineau     /* Delete from table */
51514c39362SHervé Poussineau     vfatDelFCBFromTable(pVCB, Fcb);
51614c39362SHervé Poussineau 
51714c39362SHervé Poussineau     /* Split it properly */
51814c39362SHervé Poussineau     Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
51914c39362SHervé Poussineau     Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
52014c39362SHervé Poussineau     vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
52114c39362SHervé Poussineau     Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
52214c39362SHervé Poussineau     if (vfatVolumeIsFatX(pVCB))
52314c39362SHervé Poussineau     {
52414c39362SHervé Poussineau         Fcb->ShortHash.Hash = Fcb->Hash.Hash;
52514c39362SHervé Poussineau     }
52614c39362SHervé Poussineau     else
52714c39362SHervé Poussineau     {
52814c39362SHervé Poussineau         Fcb->ShortHash.Hash = vfatNameHash(0, &Fcb->DirNameU);
52914c39362SHervé Poussineau         Fcb->ShortHash.Hash = vfatNameHash(Fcb->ShortHash.Hash, &Fcb->ShortNameU);
53014c39362SHervé Poussineau     }
53114c39362SHervé Poussineau 
53214c39362SHervé Poussineau     vfatAddFCBToTable(pVCB, Fcb);
53314c39362SHervé Poussineau     vfatReleaseFCB(pVCB, ParentFcb);
53414c39362SHervé Poussineau 
53514c39362SHervé Poussineau     return STATUS_SUCCESS;
53614c39362SHervé Poussineau }
53714c39362SHervé Poussineau 
53814c39362SHervé Poussineau NTSTATUS
vfatUpdateFCB(PDEVICE_EXTENSION pVCB,PVFATFCB Fcb,PVFAT_DIRENTRY_CONTEXT DirContext,PVFATFCB ParentFcb)53914c39362SHervé Poussineau vfatUpdateFCB(
54014c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
54114c39362SHervé Poussineau     PVFATFCB Fcb,
54214c39362SHervé Poussineau     PVFAT_DIRENTRY_CONTEXT DirContext,
54314c39362SHervé Poussineau     PVFATFCB ParentFcb)
54414c39362SHervé Poussineau {
54514c39362SHervé Poussineau     NTSTATUS Status;
54614c39362SHervé Poussineau     PVFATFCB OldParent;
54714c39362SHervé Poussineau 
54814c39362SHervé Poussineau     DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB, Fcb, DirContext, ParentFcb);
54914c39362SHervé Poussineau 
55014c39362SHervé Poussineau     /* Get full path name */
55114c39362SHervé Poussineau     Status = vfatMakeFullName(ParentFcb, &DirContext->LongNameU, &DirContext->ShortNameU, &Fcb->PathNameU);
55214c39362SHervé Poussineau     if (!NT_SUCCESS(Status))
55314c39362SHervé Poussineau     {
55414c39362SHervé Poussineau         return Status;
55514c39362SHervé Poussineau     }
55614c39362SHervé Poussineau 
55714c39362SHervé Poussineau     /* Delete old name */
55814c39362SHervé Poussineau     if (Fcb->PathNameBuffer)
55914c39362SHervé Poussineau     {
56014c39362SHervé Poussineau         ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
56114c39362SHervé Poussineau     }
56214c39362SHervé Poussineau 
56314c39362SHervé Poussineau     /* Delete from table */
56414c39362SHervé Poussineau     vfatDelFCBFromTable(pVCB, Fcb);
56514c39362SHervé Poussineau 
56614c39362SHervé Poussineau     /* Split it properly */
56714c39362SHervé Poussineau     Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
56814c39362SHervé Poussineau     Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
56914c39362SHervé Poussineau     vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
57014c39362SHervé Poussineau 
57114c39362SHervé Poussineau     /* Save old parent */
57214c39362SHervé Poussineau     OldParent = Fcb->parentFcb;
57314c39362SHervé Poussineau     RemoveEntryList(&Fcb->ParentListEntry);
57414c39362SHervé Poussineau 
57514c39362SHervé Poussineau     /* Reinit FCB */
576fa809fd2SHervé Poussineau     vfatInitFCBFromDirEntry(pVCB, ParentFcb, Fcb, DirContext);
57714c39362SHervé Poussineau 
57814c39362SHervé Poussineau     if (vfatFCBIsDirectory(Fcb))
57914c39362SHervé Poussineau     {
58014c39362SHervé Poussineau         CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
58114c39362SHervé Poussineau     }
58214c39362SHervé Poussineau     InsertTailList(&ParentFcb->ParentListHead, &Fcb->ParentListEntry);
58314c39362SHervé Poussineau     vfatAddFCBToTable(pVCB, Fcb);
58414c39362SHervé Poussineau 
58514c39362SHervé Poussineau     /* If we moved across directories, dereference our old parent
58614c39362SHervé Poussineau      * We also dereference in case we're just renaming since AddFCBToTable references it
58714c39362SHervé Poussineau      */
58814c39362SHervé Poussineau     vfatReleaseFCB(pVCB, OldParent);
58914c39362SHervé Poussineau 
59014c39362SHervé Poussineau     return STATUS_SUCCESS;
59114c39362SHervé Poussineau }
59214c39362SHervé Poussineau 
59314c39362SHervé Poussineau PVFATFCB
vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB,PUNICODE_STRING PathNameU)59414c39362SHervé Poussineau vfatGrabFCBFromTable(
59514c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
59614c39362SHervé Poussineau     PUNICODE_STRING PathNameU)
59714c39362SHervé Poussineau {
59814c39362SHervé Poussineau     PVFATFCB  rcFCB;
59914c39362SHervé Poussineau     ULONG Hash;
60014c39362SHervé Poussineau     UNICODE_STRING DirNameU;
60114c39362SHervé Poussineau     UNICODE_STRING FileNameU;
60214c39362SHervé Poussineau     PUNICODE_STRING FcbNameU;
60314c39362SHervé Poussineau 
60414c39362SHervé Poussineau     HASHENTRY* entry;
60514c39362SHervé Poussineau 
60614c39362SHervé Poussineau     DPRINT("'%wZ'\n", PathNameU);
60714c39362SHervé Poussineau 
60814c39362SHervé Poussineau     ASSERT(PathNameU->Length >= sizeof(WCHAR) && PathNameU->Buffer[0] == L'\\');
60914c39362SHervé Poussineau     Hash = vfatNameHash(0, PathNameU);
61014c39362SHervé Poussineau 
61114c39362SHervé Poussineau     entry = pVCB->FcbHashTable[Hash % pVCB->HashTableSize];
61214c39362SHervé Poussineau     if (entry)
61314c39362SHervé Poussineau     {
61414c39362SHervé Poussineau         vfatSplitPathName(PathNameU, &DirNameU, &FileNameU);
61514c39362SHervé Poussineau     }
61614c39362SHervé Poussineau 
61714c39362SHervé Poussineau     while (entry)
61814c39362SHervé Poussineau     {
61914c39362SHervé Poussineau         if (entry->Hash == Hash)
62014c39362SHervé Poussineau         {
62114c39362SHervé Poussineau             rcFCB = entry->self;
62214c39362SHervé Poussineau             DPRINT("'%wZ' '%wZ'\n", &DirNameU, &rcFCB->DirNameU);
62314c39362SHervé Poussineau             if (RtlEqualUnicodeString(&DirNameU, &rcFCB->DirNameU, TRUE))
62414c39362SHervé Poussineau             {
62514c39362SHervé Poussineau                 if (rcFCB->Hash.Hash == Hash)
62614c39362SHervé Poussineau                 {
62714c39362SHervé Poussineau                     FcbNameU = &rcFCB->LongNameU;
62814c39362SHervé Poussineau                 }
62914c39362SHervé Poussineau                 else
63014c39362SHervé Poussineau                 {
63114c39362SHervé Poussineau                     FcbNameU = &rcFCB->ShortNameU;
63214c39362SHervé Poussineau                 }
63314c39362SHervé Poussineau                 /* compare the file name */
63414c39362SHervé Poussineau                 DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU);
63514c39362SHervé Poussineau                 if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE))
63614c39362SHervé Poussineau                 {
63714c39362SHervé Poussineau                     vfatGrabFCB(pVCB, rcFCB);
63814c39362SHervé Poussineau                     return rcFCB;
63914c39362SHervé Poussineau                 }
64014c39362SHervé Poussineau             }
64114c39362SHervé Poussineau         }
64214c39362SHervé Poussineau         entry = entry->next;
64314c39362SHervé Poussineau     }
64414c39362SHervé Poussineau     return NULL;
64514c39362SHervé Poussineau }
64614c39362SHervé Poussineau 
64714c39362SHervé Poussineau PVFATFCB
vfatMakeRootFCB(PDEVICE_EXTENSION pVCB)64814c39362SHervé Poussineau vfatMakeRootFCB(
64914c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB)
65014c39362SHervé Poussineau {
65114c39362SHervé Poussineau     PVFATFCB FCB;
65214c39362SHervé Poussineau     ULONG FirstCluster, CurrentCluster, Size = 0;
65314c39362SHervé Poussineau     NTSTATUS Status = STATUS_SUCCESS;
65414c39362SHervé Poussineau     UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
65514c39362SHervé Poussineau 
65614c39362SHervé Poussineau     ASSERT(pVCB->RootFcb == NULL);
65714c39362SHervé Poussineau 
65814c39362SHervé Poussineau     FCB = vfatNewFCB(pVCB, &NameU);
65914c39362SHervé Poussineau     if (vfatVolumeIsFatX(pVCB))
66014c39362SHervé Poussineau     {
66114c39362SHervé Poussineau         memset(FCB->entry.FatX.Filename, ' ', 42);
66214c39362SHervé Poussineau         FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
66314c39362SHervé Poussineau         FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY;
66414c39362SHervé Poussineau         FCB->entry.FatX.FirstCluster = 1;
66514c39362SHervé Poussineau         Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
66614c39362SHervé Poussineau     }
66714c39362SHervé Poussineau     else
66814c39362SHervé Poussineau     {
66914c39362SHervé Poussineau         memset(FCB->entry.Fat.ShortName, ' ', 11);
67014c39362SHervé Poussineau         FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
67114c39362SHervé Poussineau         FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY;
67214c39362SHervé Poussineau         if (pVCB->FatInfo.FatType == FAT32)
67314c39362SHervé Poussineau         {
67414c39362SHervé Poussineau             CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
67514c39362SHervé Poussineau             FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
67614c39362SHervé Poussineau             FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
67714c39362SHervé Poussineau 
67814c39362SHervé Poussineau             while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
67914c39362SHervé Poussineau             {
68014c39362SHervé Poussineau                 Size += pVCB->FatInfo.BytesPerCluster;
68114c39362SHervé Poussineau                 Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
68214c39362SHervé Poussineau             }
68314c39362SHervé Poussineau         }
68414c39362SHervé Poussineau         else
68514c39362SHervé Poussineau         {
68614c39362SHervé Poussineau             FCB->entry.Fat.FirstCluster = 1;
68714c39362SHervé Poussineau             Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
68814c39362SHervé Poussineau         }
68914c39362SHervé Poussineau     }
69014c39362SHervé Poussineau     FCB->ShortHash.Hash = FCB->Hash.Hash;
69114c39362SHervé Poussineau     FCB->RefCount = 2;
69214c39362SHervé Poussineau     FCB->dirIndex = 0;
69314c39362SHervé Poussineau     FCB->RFCB.FileSize.QuadPart = Size;
69414c39362SHervé Poussineau     FCB->RFCB.ValidDataLength.QuadPart = Size;
69514c39362SHervé Poussineau     FCB->RFCB.AllocationSize.QuadPart = Size;
69614c39362SHervé Poussineau     FCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
69714c39362SHervé Poussineau 
69814c39362SHervé Poussineau     vfatFCBInitializeCacheFromVolume(pVCB, FCB);
69914c39362SHervé Poussineau     vfatAddFCBToTable(pVCB, FCB);
70014c39362SHervé Poussineau 
70114c39362SHervé Poussineau     /* Cache it */
70214c39362SHervé Poussineau     pVCB->RootFcb = FCB;
70314c39362SHervé Poussineau 
70414c39362SHervé Poussineau     return FCB;
70514c39362SHervé Poussineau }
70614c39362SHervé Poussineau 
70714c39362SHervé Poussineau PVFATFCB
vfatOpenRootFCB(PDEVICE_EXTENSION pVCB)70814c39362SHervé Poussineau vfatOpenRootFCB(
70914c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB)
71014c39362SHervé Poussineau {
71114c39362SHervé Poussineau     PVFATFCB FCB;
71214c39362SHervé Poussineau     UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
71314c39362SHervé Poussineau 
71414c39362SHervé Poussineau     FCB = vfatGrabFCBFromTable(pVCB, &NameU);
71514c39362SHervé Poussineau     if (FCB == NULL)
71614c39362SHervé Poussineau     {
71714c39362SHervé Poussineau         FCB = vfatMakeRootFCB(pVCB);
71814c39362SHervé Poussineau     }
71914c39362SHervé Poussineau     ASSERT(FCB == pVCB->RootFcb);
72014c39362SHervé Poussineau 
72114c39362SHervé Poussineau     return FCB;
72214c39362SHervé Poussineau }
72314c39362SHervé Poussineau 
72414c39362SHervé Poussineau NTSTATUS
vfatMakeFCBFromDirEntry(PVCB vcb,PVFATFCB directoryFCB,PVFAT_DIRENTRY_CONTEXT DirContext,PVFATFCB * fileFCB)72514c39362SHervé Poussineau vfatMakeFCBFromDirEntry(
72614c39362SHervé Poussineau     PVCB vcb,
72714c39362SHervé Poussineau     PVFATFCB directoryFCB,
72814c39362SHervé Poussineau     PVFAT_DIRENTRY_CONTEXT DirContext,
72914c39362SHervé Poussineau     PVFATFCB *fileFCB)
73014c39362SHervé Poussineau {
73114c39362SHervé Poussineau     PVFATFCB rcFCB;
73214c39362SHervé Poussineau     UNICODE_STRING NameU;
73314c39362SHervé Poussineau     NTSTATUS Status;
73414c39362SHervé Poussineau 
73514c39362SHervé Poussineau     Status = vfatMakeFullName(directoryFCB, &DirContext->LongNameU, &DirContext->ShortNameU, &NameU);
73614c39362SHervé Poussineau     if (!NT_SUCCESS(Status))
73714c39362SHervé Poussineau     {
73814c39362SHervé Poussineau         return Status;
73914c39362SHervé Poussineau     }
74014c39362SHervé Poussineau 
74114c39362SHervé Poussineau     rcFCB = vfatNewFCB(vcb, &NameU);
742fa809fd2SHervé Poussineau     vfatInitFCBFromDirEntry(vcb, directoryFCB, rcFCB, DirContext);
74314c39362SHervé Poussineau 
74414c39362SHervé Poussineau     rcFCB->RefCount = 1;
74514c39362SHervé Poussineau     InsertTailList(&directoryFCB->ParentListHead, &rcFCB->ParentListEntry);
74614c39362SHervé Poussineau     vfatAddFCBToTable(vcb, rcFCB);
74714c39362SHervé Poussineau     *fileFCB = rcFCB;
74814c39362SHervé Poussineau 
74914c39362SHervé Poussineau     ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
75014c39362SHervé Poussineau     return STATUS_SUCCESS;
75114c39362SHervé Poussineau }
75214c39362SHervé Poussineau 
75314c39362SHervé Poussineau NTSTATUS
vfatAttachFCBToFileObject(PDEVICE_EXTENSION vcb,PVFATFCB fcb,PFILE_OBJECT fileObject)75414c39362SHervé Poussineau vfatAttachFCBToFileObject(
75514c39362SHervé Poussineau     PDEVICE_EXTENSION vcb,
75614c39362SHervé Poussineau     PVFATFCB fcb,
75714c39362SHervé Poussineau     PFILE_OBJECT fileObject)
75814c39362SHervé Poussineau {
75914c39362SHervé Poussineau     PVFATCCB newCCB;
76014c39362SHervé Poussineau 
76114c39362SHervé Poussineau #ifdef KDBG
76214c39362SHervé Poussineau     if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
76314c39362SHervé Poussineau     {
76414c39362SHervé Poussineau         DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
76514c39362SHervé Poussineau     }
76614c39362SHervé Poussineau #endif
76714c39362SHervé Poussineau 
76814c39362SHervé Poussineau     newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
76914c39362SHervé Poussineau     if (newCCB == NULL)
77014c39362SHervé Poussineau     {
77114c39362SHervé Poussineau         return  STATUS_INSUFFICIENT_RESOURCES;
77214c39362SHervé Poussineau     }
77314c39362SHervé Poussineau     RtlZeroMemory(newCCB, sizeof (VFATCCB));
77414c39362SHervé Poussineau 
77514c39362SHervé Poussineau     fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
77614c39362SHervé Poussineau     fileObject->FsContext = fcb;
77714c39362SHervé Poussineau     fileObject->FsContext2 = newCCB;
77814c39362SHervé Poussineau     fileObject->Vpb = vcb->IoVPB;
77914c39362SHervé Poussineau     DPRINT("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU);
78014c39362SHervé Poussineau 
78114c39362SHervé Poussineau #ifdef KDBG
78214c39362SHervé Poussineau     fcb->Flags &= ~FCB_CLEANED_UP;
78314c39362SHervé Poussineau     fcb->Flags &= ~FCB_CLOSED;
78414c39362SHervé Poussineau #endif
78514c39362SHervé Poussineau 
78614c39362SHervé Poussineau     return STATUS_SUCCESS;
78714c39362SHervé Poussineau }
78814c39362SHervé Poussineau 
78914c39362SHervé Poussineau NTSTATUS
vfatDirFindFile(PDEVICE_EXTENSION pDeviceExt,PVFATFCB pDirectoryFCB,PUNICODE_STRING FileToFindU,PVFATFCB * pFoundFCB)79014c39362SHervé Poussineau vfatDirFindFile(
79114c39362SHervé Poussineau     PDEVICE_EXTENSION pDeviceExt,
79214c39362SHervé Poussineau     PVFATFCB pDirectoryFCB,
79314c39362SHervé Poussineau     PUNICODE_STRING FileToFindU,
79414c39362SHervé Poussineau     PVFATFCB *pFoundFCB)
79514c39362SHervé Poussineau {
79614c39362SHervé Poussineau     NTSTATUS status;
79714c39362SHervé Poussineau     PVOID Context = NULL;
79814c39362SHervé Poussineau     PVOID Page = NULL;
79914c39362SHervé Poussineau     BOOLEAN First = TRUE;
80014c39362SHervé Poussineau     VFAT_DIRENTRY_CONTEXT DirContext;
80114c39362SHervé Poussineau     /* This buffer must have a size of 260 characters, because
80214c39362SHervé Poussineau     vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
80314c39362SHervé Poussineau     WCHAR LongNameBuffer[260];
80414c39362SHervé Poussineau     WCHAR ShortNameBuffer[13];
80514c39362SHervé Poussineau     BOOLEAN FoundLong = FALSE;
80614c39362SHervé Poussineau     BOOLEAN FoundShort = FALSE;
80714c39362SHervé Poussineau     BOOLEAN IsFatX = vfatVolumeIsFatX(pDeviceExt);
80814c39362SHervé Poussineau 
80914c39362SHervé Poussineau     ASSERT(pDeviceExt);
81014c39362SHervé Poussineau     ASSERT(pDirectoryFCB);
81114c39362SHervé Poussineau     ASSERT(FileToFindU);
81214c39362SHervé Poussineau 
81314c39362SHervé Poussineau     DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
81414c39362SHervé Poussineau            pDeviceExt, pDirectoryFCB, FileToFindU);
81514c39362SHervé Poussineau     DPRINT("Dir Path:%wZ\n", &pDirectoryFCB->PathNameU);
81614c39362SHervé Poussineau 
81714c39362SHervé Poussineau     DirContext.DirIndex = 0;
81814c39362SHervé Poussineau     DirContext.LongNameU.Buffer = LongNameBuffer;
81914c39362SHervé Poussineau     DirContext.LongNameU.Length = 0;
82014c39362SHervé Poussineau     DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
82114c39362SHervé Poussineau     DirContext.ShortNameU.Buffer = ShortNameBuffer;
82214c39362SHervé Poussineau     DirContext.ShortNameU.Length = 0;
82314c39362SHervé Poussineau     DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
82414c39362SHervé Poussineau     DirContext.DeviceExt = pDeviceExt;
82514c39362SHervé Poussineau 
82614c39362SHervé Poussineau     while (TRUE)
82714c39362SHervé Poussineau     {
82814c39362SHervé Poussineau         status = VfatGetNextDirEntry(pDeviceExt,
82914c39362SHervé Poussineau             &Context,
83014c39362SHervé Poussineau             &Page,
83114c39362SHervé Poussineau             pDirectoryFCB,
83214c39362SHervé Poussineau             &DirContext,
83314c39362SHervé Poussineau             First);
83414c39362SHervé Poussineau         First = FALSE;
83514c39362SHervé Poussineau         if (status == STATUS_NO_MORE_ENTRIES)
83614c39362SHervé Poussineau         {
83714c39362SHervé Poussineau             return STATUS_OBJECT_NAME_NOT_FOUND;
83814c39362SHervé Poussineau         }
83914c39362SHervé Poussineau         if (!NT_SUCCESS(status))
84014c39362SHervé Poussineau         {
84114c39362SHervé Poussineau             return status;
84214c39362SHervé Poussineau         }
84314c39362SHervé Poussineau 
84414c39362SHervé Poussineau         DPRINT("  Index:%u  longName:%wZ\n",
84514c39362SHervé Poussineau                DirContext.DirIndex, &DirContext.LongNameU);
84614c39362SHervé Poussineau 
84714c39362SHervé Poussineau         if (!ENTRY_VOLUME(IsFatX, &DirContext.DirEntry))
84814c39362SHervé Poussineau         {
84914c39362SHervé Poussineau             if (DirContext.LongNameU.Length == 0 ||
85014c39362SHervé Poussineau                 DirContext.ShortNameU.Length == 0)
85114c39362SHervé Poussineau             {
85214c39362SHervé Poussineau                 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
85314c39362SHervé Poussineau                 if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
85414c39362SHervé Poussineau                 {
85514c39362SHervé Poussineau                     ASSERT(DirContext.LongNameU.Length != 0 &&
85614c39362SHervé Poussineau                            DirContext.ShortNameU.Length != 0);
85714c39362SHervé Poussineau                 }
85814c39362SHervé Poussineau                 DirContext.DirIndex++;
85914c39362SHervé Poussineau                 continue;
86014c39362SHervé Poussineau             }
86114c39362SHervé Poussineau             FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE);
86214c39362SHervé Poussineau             if (FoundLong == FALSE)
86314c39362SHervé Poussineau             {
86414c39362SHervé Poussineau                 FoundShort = RtlEqualUnicodeString(FileToFindU, &DirContext.ShortNameU, TRUE);
86514c39362SHervé Poussineau             }
86614c39362SHervé Poussineau             if (FoundLong || FoundShort)
86714c39362SHervé Poussineau             {
86814c39362SHervé Poussineau                 status = vfatMakeFCBFromDirEntry(pDeviceExt,
86914c39362SHervé Poussineau                     pDirectoryFCB,
87014c39362SHervé Poussineau                     &DirContext,
87114c39362SHervé Poussineau                     pFoundFCB);
87214c39362SHervé Poussineau                 CcUnpinData(Context);
87314c39362SHervé Poussineau                 return status;
87414c39362SHervé Poussineau             }
87514c39362SHervé Poussineau         }
87614c39362SHervé Poussineau         DirContext.DirIndex++;
87714c39362SHervé Poussineau     }
87814c39362SHervé Poussineau 
87914c39362SHervé Poussineau     return STATUS_OBJECT_NAME_NOT_FOUND;
88014c39362SHervé Poussineau }
88114c39362SHervé Poussineau 
88214c39362SHervé Poussineau NTSTATUS
vfatGetFCBForFile(PDEVICE_EXTENSION pVCB,PVFATFCB * pParentFCB,PVFATFCB * pFCB,PUNICODE_STRING pFileNameU)88314c39362SHervé Poussineau vfatGetFCBForFile(
88414c39362SHervé Poussineau     PDEVICE_EXTENSION pVCB,
88514c39362SHervé Poussineau     PVFATFCB *pParentFCB,
88614c39362SHervé Poussineau     PVFATFCB *pFCB,
88714c39362SHervé Poussineau     PUNICODE_STRING pFileNameU)
88814c39362SHervé Poussineau {
88914c39362SHervé Poussineau     NTSTATUS status;
89014c39362SHervé Poussineau     PVFATFCB FCB = NULL;
89114c39362SHervé Poussineau     PVFATFCB parentFCB;
89214c39362SHervé Poussineau     UNICODE_STRING NameU;
89314c39362SHervé Poussineau     UNICODE_STRING RootNameU = RTL_CONSTANT_STRING(L"\\");
89414c39362SHervé Poussineau     UNICODE_STRING FileNameU;
89514c39362SHervé Poussineau     WCHAR NameBuffer[260];
89614c39362SHervé Poussineau     PWCHAR curr, prev, last;
89714c39362SHervé Poussineau     ULONG Length;
89814c39362SHervé Poussineau 
89914c39362SHervé Poussineau     DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
90014c39362SHervé Poussineau            pVCB, pParentFCB, pFCB, pFileNameU);
90114c39362SHervé Poussineau 
90214c39362SHervé Poussineau     RtlInitEmptyUnicodeString(&FileNameU, NameBuffer, sizeof(NameBuffer));
90314c39362SHervé Poussineau 
90414c39362SHervé Poussineau     parentFCB = *pParentFCB;
90514c39362SHervé Poussineau 
90614c39362SHervé Poussineau     if (parentFCB == NULL)
90714c39362SHervé Poussineau     {
90814c39362SHervé Poussineau         /* Passed-in name is the full name */
90914c39362SHervé Poussineau         RtlCopyUnicodeString(&FileNameU, pFileNameU);
91014c39362SHervé Poussineau 
91114c39362SHervé Poussineau         //  Trivial case, open of the root directory on volume
91214c39362SHervé Poussineau         if (RtlEqualUnicodeString(&FileNameU, &RootNameU, FALSE))
91314c39362SHervé Poussineau         {
91414c39362SHervé Poussineau             DPRINT("returning root FCB\n");
91514c39362SHervé Poussineau 
91614c39362SHervé Poussineau             FCB = vfatOpenRootFCB(pVCB);
91714c39362SHervé Poussineau             *pFCB = FCB;
91814c39362SHervé Poussineau             *pParentFCB = NULL;
91914c39362SHervé Poussineau 
92014c39362SHervé Poussineau             return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
92114c39362SHervé Poussineau         }
92214c39362SHervé Poussineau 
92314c39362SHervé Poussineau         /* Check for an existing FCB */
92414c39362SHervé Poussineau         FCB = vfatGrabFCBFromTable(pVCB, &FileNameU);
92514c39362SHervé Poussineau         if (FCB)
92614c39362SHervé Poussineau         {
92714c39362SHervé Poussineau             *pFCB = FCB;
92814c39362SHervé Poussineau             *pParentFCB = FCB->parentFcb;
92914c39362SHervé Poussineau             vfatGrabFCB(pVCB, *pParentFCB);
93014c39362SHervé Poussineau             return STATUS_SUCCESS;
93114c39362SHervé Poussineau         }
93214c39362SHervé Poussineau 
93314c39362SHervé Poussineau         last = curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
93414c39362SHervé Poussineau         while (*curr != L'\\' && curr > FileNameU.Buffer)
93514c39362SHervé Poussineau         {
93614c39362SHervé Poussineau             curr--;
93714c39362SHervé Poussineau         }
93814c39362SHervé Poussineau 
93914c39362SHervé Poussineau         if (curr > FileNameU.Buffer)
94014c39362SHervé Poussineau         {
94114c39362SHervé Poussineau             NameU.Buffer = FileNameU.Buffer;
94214c39362SHervé Poussineau             NameU.MaximumLength = NameU.Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
94314c39362SHervé Poussineau             FCB = vfatGrabFCBFromTable(pVCB, &NameU);
94414c39362SHervé Poussineau             if (FCB)
94514c39362SHervé Poussineau             {
94614c39362SHervé Poussineau                 Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
94714c39362SHervé Poussineau                 if (Length != FCB->PathNameU.Length)
94814c39362SHervé Poussineau                 {
94914c39362SHervé Poussineau                     if (FileNameU.Length + FCB->PathNameU.Length - Length > FileNameU.MaximumLength)
95014c39362SHervé Poussineau                     {
95114c39362SHervé Poussineau                         vfatReleaseFCB(pVCB, FCB);
95214c39362SHervé Poussineau                         return STATUS_OBJECT_NAME_INVALID;
95314c39362SHervé Poussineau                     }
95414c39362SHervé Poussineau                     RtlMoveMemory(FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR),
95514c39362SHervé Poussineau                         curr, FileNameU.Length - Length);
95614c39362SHervé Poussineau                     FileNameU.Length += (USHORT)(FCB->PathNameU.Length - Length);
95714c39362SHervé Poussineau                     curr = FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR);
95814c39362SHervé Poussineau                     last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
95914c39362SHervé Poussineau                 }
96014c39362SHervé Poussineau                 RtlCopyMemory(FileNameU.Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
96114c39362SHervé Poussineau             }
96214c39362SHervé Poussineau         }
96314c39362SHervé Poussineau         else
96414c39362SHervé Poussineau         {
96514c39362SHervé Poussineau             FCB = NULL;
96614c39362SHervé Poussineau         }
96714c39362SHervé Poussineau 
96814c39362SHervé Poussineau         if (FCB == NULL)
96914c39362SHervé Poussineau         {
97014c39362SHervé Poussineau             FCB = vfatOpenRootFCB(pVCB);
97114c39362SHervé Poussineau             curr = FileNameU.Buffer;
97214c39362SHervé Poussineau         }
97314c39362SHervé Poussineau 
97414c39362SHervé Poussineau         parentFCB = NULL;
97514c39362SHervé Poussineau         prev = curr;
97614c39362SHervé Poussineau     }
97714c39362SHervé Poussineau     else
97814c39362SHervé Poussineau     {
97914c39362SHervé Poussineau         /* Make absolute path */
98014c39362SHervé Poussineau         RtlCopyUnicodeString(&FileNameU, &parentFCB->PathNameU);
98114c39362SHervé Poussineau         curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
98214c39362SHervé Poussineau         if (*curr != L'\\')
98314c39362SHervé Poussineau         {
98414c39362SHervé Poussineau             RtlAppendUnicodeToString(&FileNameU, L"\\");
98514c39362SHervé Poussineau             curr++;
98614c39362SHervé Poussineau         }
98714c39362SHervé Poussineau         ASSERT(*curr == L'\\');
98814c39362SHervé Poussineau         RtlAppendUnicodeStringToString(&FileNameU, pFileNameU);
98914c39362SHervé Poussineau 
99014c39362SHervé Poussineau         FCB = parentFCB;
99114c39362SHervé Poussineau         parentFCB = NULL;
99214c39362SHervé Poussineau         prev = curr;
99314c39362SHervé Poussineau         last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
99414c39362SHervé Poussineau     }
99514c39362SHervé Poussineau 
99614c39362SHervé Poussineau     while (curr <= last)
99714c39362SHervé Poussineau     {
99814c39362SHervé Poussineau         if (parentFCB)
99914c39362SHervé Poussineau         {
100014c39362SHervé Poussineau             vfatReleaseFCB(pVCB, parentFCB);
100114c39362SHervé Poussineau             parentFCB = NULL;
100214c39362SHervé Poussineau         }
100314c39362SHervé Poussineau         //  fail if element in FCB is not a directory
100414c39362SHervé Poussineau         if (!vfatFCBIsDirectory(FCB))
100514c39362SHervé Poussineau         {
100614c39362SHervé Poussineau             DPRINT ("Element in requested path is not a directory\n");
100714c39362SHervé Poussineau 
100814c39362SHervé Poussineau             vfatReleaseFCB(pVCB, FCB);
100914c39362SHervé Poussineau             FCB = NULL;
101014c39362SHervé Poussineau             *pParentFCB = NULL;
101114c39362SHervé Poussineau             *pFCB = NULL;
101214c39362SHervé Poussineau 
101314c39362SHervé Poussineau             return  STATUS_OBJECT_PATH_NOT_FOUND;
101414c39362SHervé Poussineau         }
101514c39362SHervé Poussineau         parentFCB = FCB;
101614c39362SHervé Poussineau         if (prev < curr)
101714c39362SHervé Poussineau         {
101814c39362SHervé Poussineau             Length = (curr - prev) * sizeof(WCHAR);
101914c39362SHervé Poussineau             if (Length != parentFCB->LongNameU.Length)
102014c39362SHervé Poussineau             {
102114c39362SHervé Poussineau                 if (FileNameU.Length + parentFCB->LongNameU.Length - Length > FileNameU.MaximumLength)
102214c39362SHervé Poussineau                 {
102314c39362SHervé Poussineau                     vfatReleaseFCB(pVCB, parentFCB);
102414c39362SHervé Poussineau                     *pParentFCB = NULL;
102514c39362SHervé Poussineau                     *pFCB = NULL;
102614c39362SHervé Poussineau                     return STATUS_OBJECT_NAME_INVALID;
102714c39362SHervé Poussineau                 }
102814c39362SHervé Poussineau                 RtlMoveMemory(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr,
102914c39362SHervé Poussineau                     FileNameU.Length - (curr - FileNameU.Buffer) * sizeof(WCHAR));
103014c39362SHervé Poussineau                 FileNameU.Length += (USHORT)(parentFCB->LongNameU.Length - Length);
103114c39362SHervé Poussineau                 curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR);
103214c39362SHervé Poussineau                 last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
103314c39362SHervé Poussineau             }
103414c39362SHervé Poussineau             RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
103514c39362SHervé Poussineau         }
103614c39362SHervé Poussineau         curr++;
103714c39362SHervé Poussineau         prev = curr;
103814c39362SHervé Poussineau         while (*curr != L'\\' && curr <= last)
103914c39362SHervé Poussineau         {
104014c39362SHervé Poussineau             curr++;
104114c39362SHervé Poussineau         }
104214c39362SHervé Poussineau         NameU.Buffer = FileNameU.Buffer;
104314c39362SHervé Poussineau         NameU.Length = (curr - NameU.Buffer) * sizeof(WCHAR);
104414c39362SHervé Poussineau         NameU.MaximumLength = FileNameU.MaximumLength;
104514c39362SHervé Poussineau         DPRINT("%wZ\n", &NameU);
104614c39362SHervé Poussineau         FCB = vfatGrabFCBFromTable(pVCB, &NameU);
104714c39362SHervé Poussineau         if (FCB == NULL)
104814c39362SHervé Poussineau         {
104914c39362SHervé Poussineau             NameU.Buffer = prev;
105014c39362SHervé Poussineau             NameU.MaximumLength = NameU.Length = (curr - prev) * sizeof(WCHAR);
105114c39362SHervé Poussineau             status = vfatDirFindFile(pVCB, parentFCB, &NameU, &FCB);
105214c39362SHervé Poussineau             if (status == STATUS_OBJECT_NAME_NOT_FOUND)
105314c39362SHervé Poussineau             {
105414c39362SHervé Poussineau                 *pFCB = NULL;
105514c39362SHervé Poussineau                 if (curr > last)
105614c39362SHervé Poussineau                 {
105714c39362SHervé Poussineau                     *pParentFCB = parentFCB;
105814c39362SHervé Poussineau                     return STATUS_OBJECT_NAME_NOT_FOUND;
105914c39362SHervé Poussineau                 }
106014c39362SHervé Poussineau                 else
106114c39362SHervé Poussineau                 {
106214c39362SHervé Poussineau                     vfatReleaseFCB(pVCB, parentFCB);
106314c39362SHervé Poussineau                     *pParentFCB = NULL;
106414c39362SHervé Poussineau                     return STATUS_OBJECT_PATH_NOT_FOUND;
106514c39362SHervé Poussineau                 }
106614c39362SHervé Poussineau             }
106714c39362SHervé Poussineau             else if (!NT_SUCCESS(status))
106814c39362SHervé Poussineau             {
106914c39362SHervé Poussineau                 vfatReleaseFCB(pVCB, parentFCB);
107014c39362SHervé Poussineau                 *pParentFCB = NULL;
107114c39362SHervé Poussineau                 *pFCB = NULL;
107214c39362SHervé Poussineau 
107314c39362SHervé Poussineau                 return status;
107414c39362SHervé Poussineau             }
107514c39362SHervé Poussineau         }
107614c39362SHervé Poussineau     }
107714c39362SHervé Poussineau 
107814c39362SHervé Poussineau     *pParentFCB = parentFCB;
107914c39362SHervé Poussineau     *pFCB = FCB;
108014c39362SHervé Poussineau 
108114c39362SHervé Poussineau     return STATUS_SUCCESS;
108214c39362SHervé Poussineau }
1083