xref: /reactos/drivers/filesystems/ntfs/fcb.c (revision 4561998a)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002, 2014 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * COPYRIGHT:        See COPYING in the top level directory
20  * PROJECT:          ReactOS kernel
21  * FILE:             drivers/filesystem/ntfs/fcb.c
22  * PURPOSE:          NTFS filesystem driver
23  * PROGRAMMERS:      Eric Kohl
24  *                   Pierre Schweitzer (pierre@reactos.org)
25  *                   Hervé Poussineau (hpoussin@reactos.org)
26  */
27 
28 /* INCLUDES *****************************************************************/
29 
30 #include "ntfs.h"
31 
32 #define NDEBUG
33 #include <debug.h>
34 
35 /* FUNCTIONS ****************************************************************/
36 
37 static
38 PCWSTR
39 NtfsGetNextPathElement(PCWSTR FileName)
40 {
41     if (*FileName == L'\0')
42     {
43         return NULL;
44     }
45 
46     while (*FileName != L'\0' && *FileName != L'\\')
47     {
48         FileName++;
49     }
50 
51     return FileName;
52 }
53 
54 
55 static
56 VOID
57 NtfsWSubString(PWCHAR pTarget,
58                PCWSTR pSource,
59                size_t pLength)
60 {
61     wcsncpy(pTarget, pSource, pLength);
62     pTarget[pLength] = L'\0';
63 }
64 
65 
66 PNTFS_FCB
67 NtfsCreateFCB(PCWSTR FileName,
68               PCWSTR Stream,
69               PNTFS_VCB Vcb)
70 {
71     PNTFS_FCB Fcb;
72 
73     ASSERT(Vcb);
74     ASSERT(Vcb->Identifier.Type == NTFS_TYPE_VCB);
75 
76     Fcb = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->FcbLookasideList);
77     RtlZeroMemory(Fcb, sizeof(NTFS_FCB));
78 
79     Fcb->Identifier.Type = NTFS_TYPE_FCB;
80     Fcb->Identifier.Size = sizeof(NTFS_TYPE_FCB);
81 
82     Fcb->Vcb = Vcb;
83 
84     if (FileName)
85     {
86         wcscpy(Fcb->PathName, FileName);
87         if (wcsrchr(Fcb->PathName, '\\') != 0)
88         {
89             Fcb->ObjectName = wcsrchr(Fcb->PathName, '\\');
90         }
91         else
92         {
93             Fcb->ObjectName = Fcb->PathName;
94         }
95     }
96 
97     if (Stream)
98     {
99         wcscpy(Fcb->Stream, Stream);
100     }
101     else
102     {
103         Fcb->Stream[0] = UNICODE_NULL;
104     }
105 
106     ExInitializeResourceLite(&Fcb->MainResource);
107 
108     Fcb->RFCB.Resource = &(Fcb->MainResource);
109 
110     return Fcb;
111 }
112 
113 
114 VOID
115 NtfsDestroyFCB(PNTFS_FCB Fcb)
116 {
117     ASSERT(Fcb);
118     ASSERT(Fcb->Identifier.Type == NTFS_TYPE_FCB);
119 
120     ExDeleteResourceLite(&Fcb->MainResource);
121 
122     ExFreeToNPagedLookasideList(&NtfsGlobalData->FcbLookasideList, Fcb);
123 }
124 
125 
126 BOOLEAN
127 NtfsFCBIsDirectory(PNTFS_FCB Fcb)
128 {
129     return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_DIRECTORY) == NTFS_FILE_TYPE_DIRECTORY);
130 }
131 
132 
133 BOOLEAN
134 NtfsFCBIsReparsePoint(PNTFS_FCB Fcb)
135 {
136     return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_REPARSE) == NTFS_FILE_TYPE_REPARSE);
137 }
138 
139 
140 BOOLEAN
141 NtfsFCBIsCompressed(PNTFS_FCB Fcb)
142 {
143     return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_COMPRESSED) == NTFS_FILE_TYPE_COMPRESSED);
144 }
145 
146 BOOLEAN
147 NtfsFCBIsRoot(PNTFS_FCB Fcb)
148 {
149     return (wcscmp(Fcb->PathName, L"\\") == 0);
150 }
151 
152 
153 VOID
154 NtfsGrabFCB(PNTFS_VCB Vcb,
155             PNTFS_FCB Fcb)
156 {
157     KIRQL oldIrql;
158 
159     DPRINT("grabbing FCB at %p: %S, refCount:%d\n",
160            Fcb,
161            Fcb->PathName,
162            Fcb->RefCount);
163 
164     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
165     Fcb->RefCount++;
166     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
167 }
168 
169 
170 VOID
171 NtfsReleaseFCB(PNTFS_VCB Vcb,
172                PNTFS_FCB Fcb)
173 {
174     KIRQL oldIrql;
175 
176     DPRINT("releasing FCB at %p: %S, refCount:%d\n",
177            Fcb,
178            Fcb->PathName,
179            Fcb->RefCount);
180 
181     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
182     Fcb->RefCount--;
183     if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb))
184     {
185         RemoveEntryList(&Fcb->FcbListEntry);
186         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
187         CcUninitializeCacheMap(Fcb->FileObject, NULL, NULL);
188         NtfsDestroyFCB(Fcb);
189     }
190     else
191     {
192         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
193     }
194 }
195 
196 
197 VOID
198 NtfsAddFCBToTable(PNTFS_VCB Vcb,
199                   PNTFS_FCB Fcb)
200 {
201     KIRQL oldIrql;
202 
203     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
204     Fcb->Vcb = Vcb;
205     InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
206     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
207 }
208 
209 
210 PNTFS_FCB
211 NtfsGrabFCBFromTable(PNTFS_VCB Vcb,
212                      PCWSTR FileName)
213 {
214     KIRQL oldIrql;
215     PNTFS_FCB Fcb;
216     PLIST_ENTRY current_entry;
217 
218     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
219 
220     if (FileName == NULL || *FileName == 0)
221     {
222         DPRINT("Return FCB for stream file object\n");
223         Fcb = Vcb->StreamFileObject->FsContext;
224         Fcb->RefCount++;
225         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
226         return Fcb;
227     }
228 
229     current_entry = Vcb->FcbListHead.Flink;
230     while (current_entry != &Vcb->FcbListHead)
231     {
232         Fcb = CONTAINING_RECORD(current_entry, NTFS_FCB, FcbListEntry);
233 
234         DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName);
235         if (_wcsicmp(FileName, Fcb->PathName) == 0)
236         {
237             Fcb->RefCount++;
238             KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
239             return Fcb;
240         }
241 
242         //FIXME: need to compare against short name in FCB here
243 
244         current_entry = current_entry->Flink;
245     }
246 
247     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
248 
249     return NULL;
250 }
251 
252 
253 NTSTATUS
254 NtfsFCBInitializeCache(PNTFS_VCB Vcb,
255                        PNTFS_FCB Fcb)
256 {
257     PFILE_OBJECT FileObject;
258     NTSTATUS Status;
259     PNTFS_CCB newCCB;
260 
261     FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
262 
263     newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
264     if (newCCB == NULL)
265     {
266         return STATUS_INSUFFICIENT_RESOURCES;
267     }
268 
269     RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
270 
271     newCCB->Identifier.Type = NTFS_TYPE_CCB;
272     newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
273 
274     FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
275     FileObject->FsContext = Fcb;
276     FileObject->FsContext2 = newCCB;
277     newCCB->PtrFileObject = FileObject;
278     Fcb->FileObject = FileObject;
279     Fcb->Vcb = Vcb;
280 
281     Status = STATUS_SUCCESS;
282     _SEH2_TRY
283     {
284         CcInitializeCacheMap(FileObject,
285                              (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
286                              FALSE,
287                              &(NtfsGlobalData->CacheMgrCallbacks),
288                              Fcb);
289     }
290     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
291     {
292         FileObject->FsContext2 = NULL;
293         ExFreePoolWithTag(newCCB, TAG_CCB);
294         ObDereferenceObject(FileObject);
295         Fcb->FileObject = NULL;
296         return _SEH2_GetExceptionCode();
297     }
298     _SEH2_END;
299 
300     ObDereferenceObject(FileObject);
301     Fcb->Flags |= FCB_CACHE_INITIALIZED;
302 
303     return Status;
304 }
305 
306 
307 PNTFS_FCB
308 NtfsMakeRootFCB(PNTFS_VCB Vcb)
309 {
310     PNTFS_FCB Fcb;
311     PFILE_RECORD_HEADER MftRecord;
312     PFILENAME_ATTRIBUTE FileName;
313 
314     MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
315     if (MftRecord == NULL)
316     {
317         return NULL;
318     }
319 
320     if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
321     {
322         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
323         return NULL;
324     }
325 
326     FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
327     if (!FileName)
328     {
329         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
330         return NULL;
331     }
332 
333     Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
334     if (!Fcb)
335     {
336         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
337         return NULL;
338     }
339 
340     memcpy(&Fcb->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
341     Fcb->Entry.NameType = FileName->NameType;
342     Fcb->Entry.NameLength = 0;
343     Fcb->Entry.Name[0] = UNICODE_NULL;
344     Fcb->RefCount = 1;
345     Fcb->DirIndex = 0;
346     Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
347     Fcb->RFCB.ValidDataLength.QuadPart = FileName->DataSize;
348     Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
349     Fcb->MFTIndex = NTFS_FILE_ROOT;
350     Fcb->LinkCount = MftRecord->LinkCount;
351 
352     NtfsFCBInitializeCache(Vcb, Fcb);
353     NtfsAddFCBToTable(Vcb, Fcb);
354     NtfsGrabFCB(Vcb, Fcb);
355 
356     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
357 
358     return Fcb;
359 }
360 
361 
362 PNTFS_FCB
363 NtfsOpenRootFCB(PNTFS_VCB Vcb)
364 {
365     PNTFS_FCB Fcb;
366 
367     Fcb = NtfsGrabFCBFromTable(Vcb, L"\\");
368     if (Fcb == NULL)
369     {
370         Fcb = NtfsMakeRootFCB(Vcb);
371     }
372 
373     return Fcb;
374 }
375 
376 
377 NTSTATUS
378 NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
379                         PNTFS_FCB DirectoryFCB,
380                         PUNICODE_STRING Name,
381                         PCWSTR Stream,
382                         PFILE_RECORD_HEADER Record,
383                         ULONGLONG MFTIndex,
384                         PNTFS_FCB * fileFCB)
385 {
386     WCHAR pathName[MAX_PATH];
387     PFILENAME_ATTRIBUTE FileName;
388     PSTANDARD_INFORMATION StdInfo;
389     PNTFS_FCB rcFCB;
390     ULONGLONG Size, AllocatedSize;
391 
392     DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
393 
394     FileName = GetBestFileNameFromRecord(Vcb, Record);
395     if (!FileName)
396     {
397         return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
398     }
399 
400     if (DirectoryFCB && Name)
401     {
402         if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
403             sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
404         {
405             return STATUS_OBJECT_NAME_INVALID;
406         }
407 
408         wcscpy(pathName, DirectoryFCB->PathName);
409         if (!NtfsFCBIsRoot(DirectoryFCB))
410         {
411             wcscat(pathName, L"\\");
412         }
413         wcscat(pathName, Name->Buffer);
414     }
415     else
416     {
417         RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
418         pathName[FileName->NameLength] = UNICODE_NULL;
419     }
420 
421     Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
422 
423     rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
424     if (!rcFCB)
425     {
426         return STATUS_INSUFFICIENT_RESOURCES;
427     }
428 
429     memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
430     rcFCB->Entry.NameType = FileName->NameType;
431     rcFCB->RFCB.FileSize.QuadPart = Size;
432     rcFCB->RFCB.ValidDataLength.QuadPart = Size;
433     rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
434 
435     StdInfo = GetStandardInformationFromRecord(Vcb, Record);
436     if (StdInfo != NULL)
437     {
438         rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
439     }
440 
441     NtfsFCBInitializeCache(Vcb, rcFCB);
442     rcFCB->RefCount = 1;
443     rcFCB->MFTIndex = MFTIndex;
444     rcFCB->LinkCount = Record->LinkCount;
445     NtfsAddFCBToTable(Vcb, rcFCB);
446     *fileFCB = rcFCB;
447 
448     return STATUS_SUCCESS;
449 }
450 
451 
452 NTSTATUS
453 NtfsAttachFCBToFileObject(PNTFS_VCB Vcb,
454                           PNTFS_FCB Fcb,
455                           PFILE_OBJECT FileObject)
456 {
457     PNTFS_CCB newCCB;
458 
459     newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
460     if (newCCB == NULL)
461     {
462         return STATUS_INSUFFICIENT_RESOURCES;
463     }
464 
465     RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
466 
467     newCCB->Identifier.Type = NTFS_TYPE_CCB;
468     newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
469 
470     FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
471     FileObject->FsContext = Fcb;
472     FileObject->FsContext2 = newCCB;
473     newCCB->PtrFileObject = FileObject;
474     Fcb->Vcb = Vcb;
475 
476     if (!(Fcb->Flags & FCB_CACHE_INITIALIZED))
477     {
478         _SEH2_TRY
479         {
480             CcInitializeCacheMap(FileObject,
481                                  (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
482                                  FALSE,
483                                  &(NtfsGlobalData->CacheMgrCallbacks),
484                                  Fcb);
485         }
486         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
487         {
488             FileObject->FsContext2 = NULL;
489             ExFreePoolWithTag(newCCB, TAG_CCB);
490             return _SEH2_GetExceptionCode();
491         }
492         _SEH2_END;
493 
494         Fcb->Flags |= FCB_CACHE_INITIALIZED;
495     }
496 
497     //DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
498 
499     return STATUS_SUCCESS;
500 }
501 
502 
503 static NTSTATUS
504 NtfsDirFindFile(PNTFS_VCB Vcb,
505                 PNTFS_FCB DirectoryFcb,
506                 PWSTR FileToFind,
507                 BOOLEAN CaseSensitive,
508                 PNTFS_FCB *FoundFCB)
509 {
510     NTSTATUS Status;
511     ULONGLONG CurrentDir;
512     UNICODE_STRING File;
513     PFILE_RECORD_HEADER FileRecord;
514     ULONGLONG MFTIndex;
515     PWSTR Colon, OldColon;
516     PNTFS_ATTR_CONTEXT DataContext;
517     USHORT Length = 0;
518 
519     DPRINT1("NtfsDirFindFile(%p, %p, %S, %s, %p)\n",
520             Vcb,
521             DirectoryFcb,
522             FileToFind,
523             CaseSensitive ? "TRUE" : "FALSE",
524             FoundFCB);
525 
526     *FoundFCB = NULL;
527     RtlInitUnicodeString(&File, FileToFind);
528     CurrentDir = DirectoryFcb->MFTIndex;
529 
530     Colon = wcsrchr(FileToFind, L':');
531     if (Colon != NULL)
532     {
533         Length = File.Length;
534         File.Length = (Colon - FileToFind) * sizeof(WCHAR);
535 
536         if (_wcsicmp(Colon + 1, L"$DATA") == 0)
537         {
538             OldColon = Colon;
539             Colon[0] = UNICODE_NULL;
540             Colon = wcsrchr(FileToFind, L':');
541             if (Colon != NULL)
542             {
543                 Length = File.Length;
544                 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
545             }
546             else
547             {
548                 Colon = OldColon;
549                 Colon[0] = L':';
550             }
551         }
552 
553         /* Skip colon */
554         ++Colon;
555         DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon);
556     }
557 
558     Status = NtfsLookupFileAt(Vcb, &File, CaseSensitive, &FileRecord, &MFTIndex, CurrentDir);
559     if (!NT_SUCCESS(Status))
560     {
561         return Status;
562     }
563 
564     if (Length != 0)
565     {
566         File.Length = Length;
567     }
568 
569     if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0)
570     {
571         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
572         return STATUS_INVALID_PARAMETER;
573     }
574     else if (Colon != 0)
575     {
576         Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL);
577         if (!NT_SUCCESS(Status))
578         {
579             return STATUS_OBJECT_NAME_NOT_FOUND;
580         }
581         ReleaseAttributeContext(DataContext);
582     }
583 
584     Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB);
585     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
586 
587     return Status;
588 }
589 
590 
591 NTSTATUS
592 NtfsGetFCBForFile(PNTFS_VCB Vcb,
593                   PNTFS_FCB *pParentFCB,
594                   PNTFS_FCB *pFCB,
595                   PCWSTR pFileName,
596                   BOOLEAN CaseSensitive)
597 {
598     NTSTATUS Status;
599     WCHAR pathName [MAX_PATH];
600     WCHAR elementName [MAX_PATH];
601     PCWSTR currentElement;
602     PNTFS_FCB FCB;
603     PNTFS_FCB parentFCB;
604 
605     DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n",
606            Vcb,
607            pParentFCB,
608            pFCB,
609            pFileName,
610            CaseSensitive ? "TRUE" : "FALSE");
611 
612     /* Dummy code */
613 //  FCB = NtfsOpenRootFCB(Vcb);
614 //  *pFCB = FCB;
615 //  *pParentFCB = NULL;
616 
617 #if 1
618     /* Trivial case, open of the root directory on volume */
619     if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
620     {
621         DPRINT("returning root FCB\n");
622 
623         FCB = NtfsOpenRootFCB(Vcb);
624         *pFCB = FCB;
625         *pParentFCB = NULL;
626 
627         return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
628     }
629     else
630     {
631         currentElement = pFileName + 1;
632         wcscpy (pathName, L"\\");
633         FCB = NtfsOpenRootFCB (Vcb);
634     }
635 
636     parentFCB = NULL;
637 
638     /* Parse filename and check each path element for existence and access */
639     while (NtfsGetNextPathElement(currentElement) != 0)
640     {
641         /* Skip blank directory levels */
642         if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
643         {
644             currentElement++;
645             continue;
646         }
647 
648         DPRINT("Parsing, currentElement:%S\n", currentElement);
649         DPRINT("  parentFCB:%p FCB:%p\n", parentFCB, FCB);
650 
651         /* Descend to next directory level */
652         if (parentFCB)
653         {
654             NtfsReleaseFCB(Vcb, parentFCB);
655             parentFCB = NULL;
656         }
657 
658         /* fail if element in FCB is not a directory */
659         if (!NtfsFCBIsDirectory(FCB))
660         {
661             DPRINT("Element in requested path is not a directory\n");
662 
663             NtfsReleaseFCB(Vcb, FCB);
664             FCB = 0;
665             *pParentFCB = NULL;
666             *pFCB = NULL;
667 
668             return STATUS_OBJECT_PATH_NOT_FOUND;
669         }
670 
671         parentFCB = FCB;
672 
673         /* Extract next directory level into dirName */
674         NtfsWSubString(pathName,
675                        pFileName,
676                        NtfsGetNextPathElement(currentElement) - pFileName);
677         DPRINT("  pathName:%S\n", pathName);
678 
679         FCB = NtfsGrabFCBFromTable(Vcb, pathName);
680         if (FCB == NULL)
681         {
682             NtfsWSubString(elementName,
683                            currentElement,
684                            NtfsGetNextPathElement(currentElement) - currentElement);
685             DPRINT("  elementName:%S\n", elementName);
686 
687             Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB);
688             if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
689             {
690                 *pParentFCB = parentFCB;
691                 *pFCB = NULL;
692                 currentElement = NtfsGetNextPathElement(currentElement);
693                 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
694                 {
695                     return STATUS_OBJECT_NAME_NOT_FOUND;
696                 }
697                 else
698                 {
699                     return STATUS_OBJECT_PATH_NOT_FOUND;
700                 }
701             }
702             else if (!NT_SUCCESS(Status))
703             {
704                 NtfsReleaseFCB(Vcb, parentFCB);
705                 *pParentFCB = NULL;
706                 *pFCB = NULL;
707 
708                 return Status;
709             }
710         }
711 
712         currentElement = NtfsGetNextPathElement(currentElement);
713     }
714 
715     *pParentFCB = parentFCB;
716     *pFCB = FCB;
717 #endif
718 
719     return STATUS_SUCCESS;
720 }
721 
722 
723 NTSTATUS
724 NtfsReadFCBAttribute(PNTFS_VCB Vcb,
725                      PNTFS_FCB pFCB,
726                      ULONG Type,
727                      PCWSTR Name,
728                      ULONG NameLength,
729                      PVOID * Data)
730 {
731     NTSTATUS Status;
732     PFILE_RECORD_HEADER FileRecord;
733     PNTFS_ATTR_CONTEXT AttrCtxt;
734     ULONGLONG AttrLength;
735 
736     FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
737     if (FileRecord == NULL)
738     {
739         return STATUS_INSUFFICIENT_RESOURCES;
740     }
741 
742     Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
743     if (!NT_SUCCESS(Status))
744     {
745         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
746         return Status;
747     }
748 
749     Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
750     if (!NT_SUCCESS(Status))
751     {
752         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
753         return Status;
754     }
755 
756     AttrLength = AttributeDataLength(AttrCtxt->pRecord);
757     *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
758     if (*Data == NULL)
759     {
760         ReleaseAttributeContext(AttrCtxt);
761         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
762         return STATUS_INSUFFICIENT_RESOURCES;
763     }
764 
765     ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
766 
767     ReleaseAttributeContext(AttrCtxt);
768     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
769 
770     return STATUS_SUCCESS;
771 }
772 
773 /* EOF */
774