[NTFS] Use LookasideList allocations for FILE_RECORD_HEADER.
[reactos.git] / drivers / filesystems / ntfs / fcb.c
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 */