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 = 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 BOOLEAN CaseSensitive, 510 PNTFS_FCB *FoundFCB) 511 { 512 NTSTATUS Status; 513 ULONGLONG CurrentDir; 514 UNICODE_STRING File; 515 PFILE_RECORD_HEADER FileRecord; 516 ULONGLONG MFTIndex; 517 PWSTR Colon, OldColon; 518 PNTFS_ATTR_CONTEXT DataContext; 519 USHORT Length = 0; 520 521 DPRINT1("NtfsDirFindFile(%p, %p, %S, %s, %p)\n", 522 Vcb, 523 DirectoryFcb, 524 FileToFind, 525 CaseSensitive ? "TRUE" : "FALSE", 526 FoundFCB); 527 528 *FoundFCB = NULL; 529 RtlInitUnicodeString(&File, FileToFind); 530 CurrentDir = DirectoryFcb->MFTIndex; 531 532 Colon = wcsrchr(FileToFind, L':'); 533 if (Colon != NULL) 534 { 535 Length = File.Length; 536 File.Length = (Colon - FileToFind) * sizeof(WCHAR); 537 538 if (_wcsicmp(Colon + 1, L"$DATA") == 0) 539 { 540 OldColon = Colon; 541 Colon[0] = UNICODE_NULL; 542 Colon = wcsrchr(FileToFind, L':'); 543 if (Colon != NULL) 544 { 545 Length = File.Length; 546 File.Length = (Colon - FileToFind) * sizeof(WCHAR); 547 } 548 else 549 { 550 Colon = OldColon; 551 Colon[0] = L':'; 552 } 553 } 554 555 /* Skip colon */ 556 ++Colon; 557 DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon); 558 } 559 560 Status = NtfsLookupFileAt(Vcb, &File, CaseSensitive, &FileRecord, &MFTIndex, CurrentDir); 561 if (!NT_SUCCESS(Status)) 562 { 563 return Status; 564 } 565 566 if (Length != 0) 567 { 568 File.Length = Length; 569 } 570 571 if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0) 572 { 573 return STATUS_INVALID_PARAMETER; 574 } 575 else if (Colon != 0) 576 { 577 Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL); 578 if (!NT_SUCCESS(Status)) 579 { 580 return STATUS_OBJECT_NAME_NOT_FOUND; 581 } 582 ReleaseAttributeContext(DataContext); 583 } 584 585 Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB); 586 ExFreePoolWithTag(FileRecord, TAG_NTFS); 587 588 return Status; 589 } 590 591 592 NTSTATUS 593 NtfsGetFCBForFile(PNTFS_VCB Vcb, 594 PNTFS_FCB *pParentFCB, 595 PNTFS_FCB *pFCB, 596 PCWSTR pFileName, 597 BOOLEAN CaseSensitive) 598 { 599 NTSTATUS Status; 600 WCHAR pathName [MAX_PATH]; 601 WCHAR elementName [MAX_PATH]; 602 PCWSTR currentElement; 603 PNTFS_FCB FCB; 604 PNTFS_FCB parentFCB; 605 606 DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n", 607 Vcb, 608 pParentFCB, 609 pFCB, 610 pFileName, 611 CaseSensitive ? "TRUE" : "FALSE"); 612 613 /* Dummy code */ 614 // FCB = NtfsOpenRootFCB(Vcb); 615 // *pFCB = FCB; 616 // *pParentFCB = NULL; 617 618 #if 1 619 /* Trivial case, open of the root directory on volume */ 620 if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0) 621 { 622 DPRINT("returning root FCB\n"); 623 624 FCB = NtfsOpenRootFCB(Vcb); 625 *pFCB = FCB; 626 *pParentFCB = NULL; 627 628 return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND; 629 } 630 else 631 { 632 currentElement = pFileName + 1; 633 wcscpy (pathName, L"\\"); 634 FCB = NtfsOpenRootFCB (Vcb); 635 } 636 637 parentFCB = NULL; 638 639 /* Parse filename and check each path element for existence and access */ 640 while (NtfsGetNextPathElement(currentElement) != 0) 641 { 642 /* Skip blank directory levels */ 643 if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0) 644 { 645 currentElement++; 646 continue; 647 } 648 649 DPRINT("Parsing, currentElement:%S\n", currentElement); 650 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB); 651 652 /* Descend to next directory level */ 653 if (parentFCB) 654 { 655 NtfsReleaseFCB(Vcb, parentFCB); 656 parentFCB = NULL; 657 } 658 659 /* fail if element in FCB is not a directory */ 660 if (!NtfsFCBIsDirectory(FCB)) 661 { 662 DPRINT("Element in requested path is not a directory\n"); 663 664 NtfsReleaseFCB(Vcb, FCB); 665 FCB = 0; 666 *pParentFCB = NULL; 667 *pFCB = NULL; 668 669 return STATUS_OBJECT_PATH_NOT_FOUND; 670 } 671 672 parentFCB = FCB; 673 674 /* Extract next directory level into dirName */ 675 NtfsWSubString(pathName, 676 pFileName, 677 NtfsGetNextPathElement(currentElement) - pFileName); 678 DPRINT(" pathName:%S\n", pathName); 679 680 FCB = NtfsGrabFCBFromTable(Vcb, pathName); 681 if (FCB == NULL) 682 { 683 NtfsWSubString(elementName, 684 currentElement, 685 NtfsGetNextPathElement(currentElement) - currentElement); 686 DPRINT(" elementName:%S\n", elementName); 687 688 Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB); 689 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 690 { 691 *pParentFCB = parentFCB; 692 *pFCB = NULL; 693 currentElement = NtfsGetNextPathElement(currentElement); 694 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0) 695 { 696 return STATUS_OBJECT_NAME_NOT_FOUND; 697 } 698 else 699 { 700 return STATUS_OBJECT_PATH_NOT_FOUND; 701 } 702 } 703 else if (!NT_SUCCESS(Status)) 704 { 705 NtfsReleaseFCB(Vcb, parentFCB); 706 *pParentFCB = NULL; 707 *pFCB = NULL; 708 709 return Status; 710 } 711 } 712 713 currentElement = NtfsGetNextPathElement(currentElement); 714 } 715 716 *pParentFCB = parentFCB; 717 *pFCB = FCB; 718 #endif 719 720 return STATUS_SUCCESS; 721 } 722 723 724 NTSTATUS 725 NtfsReadFCBAttribute(PNTFS_VCB Vcb, 726 PNTFS_FCB pFCB, 727 ULONG Type, 728 PCWSTR Name, 729 ULONG NameLength, 730 PVOID * Data) 731 { 732 NTSTATUS Status; 733 PFILE_RECORD_HEADER FileRecord; 734 PNTFS_ATTR_CONTEXT AttrCtxt; 735 ULONGLONG AttrLength; 736 737 FileRecord = ExAllocatePoolWithTag(NonPagedPool, 738 Vcb->NtfsInfo.BytesPerFileRecord, 739 TAG_NTFS); 740 if (FileRecord == NULL) 741 { 742 return STATUS_INSUFFICIENT_RESOURCES; 743 } 744 745 Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord); 746 if (!NT_SUCCESS(Status)) 747 { 748 ExFreePoolWithTag(FileRecord, TAG_NTFS); 749 return Status; 750 } 751 752 Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL); 753 if (!NT_SUCCESS(Status)) 754 { 755 ExFreePoolWithTag(FileRecord, TAG_NTFS); 756 return Status; 757 } 758 759 AttrLength = AttributeDataLength(AttrCtxt->pRecord); 760 *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS); 761 if (*Data == NULL) 762 { 763 ReleaseAttributeContext(AttrCtxt); 764 ExFreePoolWithTag(FileRecord, TAG_NTFS); 765 return STATUS_INSUFFICIENT_RESOURCES; 766 } 767 768 ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength); 769 770 ReleaseAttributeContext(AttrCtxt); 771 ExFreePoolWithTag(FileRecord, TAG_NTFS); 772 773 return STATUS_SUCCESS; 774 } 775 776 /* EOF */ 777