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/create.c 22c2c66affSColin Finck * PURPOSE: NTFS filesystem driver 23c2c66affSColin Finck * PROGRAMMERS: Eric Kohl 24c2c66affSColin Finck * Pierre Schweitzer (pierre@reactos.org) 25c2c66affSColin Finck */ 26c2c66affSColin Finck 27c2c66affSColin Finck /* INCLUDES *****************************************************************/ 28c2c66affSColin Finck 29c2c66affSColin Finck #include "ntfs.h" 30c2c66affSColin Finck 31c2c66affSColin Finck #define NDEBUG 32c2c66affSColin Finck #include <debug.h> 33c2c66affSColin Finck 34c2c66affSColin Finck static PCWSTR MftIdToName[] = { 35c2c66affSColin Finck L"$MFT", 36c2c66affSColin Finck L"$MFTMirr", 37c2c66affSColin Finck L"$LogFile", 38c2c66affSColin Finck L"$Volume", 39c2c66affSColin Finck L"AttrDef", 40c2c66affSColin Finck L".", 41c2c66affSColin Finck L"$Bitmap", 42c2c66affSColin Finck L"$Boot", 43c2c66affSColin Finck L"$BadClus", 44c2c66affSColin Finck L"$Quota", 45c2c66affSColin Finck L"$UpCase", 46c2c66affSColin Finck L"$Extended", 47c2c66affSColin Finck }; 48c2c66affSColin Finck 49c2c66affSColin Finck /* FUNCTIONS ****************************************************************/ 50c2c66affSColin Finck 51c2c66affSColin Finck static 52c2c66affSColin Finck NTSTATUS 53c2c66affSColin Finck NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject, 54c2c66affSColin Finck PWSTR pRelativeFileName, 55c2c66affSColin Finck PWSTR *pAbsoluteFilename) 56c2c66affSColin Finck { 57c2c66affSColin Finck PWSTR rcName; 58c2c66affSColin Finck PNTFS_FCB Fcb; 59c2c66affSColin Finck 60c2c66affSColin Finck DPRINT("try related for %S\n", pRelativeFileName); 61c2c66affSColin Finck Fcb = pFileObject->FsContext; 62c2c66affSColin Finck ASSERT(Fcb); 63c2c66affSColin Finck 64c2c66affSColin Finck if (Fcb->Flags & FCB_IS_VOLUME) 65c2c66affSColin Finck { 66c2c66affSColin Finck /* This is likely to be an opening by ID, return ourselves */ 67c2c66affSColin Finck if (pRelativeFileName[0] == L'\\') 68c2c66affSColin Finck { 69c2c66affSColin Finck *pAbsoluteFilename = NULL; 70c2c66affSColin Finck return STATUS_SUCCESS; 71c2c66affSColin Finck } 72c2c66affSColin Finck 73c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 74c2c66affSColin Finck } 75c2c66affSColin Finck 76c2c66affSColin Finck /* verify related object is a directory and target name 77c2c66affSColin Finck don't start with \. */ 78c2c66affSColin Finck if (NtfsFCBIsDirectory(Fcb) == FALSE || 79c2c66affSColin Finck pRelativeFileName[0] == L'\\') 80c2c66affSColin Finck { 81c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 82c2c66affSColin Finck } 83c2c66affSColin Finck 84c2c66affSColin Finck /* construct absolute path name */ 85c2c66affSColin Finck ASSERT(wcslen (Fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1 <= MAX_PATH); 86c2c66affSColin Finck rcName = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH * sizeof(WCHAR), TAG_NTFS); 87c2c66affSColin Finck if (!rcName) 88c2c66affSColin Finck { 89c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 90c2c66affSColin Finck } 91c2c66affSColin Finck 92c2c66affSColin Finck wcscpy(rcName, Fcb->PathName); 93c2c66affSColin Finck if (!NtfsFCBIsRoot(Fcb)) 94c2c66affSColin Finck wcscat (rcName, L"\\"); 95c2c66affSColin Finck wcscat (rcName, pRelativeFileName); 96c2c66affSColin Finck *pAbsoluteFilename = rcName; 97c2c66affSColin Finck 98c2c66affSColin Finck return STATUS_SUCCESS; 99c2c66affSColin Finck } 100c2c66affSColin Finck 101c2c66affSColin Finck 102c2c66affSColin Finck static 103c2c66affSColin Finck NTSTATUS 104c2c66affSColin Finck NtfsMoonWalkID(PDEVICE_EXTENSION DeviceExt, 105c2c66affSColin Finck ULONGLONG Id, 106c2c66affSColin Finck PUNICODE_STRING OutPath) 107c2c66affSColin Finck { 108c2c66affSColin Finck NTSTATUS Status; 109c2c66affSColin Finck PFILE_RECORD_HEADER MftRecord; 110c2c66affSColin Finck PFILENAME_ATTRIBUTE FileName; 111c2c66affSColin Finck WCHAR FullPath[MAX_PATH]; 112c2c66affSColin Finck ULONG WritePosition = MAX_PATH - 1; 113c2c66affSColin Finck 114c2c66affSColin Finck DPRINT1("NtfsMoonWalkID(%p, %I64x, %p)\n", DeviceExt, Id, OutPath); 115c2c66affSColin Finck 116c2c66affSColin Finck RtlZeroMemory(FullPath, sizeof(FullPath)); 117c2c66affSColin Finck MftRecord = ExAllocatePoolWithTag(NonPagedPool, 118c2c66affSColin Finck DeviceExt->NtfsInfo.BytesPerFileRecord, 119c2c66affSColin Finck TAG_NTFS); 120c2c66affSColin Finck if (MftRecord == NULL) 121c2c66affSColin Finck { 122c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 123c2c66affSColin Finck } 124c2c66affSColin Finck 125c2c66affSColin Finck while (TRUE) 126c2c66affSColin Finck { 127c2c66affSColin Finck Status = ReadFileRecord(DeviceExt, Id, MftRecord); 128c2c66affSColin Finck if (!NT_SUCCESS(Status)) 129c2c66affSColin Finck break; 130c2c66affSColin Finck 131c2c66affSColin Finck ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE); 132c2c66affSColin Finck if (!(MftRecord->Flags & FRH_IN_USE)) 133c2c66affSColin Finck { 134c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND; 135c2c66affSColin Finck break; 136c2c66affSColin Finck } 137c2c66affSColin Finck 138c2c66affSColin Finck FileName = GetBestFileNameFromRecord(DeviceExt, MftRecord); 139c2c66affSColin Finck if (FileName == NULL) 140c2c66affSColin Finck { 141c2c66affSColin Finck DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id); 142c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND; 143c2c66affSColin Finck break; 144c2c66affSColin Finck } 145c2c66affSColin Finck 146c2c66affSColin Finck WritePosition -= FileName->NameLength; 147c2c66affSColin Finck ASSERT(WritePosition < MAX_PATH); 148c2c66affSColin Finck RtlCopyMemory(FullPath + WritePosition, FileName->Name, FileName->NameLength * sizeof(WCHAR)); 149c2c66affSColin Finck WritePosition -= 1; 150c2c66affSColin Finck ASSERT(WritePosition < MAX_PATH); 151c2c66affSColin Finck FullPath[WritePosition] = L'\\'; 152c2c66affSColin Finck 153c2c66affSColin Finck Id = FileName->DirectoryFileReferenceNumber & NTFS_MFT_MASK; 154c2c66affSColin Finck if (Id == NTFS_FILE_ROOT) 155c2c66affSColin Finck break; 156c2c66affSColin Finck } 157c2c66affSColin Finck 158c2c66affSColin Finck ExFreePoolWithTag(MftRecord, TAG_NTFS); 159c2c66affSColin Finck 160c2c66affSColin Finck if (!NT_SUCCESS(Status)) 161c2c66affSColin Finck return Status; 162c2c66affSColin Finck 163c2c66affSColin Finck OutPath->Length = (MAX_PATH - WritePosition - 1) * sizeof(WCHAR); 164c2c66affSColin Finck OutPath->MaximumLength = (MAX_PATH - WritePosition) * sizeof(WCHAR); 165c2c66affSColin Finck OutPath->Buffer = ExAllocatePoolWithTag(NonPagedPool, OutPath->MaximumLength, TAG_NTFS); 166c2c66affSColin Finck if (OutPath->Buffer == NULL) 167c2c66affSColin Finck { 168c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 169c2c66affSColin Finck } 170c2c66affSColin Finck RtlCopyMemory(OutPath->Buffer, FullPath + WritePosition, OutPath->MaximumLength); 171c2c66affSColin Finck 172c2c66affSColin Finck return Status; 173c2c66affSColin Finck } 174c2c66affSColin Finck 175c2c66affSColin Finck static 176c2c66affSColin Finck NTSTATUS 177c2c66affSColin Finck NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt, 178c2c66affSColin Finck PFILE_OBJECT FileObject, 179c2c66affSColin Finck ULONGLONG MftId, 180c2c66affSColin Finck PNTFS_FCB * FoundFCB) 181c2c66affSColin Finck { 182c2c66affSColin Finck NTSTATUS Status; 183c2c66affSColin Finck PNTFS_FCB FCB; 184c2c66affSColin Finck PFILE_RECORD_HEADER MftRecord; 185c2c66affSColin Finck 186c2c66affSColin Finck DPRINT1("NtfsOpenFileById(%p, %p, %I64x, %p)\n", DeviceExt, FileObject, MftId, FoundFCB); 187c2c66affSColin Finck 188935fcd1bSTrevor Thompson ASSERT(MftId < NTFS_FILE_FIRST_USER_FILE); 189c2c66affSColin Finck if (MftId > 0xb) /* No entries are used yet beyond this */ 190c2c66affSColin Finck { 191c2c66affSColin Finck return STATUS_OBJECT_NAME_NOT_FOUND; 192c2c66affSColin Finck } 193c2c66affSColin Finck 194c2c66affSColin Finck MftRecord = ExAllocatePoolWithTag(NonPagedPool, 195c2c66affSColin Finck DeviceExt->NtfsInfo.BytesPerFileRecord, 196c2c66affSColin Finck TAG_NTFS); 197c2c66affSColin Finck if (MftRecord == NULL) 198c2c66affSColin Finck { 199c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 200c2c66affSColin Finck } 201c2c66affSColin Finck 202c2c66affSColin Finck Status = ReadFileRecord(DeviceExt, MftId, MftRecord); 203c2c66affSColin Finck if (!NT_SUCCESS(Status)) 204c2c66affSColin Finck { 205c2c66affSColin Finck ExFreePoolWithTag(MftRecord, TAG_NTFS); 206c2c66affSColin Finck return Status; 207c2c66affSColin Finck } 208c2c66affSColin Finck 209c2c66affSColin Finck if (!(MftRecord->Flags & FRH_IN_USE)) 210c2c66affSColin Finck { 211c2c66affSColin Finck ExFreePoolWithTag(MftRecord, TAG_NTFS); 212c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND; 213c2c66affSColin Finck } 214c2c66affSColin Finck 215c2c66affSColin Finck FCB = NtfsGrabFCBFromTable(DeviceExt, MftIdToName[MftId]); 216c2c66affSColin Finck if (FCB == NULL) 217c2c66affSColin Finck { 218c2c66affSColin Finck UNICODE_STRING Name; 219c2c66affSColin Finck 220c2c66affSColin Finck RtlInitUnicodeString(&Name, MftIdToName[MftId]); 221c2c66affSColin Finck Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, NULL, MftRecord, MftId, &FCB); 222c2c66affSColin Finck if (!NT_SUCCESS(Status)) 223c2c66affSColin Finck { 224c2c66affSColin Finck ExFreePoolWithTag(MftRecord, TAG_NTFS); 225c2c66affSColin Finck return Status; 226c2c66affSColin Finck } 227c2c66affSColin Finck } 228c2c66affSColin Finck 229c2c66affSColin Finck ASSERT(FCB != NULL); 230c2c66affSColin Finck 231c2c66affSColin Finck ExFreePoolWithTag(MftRecord, TAG_NTFS); 232c2c66affSColin Finck 233c2c66affSColin Finck Status = NtfsAttachFCBToFileObject(DeviceExt, 234c2c66affSColin Finck FCB, 235c2c66affSColin Finck FileObject); 236c2c66affSColin Finck *FoundFCB = FCB; 237c2c66affSColin Finck 238c2c66affSColin Finck return Status; 239c2c66affSColin Finck } 240c2c66affSColin Finck 241c2c66affSColin Finck /* 242c2c66affSColin Finck * FUNCTION: Opens a file 243c2c66affSColin Finck */ 244c2c66affSColin Finck static 245c2c66affSColin Finck NTSTATUS 246c2c66affSColin Finck NtfsOpenFile(PDEVICE_EXTENSION DeviceExt, 247c2c66affSColin Finck PFILE_OBJECT FileObject, 248c2c66affSColin Finck PWSTR FileName, 249032be029STrevor Thompson BOOLEAN CaseSensitive, 250c2c66affSColin Finck PNTFS_FCB * FoundFCB) 251c2c66affSColin Finck { 252c2c66affSColin Finck PNTFS_FCB ParentFcb; 253c2c66affSColin Finck PNTFS_FCB Fcb; 254c2c66affSColin Finck NTSTATUS Status; 255c2c66affSColin Finck PWSTR AbsFileName = NULL; 256c2c66affSColin Finck 257032be029STrevor Thompson DPRINT1("NtfsOpenFile(%p, %p, %S, %s, %p)\n", 258032be029STrevor Thompson DeviceExt, 259032be029STrevor Thompson FileObject, 260032be029STrevor Thompson FileName, 261032be029STrevor Thompson CaseSensitive ? "TRUE" : "FALSE", 262032be029STrevor Thompson FoundFCB); 263c2c66affSColin Finck 264c2c66affSColin Finck *FoundFCB = NULL; 265c2c66affSColin Finck 266c2c66affSColin Finck if (FileObject->RelatedFileObject) 267c2c66affSColin Finck { 268c2c66affSColin Finck DPRINT("Converting relative filename to absolute filename\n"); 269c2c66affSColin Finck 270c2c66affSColin Finck Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject, 271c2c66affSColin Finck FileName, 272c2c66affSColin Finck &AbsFileName); 273c2c66affSColin Finck if (AbsFileName) FileName = AbsFileName; 274c2c66affSColin Finck if (!NT_SUCCESS(Status)) 275c2c66affSColin Finck { 276c2c66affSColin Finck return Status; 277c2c66affSColin Finck } 278c2c66affSColin Finck } 279c2c66affSColin Finck 280c2c66affSColin Finck //FIXME: Get canonical path name (remove .'s, ..'s and extra separators) 281c2c66affSColin Finck 282c2c66affSColin Finck DPRINT("PathName to open: %S\n", FileName); 283c2c66affSColin Finck 284c2c66affSColin Finck /* try first to find an existing FCB in memory */ 285c2c66affSColin Finck DPRINT("Checking for existing FCB in memory\n"); 286c2c66affSColin Finck Fcb = NtfsGrabFCBFromTable(DeviceExt, 287c2c66affSColin Finck FileName); 288c2c66affSColin Finck if (Fcb == NULL) 289c2c66affSColin Finck { 290c2c66affSColin Finck DPRINT("No existing FCB found, making a new one if file exists.\n"); 291c2c66affSColin Finck Status = NtfsGetFCBForFile(DeviceExt, 292c2c66affSColin Finck &ParentFcb, 293c2c66affSColin Finck &Fcb, 294032be029STrevor Thompson FileName, 295032be029STrevor Thompson CaseSensitive); 296c2c66affSColin Finck if (ParentFcb != NULL) 297c2c66affSColin Finck { 298c2c66affSColin Finck NtfsReleaseFCB(DeviceExt, 299c2c66affSColin Finck ParentFcb); 300c2c66affSColin Finck } 301c2c66affSColin Finck 302c2c66affSColin Finck if (!NT_SUCCESS(Status)) 303c2c66affSColin Finck { 304c2c66affSColin Finck DPRINT("Could not make a new FCB, status: %x\n", Status); 305c2c66affSColin Finck 306c2c66affSColin Finck if (AbsFileName) 30739a06faeSTrevor Thompson ExFreePoolWithTag(AbsFileName, TAG_NTFS); 308c2c66affSColin Finck 309c2c66affSColin Finck return Status; 310c2c66affSColin Finck } 311c2c66affSColin Finck } 312c2c66affSColin Finck 313c2c66affSColin Finck DPRINT("Attaching FCB to fileObject\n"); 314c2c66affSColin Finck Status = NtfsAttachFCBToFileObject(DeviceExt, 315c2c66affSColin Finck Fcb, 316c2c66affSColin Finck FileObject); 317c2c66affSColin Finck 318c2c66affSColin Finck if (AbsFileName) 319c2c66affSColin Finck ExFreePool(AbsFileName); 320c2c66affSColin Finck 321c2c66affSColin Finck *FoundFCB = Fcb; 322c2c66affSColin Finck 323c2c66affSColin Finck return Status; 324c2c66affSColin Finck } 325c2c66affSColin Finck 326c2c66affSColin Finck 327c2c66affSColin Finck /* 328c2c66affSColin Finck * FUNCTION: Opens a file 329c2c66affSColin Finck */ 330c2c66affSColin Finck static 331c2c66affSColin Finck NTSTATUS 332c2c66affSColin Finck NtfsCreateFile(PDEVICE_OBJECT DeviceObject, 33398ddf610STrevor Thompson PNTFS_IRP_CONTEXT IrpContext) 334c2c66affSColin Finck { 335c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt; 336c2c66affSColin Finck PIO_STACK_LOCATION Stack; 337c2c66affSColin Finck PFILE_OBJECT FileObject; 338c2c66affSColin Finck ULONG RequestedDisposition; 339c2c66affSColin Finck ULONG RequestedOptions; 340c2c66affSColin Finck PNTFS_FCB Fcb = NULL; 341c2c66affSColin Finck // PWSTR FileName; 342c2c66affSColin Finck NTSTATUS Status; 343c2c66affSColin Finck UNICODE_STRING FullPath; 34498ddf610STrevor Thompson PIRP Irp = IrpContext->Irp; 345c2c66affSColin Finck 34698ddf610STrevor Thompson DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, IrpContext); 347c2c66affSColin Finck 348c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension; 349c2c66affSColin Finck ASSERT(DeviceExt); 350c2c66affSColin Finck Stack = IoGetCurrentIrpStackLocation(Irp); 351c2c66affSColin Finck ASSERT(Stack); 352c2c66affSColin Finck 353c2c66affSColin Finck RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); 354c2c66affSColin Finck RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; 355c2c66affSColin Finck // PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; 356c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE && 357c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 358c2c66affSColin Finck { 359c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 360c2c66affSColin Finck } 361c2c66affSColin Finck 362c2c66affSColin Finck /* Deny create if the volume is locked */ 363c2c66affSColin Finck if (DeviceExt->Flags & VCB_VOLUME_LOCKED) 364c2c66affSColin Finck { 365c2c66affSColin Finck return STATUS_ACCESS_DENIED; 366c2c66affSColin Finck } 367c2c66affSColin Finck 368c2c66affSColin Finck FileObject = Stack->FileObject; 369c2c66affSColin Finck 370c2c66affSColin Finck if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID) 371c2c66affSColin Finck { 372c2c66affSColin Finck ULONGLONG MFTId; 373c2c66affSColin Finck 374c2c66affSColin Finck if (FileObject->FileName.Length != sizeof(ULONGLONG)) 375c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 376c2c66affSColin Finck 377c2c66affSColin Finck MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK; 378935fcd1bSTrevor Thompson if (MFTId < NTFS_FILE_FIRST_USER_FILE) 379c2c66affSColin Finck { 380c2c66affSColin Finck Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb); 381c2c66affSColin Finck } 382c2c66affSColin Finck else 383c2c66affSColin Finck { 384c2c66affSColin Finck Status = NtfsMoonWalkID(DeviceExt, MFTId, &FullPath); 385c2c66affSColin Finck } 386c2c66affSColin Finck 387c2c66affSColin Finck if (!NT_SUCCESS(Status)) 388c2c66affSColin Finck { 389c2c66affSColin Finck return Status; 390c2c66affSColin Finck } 391c2c66affSColin Finck 392c2c66affSColin Finck DPRINT1("Open by ID: %I64x -> %wZ\n", (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK, &FullPath); 393c2c66affSColin Finck } 394c2c66affSColin Finck 395c2c66affSColin Finck /* This a open operation for the volume itself */ 396c2c66affSColin Finck if (FileObject->FileName.Length == 0 && 397c2c66affSColin Finck (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL)) 398c2c66affSColin Finck { 399c2c66affSColin Finck if (RequestedDisposition != FILE_OPEN && 400c2c66affSColin Finck RequestedDisposition != FILE_OPEN_IF) 401c2c66affSColin Finck { 402c2c66affSColin Finck return STATUS_ACCESS_DENIED; 403c2c66affSColin Finck } 404c2c66affSColin Finck 405c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE) 406c2c66affSColin Finck { 407c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY; 408c2c66affSColin Finck } 409c2c66affSColin Finck 410c2c66affSColin Finck NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject); 411c2c66affSColin Finck DeviceExt->VolumeFcb->RefCount++; 412c2c66affSColin Finck 413c2c66affSColin Finck Irp->IoStatus.Information = FILE_OPENED; 414c2c66affSColin Finck return STATUS_SUCCESS; 415c2c66affSColin Finck } 416c2c66affSColin Finck 417c2c66affSColin Finck if (Fcb == NULL) 418c2c66affSColin Finck { 419c2c66affSColin Finck Status = NtfsOpenFile(DeviceExt, 420c2c66affSColin Finck FileObject, 421c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? FullPath.Buffer : FileObject->FileName.Buffer), 4222dc49385STrevor Thompson BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE), 423c2c66affSColin Finck &Fcb); 424c2c66affSColin Finck 425c2c66affSColin Finck if (RequestedOptions & FILE_OPEN_BY_FILE_ID) 426c2c66affSColin Finck { 427c2c66affSColin Finck ExFreePoolWithTag(FullPath.Buffer, TAG_NTFS); 428c2c66affSColin Finck } 429c2c66affSColin Finck } 430c2c66affSColin Finck 431c2c66affSColin Finck if (NT_SUCCESS(Status)) 432c2c66affSColin Finck { 433c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE) 434c2c66affSColin Finck { 435c2c66affSColin Finck Irp->IoStatus.Information = FILE_EXISTS; 436c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 437c2c66affSColin Finck return STATUS_OBJECT_NAME_COLLISION; 438c2c66affSColin Finck } 439c2c66affSColin Finck 440c2c66affSColin Finck if (RequestedOptions & FILE_NON_DIRECTORY_FILE && 441c2c66affSColin Finck NtfsFCBIsDirectory(Fcb)) 442c2c66affSColin Finck { 443c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 444c2c66affSColin Finck return STATUS_FILE_IS_A_DIRECTORY; 445c2c66affSColin Finck } 446c2c66affSColin Finck 447c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE && 448c2c66affSColin Finck !NtfsFCBIsDirectory(Fcb)) 449c2c66affSColin Finck { 450c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 451c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY; 452c2c66affSColin Finck } 453c2c66affSColin Finck 454c2c66affSColin Finck /* 455c2c66affSColin Finck * If it is a reparse point & FILE_OPEN_REPARSE_POINT, then allow opening it 456c2c66affSColin Finck * as a normal file. 457c2c66affSColin Finck * Otherwise, attempt to read reparse data and hand them to the Io manager 458c2c66affSColin Finck * with status reparse to force a reparse. 459c2c66affSColin Finck */ 460c2c66affSColin Finck if (NtfsFCBIsReparsePoint(Fcb) && 461c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_REPARSE_POINT) != FILE_OPEN_REPARSE_POINT)) 462c2c66affSColin Finck { 463c2c66affSColin Finck PREPARSE_DATA_BUFFER ReparseData = NULL; 464c2c66affSColin Finck 465c2c66affSColin Finck Status = NtfsReadFCBAttribute(DeviceExt, Fcb, 466c2c66affSColin Finck AttributeReparsePoint, L"", 0, 467c2c66affSColin Finck (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer); 468c2c66affSColin Finck if (NT_SUCCESS(Status)) 469c2c66affSColin Finck { 470c2c66affSColin Finck ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 471c2c66affSColin Finck if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) 472c2c66affSColin Finck { 473c2c66affSColin Finck Status = STATUS_REPARSE; 474c2c66affSColin Finck } 475c2c66affSColin Finck else 476c2c66affSColin Finck { 477c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 478c2c66affSColin Finck ExFreePoolWithTag(ReparseData, TAG_NTFS); 479c2c66affSColin Finck } 480c2c66affSColin Finck } 481c2c66affSColin Finck 482c2c66affSColin Finck Irp->IoStatus.Information = ((Status == STATUS_REPARSE) ? ReparseData->ReparseTag : 0); 483c2c66affSColin Finck 484c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 485c2c66affSColin Finck return Status; 486c2c66affSColin Finck } 487c2c66affSColin Finck 488c2c66affSColin Finck if (RequestedDisposition == FILE_OVERWRITE || 489c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF || 490c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 491c2c66affSColin Finck { 49284a1280fSTrevor Thompson PFILE_RECORD_HEADER fileRecord = NULL; 49384a1280fSTrevor Thompson PNTFS_ATTR_CONTEXT dataContext = NULL; 49484a1280fSTrevor Thompson ULONG DataAttributeOffset; 49584a1280fSTrevor Thompson LARGE_INTEGER Zero; 49684a1280fSTrevor Thompson Zero.QuadPart = 0; 49784a1280fSTrevor Thompson 498037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport) 499037d8820STrevor Thompson { 500037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n"); 501037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject); 502037d8820STrevor Thompson return STATUS_ACCESS_DENIED; 503037d8820STrevor Thompson } 504037d8820STrevor Thompson 50584a1280fSTrevor Thompson // TODO: check for appropriate access 50684a1280fSTrevor Thompson 50784a1280fSTrevor Thompson ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE); 50884a1280fSTrevor Thompson 50984a1280fSTrevor Thompson fileRecord = ExAllocatePoolWithTag(NonPagedPool, 51084a1280fSTrevor Thompson Fcb->Vcb->NtfsInfo.BytesPerFileRecord, 51184a1280fSTrevor Thompson TAG_NTFS); 51284a1280fSTrevor Thompson if (fileRecord) 51384a1280fSTrevor Thompson { 51484a1280fSTrevor Thompson 51584a1280fSTrevor Thompson Status = ReadFileRecord(Fcb->Vcb, 51684a1280fSTrevor Thompson Fcb->MFTIndex, 51784a1280fSTrevor Thompson fileRecord); 51884a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 51984a1280fSTrevor Thompson goto DoneOverwriting; 52084a1280fSTrevor Thompson 52184a1280fSTrevor Thompson // find the data attribute and set it's length to 0 (TODO: Handle Alternate Data Streams) 52284a1280fSTrevor Thompson Status = FindAttribute(Fcb->Vcb, fileRecord, AttributeData, L"", 0, &dataContext, &DataAttributeOffset); 52384a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 52484a1280fSTrevor Thompson goto DoneOverwriting; 52584a1280fSTrevor Thompson 52684a1280fSTrevor Thompson Status = SetAttributeDataLength(FileObject, Fcb, dataContext, DataAttributeOffset, fileRecord, &Zero); 52784a1280fSTrevor Thompson } 52884a1280fSTrevor Thompson else 52984a1280fSTrevor Thompson { 53084a1280fSTrevor Thompson Status = STATUS_NO_MEMORY; 53184a1280fSTrevor Thompson } 53284a1280fSTrevor Thompson 53384a1280fSTrevor Thompson DoneOverwriting: 53484a1280fSTrevor Thompson if (fileRecord) 535e0048b13STrevor Thompson ExFreePoolWithTag(fileRecord, TAG_NTFS); 53684a1280fSTrevor Thompson if (dataContext) 53784a1280fSTrevor Thompson ReleaseAttributeContext(dataContext); 53884a1280fSTrevor Thompson 53984a1280fSTrevor Thompson ExReleaseResourceLite(&(Fcb->MainResource)); 54084a1280fSTrevor Thompson 54184a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 54284a1280fSTrevor Thompson { 543c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 54484a1280fSTrevor Thompson return Status; 54584a1280fSTrevor Thompson } 54684a1280fSTrevor Thompson 54784a1280fSTrevor Thompson if (RequestedDisposition == FILE_SUPERSEDE) 54884a1280fSTrevor Thompson { 54984a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_SUPERSEDED; 55084a1280fSTrevor Thompson } 55184a1280fSTrevor Thompson else 55284a1280fSTrevor Thompson { 55384a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_OVERWRITTEN; 55484a1280fSTrevor Thompson } 555c2c66affSColin Finck } 556c2c66affSColin Finck } 557c2c66affSColin Finck else 558c2c66affSColin Finck { 55958a13831STrevor Thompson /* HUGLY HACK: Can't create new files yet... */ 560c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE || 561c2c66affSColin Finck RequestedDisposition == FILE_OPEN_IF || 562c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF || 563c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 564c2c66affSColin Finck { 565037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport) 566037d8820STrevor Thompson { 567037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n"); 568037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject); 569037d8820STrevor Thompson return STATUS_ACCESS_DENIED; 570037d8820STrevor Thompson } 571037d8820STrevor Thompson 572*c63e7e54STrevor Thompson // We can't create directories yet 573*c63e7e54STrevor Thompson if (RequestedOptions & FILE_DIRECTORY_FILE) 574*c63e7e54STrevor Thompson { 575*c63e7e54STrevor Thompson DPRINT1("FIXME: Folder creation is still TODO!\n"); 576*c63e7e54STrevor Thompson return STATUS_NOT_IMPLEMENTED; 577*c63e7e54STrevor Thompson } 578*c63e7e54STrevor Thompson 5790409b316STrevor Thompson // Create the file record on disk 580948e9190STrevor Thompson Status = NtfsCreateFileRecord(DeviceExt, 581948e9190STrevor Thompson FileObject, 58239a06faeSTrevor Thompson BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE), 583948e9190STrevor Thompson BooleanFlagOn(IrpContext->Flags,IRPCONTEXT_CANWAIT)); 584e0048b13STrevor Thompson if (!NT_SUCCESS(Status)) 585e0048b13STrevor Thompson { 586e0048b13STrevor Thompson DPRINT1("ERROR: Couldn't create file record!\n"); 587e0048b13STrevor Thompson return Status; 588e0048b13STrevor Thompson } 5890409b316STrevor Thompson 5909cef4254STrevor Thompson // Before we open the file we just created, we need to change the disposition (upper 8 bits of ULONG) 5919cef4254STrevor Thompson // from create to open, since we already created the file 5929cef4254STrevor Thompson Stack->Parameters.Create.Options = (ULONG)FILE_OPEN << 24 | RequestedOptions; 5939cef4254STrevor Thompson 5949cef4254STrevor Thompson // Now we should be able to open the file using NtfsCreateFile() 5959cef4254STrevor Thompson Status = NtfsCreateFile(DeviceObject, IrpContext); 5969cef4254STrevor Thompson if (NT_SUCCESS(Status)) 5979cef4254STrevor Thompson { 5989cef4254STrevor Thompson // We need to change Irp->IoStatus.Information to reflect creation 5999cef4254STrevor Thompson Irp->IoStatus.Information = FILE_CREATED; 6009cef4254STrevor Thompson } 6019cef4254STrevor Thompson return Status; 602c2c66affSColin Finck } 603c2c66affSColin Finck } 604c2c66affSColin Finck 605c2c66affSColin Finck if (NT_SUCCESS(Status)) 606c2c66affSColin Finck { 607c2c66affSColin Finck Fcb->OpenHandleCount++; 608c2c66affSColin Finck DeviceExt->OpenHandleCount++; 609c2c66affSColin Finck } 610c2c66affSColin Finck 611c2c66affSColin Finck /* 612c2c66affSColin Finck * If the directory containing the file to open doesn't exist then 613c2c66affSColin Finck * fail immediately 614c2c66affSColin Finck */ 615c2c66affSColin Finck Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0; 616c2c66affSColin Finck 617c2c66affSColin Finck return Status; 618c2c66affSColin Finck } 619c2c66affSColin Finck 620c2c66affSColin Finck 621c2c66affSColin Finck NTSTATUS 622c2c66affSColin Finck NtfsCreate(PNTFS_IRP_CONTEXT IrpContext) 623c2c66affSColin Finck { 624c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt; 625c2c66affSColin Finck NTSTATUS Status; 626c2c66affSColin Finck PDEVICE_OBJECT DeviceObject; 627c2c66affSColin Finck 628c2c66affSColin Finck DeviceObject = IrpContext->DeviceObject; 629c2c66affSColin Finck if (DeviceObject == NtfsGlobalData->DeviceObject) 630c2c66affSColin Finck { 631c2c66affSColin Finck /* DeviceObject represents FileSystem instead of logical volume */ 632c2c66affSColin Finck DPRINT("Opening file system\n"); 633c2c66affSColin Finck IrpContext->Irp->IoStatus.Information = FILE_OPENED; 634c2c66affSColin Finck return STATUS_SUCCESS; 635c2c66affSColin Finck } 636c2c66affSColin Finck 637c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension; 638c2c66affSColin Finck 639c2c66affSColin Finck if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT)) 640c2c66affSColin Finck { 641c2c66affSColin Finck return NtfsMarkIrpContextForQueue(IrpContext); 642c2c66affSColin Finck } 643c2c66affSColin Finck 644c2c66affSColin Finck ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, 645c2c66affSColin Finck TRUE); 646c2c66affSColin Finck Status = NtfsCreateFile(DeviceObject, 64798ddf610STrevor Thompson IrpContext); 648c2c66affSColin Finck ExReleaseResourceLite(&DeviceExt->DirResource); 649c2c66affSColin Finck 650c2c66affSColin Finck return Status; 651c2c66affSColin Finck } 652c2c66affSColin Finck 6530409b316STrevor Thompson /** 6540409b316STrevor Thompson * @name NtfsCreateFileRecord() 6550409b316STrevor Thompson * @implemented 6560409b316STrevor Thompson * 657e0048b13STrevor Thompson * Creates a file record and saves it to the MFT. Adds the filename attribute of the 658e0048b13STrevor Thompson * created file to the parent directory's index. 6590409b316STrevor Thompson * 6600409b316STrevor Thompson * @param DeviceExt 6610409b316STrevor Thompson * Points to the target disk's DEVICE_EXTENSION 6620409b316STrevor Thompson * 6630409b316STrevor Thompson * @param FileObject 6640409b316STrevor Thompson * Pointer to a FILE_OBJECT describing the file to be created 6650409b316STrevor Thompson * 66698ddf610STrevor Thompson * @param CanWait 66798ddf610STrevor Thompson * Boolean indicating if the function is allowed to wait for exclusive access to the master file table. 66898ddf610STrevor Thompson * This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged. 66998ddf610STrevor Thompson * 6700409b316STrevor Thompson * @return 6710409b316STrevor Thompson * STATUS_SUCCESS on success. 6720409b316STrevor Thompson * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record. 67398ddf610STrevor Thompson * STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but 67498ddf610STrevor Thompson * couldn't get immediate, exclusive access to it. 6750409b316STrevor Thompson */ 6760409b316STrevor Thompson NTSTATUS 6770409b316STrevor Thompson NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt, 67898ddf610STrevor Thompson PFILE_OBJECT FileObject, 679948e9190STrevor Thompson BOOLEAN CaseSensitive, 68098ddf610STrevor Thompson BOOLEAN CanWait) 6810409b316STrevor Thompson { 6820409b316STrevor Thompson NTSTATUS Status = STATUS_SUCCESS; 6830409b316STrevor Thompson PFILE_RECORD_HEADER FileRecord; 6840409b316STrevor Thompson PNTFS_ATTR_RECORD NextAttribute; 685e0048b13STrevor Thompson PFILENAME_ATTRIBUTE FilenameAttribute; 686e0048b13STrevor Thompson ULONGLONG ParentMftIndex; 687e0048b13STrevor Thompson ULONGLONG FileMftIndex; 6880409b316STrevor Thompson 689948e9190STrevor Thompson DPRINT1("NtfsCreateFileRecord(%p, %p, %s, %s)\n", 690948e9190STrevor Thompson DeviceExt, 691948e9190STrevor Thompson FileObject, 692948e9190STrevor Thompson CaseSensitive ? "TRUE" : "FALSE", 693948e9190STrevor Thompson CanWait ? "TRUE" : "FALSE"); 6949ab86116STrevor Thompson 6950409b316STrevor Thompson // allocate memory for file record 6960409b316STrevor Thompson FileRecord = ExAllocatePoolWithTag(NonPagedPool, 6970409b316STrevor Thompson DeviceExt->NtfsInfo.BytesPerFileRecord, 6980409b316STrevor Thompson TAG_NTFS); 6990409b316STrevor Thompson if (!FileRecord) 7000409b316STrevor Thompson { 7010409b316STrevor Thompson DPRINT1("ERROR: Unable to allocate memory for file record!\n"); 7020409b316STrevor Thompson return STATUS_INSUFFICIENT_RESOURCES; 7030409b316STrevor Thompson } 7040409b316STrevor Thompson 7050409b316STrevor Thompson RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord); 7060409b316STrevor Thompson 7070409b316STrevor Thompson FileRecord->Ntfs.Type = NRH_FILE_TYPE; 7080409b316STrevor Thompson 7090409b316STrevor Thompson // calculate USA offset and count 7100409b316STrevor Thompson FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG); 7110409b316STrevor Thompson 7120409b316STrevor Thompson // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses 7130409b316STrevor Thompson FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord; 7140409b316STrevor Thompson FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1; 7150409b316STrevor Thompson 7160409b316STrevor Thompson // setup other file record fields 7170409b316STrevor Thompson FileRecord->SequenceNumber = 1; 7180409b316STrevor Thompson FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount); 7195ab24a5aSTrevor Thompson FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, ATTR_RECORD_ALIGNMENT); 7200409b316STrevor Thompson FileRecord->Flags = FRH_IN_USE; 7210409b316STrevor Thompson FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2; 7220409b316STrevor Thompson 7230409b316STrevor Thompson // find where the first attribute will be added 7240409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); 7250409b316STrevor Thompson 7260409b316STrevor Thompson // mark the (temporary) end of the file-record 7270409b316STrevor Thompson NextAttribute->Type = AttributeEnd; 7280409b316STrevor Thompson NextAttribute->Length = FILE_RECORD_END; 7290409b316STrevor Thompson 7300409b316STrevor Thompson // add first attribute, $STANDARD_INFORMATION 7310409b316STrevor Thompson AddStandardInformation(FileRecord, NextAttribute); 7320409b316STrevor Thompson 7330409b316STrevor Thompson // advance NextAttribute pointer to the next attribute 7340409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length); 7350409b316STrevor Thompson 7360409b316STrevor Thompson // Add the $FILE_NAME attribute 737948e9190STrevor Thompson AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &ParentMftIndex); 738e0048b13STrevor Thompson 739e0048b13STrevor Thompson // save a pointer to the filename attribute 740e0048b13STrevor Thompson FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute + NextAttribute->Resident.ValueOffset); 7410409b316STrevor Thompson 7420409b316STrevor Thompson // advance NextAttribute pointer to the next attribute 7430409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length); 7440409b316STrevor Thompson 7450409b316STrevor Thompson // add the $DATA attribute 7460409b316STrevor Thompson AddData(FileRecord, NextAttribute); 7470409b316STrevor Thompson 7480409b316STrevor Thompson // dump file record in memory (for debugging) 7490409b316STrevor Thompson NtfsDumpFileRecord(DeviceExt, FileRecord); 7500409b316STrevor Thompson 7510409b316STrevor Thompson // Now that we've built the file record in memory, we need to store it in the MFT. 75298ddf610STrevor Thompson Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait); 753e0048b13STrevor Thompson if (NT_SUCCESS(Status)) 754e0048b13STrevor Thompson { 755e0048b13STrevor Thompson // The highest 2 bytes should be the sequence number, unless the parent happens to be root 756e0048b13STrevor Thompson if (FileMftIndex == NTFS_FILE_ROOT) 757e0048b13STrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48); 758e0048b13STrevor Thompson else 759e0048b13STrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber << 48); 760e0048b13STrevor Thompson 761e0048b13STrevor Thompson DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex); 762e0048b13STrevor Thompson 763e0048b13STrevor Thompson // Add the filename attribute to the filename-index of the parent directory 764e0048b13STrevor Thompson Status = NtfsAddFilenameToDirectory(DeviceExt, 765e0048b13STrevor Thompson ParentMftIndex, 766e0048b13STrevor Thompson FileMftIndex, 76754f5c3b6STrevor Thompson FilenameAttribute, 76854f5c3b6STrevor Thompson CaseSensitive); 769e0048b13STrevor Thompson } 7700409b316STrevor Thompson 7710409b316STrevor Thompson ExFreePoolWithTag(FileRecord, TAG_NTFS); 7720409b316STrevor Thompson 7730409b316STrevor Thompson return Status; 7740409b316STrevor Thompson } 7750409b316STrevor Thompson 776c2c66affSColin Finck /* EOF */ 777