xref: /reactos/drivers/filesystems/ntfs/fcb.c (revision 9393fc32)
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 NtfsFCBIsEncrypted(PNTFS_FCB Fcb)
148 {
149     return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_ENCRYPTED) == NTFS_FILE_TYPE_ENCRYPTED);
150 }
151 
152 BOOLEAN
153 NtfsFCBIsRoot(PNTFS_FCB Fcb)
154 {
155     return (wcscmp(Fcb->PathName, L"\\") == 0);
156 }
157 
158 
159 VOID
160 NtfsGrabFCB(PNTFS_VCB Vcb,
161             PNTFS_FCB Fcb)
162 {
163     KIRQL oldIrql;
164 
165     DPRINT("grabbing FCB at %p: %S, refCount:%d\n",
166            Fcb,
167            Fcb->PathName,
168            Fcb->RefCount);
169 
170     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
171     Fcb->RefCount++;
172     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
173 }
174 
175 
176 VOID
177 NtfsReleaseFCB(PNTFS_VCB Vcb,
178                PNTFS_FCB Fcb)
179 {
180     KIRQL oldIrql;
181 
182     DPRINT("releasing FCB at %p: %S, refCount:%d\n",
183            Fcb,
184            Fcb->PathName,
185            Fcb->RefCount);
186 
187     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
188     Fcb->RefCount--;
189     if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb))
190     {
191         RemoveEntryList(&Fcb->FcbListEntry);
192         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
193         CcUninitializeCacheMap(Fcb->FileObject, NULL, NULL);
194         NtfsDestroyFCB(Fcb);
195     }
196     else
197     {
198         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
199     }
200 }
201 
202 
203 VOID
204 NtfsAddFCBToTable(PNTFS_VCB Vcb,
205                   PNTFS_FCB Fcb)
206 {
207     KIRQL oldIrql;
208 
209     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
210     Fcb->Vcb = Vcb;
211     InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
212     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
213 }
214 
215 
216 PNTFS_FCB
217 NtfsGrabFCBFromTable(PNTFS_VCB Vcb,
218                      PCWSTR FileName)
219 {
220     KIRQL oldIrql;
221     PNTFS_FCB Fcb;
222     PLIST_ENTRY current_entry;
223 
224     KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
225 
226     if (FileName == NULL || *FileName == 0)
227     {
228         DPRINT("Return FCB for stream file object\n");
229         Fcb = Vcb->StreamFileObject->FsContext;
230         Fcb->RefCount++;
231         KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
232         return Fcb;
233     }
234 
235     current_entry = Vcb->FcbListHead.Flink;
236     while (current_entry != &Vcb->FcbListHead)
237     {
238         Fcb = CONTAINING_RECORD(current_entry, NTFS_FCB, FcbListEntry);
239 
240         DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName);
241         if (_wcsicmp(FileName, Fcb->PathName) == 0)
242         {
243             Fcb->RefCount++;
244             KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
245             return Fcb;
246         }
247 
248         //FIXME: need to compare against short name in FCB here
249 
250         current_entry = current_entry->Flink;
251     }
252 
253     KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
254 
255     return NULL;
256 }
257 
258 
259 NTSTATUS
260 NtfsFCBInitializeCache(PNTFS_VCB Vcb,
261                        PNTFS_FCB Fcb)
262 {
263     PFILE_OBJECT FileObject;
264     NTSTATUS Status;
265     PNTFS_CCB newCCB;
266 
267     FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
268 
269     newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
270     if (newCCB == NULL)
271     {
272         return STATUS_INSUFFICIENT_RESOURCES;
273     }
274 
275     RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
276 
277     newCCB->Identifier.Type = NTFS_TYPE_CCB;
278     newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
279 
280     FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
281     FileObject->FsContext = Fcb;
282     FileObject->FsContext2 = newCCB;
283     newCCB->PtrFileObject = FileObject;
284     Fcb->FileObject = FileObject;
285     Fcb->Vcb = Vcb;
286 
287     Status = STATUS_SUCCESS;
288     _SEH2_TRY
289     {
290         CcInitializeCacheMap(FileObject,
291                              (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
292                              FALSE,
293                              &(NtfsGlobalData->CacheMgrCallbacks),
294                              Fcb);
295     }
296     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
297     {
298         FileObject->FsContext2 = NULL;
299         ExFreePoolWithTag(newCCB, TAG_CCB);
300         ObDereferenceObject(FileObject);
301         Fcb->FileObject = NULL;
302         return _SEH2_GetExceptionCode();
303     }
304     _SEH2_END;
305 
306     ObDereferenceObject(FileObject);
307     Fcb->Flags |= FCB_CACHE_INITIALIZED;
308 
309     return Status;
310 }
311 
312 
313 PNTFS_FCB
314 NtfsMakeRootFCB(PNTFS_VCB Vcb)
315 {
316     PNTFS_FCB Fcb;
317     PFILE_RECORD_HEADER MftRecord;
318     PFILENAME_ATTRIBUTE FileName;
319 
320     MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
321     if (MftRecord == NULL)
322     {
323         return NULL;
324     }
325 
326     if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
327     {
328         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
329         return NULL;
330     }
331 
332     FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
333     if (!FileName)
334     {
335         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
336         return NULL;
337     }
338 
339     Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
340     if (!Fcb)
341     {
342         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
343         return NULL;
344     }
345 
346     memcpy(&Fcb->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
347     Fcb->Entry.NameType = FileName->NameType;
348     Fcb->Entry.NameLength = 0;
349     Fcb->Entry.Name[0] = UNICODE_NULL;
350     Fcb->RefCount = 1;
351     Fcb->DirIndex = 0;
352     Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
353     Fcb->RFCB.ValidDataLength.QuadPart = FileName->DataSize;
354     Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
355     Fcb->MFTIndex = NTFS_FILE_ROOT;
356     Fcb->LinkCount = MftRecord->LinkCount;
357 
358     NtfsFCBInitializeCache(Vcb, Fcb);
359     NtfsAddFCBToTable(Vcb, Fcb);
360     NtfsGrabFCB(Vcb, Fcb);
361 
362     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
363 
364     return Fcb;
365 }
366 
367 
368 PNTFS_FCB
369 NtfsOpenRootFCB(PNTFS_VCB Vcb)
370 {
371     PNTFS_FCB Fcb;
372 
373     Fcb = NtfsGrabFCBFromTable(Vcb, L"\\");
374     if (Fcb == NULL)
375     {
376         Fcb = NtfsMakeRootFCB(Vcb);
377     }
378 
379     return Fcb;
380 }
381 
382 
383 NTSTATUS
384 NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
385                         PNTFS_FCB DirectoryFCB,
386                         PUNICODE_STRING Name,
387                         PCWSTR Stream,
388                         PFILE_RECORD_HEADER Record,
389                         ULONGLONG MFTIndex,
390                         PNTFS_FCB * fileFCB)
391 {
392     WCHAR pathName[MAX_PATH];
393     PFILENAME_ATTRIBUTE FileName;
394     PSTANDARD_INFORMATION StdInfo;
395     PNTFS_FCB rcFCB;
396     ULONGLONG Size, AllocatedSize;
397 
398     DPRINT("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
399 
400     FileName = GetBestFileNameFromRecord(Vcb, Record);
401     if (!FileName)
402     {
403         return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
404     }
405 
406     if (DirectoryFCB && Name)
407     {
408         if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
409             sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
410         {
411             return STATUS_OBJECT_NAME_INVALID;
412         }
413 
414         wcscpy(pathName, DirectoryFCB->PathName);
415         if (!NtfsFCBIsRoot(DirectoryFCB))
416         {
417             wcscat(pathName, L"\\");
418         }
419         wcscat(pathName, Name->Buffer);
420     }
421     else
422     {
423         RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
424         pathName[FileName->NameLength] = UNICODE_NULL;
425     }
426 
427     Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
428 
429     rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
430     if (!rcFCB)
431     {
432         return STATUS_INSUFFICIENT_RESOURCES;
433     }
434 
435     memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
436     rcFCB->Entry.NameType = FileName->NameType;
437     rcFCB->RFCB.FileSize.QuadPart = Size;
438     rcFCB->RFCB.ValidDataLength.QuadPart = Size;
439     rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
440 
441     StdInfo = GetStandardInformationFromRecord(Vcb, Record);
442     if (StdInfo != NULL)
443     {
444         rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
445     }
446 
447     NtfsFCBInitializeCache(Vcb, rcFCB);
448     rcFCB->RefCount = 1;
449     rcFCB->MFTIndex = MFTIndex;
450     rcFCB->LinkCount = Record->LinkCount;
451     NtfsAddFCBToTable(Vcb, rcFCB);
452     *fileFCB = rcFCB;
453 
454     return STATUS_SUCCESS;
455 }
456 
457 
458 NTSTATUS
459 NtfsAttachFCBToFileObject(PNTFS_VCB Vcb,
460                           PNTFS_FCB Fcb,
461                           PFILE_OBJECT FileObject)
462 {
463     PNTFS_CCB newCCB;
464 
465     newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
466     if (newCCB == NULL)
467     {
468         return STATUS_INSUFFICIENT_RESOURCES;
469     }
470 
471     RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
472 
473     newCCB->Identifier.Type = NTFS_TYPE_CCB;
474     newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
475 
476     FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
477     FileObject->FsContext = Fcb;
478     FileObject->FsContext2 = newCCB;
479     newCCB->PtrFileObject = FileObject;
480     Fcb->Vcb = Vcb;
481 
482     if (!(Fcb->Flags & FCB_CACHE_INITIALIZED))
483     {
484         _SEH2_TRY
485         {
486             CcInitializeCacheMap(FileObject,
487                                  (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
488                                  FALSE,
489                                  &(NtfsGlobalData->CacheMgrCallbacks),
490                                  Fcb);
491         }
492         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
493         {
494             FileObject->FsContext2 = NULL;
495             ExFreePoolWithTag(newCCB, TAG_CCB);
496             return _SEH2_GetExceptionCode();
497         }
498         _SEH2_END;
499 
500         Fcb->Flags |= FCB_CACHE_INITIALIZED;
501     }
502 
503     //DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
504 
505     return STATUS_SUCCESS;
506 }
507 
508 
509 static NTSTATUS
510 NtfsDirFindFile(PNTFS_VCB Vcb,
511                 PNTFS_FCB DirectoryFcb,
512                 PWSTR FileToFind,
513                 BOOLEAN CaseSensitive,
514                 PNTFS_FCB *FoundFCB)
515 {
516     NTSTATUS Status;
517     ULONGLONG CurrentDir;
518     UNICODE_STRING File;
519     PFILE_RECORD_HEADER FileRecord;
520     ULONGLONG MFTIndex;
521     PWSTR Colon, OldColon;
522     PNTFS_ATTR_CONTEXT DataContext;
523     USHORT Length = 0;
524 
525     DPRINT("NtfsDirFindFile(%p, %p, %S, %s, %p)\n",
526            Vcb,
527            DirectoryFcb,
528            FileToFind,
529            CaseSensitive ? "TRUE" : "FALSE",
530            FoundFCB);
531 
532     *FoundFCB = NULL;
533     RtlInitUnicodeString(&File, FileToFind);
534     CurrentDir = DirectoryFcb->MFTIndex;
535 
536     Colon = wcsrchr(FileToFind, L':');
537     if (Colon != NULL)
538     {
539         Length = File.Length;
540         File.Length = (Colon - FileToFind) * sizeof(WCHAR);
541 
542         if (_wcsicmp(Colon + 1, L"$DATA") == 0)
543         {
544             OldColon = Colon;
545             Colon[0] = UNICODE_NULL;
546             Colon = wcsrchr(FileToFind, L':');
547             if (Colon != NULL)
548             {
549                 Length = File.Length;
550                 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
551             }
552             else
553             {
554                 Colon = OldColon;
555                 Colon[0] = L':';
556             }
557         }
558 
559         /* Skip colon */
560         ++Colon;
561         DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon);
562     }
563 
564     Status = NtfsLookupFileAt(Vcb, &File, CaseSensitive, &FileRecord, &MFTIndex, CurrentDir);
565     if (!NT_SUCCESS(Status))
566     {
567         return Status;
568     }
569 
570     if (Length != 0)
571     {
572         File.Length = Length;
573     }
574 
575     if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0)
576     {
577         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
578         return STATUS_INVALID_PARAMETER;
579     }
580     else if (Colon != 0)
581     {
582         Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL);
583         if (!NT_SUCCESS(Status))
584         {
585             return STATUS_OBJECT_NAME_NOT_FOUND;
586         }
587         ReleaseAttributeContext(DataContext);
588     }
589 
590     Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB);
591     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
592 
593     return Status;
594 }
595 
596 
597 NTSTATUS
598 NtfsGetFCBForFile(PNTFS_VCB Vcb,
599                   PNTFS_FCB *pParentFCB,
600                   PNTFS_FCB *pFCB,
601                   PCWSTR pFileName,
602                   BOOLEAN CaseSensitive)
603 {
604     NTSTATUS Status;
605     WCHAR pathName [MAX_PATH];
606     WCHAR elementName [MAX_PATH];
607     PCWSTR currentElement;
608     PNTFS_FCB FCB;
609     PNTFS_FCB parentFCB;
610 
611     DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n",
612            Vcb,
613            pParentFCB,
614            pFCB,
615            pFileName,
616            CaseSensitive ? "TRUE" : "FALSE");
617 
618     /* Dummy code */
619 //  FCB = NtfsOpenRootFCB(Vcb);
620 //  *pFCB = FCB;
621 //  *pParentFCB = NULL;
622 
623 #if 1
624     /* Trivial case, open of the root directory on volume */
625     if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
626     {
627         DPRINT("returning root FCB\n");
628 
629         FCB = NtfsOpenRootFCB(Vcb);
630         *pFCB = FCB;
631         *pParentFCB = NULL;
632 
633         return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
634     }
635     else
636     {
637         currentElement = pFileName + 1;
638         wcscpy (pathName, L"\\");
639         FCB = NtfsOpenRootFCB (Vcb);
640     }
641 
642     parentFCB = NULL;
643 
644     /* Parse filename and check each path element for existence and access */
645     while (NtfsGetNextPathElement(currentElement) != 0)
646     {
647         /* Skip blank directory levels */
648         if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
649         {
650             currentElement++;
651             continue;
652         }
653 
654         DPRINT("Parsing, currentElement:%S\n", currentElement);
655         DPRINT("  parentFCB:%p FCB:%p\n", parentFCB, FCB);
656 
657         /* Descend to next directory level */
658         if (parentFCB)
659         {
660             NtfsReleaseFCB(Vcb, parentFCB);
661             parentFCB = NULL;
662         }
663 
664         /* fail if element in FCB is not a directory */
665         if (!NtfsFCBIsDirectory(FCB))
666         {
667             DPRINT("Element in requested path is not a directory\n");
668 
669             NtfsReleaseFCB(Vcb, FCB);
670             FCB = 0;
671             *pParentFCB = NULL;
672             *pFCB = NULL;
673 
674             return STATUS_OBJECT_PATH_NOT_FOUND;
675         }
676 
677         parentFCB = FCB;
678 
679         /* Extract next directory level into dirName */
680         NtfsWSubString(pathName,
681                        pFileName,
682                        NtfsGetNextPathElement(currentElement) - pFileName);
683         DPRINT("  pathName:%S\n", pathName);
684 
685         FCB = NtfsGrabFCBFromTable(Vcb, pathName);
686         if (FCB == NULL)
687         {
688             NtfsWSubString(elementName,
689                            currentElement,
690                            NtfsGetNextPathElement(currentElement) - currentElement);
691             DPRINT("  elementName:%S\n", elementName);
692 
693             Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB);
694             if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
695             {
696                 *pParentFCB = parentFCB;
697                 *pFCB = NULL;
698                 currentElement = NtfsGetNextPathElement(currentElement);
699                 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
700                 {
701                     return STATUS_OBJECT_NAME_NOT_FOUND;
702                 }
703                 else
704                 {
705                     return STATUS_OBJECT_PATH_NOT_FOUND;
706                 }
707             }
708             else if (!NT_SUCCESS(Status))
709             {
710                 NtfsReleaseFCB(Vcb, parentFCB);
711                 *pParentFCB = NULL;
712                 *pFCB = NULL;
713 
714                 return Status;
715             }
716         }
717 
718         currentElement = NtfsGetNextPathElement(currentElement);
719     }
720 
721     *pParentFCB = parentFCB;
722     *pFCB = FCB;
723 #endif
724 
725     return STATUS_SUCCESS;
726 }
727 
728 
729 NTSTATUS
730 NtfsReadFCBAttribute(PNTFS_VCB Vcb,
731                      PNTFS_FCB pFCB,
732                      ULONG Type,
733                      PCWSTR Name,
734                      ULONG NameLength,
735                      PVOID * Data)
736 {
737     NTSTATUS Status;
738     PFILE_RECORD_HEADER FileRecord;
739     PNTFS_ATTR_CONTEXT AttrCtxt;
740     ULONGLONG AttrLength;
741 
742     FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
743     if (FileRecord == NULL)
744     {
745         return STATUS_INSUFFICIENT_RESOURCES;
746     }
747 
748     Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
749     if (!NT_SUCCESS(Status))
750     {
751         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
752         return Status;
753     }
754 
755     Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
756     if (!NT_SUCCESS(Status))
757     {
758         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
759         return Status;
760     }
761 
762     AttrLength = AttributeDataLength(AttrCtxt->pRecord);
763     *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
764     if (*Data == NULL)
765     {
766         ReleaseAttributeContext(AttrCtxt);
767         ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
768         return STATUS_INSUFFICIENT_RESOURCES;
769     }
770 
771     ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
772 
773     ReleaseAttributeContext(AttrCtxt);
774     ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
775 
776     return STATUS_SUCCESS;
777 }
778 
779 /* EOF */
780