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