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