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