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