[REISERFS]
[reactos.git] / reactos / 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 PWCHAR
39 NtfsGetNextPathElement(PWCHAR 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 const PWCHAR 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 = ExAllocatePoolWithTag(NonPagedPool,
315 Vcb->NtfsInfo.BytesPerFileRecord,
316 TAG_NTFS);
317 if (MftRecord == NULL)
318 {
319 return NULL;
320 }
321
322 if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
323 {
324 ExFreePoolWithTag(MftRecord, TAG_NTFS);
325 return NULL;
326 }
327
328 FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
329 if (!FileName)
330 {
331 ExFreePoolWithTag(MftRecord, TAG_NTFS);
332 return NULL;
333 }
334
335 Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
336 if (!Fcb)
337 {
338 ExFreePoolWithTag(MftRecord, TAG_NTFS);
339 return NULL;
340 }
341
342 memcpy(&Fcb->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
343 Fcb->Entry.NameType = FileName->NameType;
344 Fcb->Entry.NameLength = 0;
345 Fcb->Entry.Name[0] = UNICODE_NULL;
346 Fcb->RefCount = 1;
347 Fcb->DirIndex = 0;
348 Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
349 Fcb->RFCB.ValidDataLength.QuadPart = FileName->DataSize;
350 Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
351 Fcb->MFTIndex = NTFS_FILE_ROOT;
352 Fcb->LinkCount = MftRecord->LinkCount;
353
354 NtfsFCBInitializeCache(Vcb, Fcb);
355 NtfsAddFCBToTable(Vcb, Fcb);
356 NtfsGrabFCB(Vcb, Fcb);
357
358 ExFreePoolWithTag(MftRecord, TAG_NTFS);
359
360 return Fcb;
361 }
362
363
364 PNTFS_FCB
365 NtfsOpenRootFCB(PNTFS_VCB Vcb)
366 {
367 PNTFS_FCB Fcb;
368
369 Fcb = NtfsGrabFCBFromTable(Vcb, L"\\");
370 if (Fcb == NULL)
371 {
372 Fcb = NtfsMakeRootFCB(Vcb);
373 }
374
375 return Fcb;
376 }
377
378
379 NTSTATUS
380 NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
381 PNTFS_FCB DirectoryFCB,
382 PUNICODE_STRING Name,
383 PCWSTR Stream,
384 PFILE_RECORD_HEADER Record,
385 ULONGLONG MFTIndex,
386 PNTFS_FCB * fileFCB)
387 {
388 WCHAR pathName[MAX_PATH];
389 PFILENAME_ATTRIBUTE FileName;
390 PSTANDARD_INFORMATION StdInfo;
391 PNTFS_FCB rcFCB;
392 ULONGLONG Size, AllocatedSize;
393
394 DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
395
396 FileName = GetBestFileNameFromRecord(Vcb, Record);
397 if (!FileName)
398 {
399 return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
400 }
401
402 if (DirectoryFCB && Name)
403 {
404 if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
405 sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
406 {
407 return STATUS_OBJECT_NAME_INVALID;
408 }
409
410 wcscpy(pathName, DirectoryFCB->PathName);
411 if (!NtfsFCBIsRoot(DirectoryFCB))
412 {
413 wcscat(pathName, L"\\");
414 }
415 wcscat(pathName, Name->Buffer);
416 }
417 else
418 {
419 RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
420 pathName[FileName->NameLength] = UNICODE_NULL;
421 }
422
423 Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
424
425 rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
426 if (!rcFCB)
427 {
428 return STATUS_INSUFFICIENT_RESOURCES;
429 }
430
431 memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
432 rcFCB->Entry.NameType = FileName->NameType;
433 rcFCB->RFCB.FileSize.QuadPart = Size;
434 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
435 rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
436
437 StdInfo = GetStandardInformationFromRecord(Vcb, Record);
438 if (StdInfo != NULL)
439 {
440 rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
441 }
442
443 NtfsFCBInitializeCache(Vcb, rcFCB);
444 rcFCB->RefCount = 1;
445 rcFCB->MFTIndex = MFTIndex;
446 rcFCB->LinkCount = Record->LinkCount;
447 NtfsAddFCBToTable(Vcb, rcFCB);
448 *fileFCB = rcFCB;
449
450 return STATUS_SUCCESS;
451 }
452
453
454 NTSTATUS
455 NtfsAttachFCBToFileObject(PNTFS_VCB Vcb,
456 PNTFS_FCB Fcb,
457 PFILE_OBJECT FileObject)
458 {
459 PNTFS_CCB newCCB;
460
461 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
462 if (newCCB == NULL)
463 {
464 return STATUS_INSUFFICIENT_RESOURCES;
465 }
466
467 RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
468
469 newCCB->Identifier.Type = NTFS_TYPE_CCB;
470 newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
471
472 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
473 FileObject->FsContext = Fcb;
474 FileObject->FsContext2 = newCCB;
475 newCCB->PtrFileObject = FileObject;
476 Fcb->Vcb = Vcb;
477
478 if (!(Fcb->Flags & FCB_CACHE_INITIALIZED))
479 {
480 _SEH2_TRY
481 {
482 CcInitializeCacheMap(FileObject,
483 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
484 FALSE,
485 &(NtfsGlobalData->CacheMgrCallbacks),
486 Fcb);
487 }
488 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
489 {
490 FileObject->FsContext2 = NULL;
491 ExFreePoolWithTag(newCCB, TAG_CCB);
492 return _SEH2_GetExceptionCode();
493 }
494 _SEH2_END;
495
496 Fcb->Flags |= FCB_CACHE_INITIALIZED;
497 }
498
499 //DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
500
501 return STATUS_SUCCESS;
502 }
503
504
505 static NTSTATUS
506 NtfsDirFindFile(PNTFS_VCB Vcb,
507 PNTFS_FCB DirectoryFcb,
508 PWSTR FileToFind,
509 PNTFS_FCB *FoundFCB)
510 {
511 NTSTATUS Status;
512 ULONGLONG CurrentDir;
513 UNICODE_STRING File;
514 PFILE_RECORD_HEADER FileRecord;
515 ULONGLONG MFTIndex;
516 PWSTR Colon, OldColon;
517 PNTFS_ATTR_CONTEXT DataContext;
518 USHORT Length = 0;
519
520 DPRINT1("NtfsDirFindFile(%p, %p, %S, %p)\n", Vcb, DirectoryFcb, FileToFind, FoundFCB);
521
522 *FoundFCB = NULL;
523 RtlInitUnicodeString(&File, FileToFind);
524 CurrentDir = DirectoryFcb->MFTIndex;
525
526 Colon = wcsrchr(FileToFind, L':');
527 if (Colon != NULL)
528 {
529 Length = File.Length;
530 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
531
532 if (_wcsicmp(Colon + 1, L"$DATA") == 0)
533 {
534 OldColon = Colon;
535 Colon[0] = UNICODE_NULL;
536 Colon = wcsrchr(FileToFind, L':');
537 if (Colon != NULL)
538 {
539 Length = File.Length;
540 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
541 }
542 else
543 {
544 Colon = OldColon;
545 Colon[0] = L':';
546 }
547 }
548
549 /* Skip colon */
550 ++Colon;
551 DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon);
552 }
553
554 Status = NtfsLookupFileAt(Vcb, &File, &FileRecord, &MFTIndex, CurrentDir);
555 if (!NT_SUCCESS(Status))
556 {
557 return Status;
558 }
559
560 if (Length != 0)
561 {
562 File.Length = Length;
563 }
564
565 if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0)
566 {
567 return STATUS_INVALID_PARAMETER;
568 }
569 else if (Colon != 0)
570 {
571 Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext);
572 if (!NT_SUCCESS(Status))
573 {
574 return STATUS_OBJECT_NAME_NOT_FOUND;
575 }
576 ReleaseAttributeContext(DataContext);
577 }
578
579 Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB);
580 ExFreePoolWithTag(FileRecord, TAG_NTFS);
581
582 return Status;
583 }
584
585
586 NTSTATUS
587 NtfsGetFCBForFile(PNTFS_VCB Vcb,
588 PNTFS_FCB *pParentFCB,
589 PNTFS_FCB *pFCB,
590 const PWSTR pFileName)
591 {
592 NTSTATUS Status;
593 WCHAR pathName [MAX_PATH];
594 WCHAR elementName [MAX_PATH];
595 PWCHAR currentElement;
596 PNTFS_FCB FCB;
597 PNTFS_FCB parentFCB;
598
599 DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S')\n",
600 Vcb,
601 pParentFCB,
602 pFCB,
603 pFileName);
604
605 /* Dummy code */
606 // FCB = NtfsOpenRootFCB(Vcb);
607 // *pFCB = FCB;
608 // *pParentFCB = NULL;
609
610 #if 1
611 /* Trivial case, open of the root directory on volume */
612 if (pFileName [0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
613 {
614 DPRINT("returning root FCB\n");
615
616 FCB = NtfsOpenRootFCB(Vcb);
617 *pFCB = FCB;
618 *pParentFCB = NULL;
619
620 return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
621 }
622 else
623 {
624 currentElement = pFileName + 1;
625 wcscpy (pathName, L"\\");
626 FCB = NtfsOpenRootFCB (Vcb);
627 }
628
629 parentFCB = NULL;
630
631 /* Parse filename and check each path element for existence and access */
632 while (NtfsGetNextPathElement(currentElement) != 0)
633 {
634 /* Skip blank directory levels */
635 if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
636 {
637 currentElement++;
638 continue;
639 }
640
641 DPRINT("Parsing, currentElement:%S\n", currentElement);
642 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
643
644 /* Descend to next directory level */
645 if (parentFCB)
646 {
647 NtfsReleaseFCB(Vcb, parentFCB);
648 parentFCB = NULL;
649 }
650
651 /* fail if element in FCB is not a directory */
652 if (!NtfsFCBIsDirectory(FCB))
653 {
654 DPRINT("Element in requested path is not a directory\n");
655
656 NtfsReleaseFCB(Vcb, FCB);
657 FCB = 0;
658 *pParentFCB = NULL;
659 *pFCB = NULL;
660
661 return STATUS_OBJECT_PATH_NOT_FOUND;
662 }
663
664 parentFCB = FCB;
665
666 /* Extract next directory level into dirName */
667 NtfsWSubString(pathName,
668 pFileName,
669 NtfsGetNextPathElement(currentElement) - pFileName);
670 DPRINT(" pathName:%S\n", pathName);
671
672 FCB = NtfsGrabFCBFromTable(Vcb, pathName);
673 if (FCB == NULL)
674 {
675 NtfsWSubString(elementName,
676 currentElement,
677 NtfsGetNextPathElement(currentElement) - currentElement);
678 DPRINT(" elementName:%S\n", elementName);
679
680 Status = NtfsDirFindFile(Vcb, parentFCB, elementName, &FCB);
681 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
682 {
683 *pParentFCB = parentFCB;
684 *pFCB = NULL;
685 currentElement = NtfsGetNextPathElement(currentElement);
686 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
687 {
688 return STATUS_OBJECT_NAME_NOT_FOUND;
689 }
690 else
691 {
692 return STATUS_OBJECT_PATH_NOT_FOUND;
693 }
694 }
695 else if (!NT_SUCCESS(Status))
696 {
697 NtfsReleaseFCB(Vcb, parentFCB);
698 *pParentFCB = NULL;
699 *pFCB = NULL;
700
701 return Status;
702 }
703 }
704
705 currentElement = NtfsGetNextPathElement(currentElement);
706 }
707
708 *pParentFCB = parentFCB;
709 *pFCB = FCB;
710 #endif
711
712 return STATUS_SUCCESS;
713 }
714
715
716 NTSTATUS
717 NtfsReadFCBAttribute(PNTFS_VCB Vcb,
718 PNTFS_FCB pFCB,
719 ULONG Type,
720 PCWSTR Name,
721 ULONG NameLength,
722 PVOID * Data)
723 {
724 NTSTATUS Status;
725 PFILE_RECORD_HEADER FileRecord;
726 PNTFS_ATTR_CONTEXT AttrCtxt;
727 ULONGLONG AttrLength;
728
729 FileRecord = ExAllocatePoolWithTag(NonPagedPool,
730 Vcb->NtfsInfo.BytesPerFileRecord,
731 TAG_NTFS);
732 if (FileRecord == NULL)
733 {
734 return STATUS_INSUFFICIENT_RESOURCES;
735 }
736
737 Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
738 if (!NT_SUCCESS(Status))
739 {
740 ExFreePoolWithTag(FileRecord, TAG_NTFS);
741 return Status;
742 }
743
744 Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt);
745 if (!NT_SUCCESS(Status))
746 {
747 ExFreePoolWithTag(FileRecord, TAG_NTFS);
748 return Status;
749 }
750
751 AttrLength = AttributeDataLength(&AttrCtxt->Record);
752 *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
753 if (*Data == NULL)
754 {
755 ReleaseAttributeContext(AttrCtxt);
756 ExFreePoolWithTag(FileRecord, TAG_NTFS);
757 return STATUS_INSUFFICIENT_RESOURCES;
758 }
759
760 ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
761
762 ReleaseAttributeContext(AttrCtxt);
763 ExFreePoolWithTag(FileRecord, TAG_NTFS);
764
765 return STATUS_SUCCESS;
766 }
767
768 /* EOF */