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