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